vault backup: 2026-11-07 16:33:44
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
虽然说只要高级语言能转换成 LLVM IR,就能被编译成 WebAssembly 字节码,官方也推荐c/c++的方式,但是让一个前端工程师去熟练使用c/c++显然是有点困难,那么TypeScript 的方式便是前端编写 WebAssembly 最佳选择。
|
||||
|
||||
要将TypeScript 编译为WebAssembly,就要用到[AssemblyScript](https://github.com/AssemblyScript)编译器了。
|
||||
|
||||
AssemblyScript使用Binaryen(Emscripten的WebAssembly后端)将严格类型化的TypeScript(基本的带有类型的JavaScript)编译为WebAssembly,虽然它提供了几种新的特定于WebAssembly的类型和内置函数,但它本身并不是一种真正的语言,而是一种编译器变体。 它生成精简的WebAssembly模块,只需要一个npm安装。
|
||||
|
||||
## 1.安装
|
||||
|
||||
推荐使用cnpm安装,npm太慢了。
|
||||
|
||||
1 cnpm install --save-dev AssemblyScript/assemblyscript
|
||||
|
||||
执行过程如下,安装完成之后只有一个node_modules文件夹
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 E:\Code\assembly>cnpm install --save-dev AssemblyScript/assemblyscript
|
||||
2 - [@AssemblyScript/assemblyscript] install from git github:AssemblyScript/assemblyscript, may be very slow, please keep patience
|
||||
3 √ Installed 1 packages
|
||||
4 √ Linked 15 latest versions
|
||||
5 √ Run 0 scripts
|
||||
6 Recently updated (since 2019-02-17): 1 packages (detail see file E:\Code\assembly\node_modules\.recently_updates.txt)
|
||||
7 √ All packages installed (14 packages installed from npm registry, 1 packages installed from git, used 1m(network 1m), speed 10.27kB/s, json 14(31.43kB), tarball 707.23kB)
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
## 2.创建项目
|
||||
|
||||
正确安装AssemblyScript后,它会提供一个名为asinit的小型实用工具来构建一个新项目,例如,在当前目录中:
|
||||
|
||||
1 npx asinit .
|
||||
|
||||
就像使用express初始化项目一样,执行过程如下
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 E:\Code\assembly>npx asinit .
|
||||
2 Version: 0.6.0
|
||||
3
|
||||
4 This command will make sure that the following files exist in the project 5 directory 'E:\Code\assembly':
|
||||
6
|
||||
7 ./assembly
|
||||
8 Directory holding the AssemblyScript sources being compiled to WebAssembly.
|
||||
9
|
||||
10 ./assembly/tsconfig.json
|
||||
11 TypeScript configuration inheriting recommended AssemblyScript settings.
|
||||
12
|
||||
13 ./assembly/index.ts
|
||||
14 Exemplary entry file being compiled to WebAssembly to get you started.
|
||||
15
|
||||
16 ./build
|
||||
17 Build artifact directory where compiled WebAssembly files are stored.
|
||||
18
|
||||
19 ./build/.gitignore
|
||||
20 Git configuration that excludes compiled binaries from source control.
|
||||
21
|
||||
22 ./index.js
|
||||
23 Main file loading the WebAssembly module and exporting its exports.
|
||||
24
|
||||
25 ./package.json
|
||||
26 Package info containing the necessary commands to compile to WebAssembly.
|
||||
27
|
||||
28 The command will try to update existing files to match the correct settings
|
||||
29 for this instance of the compiler in 'E:\Code\assembly\node_modules\_assemblyscript@0.6.0@assemblyscript'.
|
||||
30
|
||||
31 Do you want to proceed? [Y/n] y
|
||||
32
|
||||
33 - Making sure that the project directory exists...
|
||||
34 Exists: E:\Code\assembly
|
||||
35
|
||||
36 - Making sure that the 'assembly' directory exists...
|
||||
37 Created: E:\Code\assembly\assembly
|
||||
38
|
||||
39 - Making sure that 'assembly/tsconfig.json' is set up...
|
||||
40 Created: E:\Code\assembly\assembly\tsconfig.json
|
||||
41
|
||||
42 - Making sure that 'assembly/index.ts' exists...
|
||||
43 Created: E:\Code\assembly\assembly\index.ts
|
||||
44
|
||||
45 - Making sure that the 'build' directory exists...
|
||||
46 Created: E:\Code\assembly\build
|
||||
47
|
||||
48 - Making sure that 'build/.gitignore' is set up...
|
||||
49 Created: E:\Code\assembly\build\.gitignore
|
||||
50
|
||||
51 - Making sure that 'package.json' contains the build commands...
|
||||
52 Updated: E:\Code\assembly\package.json
|
||||
53
|
||||
54 - Making sure that 'index.js' exists...
|
||||
55 Created: E:\Code\assembly\index.js
|
||||
56
|
||||
57 Done!
|
||||
58
|
||||
59 To edit the entry file, open 'assembly/index.ts' in your editor of choice.
|
||||
60 Create as many additional files as necessary and use them as imports.
|
||||
61
|
||||
62 To build the entry file to WebAssembly when you are ready, run:
|
||||
63
|
||||
64 npm run asbuild
|
||||
65
|
||||
66 Running the command above creates the following binaries incl. their respective
|
||||
67 text format representations and source maps:
|
||||
68
|
||||
69 ./build/untouched.wasm
|
||||
70 ./build/untouched.wasm.map
|
||||
71 ./build/untouched.wat
|
||||
72
|
||||
73 ^ The untouched WebAssembly module as generated by the compiler.
|
||||
74 This one matches your sources exactly, without any optimizations.
|
||||
75
|
||||
76 ./build/optimized.wasm
|
||||
77 ./build/optimized.wasm.map
|
||||
78 ./build/optimized.wat
|
||||
79
|
||||
80 ^ The optimized WebAssembly module using default optimization settings (-O2s).
|
||||
81 You can change the optimization settings in 'package.json'.
|
||||
82
|
||||
83 Additional documentation is available at the AssemblyScript wiki:
|
||||
84
|
||||
85 https://github.com/AssemblyScript/assemblyscript/wiki
|
||||
86
|
||||
87 Have a nice day!
|
||||
88
|
||||
89 E:\Code\assembly>
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
完成的目录结构是这样的:
|
||||
|
||||
[](https://img2018.cnblogs.com/blog/1604637/201902/1604637-20190224233253174-1657805576.png)
|
||||
|
||||
目录结构含义:
|
||||
|
||||
assembly / index.ts上的示例性条目文件
|
||||
|
||||
index.js中的通用索引文件,用于加载已编译的二进制文件和必要的配置文件,如package.json和tsconfig.json
|
||||
|
||||
初始化后,只需在编码时使用现有的TypeScript工具,并使用编译器手动构建到WebAssembly,或者使用生成的构建任务:按照提示,运行以下命令:
|
||||
|
||||
1 npm run asbuild
|
||||
|
||||
build文件夹初始化只有一个.gitignore,该命令会在build文件夹中创建.wat与.wasm文件
|
||||
|
||||
以上只是构建一个示例项目,如果需要适合开发的安装,可以通过克隆GitHub存储库来实现:
|
||||
|
||||
1 $> git clone https://github.com/AssemblyScript/assemblyscript.git
|
||||
2 $> cd assemblyscript
|
||||
3 $> npm install
|
||||
4 $> npm link
|
||||
|
||||
请注意,编译器的新克隆将使用dist /中的分发文件,但它也可以在npm运行清理后直接通过ts节点运行源,这在开发中很有用。 也可以通过运行asc -v来检查这种情况(如果它声明-dev则运行源)。
|
||||
|
||||
## 3.使用编译器
|
||||
|
||||
类似于TypeScript的tsc编译为JavaScript,AssemblyScript的asc编译为WebAssembly:
|
||||
|
||||
例如,用 TypeScript 实现斐波那契序列计算的模块 f.ts 如下:
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 export function f(x: i32): i32 {
|
||||
2 if (x === 1 || x === 2) {
|
||||
3 return 1;
|
||||
4 }
|
||||
5 return f(x - 1) + f(x - 2)
|
||||
6 }
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
执行以下asc命令,就能把以上代码编译成可运行的 WebAssembly 模块,比起c/c++的编译方式,这种人性化多了。
|
||||
|
||||
1 asc f.ts -o f.wasm
|
||||
|
||||
以上代码中出现了一个新的内置类型 i32,这是 AssemblyScript 在 TypeScript 的基础上内置的类型。 AssemblyScript 和 TypeScript 有细微区别,AssemblyScript 是 TypeScript 的子集,为了方便编译成 WebAssembly 在 TypeScript 的基础上加了更严格的[类型限制](https://github.com/AssemblyScript/assemblyscript/wiki/Limitations), 区别如下:
|
||||
|
||||
- 比 TypeScript 多了很多更细致的内置类型,以优化性能和内存占用,详情[文档](https://github.com/AssemblyScript/assemblyscript/wiki/Types);
|
||||
- 不能使用 any 和 undefined 类型,以及枚举类型;
|
||||
- 可空类型的变量必须是引用类型,而不能是基本数据类型如 string、number、boolean;
|
||||
- 函数中的可选参数必须提供默认值,函数必须有返回类型,无返回值的函数返回类型需要是 void;
|
||||
- 不能使用 JS 环境中的内置函数,只能使用 [AssemblyScript 提供的内置函数](https://github.com/AssemblyScript/assemblyscript/wiki/Built-in-functions)。
|
||||
|
||||
总体来说 AssemblyScript 比 TypeScript 又多了很多限制,编写起来会觉得局限性很大; 用 AssemblyScript 来写 WebAssembly 经常会出现 tsc 编译通过但运行 WebAssembly 时出错的情况,这很可能就是你没有遵守以上限制导致的;但 AssemblyScript 通过修改 TypeScript 编译器默认配置能在编译阶段找出大多错误。
|
||||
|
||||
AssemblyScript 的实现原理其实也借助了 LLVM,它通过 TypeScript 编译器把 TS 源码解析成 AST,再把 AST 翻译成 IR,再通过 LLVM 编译成 WebAssembly 字节码实现; 上面提到的各种限制都是为了方便把 AST 转换成 LLVM IR。
|
||||
|
||||
**asc编译器具体API如下**
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 SYNTAX
|
||||
2 asc [entryFile ...] [options]
|
||||
3
|
||||
4 EXAMPLES
|
||||
5 asc hello.ts
|
||||
6 asc hello.ts -b hello.wasm -t hello.wat
|
||||
7 asc hello1.ts hello2.ts -b -O > hello.wasm
|
||||
8
|
||||
9 OPTIONS
|
||||
10 --version, -v Prints just the compiler's version and exits.
|
||||
11 --help, -h Prints this message and exits.
|
||||
12 --optimize, -O Optimizes the module. Also has the usual shorthands:
|
||||
13
|
||||
14 -O Uses defaults. Equivalent to -O2s
|
||||
15 -O0 Equivalent to --optimizeLevel 0
|
||||
16 -O1 Equivalent to --optimizeLevel 1
|
||||
17 -O2 Equivalent to --optimizeLevel 2
|
||||
18 -O3 Equivalent to --optimizeLevel 3
|
||||
19 -Oz Equivalent to -O but with --shrinkLevel 2
|
||||
20 -O3s Equivalent to -O3 with --shrinkLevel 1 etc.
|
||||
21
|
||||
22 --optimizeLevel How much to focus on optimizing code. [0-3]
|
||||
23 --shrinkLevel How much to focus on shrinking code size. [0-2, s=1, z=2]
|
||||
24 --validate, -c Validates the module using Binaryen. Exits if invalid.
|
||||
25 --baseDir Specifies the base directory of input and output files.
|
||||
26 --outFile, -o Specifies the output file. File extension indicates format.
|
||||
27 --binaryFile, -b Specifies the binary output file (.wasm).
|
||||
28 --textFile, -t Specifies the text output file (.wat).
|
||||
29 --asmjsFile, -a Specifies the asm.js output file (.js).
|
||||
30 --idlFile, -i Specifies the WebIDL output file (.webidl).
|
||||
31 --tsdFile, -d Specifies the TypeScript definition output file (.d.ts).
|
||||
32 --sourceMap Enables source map generation. Optionally takes the URL
|
||||
33 used to reference the source map from the binary file.
|
||||
34 --debug Enables debug information in emitted binaries.
|
||||
35 --noAssert Replaces assertions with just their value without trapping.
|
||||
36 --noEmit Performs compilation as usual but does not emit code.
|
||||
37 --importMemory Imports the memory instance provided by the embedder.
|
||||
38 --sharedMemory Declare memory as shared by settings the max shared memory.
|
||||
39 --memoryBase Sets the start offset of compiler-generated static memory.
|
||||
40 --importTable Imports the function table instance provided by the embedder.
|
||||
41 --noLib Does not include the shipped standard library.
|
||||
42 --lib Adds one or multiple paths to custom library components and
|
||||
43 uses exports of all top-level files at this path as globals.
|
||||
44 --use, -u Aliases a global object under another name, e.g., to switch
|
||||
45 the default 'Math' implementation used: --use Math=JSMath
|
||||
46 --trapMode Sets the trap mode to use.
|
||||
47
|
||||
48 allow Allow trapping operations. This is the default.
|
||||
49 clamp Replace trapping operations with clamping semantics.
|
||||
50 js Replace trapping operations with JS semantics.
|
||||
51
|
||||
52 --runPasses Specifies additional Binaryen passes to run after other
|
||||
53 optimizations, if any. See: Binaryen/src/passes/pass.cpp
|
||||
54 --enable Enables additional (experimental) WebAssembly features.
|
||||
55
|
||||
56 sign-extension Enables sign-extension operations
|
||||
57 mutable-global Enables mutable global imports and exports
|
||||
58 bulk-memory Enables bulk memory operations
|
||||
59 simd Enables SIMD types and operations.
|
||||
60 threads Enables threading and atomic operations.
|
||||
61
|
||||
62 --transform Specifies the path to a custom transform to 'require'.
|
||||
63 --measure Prints measuring information on I/O and compile times.
|
||||
64 --noColors Disables terminal colors.
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
编译器API也可以以编程方式使用。 它接受与CLI相同的选项,但也允许您覆盖stdout和stderr和/或提供回调:
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 const asc = require("assemblyscript/cli/asc");
|
||||
2 asc.main([
|
||||
3 "myModule.ts",
|
||||
4 "--binaryFile", "myModule.wasm",
|
||||
5 "--optimize",
|
||||
6 "--sourceMap",
|
||||
7 "--measure"
|
||||
8 ], {
|
||||
9 stdout: process.stdout,
|
||||
10 stderr: process.stderr
|
||||
11 }, function(err) {
|
||||
12 if (err)
|
||||
13 throw err;
|
||||
14 ...
|
||||
15 });
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
可以通过编程方式获取可用的命令行选项:
|
||||
|
||||
1 const options = require("assemblyscript/cli/asc.json");
|
||||
2 ...
|
||||
|
||||
您也可以直接编译源字符串,例如在浏览器环境中:
|
||||
|
||||
1 const { binary, text, stdout, stderr } = asc.compileString(`...`, { optimize: 2 });
|
||||
2 ...
|
||||
|
||||
## 4.使用编译的.wasm模块
|
||||
|
||||
index.js示例代码如下:
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 const fs = require("fs");
|
||||
2 const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
|
||||
3 const imports = {};
|
||||
4 Object.defineProperty(module, "exports", {
|
||||
5 get: () => new WebAssembly.Instance(compiled, imports).exports
|
||||
6 });
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
使用上面编译的f.wasm
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
1 fetch('f.wasm') // 网络加载 f.wasm 文件
|
||||
2 .then(res => res.arrayBuffer()) // 转成 ArrayBuffer
|
||||
3 .then(WebAssembly.instantiate) // 编译为当前 CPU 架构的机器码 + 实例化
|
||||
4 .then(mod => { // 调用模块实例上的 f 函数计算
|
||||
5 console.log(mod.instance.f(50));
|
||||
6 });
|
||||
|
||||
[](https://assets.cnblogs.com/images/copycode.gif)
|
||||
|
||||
## 5.参考文献:
|
||||
|
||||
[GitHub—AssemblyScript 开源项目](https://github.com/AssemblyScript/assemblyscript#installation)
|
||||
|
||||
[吴浩麟—WebAssembly 现状与实战](https://www.ibm.com/developerworks/cn/web/wa-lo-webassembly-status-and-reality/index.html)
|
||||
|
||||
- [1.安装](https://www.cnblogs.com/jixiaohua/p/10428785.html#tid-SJS3EZ)
|
||||
- [2.创建项目](https://www.cnblogs.com/jixiaohua/p/10428785.html#tid-4SQ4xa)
|
||||
- [3.使用编译器](https://www.cnblogs.com/jixiaohua/p/10428785.html#tid-djiMkK)
|
||||
- [4.使用编译的.wasm模块](https://www.cnblogs.com/jixiaohua/p/10428785.html#tid-RwBDGt)
|
||||
- [5.参考文献:](https://www.cnblogs.com/jixiaohua/p/10428785.html#tid-bRHtGH)
|
||||
Reference in New Issue
Block a user