Skip to content

Commit

Permalink
Vite: client references to .server code result in build-time error (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed Nov 30, 2023
1 parent a9e0102 commit 3205687
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
10 changes: 10 additions & 0 deletions .changeset/wise-pumas-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@remix-run/dev": patch
---

Vite: Errors at build-time when client imports .server default export

Remix already stripped .server file code before ensuring that server code never makes it into the client.
That results in errors when client code tries to import server code, which is exactly what we want!
But those errors were happening at runtime for default imports.
A better experience is to have those errors happen at build-time so that you guarantee that your users won't hit them.
80 changes: 77 additions & 3 deletions integration/vite-dot-server-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import { createProject, viteBuild } from "./helpers/vite.js";
let files = {
"app/utils.server.ts": String.raw`
export const dotServerFile = "SERVER_ONLY_FILE";
export default dotServerFile;
`,
"app/.server/utils.ts": String.raw`
export const dotServerDir = "SERVER_ONLY_DIR";
export default dotServerDir;
`,
};

test("Vite / build / .server file in client fails with expected error", async () => {
test("Vite / .server file / named import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-file-in-client.tsx": String.raw`
Expand All @@ -33,7 +35,43 @@ test("Vite / build / .server file in client fails with expected error", async ()
);
});

test("Vite / build / .server dir in client fails with expected error", async () => {
test("Vite / .server file / namespace import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-file-in-client.tsx": String.raw`
import * as utils from "~/utils.server";
export default function() {
console.log(utils.dotServerFile);
return <h1>Fail: Server file included in client</h1>
}
`,
});
let client = viteBuild({ cwd })[0];
let stderr = client.stderr.toString("utf8");
expect(stderr).toMatch(
`"dotServerFile" is not exported by "app/utils.server.ts"`
);
});

test("Vite / .server file / default import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-file-in-client.tsx": String.raw`
import dotServerFile from "~/utils.server";
export default function() {
console.log(dotServerFile);
return <h1>Fail: Server file included in client</h1>
}
`,
});
let client = viteBuild({ cwd })[0];
let stderr = client.stderr.toString("utf8");
expect(stderr).toMatch(`"default" is not exported by "app/utils.server.ts"`);
});

test("Vite / .server dir / named import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-dir-in-client.tsx": String.raw`
Expand All @@ -52,7 +90,43 @@ test("Vite / build / .server dir in client fails with expected error", async ()
);
});

test("Vite / build / dead-code elimination for server exports", async () => {
test("Vite / .server dir / namespace import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-dir-in-client.tsx": String.raw`
import * as utils from "~/.server/utils";
export default function() {
console.log(utils.dotServerDir);
return <h1>Fail: Server directory included in client</h1>
}
`,
});
let client = viteBuild({ cwd })[0];
let stderr = client.stderr.toString("utf8");
expect(stderr).toMatch(
`"dotServerDir" is not exported by "app/.server/utils.ts"`
);
});

test("Vite / .server dir / default import in client fails with expected error", async () => {
let cwd = await createProject({
...files,
"app/routes/fail-server-dir-in-client.tsx": String.raw`
import dotServerDir from "~/.server/utils";
export default function() {
console.log(dotServerDir);
return <h1>Fail: Server directory included in client</h1>
}
`,
});
let client = viteBuild({ cwd })[0];
let stderr = client.stderr.toString("utf8");
expect(stderr).toMatch(`"default" is not exported by "app/.server/utils.ts"`);
});

test("Vite / dead-code elimination for server exports", async () => {
let cwd = await createProject({
...files,
"app/routes/remove-server-exports-and-dce.tsx": String.raw`
Expand Down
4 changes: 2 additions & 2 deletions packages/remix-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ export const remixVitePlugin: RemixVitePlugin = (options = {}) => {
let serverDirRE = /\/\.server\//;
if (serverFileRE.test(id) || serverDirRE.test(id)) {
return {
code: "export default {}",
code: "export {}",
map: null,
};
}
Expand All @@ -927,7 +927,7 @@ export const remixVitePlugin: RemixVitePlugin = (options = {}) => {
let clientDirRE = /\/\.client\//;
if (clientFileRE.test(id) || clientDirRE.test(id)) {
return {
code: "export default {}",
code: "export {}",
map: null,
};
}
Expand Down

0 comments on commit 3205687

Please sign in to comment.