[GH-ISSUE #1031] Failed to resolve shim imports in sandbox environments #226

Open
opened 2026-05-06 12:38:21 +02:00 by BreizhHardware · 7 comments

Originally created by @eashish93 on GitHub (May 2, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/1031

vinext@0.0.46 ships two dist/server/*.js files that still import a shim via a relative path, which #1006 was meant to eliminate. The same vite:import-analysis failure that #1001 / #1006 fixed is back when running under @cloudflare/sandbox SDK.

Image

Files still wrong in 0.0.46

// dist/server/app-page-boundary-render.js:3
// dist/server/app-page-route-wiring.js:3
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";

Should be:

import { LayoutSegmentProvider } from "vinext/shims/layout-segment-context";

…matching the pattern #1006 applied to the other 67 imports across 34 files.

Symptom

[plugin:vite:import-analysis] Failed to resolve import
"/workspace/node_modules/vinext/dist/shims/layout-segment-context.js"
from "virtual:vite-rsc/client-in-server-package-proxy/%2Fworkspace%2Fnode_modules%2Fvinext%2Fdist%2Fshims%2Flayout-segment-context.js"

Fires on first paint inside a @cloudflare/sandbox-managed container, every time.

Why plain vinext dev doesn't show it

Vite's optimizeDeps pre-bundles the shim and rewrites the absolute path import to ?v=<hash> form, masking it. Under the @cloudflare/sandbox SDK invocation path the optimizer cache misses, so the raw absolute path reaches import-analysis.normalizeUrl — which treats leading / as URL-relative-to-server-root, so /workspace/foo resolves to <root>/workspace/foo = /workspace/workspace/foo and fails.

Versions

vinext 0.0.46
@vitejs/plugin-rsc ^0.5.25
vite 8.0.10
@cloudflare/vite-plugin ^1.35.0
@cloudflare/sandbox ^0.9.2

Fix

Apply #1006's transform to those two files. Worth checking why the regression test added in #1006 didn't catch this in CI for 0.0.46.

Reproduce

Zip attached. README inside has the full mechanism walkthrough.

unzip vinext-shim-bug-repro.zip
cd vinext-shim-bug-repro/main
bun install
bun run dev
# open http://localhost:5200/ → click Start sandbox

vinext-shim-bug-repro.zip

Originally created by @eashish93 on GitHub (May 2, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/1031 `vinext@0.0.46` ships two `dist/server/*.js` files that still import a shim via a relative path, which #1006 was meant to eliminate. The same `vite:import-analysis` failure that #1001 / #1006 fixed is back when running under `@cloudflare/sandbox` SDK. <img width="1253" height="600" alt="Image" src="https://github.com/user-attachments/assets/cede780b-c460-4568-9a42-b0eb802df31c" /> ## Files still wrong in 0.0.46 ```js // dist/server/app-page-boundary-render.js:3 // dist/server/app-page-route-wiring.js:3 import { LayoutSegmentProvider } from "../shims/layout-segment-context.js"; ``` Should be: ```js import { LayoutSegmentProvider } from "vinext/shims/layout-segment-context"; ``` …matching the pattern #1006 applied to the other 67 imports across 34 files. ## Symptom ``` [plugin:vite:import-analysis] Failed to resolve import "/workspace/node_modules/vinext/dist/shims/layout-segment-context.js" from "virtual:vite-rsc/client-in-server-package-proxy/%2Fworkspace%2Fnode_modules%2Fvinext%2Fdist%2Fshims%2Flayout-segment-context.js" ``` Fires on first paint inside a `@cloudflare/sandbox`-managed container, every time. ## Why plain `vinext dev` doesn't show it Vite's `optimizeDeps` pre-bundles the shim and rewrites the absolute path import to `?v=<hash>` form, masking it. Under the `@cloudflare/sandbox` SDK invocation path the optimizer cache misses, so the raw absolute path reaches `import-analysis.normalizeUrl` — which treats leading `/` as URL-relative-to-server-root, so `/workspace/foo` resolves to `<root>/workspace/foo` = `/workspace/workspace/foo` and fails. ## Versions | | | |---|---| | `vinext` | **0.0.46** | | `@vitejs/plugin-rsc` | `^0.5.25` | | `vite` | `8.0.10` | | `@cloudflare/vite-plugin` | `^1.35.0` | | `@cloudflare/sandbox` | `^0.9.2` | ## Fix Apply #1006's transform to those two files. Worth checking why the regression test added in #1006 didn't catch this in CI for 0.0.46. ## Reproduce Zip attached. README inside has the full mechanism walkthrough. ```sh unzip vinext-shim-bug-repro.zip cd vinext-shim-bug-repro/main bun install bun run dev # open http://localhost:5200/ → click Start sandbox ``` [vinext-shim-bug-repro.zip](https://github.com/user-attachments/files/27309707/vinext-shim-bug-repro.zip)
Author
Owner

@james-elicx commented on GitHub (May 2, 2026):

The prerelease for the last commit on main is https://pkg.pr.new/vinext@a49be5c

Please can you try that?

<!-- gh-comment-id:4364948593 --> @james-elicx commented on GitHub (May 2, 2026): The prerelease for the last commit on main is https://pkg.pr.new/vinext@a49be5c Please can you try that?
Author
Owner

@james-elicx commented on GitHub (May 2, 2026):

Oh I see. The build that gets published is resolving the aliases and they're going back to relative paths.

<!-- gh-comment-id:4364954588 --> @james-elicx commented on GitHub (May 2, 2026): Oh I see. The build that gets published is resolving the aliases and they're going back to relative paths.
Author
Owner

@eashish93 commented on GitHub (May 2, 2026):

Trying now. Zip file though I've uploaded is using 0.0.46 (not .45) btw and now you can easily reproduce it.

<!-- gh-comment-id:4364963596 --> @eashish93 commented on GitHub (May 2, 2026): Trying now. Zip file though I've uploaded is using 0.0.46 (not .45) btw and now you can easily reproduce it.
Author
Owner

@james-elicx commented on GitHub (May 2, 2026):

Yes it won't make a difference, the imports are being transformed back to relative, which makes sense.

I think you should file an issue in the RSC plugin's repo as this sounds like a bug that will need fixing in how they deal with deps.

<!-- gh-comment-id:4364965258 --> @james-elicx commented on GitHub (May 2, 2026): Yes it won't make a difference, the imports are being transformed back to relative, which makes sense. I think you should file an issue in the RSC plugin's repo as this sounds like a bug that will need fixing in how they deal with deps.
Author
Owner

@eashish93 commented on GitHub (May 3, 2026):

I tried that pre-release and it's same, then I tried this patch:

#!/usr/bin/env bun
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';

const distRoot = process.argv[2];
if (!distRoot) {
  console.error('usage: patch-vinext-shims.ts <path-to-vinext/dist>');
  process.exit(1);
}

async function* walkJs(dir: string): AsyncGenerator<string> {
  for (const entry of await readdir(dir, { withFileTypes: true })) {
    const full = join(dir, entry.name);
    if (entry.isDirectory()) {
      if (entry.name === 'shims') continue;
      yield* walkJs(full);
    } else if (entry.isFile() && entry.name.endsWith('.js')) {
      yield full;
    }
  }
}

const importRe = /from "(?:\.\.\/)+shims\/([^"]+)\.js"|from "\.\/shims\/([^"]+)\.js"/g;
let totalRewrites = 0;
let touchedFiles = 0;

for await (const file of walkJs(distRoot)) {
  const original = await readFile(file, 'utf8');
  let count = 0;
  const rewritten = original.replace(importRe, (_m, a, b) => {
    count++;
    return `from "vinext/shims/${a ?? b}"`;
  });
  if (count > 0) {
    await writeFile(file, rewritten);
    touchedFiles++;
    totalRewrites += count;
    console.log(`  ${file.replace(distRoot, '')}: ${count}`);
  }
}

console.log(`\npatched ${totalRewrites} imports across ${touchedFiles} files`);

That fixes the issue for me, but then another vite plugin error occur which recently fixed here #1008 .

So I asked claude to give me a patch to apply. Here's the patch for this one:

#!/usr/bin/env bun
// Workaround for cloudflare/vinext#1008 / upstream vitejs/vite-plugin-react.
// `client-package-proxy`'s load handler crashes with
//   "Cannot read properties of undefined (reading 'exportNames')"
// when the rsc env hasn't yet transformed the package's shim file before the
// proxy URL is fetched. Patch the load handler to fall back to a wildcard
// re-export when the metadata isn't there yet.
//
// Idempotent — re-running it on already-patched files is a no-op.
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';

const root = process.argv[2];
if (!root) {
  console.error('usage: patch-plugin-rsc.ts <path-to-@vitejs/plugin-rsc>');
  process.exit(1);
}

const distDir = join(root, 'dist');
const files = (await readdir(distDir)).filter(
  (f) => f.startsWith('plugin-') && f.endsWith('.js')
);

const NEEDLE =
  'return `export {${Object.values(manager.clientReferenceMetaMap).find((v) => v.packageSource === source).exportNames.join(",")}} from ${JSON.stringify(source)};\\n`;';

const REPLACEMENT =
  '{ const _m = Object.values(manager.clientReferenceMetaMap).find((v) => v.packageSource === source); return _m ? `export {${_m.exportNames.join(",")}} from ${JSON.stringify(source)};\\n` : `export * from ${JSON.stringify(source)};\\n`; }';

let patched = 0;
let skipped = 0;
for (const file of files) {
  const path = join(distDir, file);
  const content = await readFile(path, 'utf8');
  if (content.includes(REPLACEMENT)) {
    skipped++;
    continue;
  }
  if (!content.includes(NEEDLE)) continue;
  await writeFile(path, content.replace(NEEDLE, REPLACEMENT));
  console.log(`  patched ${file}`);
  patched++;
}

console.log(`\npatched ${patched} files (${skipped} already patched)`);

You can reproduce both error on same zip file, one by one. Apply first patch and then you'll get another error (related to #1008 , exportNames).

Also I'll try to file a bug on vite-plugin-react also, but they require live demo url for reproduction. Will try with github link there.

<!-- gh-comment-id:4365035058 --> @eashish93 commented on GitHub (May 3, 2026): I tried that pre-release and it's same, then I tried this patch: ```ts #!/usr/bin/env bun import { readdir, readFile, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; const distRoot = process.argv[2]; if (!distRoot) { console.error('usage: patch-vinext-shims.ts <path-to-vinext/dist>'); process.exit(1); } async function* walkJs(dir: string): AsyncGenerator<string> { for (const entry of await readdir(dir, { withFileTypes: true })) { const full = join(dir, entry.name); if (entry.isDirectory()) { if (entry.name === 'shims') continue; yield* walkJs(full); } else if (entry.isFile() && entry.name.endsWith('.js')) { yield full; } } } const importRe = /from "(?:\.\.\/)+shims\/([^"]+)\.js"|from "\.\/shims\/([^"]+)\.js"/g; let totalRewrites = 0; let touchedFiles = 0; for await (const file of walkJs(distRoot)) { const original = await readFile(file, 'utf8'); let count = 0; const rewritten = original.replace(importRe, (_m, a, b) => { count++; return `from "vinext/shims/${a ?? b}"`; }); if (count > 0) { await writeFile(file, rewritten); touchedFiles++; totalRewrites += count; console.log(` ${file.replace(distRoot, '')}: ${count}`); } } console.log(`\npatched ${totalRewrites} imports across ${touchedFiles} files`); ``` That fixes the issue for me, but then another vite plugin error occur which recently fixed here #1008 . So I asked claude to give me a patch to apply. Here's the patch for this one: ```ts #!/usr/bin/env bun // Workaround for cloudflare/vinext#1008 / upstream vitejs/vite-plugin-react. // `client-package-proxy`'s load handler crashes with // "Cannot read properties of undefined (reading 'exportNames')" // when the rsc env hasn't yet transformed the package's shim file before the // proxy URL is fetched. Patch the load handler to fall back to a wildcard // re-export when the metadata isn't there yet. // // Idempotent — re-running it on already-patched files is a no-op. import { readdir, readFile, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; const root = process.argv[2]; if (!root) { console.error('usage: patch-plugin-rsc.ts <path-to-@vitejs/plugin-rsc>'); process.exit(1); } const distDir = join(root, 'dist'); const files = (await readdir(distDir)).filter( (f) => f.startsWith('plugin-') && f.endsWith('.js') ); const NEEDLE = 'return `export {${Object.values(manager.clientReferenceMetaMap).find((v) => v.packageSource === source).exportNames.join(",")}} from ${JSON.stringify(source)};\\n`;'; const REPLACEMENT = '{ const _m = Object.values(manager.clientReferenceMetaMap).find((v) => v.packageSource === source); return _m ? `export {${_m.exportNames.join(",")}} from ${JSON.stringify(source)};\\n` : `export * from ${JSON.stringify(source)};\\n`; }'; let patched = 0; let skipped = 0; for (const file of files) { const path = join(distDir, file); const content = await readFile(path, 'utf8'); if (content.includes(REPLACEMENT)) { skipped++; continue; } if (!content.includes(NEEDLE)) continue; await writeFile(path, content.replace(NEEDLE, REPLACEMENT)); console.log(` patched ${file}`); patched++; } console.log(`\npatched ${patched} files (${skipped} already patched)`); ``` You can reproduce both error on same zip file, one by one. Apply first patch and then you'll get another error (related to #1008 , exportNames). Also I'll try to file a bug on vite-plugin-react also, but they require live demo url for reproduction. Will try with github link there.
Author
Owner

@james-elicx commented on GitHub (May 3, 2026):

The bug is in the RSC plugin or Vite from what I can tell - relative imports within our library should work fine...

<!-- gh-comment-id:4365049775 --> @james-elicx commented on GitHub (May 3, 2026): The bug is in the RSC plugin or Vite from what I can tell - relative imports within our library should work fine...
Author
Owner

@eashish93 commented on GitHub (May 3, 2026):

Linked here the bug I filed (description auto-gen via claude): https://github.com/vitejs/vite-plugin-react/issues/1207

<!-- gh-comment-id:4365052558 --> @eashish93 commented on GitHub (May 3, 2026): Linked here the bug I filed (description auto-gen via claude): https://github.com/vitejs/vite-plugin-react/issues/1207
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#226
No description provided.