Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.
Merged
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
2 changes: 1 addition & 1 deletion packages/vite-plugin-cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"dependencies": {
"@hattip/adapter-node": "^0.0.49",
"miniflare": "3.20241205.0",
"miniflare": "3.20241230.1",
"unenv": "catalog:default",
"ws": "^8.18.0"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name = "my-worker"
main = "./index.ts"
compatibility_date = "2024-09-09"
compatibility_date = "2024-12-30"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "my-worker"
main = "./index.ts"
compatibility_date = "2024-09-09"
compatibility_date = "2024-12-30"

base_dir = "./src"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ describe('getWorkerConfig', () => {
test('should return a simple raw config', () => {
const { raw } = getWorkerConfig(
fileURLToPath(new URL('fixtures/simple-wrangler.toml', import.meta.url)),
undefined,
);
expect(typeof raw).toEqual('object');

Expand Down Expand Up @@ -35,6 +36,7 @@ describe('getWorkerConfig', () => {
test('should return a simple config without non-applicable fields', () => {
const { config } = getWorkerConfig(
fileURLToPath(new URL('fixtures/simple-wrangler.toml', import.meta.url)),
undefined,
);
expect(typeof config).toEqual('object');

Expand All @@ -44,6 +46,7 @@ describe('getWorkerConfig', () => {
test("should not return any non-applicable config when there isn't any", () => {
const { nonApplicable } = getWorkerConfig(
fileURLToPath(new URL('fixtures/simple-wrangler.toml', import.meta.url)),
undefined,
);
expect(nonApplicable).toEqual({
replacedByVite: new Set(),
Expand All @@ -55,6 +58,7 @@ describe('getWorkerConfig', () => {
test('should read a simple wrangler.toml file', () => {
const { config, raw, nonApplicable } = getWorkerConfig(
fileURLToPath(new URL('fixtures/simple-wrangler.toml', import.meta.url)),
undefined,
);
expect(typeof config).toEqual('object');

Expand Down Expand Up @@ -91,6 +95,7 @@ describe('getWorkerConfig', () => {
import.meta.url,
),
),
undefined,
);

expect(typeof config).toEqual('object');
Expand Down
2 changes: 1 addition & 1 deletion packages/vite-plugin-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin {
return { appType: 'custom' };
}

resolvedPluginConfig = resolvePluginConfig(pluginConfig, userConfig);
resolvedPluginConfig = resolvePluginConfig(pluginConfig, userConfig, env);

if (!workersConfigsWarningShown) {
workersConfigsWarningShown = true;
Expand Down
49 changes: 34 additions & 15 deletions packages/vite-plugin-cloudflare/src/plugin-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,38 @@ import type {

export type PersistState = boolean | { path: string };

interface PluginWorkerConfig {
configPath: string;
interface BaseWorkerConfig {
viteEnvironment?: { name?: string };
}

export interface PluginConfig extends Partial<PluginWorkerConfig> {
auxiliaryWorkers?: PluginWorkerConfig[];
interface EntryWorkerConfig extends BaseWorkerConfig {
configPath?: string;
}

interface AuxiliaryWorkerConfig extends BaseWorkerConfig {
configPath: string;
}

export interface PluginConfig extends EntryWorkerConfig {
auxiliaryWorkers?: AuxiliaryWorkerConfig[];
persistState?: PersistState;
}

type Defined<T> = Exclude<T, undefined>;

export type AssetsOnlyConfig = SanitizedWorkerConfig & {
interface BaseConfig extends SanitizedWorkerConfig {
topLevelName: Defined<SanitizedWorkerConfig['topLevelName']>;
name: Defined<SanitizedWorkerConfig['name']>;
compatibility_date: Defined<SanitizedWorkerConfig['compatibility_date']>;
}

export interface AssetsOnlyConfig extends BaseConfig {
assets: Defined<SanitizedWorkerConfig['assets']>;
};
}

export type WorkerConfig = SanitizedWorkerConfig & {
name: Defined<SanitizedWorkerConfig['name']>;
export interface WorkerConfig extends BaseConfig {
main: Defined<SanitizedWorkerConfig['main']>;
};
}

interface BasePluginConfig {
configPaths: Set<string>;
Expand Down Expand Up @@ -65,10 +77,12 @@ function workerNameToEnvironmentName(workerName: string) {
export function resolvePluginConfig(
pluginConfig: PluginConfig,
userConfig: vite.UserConfig,
viteEnv: vite.ConfigEnv,
): ResolvedPluginConfig {
const configPaths = new Set<string>();
const persistState = pluginConfig.persistState ?? true;
const root = userConfig.root ? path.resolve(userConfig.root) : process.cwd();
const { CLOUDFLARE_ENV } = vite.loadEnv(viteEnv.mode, root, '');

const configPath = pluginConfig.configPath
? path.resolve(root, pluginConfig.configPath)
Expand All @@ -79,10 +93,14 @@ export function resolvePluginConfig(
`Config not found. Have you created a wrangler.json(c) or wrangler.toml file?`,
);

const entryWorkerResolvedConfig = getWorkerConfig(configPath, {
visitedConfigPaths: configPaths,
isEntryWorker: true,
});
const entryWorkerResolvedConfig = getWorkerConfig(
configPath,
CLOUDFLARE_ENV,
{
visitedConfigPaths: configPaths,
isEntryWorker: true,
},
);

if (entryWorkerResolvedConfig.type === 'assets-only') {
return {
Expand All @@ -100,7 +118,7 @@ export function resolvePluginConfig(

const entryWorkerEnvironmentName =
pluginConfig.viteEnvironment?.name ??
workerNameToEnvironmentName(entryWorkerConfig.name);
workerNameToEnvironmentName(entryWorkerConfig.topLevelName);

const workers = {
[entryWorkerEnvironmentName]: entryWorkerConfig,
Expand All @@ -111,6 +129,7 @@ export function resolvePluginConfig(
for (const auxiliaryWorker of pluginConfig.auxiliaryWorkers ?? []) {
const workerResolvedConfig = getWorkerConfig(
path.resolve(root, auxiliaryWorker.configPath),
CLOUDFLARE_ENV,
{
visitedConfigPaths: configPaths,
},
Expand All @@ -127,7 +146,7 @@ export function resolvePluginConfig(

const workerEnvironmentName =
auxiliaryWorker.viteEnvironment?.name ??
workerNameToEnvironmentName(workerConfig.name);
workerNameToEnvironmentName(workerConfig.topLevelName);

if (workers[workerEnvironmentName]) {
throw new Error(
Expand Down
50 changes: 39 additions & 11 deletions packages/vite-plugin-cloudflare/src/workers-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'node:assert';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { unstable_readConfig } from 'wrangler';
import { name } from '../package.json';
import { name as packageName } from '../package.json';
import type { AssetsOnlyConfig, WorkerConfig } from './plugin-config';
import type { Optional } from './utils';
import type { Unstable_Config as RawWorkerConfig } from 'wrangler';
Expand Down Expand Up @@ -128,7 +128,10 @@ const nullableNonApplicable = [
'upload_source_maps',
] as const;

function readWorkerConfig(configPath: string): {
function readWorkerConfig(
configPath: string,
env: string | undefined,
): {
raw: RawWorkerConfig;
config: SanitizedWorkerConfig;
nonApplicable: NonApplicableConfigMap;
Expand All @@ -139,7 +142,7 @@ function readWorkerConfig(configPath: string): {
overridden: new Set(),
};
const config: Optional<RawWorkerConfig, 'build' | 'define'> =
unstable_readConfig({ config: configPath }, {});
unstable_readConfig({ config: configPath, env }, {});
const raw = structuredClone(config) as RawWorkerConfig;

nullableNonApplicable.forEach((prop) => {
Expand Down Expand Up @@ -273,7 +276,7 @@ function getWorkerNonApplicableWarnLines(

if (overridden.size > 0)
lines.push(
`${linePrefix}${[...overridden].map((config) => `\`${config}\``).join(', ')} which ${overridden.size > 1 ? 'are' : 'is'} overridden by \`${name}\``,
`${linePrefix}${[...overridden].map((config) => `\`${config}\``).join(', ')} which ${overridden.size > 1 ? 'are' : 'is'} overridden by \`${packageName}\``,
);

return lines;
Expand All @@ -297,8 +300,17 @@ function isOverridden(
return nonApplicableWorkerConfigs.overridden.includes(configName as any);
}

function missingFieldErrorMessage(
field: string,
configPath: string,
env: string | undefined,
) {
return `No ${field} field provided in '${configPath}'${env ? ` for '${env}' environment` : ''}`;
}

export function getWorkerConfig(
configPath: string,
env: string | undefined,
opts?: {
visitedConfigPaths?: Set<string>;
isEntryWorker?: boolean;
Expand All @@ -308,34 +320,50 @@ export function getWorkerConfig(
throw new Error(`Duplicate Wrangler config path found: ${configPath}`);
}

const { raw, config, nonApplicable } = readWorkerConfig(configPath);
const { raw, config, nonApplicable } = readWorkerConfig(configPath, env);

opts?.visitedConfigPaths?.add(configPath);

assert(
config.topLevelName,
missingFieldErrorMessage(`top-level 'name'`, configPath, env),
);
assert(config.name, missingFieldErrorMessage(`'name'`, configPath, env));
assert(
config.compatibility_date,
missingFieldErrorMessage(`'compatibility_date'`, configPath, env),
);

if (opts?.isEntryWorker && !config.main) {
assert(
config.assets,
`No main or assets field provided in ${config.configPath}`,
missingFieldErrorMessage(`'main' or 'assets'`, configPath, env),
);

return {
raw,
type: 'assets-only',
config: { ...config, assets: config.assets },
raw,
config: {
...config,
topLevelName: config.topLevelName,
name: config.name,
compatibility_date: config.compatibility_date,
assets: config.assets,
},
nonApplicable,
};
}

assert(config.main, `No main field provided in ${config.configPath}`);

assert(config.name, `No name field provided in ${config.configPath}`);
assert(config.main, missingFieldErrorMessage(`'main'`, configPath, env));

return {
type: 'worker',
raw,
config: {
...config,
topLevelName: config.topLevelName,
name: config.name,
compatibility_date: config.compatibility_date,
main: config.main,
},
nonApplicable,
Expand Down
1 change: 1 addition & 0 deletions playground/cloudflare-env/.env.custom-mode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CLOUDFLARE_ENV=custom-env
6 changes: 6 additions & 0 deletions playground/cloudflare-env/__tests__/cloudflare-env.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from 'vitest';
import { getTextResponse } from '../../__test-utils__';

test('returns the correct top-level var when CLOUDFLARE_ENV is undefined', async () => {
expect(await getTextResponse()).toEqual('Top level var');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from 'vitest';
import { getTextResponse } from '../../../__test-utils__';

test('returns the correct var when CLOUDFLARE_ENV is provided in a .env.[mode] file', async () => {
expect(await getTextResponse()).toEqual('Custom env var');
});
22 changes: 22 additions & 0 deletions playground/cloudflare-env/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@playground/cloudflare-env",
"private": true,
"type": "module",
"scripts": {
"build": "vite build --app",
"build:custom-mode": "vite build --app -c vite.config.custom-mode.ts",
"check:types": "tsc --build",
"dev": "vite dev",
"dev:custom-mode": "vite dev -c vite.config.custom-mode.ts",
"preview": "vite preview",
"preview:custom-mode": "vite preview -c vite.config.custom-mode.ts"
},
"devDependencies": {
"@cloudflare/workers-types": "catalog:default",
"@flarelabs-net/vite-plugin-cloudflare": "workspace:*",
"@vite-plugin-cloudflare/typescript-config": "workspace:*",
"typescript": "catalog:default",
"vite": "catalog:default",
"wrangler": "catalog:default"
}
}
9 changes: 9 additions & 0 deletions playground/cloudflare-env/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface Env {
MY_VAR: string;
}

export default {
async fetch(request, env) {
return new Response(env.MY_VAR);
},
} satisfies ExportedHandler<Env>;
7 changes: 7 additions & 0 deletions playground/cloudflare-env/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.worker.json" }
]
}
4 changes: 4 additions & 0 deletions playground/cloudflare-env/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@vite-plugin-cloudflare/typescript-config/base.json"],
"include": ["vite.config.ts", "vite.config.custom-mode.ts", "__tests__"]
}
4 changes: 4 additions & 0 deletions playground/cloudflare-env/tsconfig.worker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["@vite-plugin-cloudflare/typescript-config/worker.json"],
"include": ["src"]
}
7 changes: 7 additions & 0 deletions playground/cloudflare-env/vite.config.custom-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { cloudflare } from '@flarelabs-net/vite-plugin-cloudflare';
import { defineConfig } from 'vite';

export default defineConfig({
mode: 'custom-mode',
plugins: [cloudflare({ persistState: false })],
});
6 changes: 6 additions & 0 deletions playground/cloudflare-env/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { cloudflare } from '@flarelabs-net/vite-plugin-cloudflare';
import { defineConfig } from 'vite';

export default defineConfig({
plugins: [cloudflare({ persistState: false })],
});
8 changes: 8 additions & 0 deletions playground/cloudflare-env/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name = "worker"
main = "./src/index.ts"
compatibility_date = "2024-12-30"

vars = { MY_VAR = "Top level var" }

[env.custom-env]
vars = { MY_VAR = "Custom env var" }
2 changes: 1 addition & 1 deletion playground/durable-objects/wrangler.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "worker"
main = "./src/index.ts"
compatibility_date = "2024-09-09"
compatibility_date = "2024-12-30"

[durable_objects]
bindings = [{ name = "COUNTERS", class_name = "Counter" }]
Expand Down
2 changes: 1 addition & 1 deletion playground/external-durable-objects/worker-a/wrangler.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "worker-a"
main = "./index.ts"
compatibility_date = "2024-09-09"
compatibility_date = "2024-12-30"

[durable_objects]
bindings = [
Expand Down
Loading
Loading