# 前端云析布局集成 WebAssembly

# 引入 WASM

首先需要生成相应的 WASM,这块是直接让 C++的同学帮忙生成提供给前端。其中包括layouter.jslayouter.wasm 两个文件。

为了 WASM 布局算法不影响浏览器渲染,这块使用了 HTML5 的标准Web Worker,Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。

可以通postMessage()方法和onmessage事件处理函数触发 worker。

为了更好的使用 Web Worker,需要在 webpack 引入一个插件,首先来安装:

npm install -D worker-plugin
1

然后在项目的vue.config.js 引入并使用,如下:

const WorkerPlugin = require("worker-plugin");
// Adds native Web Worker bundling support to Webpack.
module.exports = {
  configureWebpack: {
    plugins: [
      // other plugins
      new WorkerPlugin({
        // use "self" as the global object when receiving hot updates.
        globalObject: "self", // <-- this is the default value
      }),
    ],
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13

# 踩坑

在开发环境下,由于我们是直接引入layouter.js 的,所以相对应的,layouter.wasm的路径是相对路径,但是目前来说,webpack 并没有很好的处理wasmloader ,所以webpack 并不会去主动处理wasm 文件,在这种情况下直接调用布局算法会发现路径不对。

解决办法是,在layouter.js 通过判断环境来处理:

var wasmBinaryFile = "layouter.wasm";
if (!isDataURI(wasmBinaryFile)) {
  var isPro = process.env.NODE_ENV === "production";
  wasmBinaryFile = isPro
    ? locateFile(wasmBinaryFile)
    : "http://localhost:8082/static/layouter.wasm";
}
// 开发环境的路径因人而异,取决于wasm存放位置
1
2
3
4
5
6
7
8

第二个坑是打包时候的路径处理,同样的,因为webpack 不认识wasm 文件,我们需要将wasm 复制到 js 文件夹下,因为layouter.js 会被打包至 js 文件夹下。此时需要用到copy-webpack-plugin ,在生产环境下配置该插件:

new CopyPlugin([
   { from: 'static/layouter.wasm', to: 'js/' },
]),
1
2
3

第三个坑是当打包好发布到生产环境后,依旧报错。通过一番定位,发现是由于去除了 console.*函数,导致在Web Worker 中运行的layouter.js 中打印日志变成了调用undefined

去除 console.*函数是项目中在生产环境引入了terser-webpack-plugin ,该插件是用来压缩 js 代码,是官方推荐的插件。我们来修改下配置:

const TerserPlugin = require("terser-webpack-plugin"); // 压缩js代码,同时支持多进程压缩

module.exports.configureWebpack.optimization = {
  minimize: true,
  minimizer: [
    new TerserPlugin({
      parallel: true,
      terserOptions: {
        output: {
          comments: false, // remove comments
        },
        compress: {
          drop_console: false, // 由于wasm有打印日志,暂不去除console
          drop_debugger: true,
          pure_funcs: ["console.log"],
        },
      },
      extractComments: false,
    }),
  ],
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

主要就是把drop_console: true 改成drop_console: false

第四个坑是nginx 的配置。nginx 目前默认生成的mine.types 并不包含wasm 的格式,所以需要手动来添加。

我们期望nginx 遇到wasm 文件时,将它的Content-Type 设置为Content-Type: application/wasm 。找到 nginx 的mine.types 文件,在合适的位置添加:

application/wasm                                 wasm;
1

然后重启nginx