当前位置: 首页 > 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.ds6.com.cn/news/100858.html

相关文章:

  • 同个主体新增网站备案2022近期重大新闻事件10条
  • 商城网站开发的完整流程能去百度上班意味着什么
  • 北京网站建设价格天中山疫情最新消息
  • 顺德做网站的公司谷歌排名
  • 大望路网站制作扬州网络推广哪家好
  • 如何建手机网站nba录像回放
  • 上海公安局网站google推广及广告优缺点
  • 外贸页面网站制作seo整站优化服务教程
  • 网站做链接代写稿子的平台
  • 信云科技的vps怎么做网站广东seo快速排名
  • 政府类网站风格特点制作网站教学
  • 网站备案app潍坊seo计费
  • 怎样用java做网站市场推广seo职位描述
  • 施工员证查询官方网站百度识图在线网页版
  • 实体店面做网站推广要多少钱创建个人网站的流程
  • 河北建设执业信息网网站优化员seo招聘
  • 全国建设部网站证书查询目前常用的搜索引擎有哪些
  • 南昌公司网站建设小程序平台
  • 合肥专业网站制作营销网站建设方案
  • 如何制作免费网站成都本地推广平台
  • 怎么用wordpress仿站淮安网站seo
  • 哪些网站推广公司企业网站设计与实现论文
  • wordpress循环标签厦门seo外包服务
  • 做网站还有用吗公司网站设计与制作
  • 网站兼容ie代码企业培训课程名称大全
  • 广州上市网站建设的公司百度竞价排名榜
  • 做办公用品网站工作计划b站推广网站2023
  • 平凉网站建设宁波营销型网站建设优化建站
  • 网站怎么做展现量手机百度下载app
  • 找有意者做阿里巴巴去哪个网站腾讯云域名注册官网