我有一些 rust 代码可以使用wasm-pack
和编译为 Web 程序集wasm-bindgen
。我想从 web worklet/worker 调用这段代码。整个应用程序最终应该只是一个 *.js 文件,其他所有内容都内联。
这就是我想象的构建过程的样子:
- 用于
wasm-pack
将 rust 代码编译为 *.wasm 和 *.js 绑定(此步骤工作正常) - 用于
webpack
构建一个独立的 *.js 文件,我可以将其作为工作集/工作人员加载。*.wasm 必须包含在此文件中。(此步骤失败) - 再次使用
webpack
来构建我的最终应用程序/包,内联步骤 2 中的 worklet/worker 文件。(此步骤工作正常)
我的问题出在第 2 步:我无法webpack
将 *.wasm 内联到 worklet/worker 文件中。我在我的 webpack 配置中尝试了这个:
entry: {
worker: {
import: './src/worker.ts',
filename: '../lib/worker.js',
}
},
// ...
module: {
rules: [
// ...
{
test: /\.wasm$/,
// 1st option: type: 'webassembly/sync',
// 2nd option: type: 'asset/inline',
},
// ...
],
},
无论我做什么,webpack
总是会发出两个文件,一个worker.js
是我的 worklet/worker 脚本本身,另一个是vendor_my_package_name_wasm_js.js
只包含 *.wasm 及其绑定。显然,当worker.js
作为 web worker 加载时,它会失败 - 第二个文件无法从 worker 范围加载。
我的目标是包含所有内容,worker.js
而不是发出单独的文件。但是我该怎么做呢?
编辑:记录解决方案的步骤:
Webpack 原生 wasm 加载似乎不允许内联 wasm 文件。我们可以尝试使用常规的 raw-loader:
// in module.rules
{
test: /\.wasm$/,
loader: 'raw-loader',
},
这会导致以下错误:
ERROR in ./node_modules/my-module/my-wasm-file.wasm
Module parse failed: magic header not detected
File was processed with these loaders:
* ../../node_modules/raw-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
发生这种情况是因为仍然存在一个隐式默认规则。我们可以通过覆盖默认规则来禁用它,只考虑json
和js
文件:
// in webpack.config.js
module: {
defaultRules: [
{
type: 'javascript/auto',
resolve: {},
},
{
test: /\.json$/i,
type: 'json',
},
],
rules: [
// ...
{
test: /\.wasm$/,
loader: 'raw-loader',
},
],
},
现在我们终于将我们的 worker 捆绑到了一个 *.js 文件中!但是,在加载它时,我们最终会出现以下错误:
Uncaught ReferenceError: document is not defined
指向这段 webpack 生成的代码:
/* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ __webpack_require__.b = document.baseURI || self.location.href; // <<< error here
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ "myModuleName": 0
/******/ };
/******/
/******/ // no chunk on demand loading
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/
/******/ // no on chunks loaded
/******/
/******/ // no jsonp function
/******/ })();
出于某种原因,webpack 试图支持动态加载东西(?)。我们可以将问题隔离到使用CLI 参数wasm-pack
时作为 javascript 绑定的一部分生成的这段代码:--target=web
async function init(input) {
if (typeof input === 'undefined') {
input = new URL('my_wasm_file.wasm', import.meta.url);
}
const imports = {};
// ...
显然,必须生成 URL 的可能性使得 webpack 依赖document
哪个在工作范围内加载工作脚本时不可用。取消注释该new URL()
部分会使document
引用从 webpack 输出中消失。
不知道从这里去哪里。编写我自己的 wasm-loader?我为此工作了一段时间,对 wasm 文件进行 base64 编码并将其内联为字符串 - 但随后我必须大幅更改使用者代码以手动异步加载 wasm。这意味着我不能再使用wasm-bindgen
绑定,因为它们依赖于URL
上面显示的部分(使用时--target=web
)或 webpack 5 的捆绑逻辑(使用时--target=bundler
),我无法从我自己的简单 wasm-loader 尝试中获得支持. 本质上,这意味着我必须提供自己的 JS 绑定,这很不方便。
一定有更好的方法——对吧?