Skip to content

Commit

Permalink
future flag for automatic optimize deps (#9927)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori authored Aug 30, 2024
1 parent e9f2684 commit 5117fb7
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 10 deletions.
6 changes: 3 additions & 3 deletions .changeset/hot-dogs-applaud.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"@remix-run/dev": patch
---

Automatically optimize dependencies during development
(unstable) Automatic dependency optimization

Now Remix will tell Vite to find dependencies by crawling imports starting with your route modules.
This should resolve most (if not all) `504 Outdated Dependency` errors that could previously break HMR.
You can now opt-in to automatic dependency optimization during development by using the `future.unstable_optimizeDeps` future flag.
For details, check out the docs at [`Guides` > `Dependency optimization`](https://remix.run/docs/en/main/guides/dependency-optimization).

For users who were previously working around this limiation, you no longer need to explicitly add routes to Vite's `optimizeDeps.entries` nor do you need to disable the `remix-dot-server` plugin.
64 changes: 64 additions & 0 deletions docs/guides/dependency-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Dependency optimization
---

<docs-info>This feature only affects development. It does not impact production builds.</docs-info>

# Dependency optimization

Remix introduced automatic dependency optimization in development behind the `future.unstable_optimizeDeps` [Future Flag][future-flags].
This allows you to opt-into this behavior which will become the default in the next major version of Remix - a.k.a. React Router v7 ([1][rr-v7], [2][rr-v7-2]).

In development, Vite aims to [prebundle dependencies](https://vitejs.dev/guide/dep-pre-bundling.html) so that it can efficiently serve up those dependencies on-demand.
To do this, Vite needs to know where to start crawling your app's module graph to look for dependencies.

Previously, Remix did not inform Vite to start dependency detection at route modules nor at the client entry.
That meant that in development, Vite would encounter new dependencies as you navigated around in your app resulting in `504 Outdated Dependency` errors.
Consequently, the development experience could feel janky at times since those errors could cause HMR to break or link navigations to be aborted.
Navigation could also feel sluggish as processing dependencies interactively could sometimes be slow.

For more information, see [Vite's Dep Optimization Options](https://vitejs.dev/config/dep-optimization-options#dep-optimization-options).

## Troubleshooting

### `Failed to resolve entry for package`

```txt
✘ [ERROR] Failed to resolve entry for package "<package>". The package may have incorrect main/module/exports specified in its package.json. [plugin vite:dep-pre-bundle]
```

This is usually caused by a misconfigured dependency.
You use [publint](https://publint.dev/) to check if the offending package is misconfigured.
To fix the issue, you'll need to use `npm why` or `pnpm why` to determine which of your direct dependencies to add to `optimizeDeps.exclude`.

For example, let's say your app is running into this error:

```txt
✘ [ERROR] Failed to resolve entry for package "jimp". The package may have incorrect main/module/exports specified in its package.json. [plugin vite:dep-pre-bundle]
```

Sure enough, `publint` reports that the [`jimp` package is misconfigured](https://publint.dev/[email protected]).
Then, you determine that `jimp` is an indirect dependency being pulled in by your `svg2img` direct dependency:

```sh
❯ npm why jimp
[email protected]
node_modules/jimp
jimp@"^0.16.1" from [email protected]
node_modules/svg2img
svg2img@"^1.0.0-beta.2" from the root project
```

Finally, you add `svg2img` to `optimizeDeps.exclude`, which should fix the issue:

```ts filename=vite.config.ts
export default defineConfig({
optimizeDeps: {
exclude: ["svg2img"],
},
});
```

[future-flags]: ../guides/api-development-strategy
[rr-v7]: https://remix.run/blog/merging-remix-and-react-router
[rr-v7-2]: https://remix.run/blog/incremental-path-to-react-19
2 changes: 1 addition & 1 deletion docs/guides/single-fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ With Single Fetch, naked objects will be streamed directly, so the built-in type
#### Enable Single Fetch types

To switch over to Single Fetch types, you should [augment][augment] Remix's `Future` interface with `unstable_singleFetch: true`.
You can do this in any file covered by your `tsconfig.json` > `includes`.
You can do this in any file covered by your `tsconfig.json` > `include`.
We recommend you do this in your `vite.config.ts` to keep it colocated with the `future.unstable_singleFetch` future flag in the Remix plugin:

```ts
Expand Down
5 changes: 5 additions & 0 deletions docs/start/future-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ Opt into [Single Fetch][single-fetch] behavior (details will be expanded once th

Opt into [Lazy Route Discovery][lazy-route-discovery] behavior (details will be expanded once the flag stabilizes).

## unstable_optimizeDeps

Opt into automatic [dependency optimization][dependency-optimization] during development.

[development-strategy]: ../guides/api-development-strategy
[fetcherpersist-rfc]: https://github.com/remix-run/remix/discussions/7698
[relativesplatpath-changelog]: https://github.com/remix-run/remix/blob/main/CHANGELOG.md#futurev3_relativesplatpath
Expand All @@ -357,3 +361,4 @@ Opt into [Lazy Route Discovery][lazy-route-discovery] behavior (details will be
[vite-url-imports]: https://vitejs.dev/guide/assets.html#explicit-url-imports
[mdx]: https://mdxjs.com
[mdx-rollup-plugin]: https://mdxjs.com/packages/rollup
[dependency-optimization]: ../guides/dependency-optimization
1 change: 1 addition & 0 deletions packages/remix-dev/__tests__/readConfig-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe("readConfig", () => {
"entryServerFilePath": Any<String>,
"future": {
"unstable_lazyRouteDiscovery": false,
"unstable_optimizeDeps": false,
"unstable_singleFetch": false,
"v3_fetcherPersist": false,
"v3_relativeSplatPath": false,
Expand Down
2 changes: 2 additions & 0 deletions packages/remix-dev/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface FutureConfig {
v3_throwAbortReason: boolean;
unstable_singleFetch: boolean;
unstable_lazyRouteDiscovery: boolean;
unstable_optimizeDeps: boolean;
}

type NodeBuiltinsPolyfillOptions = Pick<
Expand Down Expand Up @@ -611,6 +612,7 @@ export async function resolveConfig(
unstable_singleFetch: appConfig.future?.unstable_singleFetch === true,
unstable_lazyRouteDiscovery:
appConfig.future?.unstable_lazyRouteDiscovery === true,
unstable_optimizeDeps: appConfig.future?.unstable_optimizeDeps === true,
};

if (appConfig.future) {
Expand Down
14 changes: 8 additions & 6 deletions packages/remix-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1075,12 +1075,14 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
: undefined,
},
optimizeDeps: {
entries: [
ctx.entryClientFilePath,
...Object.values(ctx.remixConfig.routes).map((route) =>
path.join(ctx.remixConfig.appDirectory, route.file)
),
],
entries: ctx.remixConfig.future.unstable_optimizeDeps
? [
ctx.entryClientFilePath,
...Object.values(ctx.remixConfig.routes).map((route) =>
path.join(ctx.remixConfig.appDirectory, route.file)
),
]
: [],
include: [
// Pre-bundle React dependencies to avoid React duplicates,
// even if React dependencies are not direct dependencies.
Expand Down

0 comments on commit 5117fb7

Please sign in to comment.