From c16f0fc35c96452f73ebdbd2969b593a5a824f39 Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Mon, 26 Oct 2026 15:14:41 +0900 Subject: [PATCH] fix(deploy): resolve hosted framework bundles with Worker conditions Claude-Session: https://claude.ai/code/session_01BuqBPCT2mTmoaAxd2EDtv1 --- packages/void/src/cli/wrapper.ts | 3 ++ packages/void/test/unit/wrapper.test.ts | 53 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/packages/void/src/cli/wrapper.ts b/packages/void/src/cli/wrapper.ts index 4ca710ce4..36fd7f51e 100644 --- a/packages/void/src/cli/wrapper.ts +++ b/packages/void/src/cli/wrapper.ts @@ -523,6 +523,9 @@ export async function bundleEntry(root: string, entry: string): Promise { }); }); +describe('bundleEntry', () => { + const roots: Array = []; + afterEach(() => { + for (const root of roots.splice(0)) { + rmSync(root, { recursive: true, force: true }); + } + }); + + it('resolves dependencies with Worker conditions in a production build', async () => { + const root = mkdtempSync(join(tmpdir(), 'void-bundle-entry-conditions-')); + roots.push(root); + writeFileSync(join(root, 'package.json'), JSON.stringify({ type: 'module' })); + const packages = { + dual: { + exports: { workerd: './worker.js', browser: './browser.js', default: './node.js' }, + files: { + 'worker.js': 'dual-workerd', + 'browser.js': 'dual-browser', + 'node.js': 'dual-node', + }, + }, + modes: { + exports: { development: './dev.js', production: './prod.js', default: './dev.js' }, + files: { 'dev.js': 'modes-development', 'prod.js': 'modes-production' }, + }, + }; + for (const [name, { exports, files }] of Object.entries(packages)) { + const dir = join(root, 'node_modules', name); + mkdirSync(dir, { recursive: true }); + writeFileSync(join(dir, 'package.json'), JSON.stringify({ name, type: 'module', exports })); + for (const [file, value] of Object.entries(files)) { + writeFileSync(join(dir, file), `export const value = '${value}';\n`); + } + } + const entry = join(root, 'build', '_worker.js'); + mkdirSync(dirname(entry)); + writeFileSync( + entry, + "import { value as target } from 'dual'; import { value as mode } from 'modes';\n" + + 'export default { fetch() { return new Response(target + mode) } };\n', + ); + + const { outputDir, entryFilename } = await bundleEntry(root, entry); + + const bundle = readFileSync(join(outputDir, entryFilename), 'utf8'); + expect(bundle).toContain('dual-workerd'); + expect(bundle).not.toContain('dual-browser'); + expect(bundle).toContain('modes-production'); + expect(bundle).not.toContain('modes-development'); + }); +}); + describe('cleanupWrapper', () => { const roots: Array = [];