Skip to content

Commit f29e699

Browse files
authored
Add support for using the Vite plugin without a Wrangler config file (#11408)
* Add support for zero-config Vite use * Remove e2e test for missing config * Move worker name logic into wrangler * Remove logger
1 parent 8ecabd8 commit f29e699

File tree

12 files changed

+120
-63
lines changed

12 files changed

+120
-63
lines changed

.changeset/curly-weeks-run.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Export unstable helpers useful for generating wrangler config

.changeset/public-baths-change.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@cloudflare/vite-plugin": minor
3+
---
4+
5+
Support zero-config operation
6+
7+
If the Vite plugin is used in a project without an existing Wrangler config file, it should be able to operate in "zero-config" mode by generating a default Wrangler configuration for an assets-only worker.

packages/vite-plugin-cloudflare/e2e/fixtures/no-wrangler-config/package.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

packages/vite-plugin-cloudflare/e2e/fixtures/no-wrangler-config/vite.config.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/vite-plugin-cloudflare/e2e/wrangler-configs-validation.test.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@ import { runLongLived, seed } from "./helpers";
55
// testing regarding the validation there are unit tests in src/__tests__/get-validated-wrangler-config-path.spec.ts
66

77
describe("during development wrangler config files are validated", () => {
8-
const noWranglerConfigProjectPath = seed("no-wrangler-config", "pnpm");
9-
test("for the entry worker", async ({ expect }) => {
10-
const proc = await runLongLived("pnpm", "dev", noWranglerConfigProjectPath);
11-
expect(await proc.exitCode).not.toBe(0);
12-
expect(proc.stderr).toMatch(
13-
/Error: No config file found in the .*? directory/
14-
);
15-
});
16-
178
const noWranglerConfigAuxProjectPath = seed(
189
"no-wrangler-config-for-auxiliary-worker",
1910
"pnpm"

packages/vite-plugin-cloudflare/playground/static/wrangler.jsonc

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/vite-plugin-cloudflare/src/__tests__/get-validated-wrangler-config-path.spec.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,40 @@ const isWindows = process.platform === "win32";
99

1010
describe("valid cases", () => {
1111
test("should return the value of a found wrangler config", () => {
12-
const path = getValidatedWranglerConfigPath(fixturesPath, undefined);
13-
expect(normalize(path)).toMatch(
12+
const result = getValidatedWranglerConfigPath(fixturesPath, undefined);
13+
expect(result).toBeDefined();
14+
expect(normalize(result!)).toMatch(
1415
isWindows
1516
? /\\__tests__\\fixtures\\wrangler\.jsonc/
1617
: /\/__tests__\/fixtures\/wrangler\.jsonc/
1718
);
1819
});
1920

2021
test("should return the value of a requested wrangler config", () => {
21-
const path = getValidatedWranglerConfigPath(
22+
const result = getValidatedWranglerConfigPath(
2223
fixturesPath,
2324
join(fixturesPath, "simple-wrangler.jsonc")
2425
);
25-
expect(normalize(path)).toMatch(
26+
expect(result).toBeDefined();
27+
expect(normalize(result!)).toMatch(
2628
isWindows
2729
? /\\__tests__\\fixtures\\simple-wrangler\.jsonc/
2830
: /\/__tests__\/fixtures\/simple-wrangler\.jsonc/
2931
);
3032
});
3133
});
3234

33-
describe("invalid cases", () => {
34-
test("should error with an helpful message if a wrangler config could not be found", () => {
35-
expect(() => {
36-
getValidatedWranglerConfigPath(
37-
join(fixturesPath, "empty-dir"),
38-
undefined
39-
);
40-
}).toThrowError(
41-
/No config file found in the .*?empty-dir directory\. Please add a wrangler.\(jsonc\|json\|toml\) file\./
35+
describe("zero-config cases", () => {
36+
test("should return undefined when no wrangler config is found (zero-config mode)", () => {
37+
const result = getValidatedWranglerConfigPath(
38+
join(fixturesPath, "empty-dir"),
39+
undefined
4240
);
41+
expect(result).toBeUndefined();
4342
});
43+
});
4444

45+
describe("invalid cases", () => {
4546
[false, true].forEach((forAuxiliaryWorker) => {
4647
const testPrefix = forAuxiliaryWorker
4748
? "[auxiliary worker]"

packages/vite-plugin-cloudflare/src/plugin-config.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as vite from "vite";
55
import { getWorkerConfigs } from "./deploy-config";
66
import { hasNodeJsCompat, NodeJsCompat } from "./nodejs-compat";
77
import {
8+
getDefaultWorkerConfig,
89
getValidatedWranglerConfigPath,
910
getWorkerConfig,
1011
} from "./workers-configs";
@@ -137,14 +138,14 @@ export function resolvePluginConfig(
137138
pluginConfig.configPath
138139
);
139140

140-
const entryWorkerResolvedConfig = getWorkerConfig(
141-
entryWorkerConfigPath,
142-
cloudflareEnv,
143-
{
144-
visitedConfigPaths: configPaths,
145-
isEntryWorker: true,
146-
}
147-
);
141+
// Handle zero-config mode when no wrangler config file is found
142+
const entryWorkerResolvedConfig =
143+
entryWorkerConfigPath === undefined
144+
? getDefaultWorkerConfig(root)
145+
: getWorkerConfig(entryWorkerConfigPath, cloudflareEnv, {
146+
visitedConfigPaths: configPaths,
147+
isEntryWorker: true,
148+
});
148149

149150
if (entryWorkerResolvedConfig.type === "assets-only") {
150151
return {

packages/vite-plugin-cloudflare/src/workers-configs.ts

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import assert from "node:assert";
22
import * as fs from "node:fs";
33
import * as path from "node:path";
4-
import { unstable_readConfig } from "wrangler";
4+
import {
5+
unstable_defaultWranglerConfig,
6+
unstable_getDevCompatibilityDate,
7+
unstable_getWorkerNameFromProject,
8+
unstable_readConfig,
9+
} from "wrangler";
510
import type { AssetsOnlyConfig, WorkerConfig } from "./plugin-config";
611
import type { Optional } from "./utils";
712
import type { Unstable_Config as RawWorkerConfig } from "wrangler";
@@ -342,6 +347,40 @@ export function getWorkerConfig(
342347
};
343348
}
344349

350+
/**
351+
* Generates a default worker config for zero-config mode when no wrangler config file is found.
352+
* The worker name is derived from package.json name or directory basename.
353+
* The compatibility date is taken from the installed workerd runtime.
354+
*
355+
* @param root the root of the vite project
356+
* @returns an assets-only worker config with sensible defaults
357+
*/
358+
export function getDefaultWorkerConfig(
359+
root: string
360+
): AssetsOnlyWorkerResolvedConfig {
361+
const workerName = unstable_getWorkerNameFromProject(root);
362+
const compatibilityDate = unstable_getDevCompatibilityDate(undefined);
363+
364+
// Start with the full default config to ensure all required fields have proper defaults,
365+
// then override the fields specific to this zero-config worker
366+
const config: RawWorkerConfig = {
367+
...unstable_defaultWranglerConfig,
368+
topLevelName: workerName,
369+
name: workerName,
370+
compatibility_date: compatibilityDate,
371+
};
372+
373+
return {
374+
type: "assets-only",
375+
raw: config,
376+
config: config as AssetsOnlyConfig,
377+
nonApplicable: {
378+
replacedByVite: new Set(),
379+
notRelevant: new Set(),
380+
},
381+
};
382+
}
383+
345384
const ENTRY_MODULE_EXTENSIONS = [".js", ".mjs", ".ts", ".mts", ".jsx", ".tsx"];
346385

347386
/**
@@ -373,13 +412,23 @@ function maybeResolveMain(main: string, configPath: string): string {
373412
* @param root the root of the vite project
374413
* @param requestedConfigPath the requested config path, if any
375414
* @param isForAuxiliaryWorker whether the config path is being requested for an auxiliary worker
376-
* @returns a valid path to a config file
415+
* @returns a valid path to a config file, or undefined for entry workers when no config is found (zero-config mode)
377416
*/
417+
export function getValidatedWranglerConfigPath(
418+
root: string,
419+
requestedConfigPath: string | undefined,
420+
isForAuxiliaryWorker: true
421+
): string;
422+
export function getValidatedWranglerConfigPath(
423+
root: string,
424+
requestedConfigPath: string | undefined,
425+
isForAuxiliaryWorker?: boolean
426+
): string | undefined;
378427
export function getValidatedWranglerConfigPath(
379428
root: string,
380429
requestedConfigPath: string | undefined,
381430
isForAuxiliaryWorker = false
382-
) {
431+
): string | undefined {
383432
if (requestedConfigPath) {
384433
const configPath = path.resolve(root, requestedConfigPath);
385434

@@ -423,12 +472,7 @@ export function getValidatedWranglerConfigPath(
423472

424473
const configPath = findWranglerConfig(root);
425474

426-
if (!configPath) {
427-
throw new Error(
428-
`No config file found in the ${root} directory. Please add a wrangler.(jsonc|json|toml) file.`
429-
);
430-
}
431-
475+
// Return undefined for zero-config mode when no config file is found
432476
return configPath;
433477
}
434478

packages/wrangler/src/api/integrations/platform/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import type {
3737
export { getVarsForDev as unstable_getVarsForDev } from "../../../dev/dev-vars";
3838
export { readConfig as unstable_readConfig };
3939
export { getDurableObjectClassNameToUseSQLiteMap as unstable_getDurableObjectClassNameToUseSQLiteMap };
40+
export { getDevCompatibilityDate as unstable_getDevCompatibilityDate } from "../../../utils/compatibility-date";
41+
export { getWorkerNameFromProject as unstable_getWorkerNameFromProject } from "../../../autoconfig/details";
4042
export type {
4143
Config as Unstable_Config,
4244
RawConfig as Unstable_RawConfig,

0 commit comments

Comments
 (0)