Skip to content

Instantly share code, notes, and snippets.

@jamsinclair
Last active October 31, 2024 08:23
Show Gist options
  • Save jamsinclair/6ad148d0590291077a4ce389c2b274ea to your computer and use it in GitHub Desktop.
Save jamsinclair/6ad148d0590291077a4ce389c2b274ea to your computer and use it in GitHub Desktop.
Vite Plugin to solve issues with Emscripten projects using Pthreads

emscripten-static-worker-options

A Vite plugin that statically inlines Emscripten worker options at build time.

This could serve as a temporary solution to the Emscripten issue (emscripten-core/emscripten#22394)

Installation

Copy the plugin.js code to a file in your project.

Usage

Add the plugin to your vite.config.js file within the Worker plugins configuration:

import { defineConfig } from 'vite'
import emscriptenStaticWorkerOptions from './your-file-with-the-plugin-code.js'

export default defineConfig({
  worker: {
    format: "es",
    plugins: [
      emscriptenStaticWorkerOptions()
    ]
  }
})

How it works

This plugin transforms code that uses dynamic worker options into static values at build time. For example:

var workerOptions = { type: "module",name: "em-pthread" };
//...
worker=new Worker(new URL("wasm-module.js",import.meta.url),workerOptions);

// Output: Transformed code
worker=new Worker(new URL("wasm-module.js",import.meta.url),{ type: "module",name: "em-pthread" });

Options

The plugin optionally accepts the following options:

  • include: Array of patterns (RegExp or glob strings) to include in transformation
    • Default: [/\.[jt]s$/]
  • exclude: Array of patterns (RegExp or glob strings) to exclude from transformation
    • Default: []

Pattern Matching

The plugin supports both RegExp and glob string patterns:

// Using RegExp
include: [/\.worker\.js$/]

// Using glob strings
include: ['src/*.worker.js']

Notes

  • It only processes emscripten presenting files
  • By default plugin is run on all .js and .ts files. This can be further customised with the include and exclude options.
  • The original workerOptions declaration is removed from the code
import { createFilter } from 'vite';
function isEmscriptenFile(code) {
return /var\s+Module\s*=|WebAssembly\.instantiate/.test(code) && /var\s+workerOptions\s*=/.test(code);
}
/**
* Vite plugin that replaces Emscripten workerOptions with static object literal to fix error with Vite
* See project issue: https://github.com/emscripten-core/emscripten/issues/22394
*
* Defaults to running for all .js and .ts files. If there are any issues you can use the include/exclude options.
*
* @param {Object} options
* @property {string[]} [include] - Glob patterns to include
* @property {string[]} [exclude] - Glob patterns to exclude
* @returns {import('vite').Plugin}
*/
export default function emscriptenStaticWorkerOptions(options = {}) {
const filter = createFilter(
options.include || /\.[jt]s$/,
options.exclude
);
return {
name: 'emscripten-static-worker-options',
enforce: 'pre',
transform(code, id) {
if (!filter(id)) return null;
if (!isEmscriptenFile(code)) return null;
const workerOptionsMatch = code.match(/var\s+workerOptions\s*=\s*({[^}]+})/);
if (!workerOptionsMatch) return null;
const optionsObjectStr = workerOptionsMatch[1];
const optionsDeclarationStr = workerOptionsMatch[0];
const modifiedCode = code
.replace(optionsDeclarationStr, '')
.replace(new RegExp('workerOptions(?![\\w$])', 'g'), optionsObjectStr);
return {
code: modifiedCode,
map: null
};
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment