Files
wasm/scripts/strip-wasm-fetch-init.mjs
rob thijssenandClaude Opus 5 e8bf9e20c7 fix(quantus-crypto): strip wasm-bindgen's fetch-based init from the shipped glue
The package could not be bundled. Every webpack consumer failed with:

  Module not found: Error: Can't resolve 'quantus_crypto_bg.wasm'
    in node_modules/@quantus/crypto/generated

wasm-bindgen's async `__wbg_init` contains

  module_or_path = new URL('quantus_crypto_bg.wasm', import.meta.url);

and webpack resolves `new URL(..., import.meta.url)` statically, at build time,
whether or not the branch can run. The file is not in the package — the wasm
ships base64'd in bytes.js, which is the entire point of this package — so the
build failed on a code path we never call.

node never sees it, which is why ten Rust tests, twelve consumer assertions and a
browser probe all passed while the package was unusable in a bundler. It took a
real extension build to surface, and that is the useful lesson: this package's
consumers bundle, and nothing in its own test suite does.

So the dead init is removed after bindgen runs. Shipping a second copy of the
wasm to satisfy a path we do not use would be the wide fix; deleting generated
code we never call is the narrow one.

The stripper asserts the shape it expects and throws if wasm-bindgen changes it,
rather than silently no-opping — a build that quietly stopped stripping would
ship the broken package again. It also re-checks that no reference to the .wasm
filename survives.

Published as 0.1.1.

Refs quantus/wasm#1, quantus/extension#2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 11:53:18 +03:00

54 lines
2.0 KiB
JavaScript

// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Removes wasm-bindgen's async `__wbg_init` from the generated glue.
//
// We never call it — the whole point of this package is `initSync` over bytes
// compiled into the JS, because the consumer is an MV3 service worker that
// cannot usefully fetch. But `__wbg_init` contains
//
// module_or_path = new URL('quantus_crypto_bg.wasm', import.meta.url);
//
// and webpack resolves `new URL(..., import.meta.url)` statically, at build
// time, whether or not the branch can ever run. The file is not in the package —
// the wasm ships base64'd in bytes.js — so every bundling consumer fails with
// "Can't resolve 'quantus_crypto_bg.wasm'". node never sees this, which is why
// it took a real extension build to surface.
//
// Deleting dead generated code is the narrow fix; shipping a second copy of the
// wasm to satisfy a code path we do not use would be the wide one.
import fs from 'node:fs';
const [file] = process.argv.slice(2);
const source = fs.readFileSync(file, 'utf-8');
// Fail loudly rather than silently no-op if wasm-bindgen changes shape: a build
// that quietly stopped stripping would ship the broken package again.
const START = '\nasync function __wbg_init(module_or_path) {';
const EXPORTS = 'export { initSync, __wbg_init as default };';
const start = source.indexOf(START);
if (start === -1 || !source.includes(EXPORTS)) {
throw new Error(`${file}: wasm-bindgen output is not the shape this expects; re-check whether __wbg_init still needs stripping`);
}
const end = source.indexOf('\n}\n', start);
if (end === -1) {
throw new Error(`${file}: could not find the end of __wbg_init`);
}
const stripped = source
.slice(0, start)
.concat(source.slice(end + 3))
.replace(EXPORTS, 'export { initSync };');
if (stripped.includes('quantus_crypto_bg.wasm')) {
throw new Error(`${file}: a reference to the .wasm file survived stripping`);
}
fs.writeFileSync(file, stripped);
console.log(`*** Stripped fetch-based init from ${file}`);