当前位置: 首页 > news >正文

电子商务网站设计中影响客户体验的元素有中国万网域名注册

电子商务网站设计中影响客户体验的元素有,中国万网域名注册,中国最新军事新闻 今天,怎么做网站弹幕前言 现代前端对速度的追求已经进入二进制工具时代,Rust 开发成为每个人的必修课。 一般我们将常见的前端 Rust 开发分为以下几类,难度由上至下递增: 开发 wasm 。 开发 swc 插件。 开发代码处理工具。 我们将默认读者具备最简单的 Rus…

前言

现代前端对速度的追求已经进入二进制工具时代,Rust 开发成为每个人的必修课。

一般我们将常见的前端 Rust 开发分为以下几类,难度由上至下递增:

  1. 开发 wasm 。

  2. 开发 swc 插件。

  3. 开发代码处理工具。

我们将默认读者具备最简单的 Rust 知识,进行快速入门介绍。

正文

开发 wasm

意义

开发 wasm 的意义在于利用浏览器运行 wasm 的优势,在 wasm 中进行大量复杂的计算、音视频、图像处理等,当你有此类需求,可以优先考虑使用 Rust 开发 wasm 分发至浏览器。

初始化

我们使用 wasm-pack 构建 wasm ,参考 wasm-pack > Quickstart 得到一个模板起始项目。

实战 case

使用 tsify 支持输出结构体的 TypeScript 类型,实现一个简单的加法运算:

# Cargo.toml 确保你含有这些依赖
[dependencies]
serde = { version = "1.0.163", features = ["derive"] }
tsify = "0.4.5"
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
use tsify::Tsify;#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Rect {pub width: u32,pub height: u32
}#[wasm_bindgen]
pub fn plus(mut rect: Rect) -> Rect {rect.width += rect.height;rect
}

构建

  # devwasm-pack build --verbose --out-dir pkg --out-name index --dev# releasewasm-pack build --verbose --out-dir pkg --out-name index --release

这将在当前目录的 pkg/* 下生成 wasm 产物与 index.js 等胶水代码,导入 index.js 便即开即用,非常方便。

运行 wasm

为了支持直接导入 .wasm 文件,我们需要 webpack 5 的 asyncWebAssembly 特性支持,此处以在 Umi 4 项目中调试为例,创建一个 Umi 4 Simple 模板项目:

  pnpm create umi wasm-demo

参考 FAQ > 怎么用 WebAssembly 配置开启 wasm 支持:

// .umirc.tsexport default {chainWebpack(config) {config.set('experiments', {...config.get('experiments'),asyncWebAssembly: true})const REG = /\.wasm$/config.module.rule('asset').exclude.add(REG).end();config.module.rule('wasm').test(REG).exclude.add(/node_modules/).end().type('webassembly/async').end()},
}

之后便可在项目中直接导入刚刚打包好,在 pkg/* 的 wasm 即开即用:

import * as wasm from './path/to/pkg'
const ret = wasm.plus({width: 1,height: 2,
})
// { width: 3, height: 2 }
console.log('ret: ', ret);

注:

  1. 由于 wasm 文件可能较大,当你需要优化时,可将使用 .wasm 的组件手动 React.lazy(() => import('./Component')) 拆包,之后在 useEffect 中懒加载 await import('./path/to/pkg')

  2. 对于非 Umi 4 的 webpack 5 项目,请自行开启 experiments.asyncWebAssembly 即可一键支持 wasm 导入。

缺点

由于当下浏览器和 PC 设备性能已足够强大,更多场合下,运行 wasm 进行数据计算,传递数据花费的时间将 远远超出使用 JavaScript 进行同逻辑计算的时间

所以除音视频场景外,你很可能不需要 wasm ,而是优先考虑使用 Worker 等优化策略。

开发 swc 插件

意义

现代前端高效构建往往将 babel 替代为 swc 化,为了替代 babel 插件实现代码转换,开发 swc 插件成为了一门必修课。

初始化

参考 swc > Create a project ,我们用 swc 脚手架初始化得到一个插件的模板起始项目。

实战 case

我们编写一个最简单的功能,将所有的 react 导入转换为 preact

# Cargo.toml 确保你含有这些依赖
[dependencies]
serde = "1.0.163"
serde_json = "1.0.96"
swc_core = { version = "0.76.39", features = ["ecma_plugin_transform"] }
use swc_core::ecma::{ast::{Program, ImportDecl, ImportSpecifier},visit::{as_folder, FoldWith, VisitMut, VisitMutWith},
};
use swc_core::plugin::{plugin_transform, proxies::TransformPluginProgramMetadata};
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
pub struct TransformPluginConfig {from: String,to: String,
}pub struct TransformVisitor {config: TransformPluginConfig,
}impl VisitMut for TransformVisitor {fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) {n.visit_mut_children_with(self);if n.specifiers.len() == 1 {if let ImportSpecifier::Default(_) = n.specifiers[0] {if n.src.value == self.config.from {n.src = Box::new(self.config.to.clone().into());}}}}
}#[plugin_transform]
pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program {let config = serde_json::from_str(&metadata.get_transform_plugin_config().unwrap()).expect("invalid config");program.fold_with(&mut as_folder(TransformVisitor { config }))
}

在编写过程中,以下文档可供参考:

  • Swc :Implementing a plugin

  • Swc :Rust docs

构建

  # devcargo build --target wasm32-wasi# releasecargo build --target wasm32-wasi --release

通过构建,你可以在当前目录下得到 wasm 形式的 swc 插件产物。

运行 swc 插件

import { transformSync } from '@swc/core'const transform = async () => {const { code } = transformSync(`
import React from 'react'`,{jsc: {experimental: {plugins: [[require.resolve('./target/wasm32-wasi/debug/my_first_plugin.wasm'),{from: 'react',to: 'preact',},],],},parser: {syntax: 'typescript',dynamicImport: true,tsx: true,},target: 'es2015',minify: {compress: false,mangle: false,},transform: {react: {runtime: 'automatic',throwIfNamespace: true,development: true,useBuiltins: true,},},},module: {type: 'es6',ignoreDynamic: true,},minify: false,isModule: true,sourceMaps: false,filename: 'index.tsx',})// import React from 'preact'console.log('code: ', code)
}transform()

缺点

为了避免多平台差异,我们分发了 wasm32-wasi 目标的 wasm 包,好处是只需构建一次即可全平台通用,缺点是产物较大,同时 wasm 运行速度不如 .node ;但现代前端已无需担心只在本地编译阶段使用的包大小,如 Nextjs 单包依赖已达 40 M 以上,TypeScript 20 M ,你可以无需关心产物体积问题。

至此,我们介绍了如何借助 swc 插件实现 babel 插件的替代,在下文中,我们将继续深入,真正构建多平台分发的二进制包,同时不会做过多细节介绍,推荐只学习到此处为止

开发代码处理工具

意义

目前最主流的前端 Rust 开发即是借助 Swc 来解析 JavaScript 、TypeScript 代码,从而实现代码信息提取、转换、编译等,我们会将 Rust 编译为 Node addon .node 文件,以获得远比 wasm 更快的运行速度。

初始化

使用 napi-rs 构建 ,参考 napi > Create project 得到一个模板起始项目。

实战 case

此处同样我们实现一个:将所有 react 导入转换为 preact 的需求,所需要的依赖与模板代码如下:

# Cargo.toml 确保你含有这些依赖
[dependencies]
napi = { version = "2.12.2", default-features = false, features = ["napi4", "error_anyhow"] }
napi-derive = "2.12.2"
swc_common = { version = "0.31.12", features = ["sourcemap"] }
swc_ecmascript = { version = "0.228.27", features = ["parser", "visit", "codegen"] }
#[macro_use]
extern crate napi_derive;use std::path::{Path, PathBuf};
use std::str;use swc_common::comments::SingleThreadedComments;
use swc_common::{sync::Lrc, FileName, Globals, SourceMap};
use swc_ecmascript::ast;
use swc_ecmascript::codegen::text_writer::JsWriter;
use swc_ecmascript::parser::lexer::Lexer;
use swc_ecmascript::parser::{EsConfig, Parser, StringInput, Syntax, TsConfig};
use swc_ecmascript::visit::{VisitMut, VisitMutWith};#[napi]
pub fn transform(code: String, options: ImportChange) -> String {let is_jsx = true;let is_typescript = true;let filename_path_buf = PathBuf::from("filename.tsx");let syntax = if is_typescript {Syntax::Typescript(TsConfig {tsx: is_jsx,decorators: true,..Default::default()})} else {Syntax::Es(EsConfig {jsx: is_jsx,export_default_from: true,..Default::default()})};let source_map = Lrc::new(SourceMap::default());let source_file = source_map.new_source_file(FileName::Real(filename_path_buf.clone()),code.clone().into(),);let comments = SingleThreadedComments::default();let lexer = Lexer::new(syntax,Default::default(),StringInput::from(&*source_file),Some(&comments),);let mut parser = Parser::new_from(lexer);let mut module = parser.parse_module().expect("failed to parse module");swc_common::GLOBALS.set(&Globals::new(), || {let mut visitor = options;module.visit_mut_with(&mut visitor);});let (code, _map) = emit_source_code(Lrc::clone(&source_map),Some(comments),&module,None,false,).unwrap();code
}#[napi(object)]
pub struct ImportChange {pub from: String,pub to: String,
}impl ImportChange {pub fn new(from: String, to: String) -> Self {Self { from, to }}
}impl VisitMut for ImportChange {fn visit_mut_module_decl(&mut self, decl: &mut ast::ModuleDecl) {if let ast::ModuleDecl::Import(import_decl) = decl {if import_decl.src.value == self.from {import_decl.src = Box::new(self.to.clone().into());}}}
}pub fn emit_source_code(source_map: Lrc<SourceMap>,comments: Option<SingleThreadedComments>,program: &ast::Module,root_dir: Option<&Path>,source_maps: bool,
) -> Result<(String, Option<String>), napi::Error> {let mut src_map_buf = Vec::new();let mut buf = Vec::new();{let writer = Box::new(JsWriter::new(Lrc::clone(&source_map),"\n",&mut buf,if source_maps {Some(&mut src_map_buf)} else {None},));let config = swc_ecmascript::codegen::Config {minify: false,target: ast::EsVersion::latest(),ascii_only: false,omit_last_semi: false,};let mut emitter = swc_ecmascript::codegen::Emitter {cfg: config,comments: Some(&comments),cm: Lrc::clone(&source_map),wr: writer,};emitter.emit_module(program)?;}let mut map_buf = vec![];let emit_source_maps = if source_maps {let mut s = source_map.build_source_map(&src_map_buf);if let Some(root_dir) = root_dir {s.set_source_root(Some(root_dir.to_str().unwrap()));}s.to_writer(&mut map_buf).is_ok()} else {false};if emit_source_maps {Ok((unsafe { str::from_utf8_unchecked(&buf).to_string() },unsafe { Some(str::from_utf8_unchecked(&map_buf).to_string()) },))} else {Ok((unsafe { str::from_utf8_unchecked(&buf).to_string() }, None))}
}

构建

  # devnapi build --platform# releasenapi build --release

一般情况下,我们通常会分发至以下 9 个平台:

  "napi": {"triples": {"defaults": false,"additional": ["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-pc-windows-msvc","aarch64-pc-windows-msvc","x86_64-unknown-linux-gnu","aarch64-unknown-linux-gnu","x86_64-unknown-linux-musl","aarch64-unknown-linux-musl","armv7-unknown-linux-gnueabihf"]}}

通常本地只能编译自己平台的 .node 二进制文件,所以需要依赖 Github Actions CI 等云环境进行多平台的构建,并且在 CICD 中构造好 npm 包使用 Npm Token 发布,此部分内容往往是大量的模板代码与调试过程,请自行研究学习。

运行二进制包

import { transform } from './index'console.log(// import React from 'preact'transform(`import React from 'react'`,{ from: 'react', to: 'preact' })
)

直接导入 napi 生成的 index.js 胶水代码即可使用 .node 二进制包。

缺点

  1. 通过构建 .node 分发至不同平台是目前最高运行效率、最小下载体积的方法,但相对应需要手动管理所有 Rust 代码,且多平台构建也强依赖云环境,这提出了一些较高的要求。

  2. 随着对 napi / Rust 异步、并发编程 / Swc 的理解精进,你可以写出更高运行效率的代码,得到更快的执行速度。但最简单的代码依然够用,因为现代计算机性能已经足够快,1s 还是 10s 的争论没有意义。

  3. 在开发过程中,你可能会遇到各种 Rust 构建相关的问题,请自行研究并解决。

总结

本文对 Rust 浅尝辄止,如希望更有所作为,你可以通过不断精进 Rust ,组织出更优雅的代码结构,实现更高的执行效率。

前端 AST 人尽皆知,如同开发 Babel 插件一样,开发 Rust Swc 插件已然成为现代前端的必修课,文本推荐只入门至 Swc 插件为止,已经能应对绝大多数场景。

另外,对于性能上无需过多追求,由于计算机的性能已经过剩,不管是 wasm 还是 .node 速度都是很快的,秒级之争没有意义。

以上。

http://www.mmbaike.com/news/86419.html

相关文章:

  • 威海高区有没有建设局的网站搜索引擎推广排名
  • 什么是网站建设流程平面设计网站
  • 做线下活动的网站抖音seo排名软件
  • 爱企查企业信息查询官网北京seo推广优化
  • 南宁手机建站公司可以免费做网站推广的平台
  • php专业网站足球世界排名国家最新
  • 卢湾区网站建设制作网页广告调词平台多少钱
  • 深圳做网站联雅百度推广工作怎么样
  • 做游戏交易网站有哪些内容培训网站推荐
  • 温州联科网站建设简单的html网页制作
  • 手机百度网站证书过期沈阳全网推广公司哪家好
  • 选择一个域名进行网站建设前端开发
  • 公司网站建设情况说明书电商seo搜索引擎优化
  • 百度站长链接提交平台怎么申请自己的网络平台
  • 登封网站开发进入百度搜索网站
  • 网站备案 暂住证福州短视频seo方法
  • vps做网站 推广怎样在百度上发布广告
  • 临沂网站服务器价格淘宝关键词优化工具
  • 网站建设常态化工作机制四川网站seo
  • 南京建设银行官方网站app推广拉新
  • 龙华营销型网站费用广告竞价
  • 网站开发的业务需求分析sem推广是什么意思呢
  • 做仿站如何获取网站源码北京互联网公司排名
  • 旅游网站开发目的和意义如何在百度发布广告
  • 国外做无纺布的网站小米市场营销案例分析
  • .net建设网站步骤详解网络热词英语
  • 和平区网站制作台湾搜索引擎
  • 恶搞网站源码网上销售培训课程
  • 免费做网站有哪些家企业推广语
  • 上海营销型网站网络营销的核心是什么