Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/four-planes-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Fix source phase imports in bundled and non-bundled Workers

Wrangler now preserves `import source` syntax when it runs esbuild, including module format detection and bundled deploy output. This fixes both `--no-bundle` and bundled deployments for Workers that import WebAssembly using source phase imports.
7 changes: 7 additions & 0 deletions .changeset/source-phase-miniflare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"miniflare": patch
---

Fix source phase imports parsing in Miniflare

Miniflare now uses the `acorn-import-phases` plugin to parse `import source` syntax when analyzing module dependencies. This fixes `ERR_MODULE_PARSE` errors when running Workers that use source phase imports for WebAssembly modules in local development.
1 change: 1 addition & 0 deletions packages/miniflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@types/which": "^2.0.1",
"@types/ws": "^8.5.7",
"acorn": "8.14.0",
"acorn-import-phases": "^1.0.4",
"acorn-walk": "8.3.2",
"capnp-es": "catalog:default",
"capnweb": "catalog:default",
Expand Down
6 changes: 5 additions & 1 deletion packages/miniflare/src/plugins/core/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { builtinModules } from "node:module";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { TextDecoder, TextEncoder } from "node:util";
import { parse } from "acorn";
import { Parser } from "acorn";
import importPhases from "acorn-import-phases";
import { simple } from "acorn-walk";
import { dim } from "kleur/colors";
import { z } from "zod";
Expand All @@ -14,6 +15,9 @@ import { MatcherRegExps, testRegExps } from "../../workers";
import { getNodeCompat, NodeJSCompatMode } from "./node-compat";
import type estree from "estree";

const ExtendedParser = Parser.extend(importPhases());
const parse = ExtendedParser.parse.bind(ExtendedParser);

const SUGGEST_BUNDLE =
"If you're trying to import an npm package, you'll need to bundle your Worker first.";
const SUGGEST_NODE =
Expand Down
41 changes: 41 additions & 0 deletions packages/miniflare/test/plugins/core/modules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,44 @@ If you're trying to import an npm package, you'll need to bundle your Worker fir
/^Unable to resolve "index\.mjs" dependency "node:assert": no matching module rules\.\nIf you're trying to import a Node\.js built-in module, or an npm package that uses Node\.js built-ins, you'll either need to:/
);
});
test("Miniflare: parses source phase imports without error", async ({
expect,
}) => {
const tmp = await useTmp();
const wasmPath = path.join(tmp, "module.wasm");
const workerPath = path.join(tmp, "index.mjs");

// Create a minimal wasm file
await fs.writeFile(
wasmPath,
Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00])
);

// Create a worker that uses source phase import syntax
await fs.writeFile(
workerPath,
`import source wasmModule from "./module.wasm";
export default {
async fetch() {
return new Response("source phase import parsed successfully");
}
};`
);

// Verify the worker can be loaded without parse errors
// Note: workerd doesn't actually support source phase imports at runtime,
// but we need to ensure the parser doesn't fail on the syntax
const mf = new Miniflare({
modules: true,
modulesRoot: tmp,
modulesRules: [{ type: "CompiledWasm", include: ["**/*.wasm"] }],
compatibilityDate: "2023-08-01",
scriptPath: workerPath,
});
useDispose(mf);

// The worker should be able to load (even if the source phase import
// is not fully functional at runtime)
const res = await mf.dispatchFetch("http://localhost");
expect(await res.text()).toBe("source phase import parsed successfully");
});
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading