内容简介:在上一篇文章尽管webpack4新增了对wasm文件的编译支持,在wasm模块编写完成之后将其与webpack结合的过程中发现,wasm模块无法被正确加载。在对@ne_fe/gis编译输出文件的检查之后,有了新的解决方案直接在前端工程中引入@ne_fe/gis并使用的话,控制台会输出错误信息
在上一篇文章 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\test\node_modules\@ne_fe\gis\dist\index.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模块的编写以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Iterative Methods for Sparse Linear Systems, Second Edition
Yousef Saad / Society for Industrial and Applied Mathematics / 2003-04-30 / USD 102.00
Tremendous progress has been made in the scientific and engineering disciplines regarding the use of iterative methods for linear systems. The size and complexity of linear and nonlinear systems arisi......一起来看看 《Iterative Methods for Sparse Linear Systems, Second Edition》 这本书的介绍吧!