Skip to content
Draft
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
45 changes: 45 additions & 0 deletions samples/module-fallback-redirect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Module Fallback Redirect Reproduction

This reproduces a V2 module fallback failure involving a redirected module that
performs a dynamic import. It does not use Vite or Workers SDK.

Start the fallback service from the repository root:

```sh
node samples/module-fallback-redirect/fallback.mjs
```

In another terminal, start Workerd:

```sh
npx workerd@latest serve samples/module-fallback-redirect/config.capnp --experimental
```

Then invoke the Worker:

```sh
curl http://127.0.0.1:8080
```

The Worker imports two bare dependencies. The fallback service redirects both
to canonical `file:///project/node_modules/...` URLs. The `/project` path is a
logical, portable stand-in for a resolved project path; this reproduction does
not read the host filesystem.

- `static-test-dependency` statically imports `./value.mjs`.
- `dynamic-test-dependency` dynamically imports `./value.mjs` when `load()` is
called.

If both imports succeeded, Workerd would log:

```text
static import: loaded
dynamic import: loaded
```

Instead, the static import succeeds, but the dynamic import returns HTTP 500
with:

```text
Referring module not found in the registry: file:///project/node_modules/dynamic-test-dependency/index.mjs
```
19 changes: 19 additions & 0 deletions samples/module-fallback-redirect/config.capnp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Workerd = import "/workerd/workerd.capnp";

const config :Workerd.Config = (
services = [
(name = "main", worker = .worker),
],
sockets = [
(name = "http", address = "127.0.0.1:8080", http = (), service = "main"),
],
);

const worker :Workerd.Worker = (
modules = [
(name = "worker.js", esModule = embed "worker.js"),
],
compatibilityDate = "2026-08-03",
compatibilityFlags = ["new_module_registry"],
moduleFallback = "127.0.0.1:8888",
);
76 changes: 76 additions & 0 deletions samples/module-fallback-redirect/fallback.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) 2026 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

import { createServer } from 'node:http';

function sendJson(response, value) {
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify(value));
}

createServer(async (request, response) => {
let body = '';
for await (const chunk of request) {
body += chunk;
}

const resolution = JSON.parse(body);
console.log(resolution);

switch (resolution.specifier) {
case 'file:///bundle/static-test-dependency':
response.writeHead(301, {
location:
'file:///project/node_modules/static-test-dependency/index.mjs',
});
response.end();
return;
case 'file:///project/node_modules/static-test-dependency/index.mjs':
sendJson(response, {
esModule: [
'import { value } from "./value.mjs";',
'export { value };',
].join('\n'),
});
return;
case 'file:///bundle/value.mjs':
response.writeHead(301, {
location:
'file:///project/node_modules/static-test-dependency/value.mjs',
});
response.end();
return;
case 'file:///project/node_modules/static-test-dependency/value.mjs':
sendJson(response, {
esModule: 'export const value = "loaded";',
});
return;
case 'file:///bundle/dynamic-test-dependency':
response.writeHead(301, {
location:
'file:///project/node_modules/dynamic-test-dependency/index.mjs',
});
response.end();
return;
case 'file:///project/node_modules/dynamic-test-dependency/index.mjs':
sendJson(response, {
esModule: [
'export async function load() {',
' return await import("./value.mjs");',
'}',
].join('\n'),
});
return;
case 'file:///project/node_modules/dynamic-test-dependency/value.mjs':
sendJson(response, {
esModule: 'export const value = "loaded";',
});
return;
default:
response.writeHead(404);
response.end();
}
}).listen(8888, '127.0.0.1', () => {
console.log('Fallback service listening on http://127.0.0.1:8888');
});
15 changes: 15 additions & 0 deletions samples/module-fallback-redirect/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2026 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

import { load } from 'dynamic-test-dependency';
import { value as staticValue } from 'static-test-dependency';

export default {
async fetch() {
console.log('static import:', staticValue);
const dynamicModule = await load();
console.log('dynamic import:', dynamicModule.value);
return new Response('ok');
},
};
Loading