as-loader
AssemblyScript loader for webpack
⚠️ In development ⚠️
Installation
This loader requires AssemblyScript ~0.18,
Node.js >= 12 and webpack 4 or webpack 5
npm install --save-dev as-loader assemblyscript
yarn add --dev as-loader assemblyscript
The minimal webpack.config.js
:
module.exports = {
entry: "src/index.ts",
resolve: {
extensions: [".ts", ".js"],
},
module: {
rules: [
{
test: /\.ts$/,
include: path.resolve(__dirname, "src/assembly"),
loader: "as-loader",
options: {
}
},
{
test: /\.ts$/,
exclude: path.resolve(__dirname, "src/assembly"),
loader: "ts-loader",
},
],
},
};
Usage
By default, the loader emits .wasm
file (+ .wasm.map
if source maps are enabled) and
creates CommonJS module that exports URL to the emitted .wasm
file.
If you enable fallback
option, the loader will emit additional .js
file (+ .js.map
if source maps are enabled)
and will expose async fallback()
function which dynamically imports fallback module.
To simplify loading logic, you can use as-loader/runtime
loader which uses
@assemblyscript/loader
under the hood.
The loader provides correct types, checks for WebAssembly support, and uses fallback if available.
import * as myModule from "./assembly/myModule";
import { instantiate } from "as-loader/runtime";
async function loadAndRun() {
const { exports } = await instantiate(myModule);
exports.myFunction(100);
}
loadAndRun();
Alternatively, you can use exported URL directly:
import * as myModule from "./assembly/myModule";
import { instantiate } from "@assemblyscript/loader";
async function loadAndRun() {
const { exports } = await instantiate<typeof myModule>(
fetch((myModule as unknown) as string)
);
exports.myFunction(100);
}
loadAndRun();
API
For more details, check src/runtime directory
as-loader/runtime
This runtime loader uses @assemblyscript/loader
under the hood.
export interface WasmModuleInstance<TModule> {
type: "wasm";
exports: AsLoaderRuntime & PointerCastObject<TModule>;
module: WebAssembly.Module;
instance: WebAssembly.Instance;
}
export interface JsModuleInstance<TModule> {
type: "js";
exports: TModule;
}
export type ModuleInstance<TModule> =
| WasmModuleInstance<TModule>
| JsModuleInstance<TModule>;
export function instantiate<TModule>(
module: TModule,
load: (url: string) => Promise<unknown>,
imports?: object,
fallback?: boolean,
supports?: () => boolean
): Promise<ModuleInstance<TModule>>
as-loader/runtime/bind
This runtime loader uses as-bind
under the hood, so you don't have to resolve pointers for
types like string
, number[]
, Int8Array
, etc. You still have to resolve pointers to objects.
Requires bind: true
option in the webpack loader configuration.
Keep in mind that currently it's recommended to manually set Function.returnType
export interface BoundWasmModuleInstance<TModule, TImports> {
type: "wasm-bound";
exports: AsLoaderRuntime & BoundExports<TModule>;
unboundExports: AsLoaderRuntime & PointerCastObject<TModule>;
importObject: TImports;
module: WebAssembly.Module;
instance: WebAssembly.Instance;
enableExportFunctionTypeCaching(): void;
disableExportFunctionTypeCaching(): void;
enableExportFunctionUnsafeReturnValue(): void;
disableExportFunctionUnsafeReturnValue(): void;
enableImportFunctionTypeCaching(): void;
disableImportFunctionTypeCaching(): void;
}
export interface JsModuleInstance<TModule> {
type: "js";
exports: TModule;
}
type BoundModuleInstance<TModule, TImports> =
| BoundWasmModuleInstance<TModule, TImports>
| JsModuleInstance<TModule>;
export function instantiate<TModule, TImports>(
module: TModule,
load: (url: string) => Promise<unknown>,
imports?: TImports,
fallback?: boolean,
supports?: () => boolean
): Promise<BoundModuleInstance<TModule, TImports>>
export const RETURN_TYPES: AsBindReturnTypes;
Binding
There are 2 aspects that you have to consider when interacting with WebAssembly module:
- WebAssembly doesn't support function arguments and returns others than
number
and boolean
yet.
Because of that, you have to manually translate between WebAssembly pointers and JavaScript objects.
The alternative solution is to use as-bind
library which
does this automatically for string
and array
types (doesn't support objects yet). - WebAssembly doesn't provide GC yet (proposal) - to manage memory,
AssemblyScript offers very lightweight GC implementation. If you use it (see
runtime
option - it's "incremental"
by default),
you have to manually __pin
and __unpin
pointers to instruct GC if given data can be collected or not.
The as-loader/runtime
uses @assemblyscript/loader
under the hood -
see the docs for more information.
`as-loader/runtime` binding code example:
export function sayHello(firstName: string, lastName: string): string {
return `Hello ${firstName} ${lastName}!`;
}
import * as sayHelloModule from "./assembly/sayHello";
import { instantiate } from "as-loader/runtime";
export async function loadModule(): Promise<typeof sayHelloModule> {
const { exports } = await instantiate(sayHelloModule, fetch, undefined, false);
const { __pin, __unpin, __newString, __getString } = exports;
function sayHello(firstName: string, lastName: string): string {
const firstNamePtr = __pin(__newString(firstName));
const lastNamePtr = __pin(__newString(lastName));
const result = __getString(
exports.sayHello(firstNamePtr, lastNamePtr)
);
__unpin(firstNamePtr);
__unpin(lastNamePtr);
return result;
}
return { sayHello };
}
You can consider using bind: true
option and as-loader/runtime/bind
runtime loader which uses
as-bind
under the hood - this makes passing types like string
and array
much easier.
`as-loader/runtime/bind` binding code example:
export function sayHello(firstName: string, lastName: string): string {
return `Hello ${firstName} ${lastName}!`;
}
import * as sayHelloModule from "./assembly/sayHello";
import { instantiate, RETURN_TYPES } from "as-loader/runtime/bind";
export async function loadModule(): Promise<typeof sayHelloModule> {
const { exports } = await instantiate(sayHelloModule, fetch, undefined, false);
const { sayHello } = exports;
sayHello.returnType = RETURN_TYPES.STRING;
return { sayHello };
}
Options
Loader Options
Name | Type | Description |
---|
name | string | Output asset name template, [name].[contenthash].wasm by default. |
raw | boolean | If true, returns binary instead of emitting file. Use for chaining with other loaders. |
fallback | boolean | If true, creates additional JavaScript file which can be used if WebAssembly is not supported. |
bind | boolean | If true, adds as-bind library files to the compilation (required if you want to use as-loader/runtime/bind ). |
Compiler Options
Options passed to the AssemblyScript compiler.
Name | Type | Description |
---|
debug | boolean | Enables debug information in emitted binaries. |
optimizeLevel | number | How much to focus on optimizing code. [0-3] |
shrinkLevel | number | How much to focus on shrinking code size. [0-2] |
coverage | boolean | Re-optimizes until no further improvements can be made. |
noAssert | boolean | Replaces assertions with just their value without trapping. |
importMemory | boolean | Imports the memory provided as 'env.memory'. |
noExportMemory | boolean | Does not export the memory as 'memory'. |
initialMemory | number | Sets the initial memory size in pages. |
maximumMemory | number | Sets the maximum memory size in pages. |
sharedMemory | boolean | Declare memory as shared. Requires maximumMemory. |
importTable | boolean | Imports the function table provided as 'env.table'. |
exportTable | boolean | Exports the function table as 'table'. |
runtime | string | Specifies the runtime variant to include in the program. Available runtimes are: "incremental" (default), "minimal", "stub" |
exportRuntime | boolean | Exports the runtime helpers (__new, __collect etc.). Enabled by default. |
explicitStart | boolean | Exports an explicit '_start' function to call. |
enable | string[] | Enables WebAssembly features being disabled by default. Available features are: "sign-extension", "bulk-memory", "simd", "threads", "reference-types", "gc" |
disable | string[] | Disables WebAssembly features being enabled by default. Available features are: "mutable-globals" |
lowMemoryLimit | boolean | Enforces very low (<64k) memory constraints. |
memoryBase | number | Sets the start offset of emitted memory segments. |
tableBase | number | Sets the start offset of emitted table elements. |
trapMode | string | Sets the trap mode to use. Available modes are: "allow", "clamp", "js" |
noValidate | boolean | Skips validating the module using Binaryen. |
License
MIT