Skip to content

Commit 37adc1d

Browse files
dario-piotrowiczpetebacondarwinjamesopstad
authored
[vite-plugin]: make sure that process.env is correctly populated (#8489)
* set `keepProcessEnv` to `true` when the `nodejs_compat` and `nodejs_compat_populate_process_env` flags are set * remove `__VITE_ROOT__` and `__VITE_ENTRY_PATH__` bindings remove the `__VITE_ROOT__` and `__VITE_ENTRY_PATH__` bindings that pollute the populated `process.env`. instead of using such bundings these values are not passed to the environment via the init request --------- Co-authored-by: Pete Bacon Darwin <[email protected]> Co-authored-by: James Opstad <[email protected]>
1 parent 03ec951 commit 37adc1d

File tree

25 files changed

+291
-168
lines changed

25 files changed

+291
-168
lines changed

.changeset/crazy-groups-lie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/vite-plugin": patch
3+
---
4+
5+
fix: make sure `process.env` is populated when the `nodejs_compat_populate_process_env` flag is set
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { afterAll, describe, expect, test } from "vitest";
2+
import {
3+
getJsonResponse,
4+
getTextResponse,
5+
isBuild,
6+
serverLogs,
7+
} from "../../__test-utils__";
8+
9+
describe("module resolution", async () => {
10+
afterAll(() => {
11+
expect(serverLogs.errors).toEqual([]);
12+
});
13+
14+
describe("basic module resolution", () => {
15+
test("`require` js/cjs files with specifying their file extension", async () => {
16+
const result = await getJsonResponse("/require-ext");
17+
expect(result).toEqual({
18+
"(requires/ext) hello.cjs (wrong-extension)": null,
19+
"(requires/ext) helloWorld": "hello (.js) world (.cjs)",
20+
"(requires/ext) world.js (wrong-extension)": null,
21+
});
22+
});
23+
24+
test("`require` js/cjs files without specifying their file extension", async () => {
25+
const result = await getJsonResponse("/require-no-ext");
26+
expect(result).toEqual({
27+
"(requires/no-ext) helloWorld": "hello (.js) world (.cjs)",
28+
});
29+
});
30+
31+
test("`require` json files", async () => {
32+
const result = await getJsonResponse("/require-json");
33+
expect(result).toEqual({
34+
"(requires/json) package name":
35+
"@playground/module-resolution-requires",
36+
"(requires/json) package version": "1.0.0",
37+
});
38+
});
39+
});
40+
41+
describe("Cloudflare specific module resolution", () => {
42+
test("internal imports from `cloudflare:*`", async () => {
43+
const result = await getJsonResponse("/cloudflare-imports");
44+
45+
// Note: in some cases the DurableObject class name (erroneously) includes
46+
// the `Base` suffix, that's a workerd bug that happens for us on builds
47+
const durableObjectName = isBuild ? "DurableObjectBase" : "DurableObject";
48+
49+
expect(result).toEqual({
50+
"(cloudflare:workers) WorkerEntrypoint.name": "WorkerEntrypoint",
51+
"(cloudflare:workers) DurableObject.name": durableObjectName,
52+
"(cloudflare:sockets) typeof connect": "function",
53+
});
54+
});
55+
56+
test("external imports from `cloudflare:*`", async () => {
57+
const result = await getJsonResponse("/external-cloudflare-imports");
58+
59+
// Note: in some cases the DurableObject class name (erroneously) includes
60+
// the `Base` suffix, that's a workerd bug that happens for us on builds
61+
const durableObjectName = isBuild ? "DurableObjectBase" : "DurableObject";
62+
63+
expect(result).toEqual({
64+
"(EXTERNAL) (cloudflare:workers) DurableObject.name": durableObjectName,
65+
});
66+
});
67+
});
68+
69+
/**
70+
* These tests check that module resolution works as intended for various third party npm packages (these tests are more
71+
* realistic but less helpful than the other ones (these can be considered integration tests whilst the other unit tests)).
72+
*
73+
* These are packages that involve non-trivial module resolutions (and that in the past we had issues with), they have no
74+
* special meaning to us.
75+
*/
76+
describe("third party packages resolutions", () => {
77+
test("react", async () => {
78+
const result = await getJsonResponse("/third-party/react");
79+
expect(result).toEqual({
80+
"(react) reactVersionsMatch": true,
81+
"(react) typeof React": "object",
82+
"(react) typeof React.cloneElement": "function",
83+
});
84+
});
85+
86+
test("@remix-run/cloudflare", async () => {
87+
const result = await getJsonResponse("/third-party/remix");
88+
expect(result).toEqual({
89+
"(remix) remixRunCloudflareCookieName":
90+
"my-remix-run-cloudflare-cookie",
91+
});
92+
});
93+
94+
test("discord-api-types/v10", async () => {
95+
const result = await getJsonResponse("/third-party/discord-api-types");
96+
expect(result).toEqual({
97+
"(discord-api-types/v10) RPCErrorCodes.InvalidUser": 4010,
98+
"(discord-api-types/v10) Utils.isLinkButton({})": false,
99+
});
100+
});
101+
102+
test("slash-create", async () => {
103+
const result = await getJsonResponse("/third-party/slash-create");
104+
expect(result).toEqual({
105+
"(slash-create/web) VERSION": "6.2.1",
106+
"(slash-create/web) myCollection.random()": 54321,
107+
"(slash-create/web) slashCreatorInstance is instance of SlashCreator":
108+
true,
109+
});
110+
});
111+
});
112+
113+
describe("user aliases", () => {
114+
test("imports from an aliased package", async () => {
115+
const result = await getTextResponse("/@alias/test");
116+
expect(result).toBe("OK!");
117+
});
118+
});
119+
});
Lines changed: 1 addition & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1 @@
1-
import { afterAll, describe, expect, test } from "vitest";
2-
import {
3-
getJsonResponse,
4-
getTextResponse,
5-
isBuild,
6-
page,
7-
serverLogs,
8-
viteTestUrl,
9-
} from "../../__test-utils__";
10-
11-
describe("module resolution", async () => {
12-
afterAll(() => {
13-
expect(serverLogs.errors).toEqual([]);
14-
});
15-
16-
describe("basic module resolution", () => {
17-
test("`require` js/cjs files with specifying their file extension", async () => {
18-
const result = await getJsonResponse("/require-ext");
19-
expect(result).toEqual({
20-
"(requires/ext) hello.cjs (wrong-extension)": null,
21-
"(requires/ext) helloWorld": "hello (.js) world (.cjs)",
22-
"(requires/ext) world.js (wrong-extension)": null,
23-
});
24-
});
25-
26-
test("`require` js/cjs files without specifying their file extension", async () => {
27-
const result = await getJsonResponse("/require-no-ext");
28-
expect(result).toEqual({
29-
"(requires/no-ext) helloWorld": "hello (.js) world (.cjs)",
30-
});
31-
});
32-
33-
test("`require` json files", async () => {
34-
const result = await getJsonResponse("/require-json");
35-
expect(result).toEqual({
36-
"(requires/json) package name":
37-
"@playground/module-resolution-requires",
38-
"(requires/json) package version": "1.0.0",
39-
});
40-
});
41-
});
42-
43-
describe("Cloudflare specific module resolution", () => {
44-
test("internal imports from `cloudflare:*`", async () => {
45-
const result = await getJsonResponse("/cloudflare-imports");
46-
47-
// Note: in some cases the DurableObject class name (erroneously) includes
48-
// the `Base` suffix, that's a workerd bug that happens for us on builds
49-
const durableObjectName = isBuild ? "DurableObjectBase" : "DurableObject";
50-
51-
expect(result).toEqual({
52-
"(cloudflare:workers) WorkerEntrypoint.name": "WorkerEntrypoint",
53-
"(cloudflare:workers) DurableObject.name": durableObjectName,
54-
"(cloudflare:sockets) typeof connect": "function",
55-
});
56-
});
57-
58-
test("external imports from `cloudflare:*`", async () => {
59-
const result = await getJsonResponse("/external-cloudflare-imports");
60-
61-
// Note: in some cases the DurableObject class name (erroneously) includes
62-
// the `Base` suffix, that's a workerd bug that happens for us on builds
63-
const durableObjectName = isBuild ? "DurableObjectBase" : "DurableObject";
64-
65-
expect(result).toEqual({
66-
"(EXTERNAL) (cloudflare:workers) DurableObject.name": durableObjectName,
67-
});
68-
});
69-
});
70-
71-
/**
72-
* These tests check that module resolution works as intended for various third party npm packages (these tests are more
73-
* realistic but less helpful than the other ones (these can be considered integration tests whilst the other unit tests)).
74-
*
75-
* These are packages that involve non-trivial module resolutions (and that in the past we had issues with), they have no
76-
* special meaning to us.
77-
*/
78-
describe("third party packages resolutions", () => {
79-
test("react", async () => {
80-
const result = await getJsonResponse("/third-party/react");
81-
expect(result).toEqual({
82-
"(react) reactVersionsMatch": true,
83-
"(react) typeof React": "object",
84-
"(react) typeof React.cloneElement": "function",
85-
});
86-
});
87-
88-
test("@remix-run/cloudflare", async () => {
89-
const result = await getJsonResponse("/third-party/remix");
90-
expect(result).toEqual({
91-
"(remix) remixRunCloudflareCookieName":
92-
"my-remix-run-cloudflare-cookie",
93-
});
94-
});
95-
96-
test("discord-api-types/v10", async () => {
97-
const result = await getJsonResponse("/third-party/discord-api-types");
98-
expect(result).toEqual({
99-
"(discord-api-types/v10) RPCErrorCodes.InvalidUser": 4010,
100-
"(discord-api-types/v10) Utils.isLinkButton({})": false,
101-
});
102-
});
103-
104-
test("slash-create", async () => {
105-
const result = await getJsonResponse("/third-party/slash-create");
106-
expect(result).toEqual({
107-
"(slash-create/web) VERSION": "6.2.1",
108-
"(slash-create/web) myCollection.random()": 54321,
109-
"(slash-create/web) slashCreatorInstance is instance of SlashCreator":
110-
true,
111-
});
112-
});
113-
});
114-
115-
describe("user aliases", () => {
116-
test("imports from an aliased package", async () => {
117-
const result = await getTextResponse("/@alias/test");
118-
expect(result).toBe("OK!");
119-
});
120-
});
121-
});
1+
import "./base-tests";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import "../base-tests";

packages/vite-plugin-cloudflare/playground/module-resolution/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
"scripts": {
66
"build": "vite build --app",
77
"build:no-prebundling": "vite build --app -c ./vite.config.no-prebundling.ts",
8+
"build:nodejs-compat": "vite build --app -c ./vite.config.nodejs-compat.ts",
89
"check:types": "tsc --build",
910
"dev": "vite dev",
1011
"dev:no-prebundling": "vite dev -c ./vite.config.no-prebundling.ts",
12+
"dev:nodejs-compat": "vite dev -c ./vite.config.nodejs-compat.ts",
1113
"preview": "vite preview",
12-
"preview:no-prebundling": "vite preview -c ./vite.config.no-prebundling.ts"
14+
"preview:no-prebundling": "vite preview -c ./vite.config.no-prebundling.ts",
15+
"preview:nodejs-compat": "vite preview -c ./vite.config.nodejs-compat.ts"
1316
},
1417
"devDependencies": {
1518
"@cloudflare-dev-module-resolution/imports": "file:./packages/imports",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { resolve } from "node:path";
2+
import { cloudflare } from "@cloudflare/vite-plugin";
3+
import { defineConfig } from "vite";
4+
5+
export default defineConfig({
6+
resolve: {
7+
alias: {
8+
"@alias/test": resolve(__dirname, "./src/aliasing.ts"),
9+
},
10+
},
11+
plugins: [cloudflare({ persistState: false })],
12+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name = "worker"
2+
main = "./src/index.ts"
3+
compatibility_date = "2024-12-30"
4+
compatibility_flags = [ "nodejs_compat" ]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { expect, test } from "vitest";
2+
import { getTextResponse } from "../../../__test-utils__";
3+
4+
test("should get a populated process.env object", async () => {
5+
const result = await getTextResponse();
6+
expect(result).toBe(`OK!`);
7+
});

packages/vite-plugin-cloudflare/playground/node-compat/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
"postgres:dev": "vite dev -c vite.config.worker-postgres.ts",
2323
"postgres:preview": "vite preview -c vite.config.worker-postgres.ts",
2424
"postgres:test": "vitest run -c ../vitest.config.e2e.ts worker-postgres",
25+
"process-populated-env:build": "vite build --app -c vite.config.worker-process-populated-env.ts",
26+
"process-populated-env:dev": "vite dev -c vite.config.worker-process-populated-env.ts",
27+
"process-populated-env:preview": "vite preview -c vite.config.worker-process-populated-env.ts",
28+
"process-populated-env:test": "vitest run -c ../vitest.config.e2e.ts worker-process-populated-env",
2529
"process:build": "vite build --app -c vite.config.worker-process.ts",
2630
"process:dev": "vite dev -c vite.config.worker-process.ts",
2731
"process:preview": "vite preview -c vite.config.worker-process.ts",
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { cloudflare } from "@cloudflare/vite-plugin";
2+
import { defineConfig } from "vite";
3+
4+
export default defineConfig({
5+
build: {
6+
outDir: "dist/worker-process-populated-env",
7+
},
8+
plugins: [
9+
cloudflare({
10+
configPath: "./worker-process-populated-env/wrangler.toml",
11+
persistState: false,
12+
}),
13+
],
14+
});

0 commit comments

Comments
 (0)