Skip to content

Commit 94bc852

Browse files
Add .env file support to RSC Framework Mode (#14322)
1 parent e72fc6e commit 94bc852

File tree

4 files changed

+136
-78
lines changed

4 files changed

+136
-78
lines changed

integration/vite-dotenv-test.ts

Lines changed: 99 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,32 @@ import { test, expect } from "@playwright/test";
22
import getPort from "get-port";
33

44
import {
5+
type TemplateName,
56
createProject,
67
customDev,
78
EXPRESS_SERVER,
89
viteConfig,
910
} from "./helpers/vite.js";
1011

11-
let getFiles = async ({ envDir, port }: { envDir?: string; port: number }) => {
12+
const templateNames = [
13+
"vite-5-template",
14+
"rsc-vite-framework",
15+
] as const satisfies TemplateName[];
16+
17+
let getFiles = async ({
18+
templateName,
19+
envDir,
20+
port,
21+
}: {
22+
templateName: TemplateName;
23+
envDir?: string;
24+
port: number;
25+
}) => {
1226
let envPath = `${envDir ? `${envDir}/` : ""}.env`;
1327

1428
return {
15-
"vite.config.js": await viteConfig.basic({ port, envDir }),
16-
"server.mjs": EXPRESS_SERVER({ port }),
29+
"vite.config.js": await viteConfig.basic({ templateName, port, envDir }),
30+
"server.mjs": EXPRESS_SERVER({ port, templateName }),
1731
[envPath]: `
1832
ENV_VAR_FROM_DOTENV_FILE=Content from ${envPath} file
1933
`,
@@ -49,72 +63,90 @@ let getFiles = async ({ envDir, port }: { envDir?: string; port: number }) => {
4963
};
5064

5165
test.describe("Vite .env", () => {
52-
test.describe("defaults", async () => {
53-
let port: number;
54-
let cwd: string;
55-
let stop: () => void;
56-
57-
test.beforeAll(async () => {
58-
port = await getPort();
59-
cwd = await createProject(await getFiles({ port }));
60-
stop = await customDev({ cwd, port });
61-
});
62-
test.afterAll(() => stop());
63-
64-
test("express", async ({ page }) => {
65-
let pageErrors: unknown[] = [];
66-
page.on("pageerror", (error) => pageErrors.push(error));
67-
68-
await page.goto(`http://localhost:${port}/dotenv`, {
69-
waitUntil: "networkidle",
66+
for (const templateName of templateNames) {
67+
test.describe(`template: ${templateName}`, () => {
68+
test.describe("defaults", async () => {
69+
let port: number;
70+
let cwd: string;
71+
let stop: () => void;
72+
73+
test.beforeAll(async () => {
74+
port = await getPort();
75+
cwd = await createProject(
76+
await getFiles({ port, templateName }),
77+
templateName,
78+
);
79+
stop = await customDev({ cwd, port });
80+
});
81+
test.afterAll(() => stop());
82+
83+
test("express", async ({ page }) => {
84+
let pageErrors: unknown[] = [];
85+
page.on("pageerror", (error) => pageErrors.push(error));
86+
87+
await page.goto(`http://localhost:${port}/dotenv`, {
88+
waitUntil: "networkidle",
89+
});
90+
expect(pageErrors).toEqual([]);
91+
92+
let loaderContent = page.locator(
93+
"[data-dotenv-route-loader-content]",
94+
);
95+
await expect(loaderContent).toHaveText("Content from .env file");
96+
97+
let clientContent = page.locator(
98+
"[data-dotenv-route-client-content]",
99+
);
100+
await expect(clientContent).toHaveText(
101+
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
102+
);
103+
104+
expect(pageErrors).toEqual([]);
105+
});
70106
});
71-
expect(pageErrors).toEqual([]);
72-
73-
let loaderContent = page.locator("[data-dotenv-route-loader-content]");
74-
await expect(loaderContent).toHaveText("Content from .env file");
75-
76-
let clientContent = page.locator("[data-dotenv-route-client-content]");
77-
await expect(clientContent).toHaveText(
78-
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
79-
);
80-
81-
expect(pageErrors).toEqual([]);
82-
});
83-
});
84-
85-
test.describe("custom env dir", async () => {
86-
let port: number;
87-
let cwd: string;
88-
let stop: () => void;
89-
90-
test.beforeAll(async () => {
91-
const envDir = "custom-env-dir";
92-
port = await getPort();
93-
cwd = await createProject(await getFiles({ envDir, port }));
94-
stop = await customDev({ cwd, port });
95-
});
96-
test.afterAll(() => stop());
97-
98-
test("express", async ({ page }) => {
99-
let pageErrors: unknown[] = [];
100-
page.on("pageerror", (error) => pageErrors.push(error));
101107

102-
await page.goto(`http://localhost:${port}/dotenv`, {
103-
waitUntil: "networkidle",
108+
test.describe("custom env dir", async () => {
109+
let port: number;
110+
let cwd: string;
111+
let stop: () => void;
112+
113+
test.beforeAll(async () => {
114+
const envDir = "custom-env-dir";
115+
port = await getPort();
116+
cwd = await createProject(
117+
await getFiles({ envDir, port, templateName }),
118+
templateName,
119+
);
120+
stop = await customDev({ cwd, port });
121+
});
122+
test.afterAll(() => stop());
123+
124+
test("express", async ({ page }) => {
125+
let pageErrors: unknown[] = [];
126+
page.on("pageerror", (error) => pageErrors.push(error));
127+
128+
await page.goto(`http://localhost:${port}/dotenv`, {
129+
waitUntil: "networkidle",
130+
});
131+
expect(pageErrors).toEqual([]);
132+
133+
let loaderContent = page.locator(
134+
"[data-dotenv-route-loader-content]",
135+
);
136+
await expect(loaderContent).toHaveText(
137+
"Content from custom-env-dir/.env file",
138+
);
139+
140+
let clientContent = page.locator(
141+
"[data-dotenv-route-client-content]",
142+
);
143+
await expect(clientContent).toHaveText(
144+
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
145+
);
146+
147+
expect(pageErrors).toEqual([]);
148+
});
104149
});
105-
expect(pageErrors).toEqual([]);
106-
107-
let loaderContent = page.locator("[data-dotenv-route-loader-content]");
108-
await expect(loaderContent).toHaveText(
109-
"Content from custom-env-dir/.env file",
110-
);
111-
112-
let clientContent = page.locator("[data-dotenv-route-client-content]");
113-
await expect(clientContent).toHaveText(
114-
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
115-
);
116-
117-
expect(pageErrors).toEqual([]);
118150
});
119-
});
151+
}
120152
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type * as Vite from "vite";
2+
3+
export async function loadDotenv({
4+
rootDirectory,
5+
viteUserConfig,
6+
mode,
7+
}: {
8+
rootDirectory: string;
9+
viteUserConfig: Vite.UserConfig;
10+
mode: string;
11+
}) {
12+
const vite = await import("vite");
13+
Object.assign(
14+
process.env,
15+
vite.loadEnv(
16+
mode,
17+
viteUserConfig.envDir ?? rootDirectory,
18+
// We override the default prefix of "VITE_" with a blank string since
19+
// we're targeting the server, so we want to load all environment
20+
// variables, not just those explicitly marked for the client
21+
"",
22+
),
23+
);
24+
}

packages/react-router-dev/vite/plugin.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import {
8181
} from "../config/config";
8282
import { getOptimizeDepsEntries } from "./optimize-deps-entries";
8383
import { decorateComponentExportsWithProps } from "./with-props";
84+
import { loadDotenv } from "./load-dotenv";
8485
import { validatePluginOrder } from "./plugins/validate-plugin-order";
8586
import { warnOnClientSourceMaps } from "./plugins/warn-on-client-source-maps";
8687

@@ -1211,17 +1212,11 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
12111212

12121213
await updatePluginContext();
12131214

1214-
Object.assign(
1215-
process.env,
1216-
vite.loadEnv(
1217-
viteConfigEnv.mode,
1218-
viteUserConfig.envDir ?? ctx.rootDirectory,
1219-
// We override the default prefix of "VITE_" with a blank string since
1220-
// we're targeting the server, so we want to load all environment
1221-
// variables, not just those explicitly marked for the client
1222-
"",
1223-
),
1224-
);
1215+
await loadDotenv({
1216+
rootDirectory,
1217+
viteUserConfig,
1218+
mode,
1219+
});
12251220

12261221
let environments = await getEnvironmentsOptions(ctx, viteCommand, {
12271222
viteUserConfig,

packages/react-router-dev/vite/rsc/plugin.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
isVirtualClientRouteModuleId,
2525
CLIENT_NON_COMPONENT_EXPORTS,
2626
} from "./virtual-route-modules";
27+
import { loadDotenv } from "../load-dotenv";
2728
import { validatePluginOrder } from "../plugins/validate-plugin-order";
2829
import { warnOnClientSourceMaps } from "../plugins/warn-on-client-source-maps";
2930

@@ -101,6 +102,12 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
101102
);
102103
}
103104

105+
await loadDotenv({
106+
rootDirectory,
107+
viteUserConfig,
108+
mode,
109+
});
110+
104111
const vite = await import("vite");
105112
logger = vite.createLogger(viteUserConfig.logLevel, {
106113
prefix: "[react-router]",

0 commit comments

Comments
 (0)