Skip to content

Commit 1ab4e91

Browse files
committed
docs(vite): address pr feedback and add treeshaking explanation
1 parent adaab01 commit 1ab4e91

File tree

1 file changed

+39
-8
lines changed

1 file changed

+39
-8
lines changed

docs/future/vite.md

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -637,15 +637,46 @@ const posts = import.meta.glob("./posts/*.mdx", {
637637
#### Strict route exports
638638

639639
With Vite, Remix gets stricter about which exports are allowed from your route modules.
640-
Previously, the Remix compiler would allow any export from routes.
641-
While this was convenient, it was also a common source of bugs that were hard to track down because they only surfaced at runtime.
642640

643-
👉 **Move any non-route exports to a separate file**
641+
Previously, Remix allowed user-defined exports from routes.
642+
The Remix compiler would then rely on treeshaking to remove any code only intended for use on the server from the client bundle.
644643

645-
For example, with take this route:
644+
In contrast, Vite processes each module in isolation during development, so cross-module treeshaking is not possible.
645+
You should already be separating server-only code into `.server` files or directories, so treeshaking isn't needed for those modules.
646+
But routes are a special case since they intentionally blend client and server code.
647+
Remix knows that exports like `loader`, `action`, `headers`, etc. are server-only, so it can safely remove them from the client bundle.
648+
But there's no way to know when looking at a single route module in isolation whether user-defined exports are server-only.
649+
That's why Remix's Vite plugin is stricter about which exports are allowed from your route modules.
650+
651+
In fact, we'd rather not rely on treeshaking for correctness at all.
652+
If tomorrow you or your coworker accidentally imports something you _thought_ was client safe,
653+
treeshaking will no longer exclude that from your client bundle and you might end up with server code in your app!
654+
Treeshaking is designed as a pure optimization, so relying on it for correctness is brittle.
655+
In short, Vite made us eat our veggies, but turns out they were delicious all along!
656+
657+
So instead of treeshaking, its better to be explicit about what code is server-only.
658+
For route modules, that means only exporting Remix route exports.
659+
For anything else, put it in a separate module and use a `.server` file or directory when needed.
660+
661+
Ultimately, Route exports are Remix API.
662+
Think of a Remix route module like a function and the exports like named arguments to the function.
663+
664+
```ts
665+
// Not real API, just a mental model
666+
let route = createRoute({ loader, mySuperCoolThing });
667+
// ^^^^^^^^^^^^^^^^
668+
// Object literal may only specify known properties, and 'mySuperCoolThing' does not exist in type 'RemixRoute'
669+
```
670+
671+
Just like how you shouldn't pass unexpected named arguments to a function, you shouldn't create unexpected exports from a route module.
672+
The result is that Remix is simpler and more predictable.
673+
674+
👉 **Move any user-defined route exports to a separate module**
675+
676+
For example, here's a route with a user-defined export called `mySuperCoolThing`:
646677

647678
```ts filename=app/routes/super-cool.tsx
648-
// ❌ This is the problematic export
679+
// ❌ This isn't a Remix-specific route export, just something I made up
649680
export const mySuperCoolThing =
650681
"Some value I wanted to colocate with my route!";
651682

@@ -656,7 +687,8 @@ export const loader = () => {};
656687
export default function SuperCool() {}
657688
```
658689

659-
Using the default route convention in v2, you can refactor to:
690+
One option is to colocate your route and related utilities in the same directory if your routing convention allows it.
691+
For example, with the default route convention in v2:
660692

661693
```ts filename=app/routes/super-cool/route.tsx
662694
export const loader = () => {};
@@ -665,12 +697,11 @@ export default function SuperCool() {}
665697
```
666698

667699
```ts filename=app/routes/super-cool/utils.ts
700+
// If this was server-only code, I'd rename this file to "utils.server.ts"
668701
export const mySuperCoolThing =
669702
"Some value I wanted to colocate with my route!";
670703
```
671704

672-
That way your utilities are still colocated with your route, but in a separate module.
673-
674705
## Troubleshooting
675706

676707
Check out the [known issues with the Remix Vite plugin on GitHub][issues-vite] before filing a new bug report!

0 commit comments

Comments
 (0)