diff --git a/.changeset/gentle-animals-fail.md b/.changeset/gentle-animals-fail.md new file mode 100644 index 000000000000..c2a9b3071d6c --- /dev/null +++ b/.changeset/gentle-animals-fail.md @@ -0,0 +1,7 @@ +--- +"@cloudflare/vite-plugin": minor +--- + +Nest child environment build output in parent environment build output directory. + +This ensures that a single output directory is used for the Worker without additional configuration. diff --git a/packages/vite-plugin-cloudflare/playground/child-environment/__tests__/child-environment.spec.ts b/packages/vite-plugin-cloudflare/playground/child-environment/__tests__/child-environment.spec.ts index 6037ad75d9a9..905b97e22d9a 100644 --- a/packages/vite-plugin-cloudflare/playground/child-environment/__tests__/child-environment.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/child-environment/__tests__/child-environment.spec.ts @@ -1,5 +1,7 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; import { test } from "vitest"; -import { getTextResponse, isBuild } from "../../__test-utils__"; +import { getTextResponse, isBuild, testDir } from "../../__test-utils__"; test.runIf(!isBuild)( "can import module from child environment", @@ -8,3 +10,15 @@ test.runIf(!isBuild)( expect(response).toBe("Hello from the child environment"); } ); + +test.runIf(isBuild)( + "nests child environment output in parent environment output directory", + ({ expect }) => { + const childEnvironmentEntryPath = path.join( + testDir, + "dist/parent/child/child-environment-module.js" + ); + + expect(fs.existsSync(childEnvironmentEntryPath)).toBe(true); + } +); diff --git a/packages/vite-plugin-cloudflare/playground/child-environment/vite.config.ts b/packages/vite-plugin-cloudflare/playground/child-environment/vite.config.ts index 6a7bc6827e7a..ca05fb406f0f 100644 --- a/packages/vite-plugin-cloudflare/playground/child-environment/vite.config.ts +++ b/packages/vite-plugin-cloudflare/playground/child-environment/vite.config.ts @@ -1,7 +1,30 @@ +import assert from "node:assert"; +import * as path from "node:path"; import { cloudflare } from "@cloudflare/vite-plugin"; import { defineConfig } from "vite"; export default defineConfig({ + environments: { + child: { + build: { + rollupOptions: { + input: path.resolve(__dirname, "src/child-environment-module.ts"), + }, + }, + }, + }, + builder: { + async buildApp(builder) { + const parentEnvironment = builder.environments.parent; + const childEnvironment = builder.environments.child; + + assert(parentEnvironment, `No "parent" environment`); + assert(childEnvironment, `No "child" environment`); + + await builder.build(parentEnvironment); + await builder.build(childEnvironment); + }, + }, plugins: [ cloudflare({ inspectorPort: false, diff --git a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts index 9c9159b9949c..0771714a208d 100644 --- a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts +++ b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts @@ -14,7 +14,12 @@ import { VIRTUAL_WORKER_ENTRY, WORKER_ENTRY_PATH_HEADER, } from "./shared"; -import { debuglog, getOutputDirectory, isRolldown } from "./utils"; +import { + debuglog, + getChildOutputDirectory, + getOutputDirectory, + isRolldown, +} from "./utils"; import type { ExportTypes } from "./export-types"; import type { ResolvedWorkerConfig, @@ -196,7 +201,7 @@ export function createCloudflareEnvironmentOptions({ mode, environmentName, isEntryWorker, - isParentEnvironment, + parentEnvironmentOptions, hasNodeJsCompat, }: { workerConfig: ResolvedWorkerConfig; @@ -204,10 +209,10 @@ export function createCloudflareEnvironmentOptions({ mode: vite.ConfigEnv["mode"]; environmentName: string; isEntryWorker: boolean; - isParentEnvironment: boolean; hasNodeJsCompat: boolean; + parentEnvironmentOptions: vite.EnvironmentOptions | undefined; }): vite.EnvironmentOptions { - const rollupOptions: vite.Rollup.RollupOptions = isParentEnvironment + const rollupOptions: vite.Rollup.RollupOptions = !parentEnvironmentOptions ? { input: { [MAIN_ENTRY_NAME]: VIRTUAL_WORKER_ENTRY, @@ -254,7 +259,9 @@ export function createCloudflareEnvironmentOptions({ target, emitAssets: true, manifest: isEntryWorker, - outDir: getOutputDirectory(userConfig, environmentName), + outDir: parentEnvironmentOptions + ? getChildOutputDirectory(parentEnvironmentOptions, environmentName) + : getOutputDirectory(userConfig, environmentName), copyPublicDir: false, ssr: true, ...(isRolldown diff --git a/packages/vite-plugin-cloudflare/src/plugins/config.ts b/packages/vite-plugin-cloudflare/src/plugins/config.ts index bc09e37afa93..8a1de8c1143c 100644 --- a/packages/vite-plugin-cloudflare/src/plugins/config.ts +++ b/packages/vite-plugin-cloudflare/src/plugins/config.ts @@ -174,14 +174,16 @@ function getEnvironmentsConfig( environmentName === ctx.resolvedPluginConfig.entryWorkerEnvironmentName); + const parentEnvironmentOptions = createCloudflareEnvironmentOptions({ + ...sharedOptions, + environmentName, + isEntryWorker, + parentEnvironmentOptions: undefined, + }); + const parentConfig = [ environmentName, - createCloudflareEnvironmentOptions({ - ...sharedOptions, - environmentName, - isEntryWorker, - isParentEnvironment: true, - }), + parentEnvironmentOptions, ] as const; const childConfigs = childEnvironmentNames.map( @@ -192,7 +194,7 @@ function getEnvironmentsConfig( ...sharedOptions, environmentName: childEnvironmentName, isEntryWorker: false, - isParentEnvironment: false, + parentEnvironmentOptions, }), ] as const ); diff --git a/packages/vite-plugin-cloudflare/src/utils.ts b/packages/vite-plugin-cloudflare/src/utils.ts index 7be3d07f6eab..eee13ca09211 100644 --- a/packages/vite-plugin-cloudflare/src/utils.ts +++ b/packages/vite-plugin-cloudflare/src/utils.ts @@ -1,3 +1,4 @@ +import assert from "node:assert"; import * as nodePath from "node:path"; import * as util from "node:util"; import { createRequest, sendResponse } from "@remix-run/node-fetch-server"; @@ -43,6 +44,16 @@ export function getOutputDirectory( ); } +export function getChildOutputDirectory( + parentEnvironmentOptions: vite.EnvironmentOptions, + childEnvironmentName: string +): string { + const parentOutDir = parentEnvironmentOptions.build?.outDir; + assert(parentOutDir, "Parent environment outDir is not defined"); + + return nodePath.join(parentOutDir, childEnvironmentName); +} + const postfixRE = /[?#].*$/; export function cleanUrl(url: string): string { return url.replace(postfixRE, "");