Skip to content

Commit

Permalink
docs(vite): address pr feedback and add treeshaking explanation
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed Dec 1, 2023
1 parent adaab01 commit db780a2
Showing 1 changed file with 39 additions and 8 deletions.
47 changes: 39 additions & 8 deletions docs/future/vite.md
Original file line number Diff line number Diff line change
Expand Up @@ -637,15 +637,46 @@ const posts = import.meta.glob("./posts/*.mdx", {
#### Strict route exports

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

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

For example, with take this route:
In contrast, Vite processes each module in isolation during development, so cross-module treeshaking is not possible.
You should already be separating server-only code into `.server` files or directories, so treeshaking isn't needed for those modules.
But routes are a special case since they intentionally blend client and server code.
Remix knows that exports like `loader`, `action`, `headers`, etc. are server-only, so it can safely remove them from the client bundle.
But there's no way to know when looking at a single route module in isolation whether user-defined exports are server-only.
That's why Remix's Vite plugin is stricter about which exports are allowed from your route modules.

In fact, we'd rather not rely on treeshaking for correctness at all.
If tomorrow you or your coworker accidentally imports something you _thought_ was client-safe,
treeshaking will no longer exclude that from your client bundle and you might end up with server code in your app!
Treeshaking is designed as a pure optimization, so relying on it for correctness is brittle.

So instead of treeshaking, its better to be explicit about what code is client-safe and what code is server-only.
For route modules, that means only exporting Remix route exports.
For anything else, put it in a separate module and use a `.server` file or directory when needed.

Ultimately, Route exports are Remix API.
Think of a Remix route module like a function and the exports like named arguments to the function.

```ts
// Not real API, just a mental model
let route = createRoute({ loader, mySuperCoolThing });
// ^^^^^^^^^^^^^^^^
// Object literal may only specify known properties, and 'mySuperCoolThing' does not exist in type 'RemixRoute'
```

Just like how you shouldn't pass unexpected named arguments to a function, you shouldn't create unexpected exports from a route module.
The result is that Remix is simpler and more predictable.
In short, Vite made us eat our veggies, but turns out they were delicious all along!

👉 **Move any user-defined route exports to a separate module**

For example, here's a route with a user-defined export called `mySuperCoolThing`:

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

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

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

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

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

That way your utilities are still colocated with your route, but in a separate module.

## Troubleshooting

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

0 comments on commit db780a2

Please sign in to comment.