Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle custom envDir in Vite config #12969

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions .changeset/afraid-buses-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-router/dev": patch
---

Handle custom `envDir` in Vite config
11 changes: 9 additions & 2 deletions integration/helpers/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,14 @@ export const reactRouterConfig = ({
`;
};

type ViteConfigArgs = {
port: number;
fsAllow?: string[];
envDir?: string;
};

export const viteConfig = {
server: async (args: { port: number; fsAllow?: string[] }) => {
server: async (args: ViteConfigArgs) => {
let { port, fsAllow } = args;
let hmrPort = await getPort();
let text = dedent`
Expand All @@ -72,14 +78,15 @@ export const viteConfig = {
`;
return text;
},
basic: async (args: { port: number; fsAllow?: string[] }) => {
basic: async (args: ViteConfigArgs) => {
return dedent`
import { reactRouter } from "@react-router/dev/vite";
import { envOnlyMacros } from "vite-env-only";
import tsconfigPaths from "vite-tsconfig-paths";

export default {
${await viteConfig.server(args)}
envDir: ${args.envDir ? `"${args.envDir}"` : "undefined"},
plugins: [
reactRouter(),
envOnlyMacros(),
Expand Down
150 changes: 95 additions & 55 deletions integration/vite-dotenv-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,73 +8,113 @@ import {
viteConfig,
} from "./helpers/vite.js";

let files = {
".env": `
ENV_VAR_FROM_DOTENV_FILE=Content from .env file
`,
"app/routes/dotenv.tsx": String.raw`
import { useState, useEffect } from "react";
import { useLoaderData } from "react-router";

export const loader = () => {
return {
loaderContent: process.env.ENV_VAR_FROM_DOTENV_FILE,
}
}
let getFiles = async ({ envDir, port }: { envDir?: string; port: number }) => {
let envPath = `${envDir ? `${envDir}/` : ""}.env`;

export default function DotenvRoute() {
const { loaderContent } = useLoaderData();
return {
"vite.config.js": await viteConfig.basic({ port, envDir }),
"server.mjs": EXPRESS_SERVER({ port }),
[envPath]: `
ENV_VAR_FROM_DOTENV_FILE=Content from ${envPath} file
`,
"app/routes/dotenv.tsx": String.raw`
import { useState, useEffect } from "react";
import { useLoaderData } from "react-router";

const [clientContent, setClientContent] = useState('');
useEffect(() => {
try {
setClientContent("process.env.ENV_VAR_FROM_DOTENV_FILE shouldn't be available on the client, found: " + process.env.ENV_VAR_FROM_DOTENV_FILE);
} catch (err) {
setClientContent("process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing");
export const loader = () => {
return {
loaderContent: process.env.ENV_VAR_FROM_DOTENV_FILE,
}
}, []);

return <>
<div data-dotenv-route-loader-content>{loaderContent}</div>
<div data-dotenv-route-client-content>{clientContent}</div>
</>
}
`,
}

export default function DotenvRoute() {
const { loaderContent } = useLoaderData();

const [clientContent, setClientContent] = useState('');
useEffect(() => {
try {
setClientContent("process.env.ENV_VAR_FROM_DOTENV_FILE shouldn't be available on the client, found: " + process.env.ENV_VAR_FROM_DOTENV_FILE);
} catch (err) {
setClientContent("process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing");
}
}, []);

return <>
<div data-dotenv-route-loader-content>{loaderContent}</div>
<div data-dotenv-route-client-content>{clientContent}</div>
</>
}
`,
};
};

test.describe(async () => {
let port: number;
let cwd: string;
let stop: () => void;

test.beforeAll(async () => {
port = await getPort();
cwd = await createProject({
"vite.config.js": await viteConfig.basic({ port }),
"server.mjs": EXPRESS_SERVER({ port }),
...files,
test.describe("Vite .env", () => {
test.describe("defaults", async () => {
let port: number;
let cwd: string;
let stop: () => void;

test.beforeAll(async () => {
port = await getPort();
cwd = await createProject(await getFiles({ port }));
stop = await customDev({ cwd, port });
});
test.afterAll(() => stop());

test("express", async ({ page }) => {
let pageErrors: unknown[] = [];
page.on("pageerror", (error) => pageErrors.push(error));

await page.goto(`http://localhost:${port}/dotenv`, {
waitUntil: "networkidle",
});
expect(pageErrors).toEqual([]);

let loaderContent = page.locator("[data-dotenv-route-loader-content]");
await expect(loaderContent).toHaveText("Content from .env file");

let clientContent = page.locator("[data-dotenv-route-client-content]");
await expect(clientContent).toHaveText(
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing"
);

expect(pageErrors).toEqual([]);
});
stop = await customDev({ cwd, port });
});
test.afterAll(() => stop());

test("Vite / Load context / express", async ({ page }) => {
let pageErrors: unknown[] = [];
page.on("pageerror", (error) => pageErrors.push(error));
test.describe("custom env dir", async () => {
let port: number;
let cwd: string;
let stop: () => void;

await page.goto(`http://localhost:${port}/dotenv`, {
waitUntil: "networkidle",
test.beforeAll(async () => {
const envDir = "custom-env-dir";
port = await getPort();
cwd = await createProject(await getFiles({ envDir, port }));
stop = await customDev({ cwd, port });
});
expect(pageErrors).toEqual([]);
test.afterAll(() => stop());

test("express", async ({ page }) => {
let pageErrors: unknown[] = [];
page.on("pageerror", (error) => pageErrors.push(error));

let loaderContent = page.locator("[data-dotenv-route-loader-content]");
await expect(loaderContent).toHaveText("Content from .env file");
await page.goto(`http://localhost:${port}/dotenv`, {
waitUntil: "networkidle",
});
expect(pageErrors).toEqual([]);

let clientContent = page.locator("[data-dotenv-route-client-content]");
await expect(clientContent).toHaveText(
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing"
);
let loaderContent = page.locator("[data-dotenv-route-loader-content]");
await expect(loaderContent).toHaveText(
"Content from custom-env-dir/.env file"
);

expect(pageErrors).toEqual([]);
let clientContent = page.locator("[data-dotenv-route-client-content]");
await expect(clientContent).toHaveText(
"process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing"
);

expect(pageErrors).toEqual([]);
});
});
});
2 changes: 1 addition & 1 deletion packages/react-router-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
process.env,
vite.loadEnv(
viteConfigEnv.mode,
ctx.rootDirectory,
viteUserConfig.envDir ?? ctx.rootDirectory,
// We override default prefix of "VITE_" with a blank string since
// we're targeting the server, so we want to load all environment
// variables, not just those explicitly marked for the client
Expand Down
Loading