资讯专栏INFORMATION COLUMN

WebAssembly应用到前端工程(下)—— webpack和webassembly

RichardXG / 3129人阅读

摘要:然而在当前以为主要编译工具的实际工程应用中依然存在问题。涉及到的技术主要为模块机制插件编写与插件编写。使用可以参考或,欢迎。上一篇应用到前端工程上模块的编写

在上一篇文章WebAssembly应用到前端工程(上)—— webassembly模块的编写中,完成了@ne_fe/gis模块的编写与发布。然而webassembly在当前以webpack4为主要编译工具的实际工程应用中依然存在问题。

尽管webpack4新增了对wasm文件的编译支持,在wasm模块编写完成之后将其与webpack结合的过程中发现,wasm模块无法被正确加载。在对@ne_fe/gis编译输出文件的检查之后,有了新的解决方案 wasm-module-webpack-plugin。

出现的问题

直接在前端工程中引入@ne_fe/gis并使用的话,控制台会输出错误信息

index.js?558c:1 GET http://localhost:8080/gps.wasm 404 (Not Found)
Uncaught (in promise) TypeError: Incorrect response MIME type. Expected "application/wasm".

查看所引用的@ne_fe/gis/dist/index.js后发现这样一句话

var Pn="undefined"!=typeof location?location.pathname.split("/"):[];Pn.pop(),(Cn?WebAssembly.instantiateStreaming(fetch(Pn.join("/")+"/gps.wasm"),o):fetch(Pn.join("/")+"/gps.wasm").then(e=>e.arrayBuffer()).then(e=>WebAssembly.instantiate(e,o)))

出错原因时由于fetch直接从根路径下直接获取wasm文件,但文件并没有生成或移动,webpack并不能处理fetch所加载的文件,最终导致wasm加载失败。

babel

webpack不能处理js的fetch语句,导致了上面问题的出现,那么只有一种方法能够处理fetch语句,那就是babel。
下面来编写一个babel插件处理fetch加载wasm的情况

// babel-plugin.js
module.exports = function() {
  return {
    visitor: {
      CallExpression(path, state) {
        if(path.node.callee.name === "fetch"){
          const argument = JSON.parse(JSON.stringify(path.node.arguments[0]));
          for (const i in argument.right) {
            if (i === "value" && argument.right[i].endsWith(".wasm")) {
             console.log("argument.right[ i ]", argument.right[ i ], "state.file.opts.filename", state.file.opts.filename);
            }
          }
        }
      },
    }
  }
};

在webpack中使用

// webpack.config.js
const path = require("path");
const BabelPlugin = require("./babel-plugin");
module.exports = {
  module: {
    rules: [
      ...
      {
        test: /.js$/,
        loader: "babel-loader",
        include: [ path.join(process.cwd(), "./node_modules/@ne_fe/gis") ],
        options: {
          plugins: [ BabelPlugin ],
        },
      },
      ...
    ],
  },
  plugins: [
    ...
  ],
};

启动webpack进行编译,控制台输出

argument.right[ i ] /gps.wasm 
state.file.opts.filename C:dir	est
ode_modules@ne_fegisdistindex.js

最终获得了fetch所加载的wasm文件名与fetch语句所在文件。

webpack

在上一步中获取到了fetch语句加载的wasm文件名与fetch语句所在文件。
为了将wasm文件输出到webpack编译结果中,需要添加webpack插件。经修改之后,整个结合wasm与webpack的插件如下

// event-listener.js
const EventEmitter = require("events").EventEmitter;
class Events extends EventEmitter {
  constructor(prop) {
    super(prop);
    this.data = {};
  }
}
const events = new Events();
events.on("wasm", data => {
  if (!events.data[data.wasmRefFileName]) {
    events.data[data.wasmRefFileName] = {};
    events.data[data.wasmRefFileName][data.wasmRefPath] = data.wasmDir;
  } else {
    if (!events.data[data.wasmRefFileName][data.wasmRefPath]) {
      events.data[data.wasmRefFileName][data.wasmRefPath] = data.wasmDir;
    }
  }
});
module.exports = events;
// babel-plugin.js
const eventEmitter = require("./event-listener");
const pathInternal = require("path");
module.exports = function() {
  return {
    visitor: {
      CallExpression(path, state) {
        if(path.node.callee.name === "fetch"){
          const argument = JSON.parse(JSON.stringify(path.node.arguments[0]));
          for (const i in argument.right) {
            if (i === "value" && argument.right[i].endsWith(".wasm")) {
              eventEmitter.emit("wasm", {
                wasmRefPath: argument.right[i],
                wasmRefFileName: state.file.opts.filename,
                wasmDir: pathInternal.parse(state.file.opts.filename).dir,
              });
            }
          }
        }
      },
    }
  }
};
// webpack-plugin
const eventEmitter = require("./event-listener");
const path = require("path");

class WasmPlugin {
  apply(compiler) {
    compiler.plugin("emit", function(compilation, callback) {
      for (const i in eventEmitter.data) {
        for (const j in eventEmitter.data[i]) {
          const filePath = path.join(eventEmitter.data[ i ][ j ], "." + j);
          const content = compiler.inputFileSystem._readFileSync(filePath);
          const stat = compiler.inputFileSystem._statSync(filePath);
          const wasmRefPath = j;
          const wasmName = wasmRefPath.substring(1, wasmRefPath.length);
          compilation.assets[wasmName] = {
            size() {
              return stat.size;
            },
            source() {
              return content;
            },
          };
        }
      }
      callback();
    });
  }
}

module.exports = WasmPlugin;

event-listener的作用是为了保存babel-plugin中获取到的wasm相关信息然后在webpack插件执行的时候使用,webpack-plugin将获取到的wasm文件输出到正确路径。

涉及到的技术主要为commonjs模块机制、babel插件编写与webpack插件编写。

使用

可以参考wasm-module-webpack-plugin或@ne_fe/gis,欢迎start。

尾语

尽管webassembly的出现对前端开发高性能浏览器应用有了重大的作用,webpack4也新增了对webassembly的支持,但是目前以webpack编译为主的前端工程对webassembly的支持依然不友好,开发难度不小,希望以后有更好的解决方案。
 
 
上一篇:WebAssembly应用到前端工程(上)—— webassembly模块的编写

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105127.html

相关文章

  • WebAssembly应用前端工程(上)—— webassembly模块的编写

    摘要:本文以这个模块的开发过程梳理如何应用到前端工程中。注使用完成开发至少需要基础的编码能力。具体其他信息可以参考上该模块的。配置主要针对源码文件,需要添加正确的进行处理。下一篇应用到前端工程下和 前言 WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine...

    Mr_houzi 评论0 收藏0
  • 2018前端值得关注的技术

    摘要:年前端有哪些领域,技术值得关注,哪些技术会兴起,哪些技术会没落。自从谷歌提出后,就持续的获得了业界的关注,热度可见一斑。就在今年,谷歌也宣布将获得与安卓原生应用同等的待遇与权限。但是无论都值得关注。 1.前言 2017悄然过去,2018已经来到。人在进步,技术在发展。2018年前端有哪些领域,技术值得关注,哪些技术会兴起,哪些技术会没落。下面就我个人的判断进行一个预测判断,希望能对大家...

    xiao7cn 评论0 收藏0
  • 2018前端值得关注的技术

    摘要:年前端有哪些领域,技术值得关注,哪些技术会兴起,哪些技术会没落。自从谷歌提出后,就持续的获得了业界的关注,热度可见一斑。就在今年,谷歌也宣布将获得与安卓原生应用同等的待遇与权限。但是无论都值得关注。 1.前言 2017悄然过去,2018已经来到。人在进步,技术在发展。2018年前端有哪些领域,技术值得关注,哪些技术会兴起,哪些技术会没落。下面就我个人的判断进行一个预测判断,希望能对大家...

    用户84 评论0 收藏0
  • 前端每周清单半年盘点之 WebAssembly

    摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。利用降低三倍加载速度自推出之后,很多开发者都开始尝试在小型项目中实践,不过尚缺大型真实案例比较。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目...

    Alan 评论0 收藏0
  • 前端每周清单半年盘点之 JavaScript 篇

    摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。背后的故事本文是对于年之间世界发生的大事件的详细介绍,阐述了从提出到角力到流产的前世今生。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎...

    Vixb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<