我有一些使用wasm-pack
和wasm-bindgen
编译成web汇编的rust代码。我想从一个web worklet/worker调用这些代码。整个应用程序最终应该只是一个单独的 *.js文件,其他的都是内联的。
下面是我想象中的构建过程:
1.使用wasm-pack
将rust代码编译为 *.wasm和 *.js绑定(这一步工作正常)
1.使用webpack
构建一个独立的 .js文件,我可以将其作为worklet/worker加载。.wasm必须包含在此文件中。(此步骤失败)
1.再次使用webpack
构建我的最终应用程序/包,内联步骤2中的worklet/worker文件(这一步运行良好)。
我的问题在第二步:我无法使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试图支持动态加载内容(?)。我们可以将问题隔离到wasm-pack
在使用--target=web
CLI参数时作为javascript绑定的一部分生成的这段代码:
async function init(input) {
if (typeof input === 'undefined') {
input = new URL('my_wasm_file.wasm', import.meta.url);
}
const imports = {};
// ...
显然,必须生成URL的可能性使得webpack依赖于document
,而document
在工作者作用域中加载工作者脚本时不可用。取消注解new URL()
部分会使document
引用从webpack输出中消失。
不知道该怎么做。写我自己的wasm加载程序?我写了一段时间,base64对wasm文件进行编码,并将其作为字符串进行内联-但随后我必须大幅更改使用者代码,以手动异步加载wasm。这意味着我不能再使用wasm-bindgen
绑定,因为它们依赖于上面所示的URL
部分(当使用--target=web
时)或者webpack 5的绑定逻辑(当使用--target=bundler
时),我无法从我自己的简单wasm加载器尝试中获得支持。本质上,这意味着我必须提供自己的JS绑定,这很不方便。
一定有更好的办法-对吧?
3条答案
按热度按时间qyswt5oh1#
解决方案
1.构建WASM本身:第一个月
1.构建JS绑定:
wasm-bindgen --out-dir=dist --target=web --omit-default-module-path my-wasm-package.wasm
.1.在工作面板脚本中使用wasm,如下所示:
1.使用此webpack配置将worklet脚本构建到单个 *. js文件中:
为什么有效
我观察到的核心问题是
wasm-bindgen
生成的JS绑定包含URL
关键字--这使得webpack
初始化时期望定义document
对象。该对象在worklet作用域中未定义,因此初始化webpack
会崩溃,即使我们从未进入包含URL
的代码段。如果我们不使用
wasm-pack
一次性构建wasm和绑定,我们可以传递额外的参数给wasm-bindgen
-主要是--omit-default-module-path
参数,它从绑定中删除包含URL
的部分。现在webpack
在初始化时不会引用document
,我们可以不加修改地使用绑定。从这里开始很简单:我们将wasm绑定为b64编码资产,并将其传递给JS绑定附带的
init()
函数。noj0wjuj2#
我可以得到公认的解决方案,作为我的构建过程的一部分,所以我这样做:
https://github.com/SonOfLilit/vscode-web-wasm-rust
它涉及到编写一个
webpack
WASM Loader插件(并修补webpack
以使其成为可能,PR提交)来使用此加载程序:以及在尝试导入WASM之前在
activate
中设置__webpack_public_path__
:axr492tv3#
accepted answer非常适合与问题的上下文完全匹配的情况(您希望将自己的Rust代码 * 构建到WASM模块中,然后 * 在worker中使用它 *)。我在稍微不同的上下文中遇到了完全相同的错误消息,但我认为我的发现可能对这里有所帮助。
我的背景是:我有一个WASM依赖项是由 * 其他人 * 构建的,所以改变用于构建JS绑定的标志不太方便(例如
wasm-bindgen
的--omit-default-module-path
)。在我的WASM中,甚至不是从Rust构建的,但它的JS绑定具有与问题中描述的相同的URL
标记。解决方案是在webpack的config中为
entry
指定一个baseUri
属性:在撰写本文时,该属性似乎没有出现在官方文档中,而是contributed。
这会将webpack生成的代码更改为
这将删除对
document
的引用并避免运行时错误。