rust-webpack-template
rust-webpack-template copied to clipboard
Typescript example
Seems that ts-loader and/or awesome-typescript-loader don't play nicely with the async->sync import solution bindgen produces.
This was already raised and closed here: https://github.com/rustwasm/wasm-bindgen/issues/700 but it might be helpful to have a Typescript boilerplate as a reference someday :)
TL;DR: The magic tricks are:
"module": "esNext"intsconfig.jsonawait import('./mymod')typeof import('./mymod')
Details
In your tsconfig.json, set "module": "esNext" so that you can use async import(...):
{
"compilerOptions": {
"target": "es5",
"module": "esNext",
"lib": ["dom", "es2015"],
"strict": true,
"esModuleInterop": true
}
}
In your webpack.config.js, enable ts-loader (as per the usual instructions) and the experimental built-in *.wasm loader:
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.wasm$/,
type: "webassembly/experimental"
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js', '.wasm' ]
},
Finally, let's assume you have the following files generated by wasm-bindgen:
mymod.jsmymod.d.tsmymod_bg.wasm
Then you can use a structure like this in your top-level *.ts file:
function start(mymod: typeof import('./mymod')) {
console.log("All modules loaded");
mymod.my_exported_rust_function();
}
async function load() {
start(await import('./mymod'));
}
load();
The magic trick here is typeof import('./mymod'), which allows you declare the type of the asynchronously-loaded module.
I'd be happy to try to turn this into a fully-worked test case that can run on CI and that can be used as example, but it might need to wait a few days until I have time.
Thanks @emk - that does seem to work!
Though now Typescript is having trouble loading some other modules... any clue how to fix that? Here's some specific examples:
import {mat4} from "gl-matrix";
import WebFont from "webfontloader";
In both cases typescript claims it can't find the modules, though they are npm-installed
Though now Typescript is having trouble loading some other modules... any clue how to fix that?
A lot depends on whether your TypeScript setup was working correctly before applying this workaround, I'm sad to say. :-/ It might be missing *.d.ts modules, bad lookup paths, wrong magic incantations, etc. Try removing the await import and see if you can get the rest working on its own.
Ah - moduleResolution: node seemed to do the trick :)
wasm-pack-plugin version 0.1.0 was recently released and among other improvements, it now has the option to configure wasm-pack to generate TypeScript bindings that can be used in your code.
Here's an example webpack configuration to make use of it:
webpack.config.js
const path = require("path");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./index.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
plugins: [
new HtmlWebpackPlugin(),
new WasmPackPlugin({
crateDirectory: path.resolve(__dirname, "."),
withTypeScript: true // this is new
}),
],
resolve: {
extensions: [".ts", ".tsx", ".js", ".wasm"]
},
module: {
rules: [{
test: /\.tsx?$/,
loader: "ts-loader"
}]
}
};
tsconfig.json
{
"compilerOptions": {
"module": "esnext", // needed to have dynamic imports
"lib": [
"dom",
"es2015"
]
},
"files": [
"./index.ts"
]
}
example index.ts
import("./pkg/yourlib").then(module => {
// won't typecheck if yourlib does not expose the run function
module.run();
});
I have a variant on this that I haven't quite puzzled my way through, and thats exporting a typescript package that is using wasm-bindgen as an accelerator for just some parts of it. Doing the async import dance around the entry points for browser bundles is easy, but I'm having some head scratching getting there - it seems like webpack still wants an await around that, even though as a library I would have expected that the async dance could happen upstream, by whomever is using the published package.