npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

as-loader

v0.12.0

Published

AssemblyScript loader for webpack

Downloads

85

Readme

npm version build status

Installation

This loader requires AssemblyScript ~0.18, Node.js >= 12 and webpack 5

# with npm
npm install as-loader
npm install --save-dev assemblyscript

# with yarn
yarn add as-loader
yarn add --dev 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: {
          // optional loader and compiler options
        }
      },
      {
        test: /\.ts$/,
        exclude: path.resolve(__dirname, "src/assembly"),
        loader: "ts-loader",
      },
    ],
  },
};

Usage

By default, the loader emits a .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, or as-loader/runtime/bind loader which uses as-bind. These loaders provide 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();
import * as myModule from "./assembly/myModule";
import { instantiate } from "@assemblyscript/loader";

async function loadAndRun() {
  const { exports } = await instantiate<typeof myModule>(
    // workaround for TypeScript
    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 = false,
  supports?: () => boolean
): Promise<ModuleInstance<TModule>>
// ./src/assembly/sayHello.ts
export function sayHello(firstName: string, lastName: string): string {
  return `Hello ${firstName} ${lastName}!`;
}

// ./src/sayHello.ts
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);
  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 };
}

as-loader/runtime/bind

This runtime loader uses as-bind under the hood. Requires bind option enabled 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;
}

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 = false,
  supports?: () => boolean
): Promise<BoundModuleInstance<TModule, TImports>>
// ./src/assembly/sayHello.ts
export function sayHello(firstName: string, lastName: string): string {
  return `Hello ${firstName} ${lastName}!`;
}

// ./src/sayHello.ts
import * as sayHelloModule from "./assembly/sayHello";
import { instantiate } from "as-loader/runtime/bind";

export async function loadModule(): Promise<typeof sayHelloModule> {
  const module = await instantiate(sayHelloModule, fetch);

  return { sayHello: module.exports.sayHello };
}

Binding

There are 2 aspects that you have to consider when interacting with a WebAssembly module:

  1. WebAssembly doesn't support function arguments and returns others than number | boolean | bigint yet. Because of that, you have to manually translate between WebAssembly pointers and JavaScript objects.

    The alternative is to enable the bind option and use as-loader/runtime/bind loader which uses an as-bind library. This simplifies passing types like strings and arrays.

  2. WebAssembly doesn't provide Garbage Collector yet (proposal) - to manage memory, AssemblyScript offers very lightweight GC implementation. If you use it (see runtime option), you have to manually __pin and __unpin pointers to instruct GC if given data can be collected or not.

Fallback

If you need to support older browsers like Internet Explorer or Edge < 16, you can use the fallback option. A fallback module is different from WebAssembly one because you don't have to bind it.

// webpack.config.js
module.exports = {
  entry: "src/index.ts",
  resolve: {
    extensions: [".ts", ".js"],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        include: path.resolve(__dirname, "src/assembly"),
        use: [
          // fallback loader (must be before as-loader)
          {
            loader: "ts-loader",
            options: {
              transpileOnly: true
            }   
          },   
          // as-loader, apart from building .wasm file,
          // will forward assembly script files to the fallback loader above
          // to build a .js file
          {
            loader: "as-loader",
            options: {
              fallback: true
           }
          }
        ]
      },
      {
        test: /\.ts$/,
        exclude: path.resolve(__dirname, "src/assembly"),
        loader: "ts-loader",
      },
    ],
  },
};
// ./src/assembly/sayHello.ts
export function sayHello(firstName: string, lastName: string): string {
  return `Hello ${firstName} ${lastName}!`;
}

// ./src/sayHello.ts
import * as sayHelloModule from "./assembly/sayHello";
import { instantiate } from "as-loader/runtime";

export async function loadModule(): Promise<typeof sayHelloModule> {
  // set fallback option to true (opt-in)
  const module = await instantiate(sayHelloModule, fetch, undefined, true);

  if (module.type === 'wasm') {
    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 };
  } else {
    return { sayHello: module.exports.sayHello }
  }
}

Options

Loader Options

| Name | Type | Description | |------------|---------| ----------- | | name | string | Output asset name template, [name].[contenthash].wasm by default. | | bind | boolean | If true, adds as-bind library files to the compilation (required if you want to use as-loader/runtime/bind). | | fallback | boolean | If true, creates additional JavaScript file which can be used if WebAssembly is not supported. | | raw | boolean | If true, returns binary instead of emitting file. Use for chaining with other loaders. |

Compiler Options

Options passed to the AssemblyScript compiler.

| Name | Type | Description | |------------------|----------| ----------- | | debug | boolean | Enables debug information in emitted binaries, enabled by default in webpack development mode. | | optimizeLevel | number | How much to focus on optimizing code, 3 by default. [0-3] | | shrinkLevel | number | How much to focus on shrinking code size, 1 by default. [0-2] | | coverage | boolean | Re-optimizes until no further improvements can be made. | | noAssert | boolean | Replaces assertions with just their value without trapping, enabled by default in webpack production mode. | | 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 runtime 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