From ea795f9d87da3367c0f719fc52bc904baa218f41 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Mon, 11 Mar 2024 12:13:30 +1100 Subject: [PATCH] Update docs to make Vite the default (#9017) --- docs/discussion/introduction.md | 12 +- docs/discussion/server-vs-client.md | 86 +++++++++- docs/file-conventions/-client.md | 10 +- docs/file-conventions/-server.md | 27 ++- docs/file-conventions/remix-config.md | 6 + docs/file-conventions/routes.md | 6 +- docs/file-conventions/vite-config.md | 155 ++++++++++++++++++ docs/future/vite.md | 152 ++--------------- docs/guides/data-loading.md | 3 +- docs/guides/gotchas.md | 103 ++++++------ docs/guides/local-tls.md | 3 + docs/guides/manual-mode.md | 3 + docs/guides/mdx.md | 7 +- docs/guides/migrating-react-router-app.md | 4 + docs/guides/performance.md | 23 +-- docs/guides/typescript.md | 34 ++-- docs/index.md | 2 +- docs/other-api/dev.md | 87 +++++++--- docs/start/future-flags.md | 49 +++--- docs/start/quickstart.md | 131 ++++++++------- docs/start/tutorial.md | 30 ++-- docs/start/v2.md | 4 + docs/styling/bundling.md | 5 + docs/styling/css-imports.md | 3 + docs/styling/css-modules.md | 5 + docs/styling/css.md | 22 ++- docs/styling/postcss.md | 5 + docs/styling/tailwind.md | 7 +- docs/styling/vanilla-extract.md | 5 + docs/tutorials/jokes.md | 4 + .../{.eslintrc.js => .eslintrc.cjs} | 0 templates/remix-tutorial/.gitignore | 1 - templates/remix-tutorial/README.md | 4 +- templates/remix-tutorial/app/root.tsx | 2 - templates/remix-tutorial/package.json | 13 +- templates/remix-tutorial/remix.config.js | 5 - templates/remix-tutorial/remix.env.d.ts | 2 - templates/remix-tutorial/tsconfig.json | 10 +- templates/remix-tutorial/vite.config.ts | 15 ++ 39 files changed, 659 insertions(+), 386 deletions(-) create mode 100644 docs/file-conventions/vite-config.md rename templates/remix-tutorial/{.eslintrc.js => .eslintrc.cjs} (100%) delete mode 100644 templates/remix-tutorial/remix.config.js delete mode 100644 templates/remix-tutorial/remix.env.d.ts create mode 100644 templates/remix-tutorial/vite.config.ts diff --git a/docs/discussion/introduction.md b/docs/discussion/introduction.md index c9d242f3bbc..68c30f145d8 100644 --- a/docs/discussion/introduction.md +++ b/docs/discussion/introduction.md @@ -14,10 +14,10 @@ Built on top of [React Router][react_router], Remix is four things: ## Compiler -Everything in Remix starts with the compiler: `remix build`. Using [esbuild][esbuild], this creates a few things: +Everything in Remix starts with the compiler: `remix vite:build`. Using [Vite], this creates a few things: -1. A server HTTP handler, usually in `server/build/index.js` (it's configurable) that includes all routes and modules together to be able to render on the server and handle any other server-side requests for resources. -2. A browser build, usually in `public/build/*`. This includes automatic code splitting by route, fingerprinted asset imports (like CSS and images), etc. Anything needed to run an application in the browser. +1. A server HTTP handler, usually in `build/server/index.js` (it's configurable) that includes all routes and modules together to be able to render on the server and handle any other server-side requests for resources. +2. A browser build, usually in `build/client/*`. This includes automatic code splitting by route, fingerprinted asset imports (like CSS and images), etc. Anything needed to run an application in the browser. 3. An asset manifest. Both the client and the server use this manifest to know the entire dependency graph. This is useful for preloading resources in the initial server render as well as prefetching them for client-side transitions. This is how Remix is able to eliminate the render+fetch waterfalls so common in web apps today. With these build artifacts, an application can be deployed to any hosting service that runs JavaScript. @@ -38,7 +38,9 @@ const app = express(); app.all( "*", - remix.createRequestHandler({ build: require("./build") }) + remix.createRequestHandler({ + build: require("./build/server"), + }) ); ``` @@ -222,7 +224,7 @@ For example. Building a plain HTML form and server-side handler in a back-end he We borrowed an old term and called this Progressive Enhancement in Remix. Start small with a plain HTML form (Remix scales down) and then scale the UI up when you have the time and ambition. -[esbuild]: https://esbuild.github.io/ +[vite]: https://vitejs.dev [cf]: https://workers.cloudflare.com/ [deno]: https://deno.com/deploy/docs [fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API diff --git a/docs/discussion/server-vs-client.md b/docs/discussion/server-vs-client.md index 22fd6d73b60..6f30d56a027 100644 --- a/docs/discussion/server-vs-client.md +++ b/docs/discussion/server-vs-client.md @@ -7,7 +7,7 @@ order: 5 Remix runs your app on the server as well as in the browser. However, it doesn't run all of your code in both places. -During the build step, the compiler creates both a server build and a client build. The server build bundles up everything into a single module, but the client build splits your app up into multiple bundles to optimize loading in the browser. It also removes server code from the bundles. +During the build step, the compiler creates both a server build and a client build. The server build bundles up everything into a single module (or multiple modules when using [server bundles][server-bundles]), but the client build splits your app up into multiple bundles to optimize loading in the browser. It also removes server code from the bundles. The following route exports and the dependencies used within them are removed from the client build: @@ -97,15 +97,84 @@ export default function Component() { } ``` -## Forcing Code Out of the Browser or Server Builds +## Splitting Up Client and Server Code -You can force code out of either the client or the server with the [`*.client.ts`][file_convention_client] and [`*.server.ts`][file_convention_server] conventions. +Out of the box, Vite doesn't support mixing server-only code with client-safe code in the same module. +Remix is able to make an exception for routes because we know which exports are server-only and can remove them from the client. -While rare, sometimes server code makes it to client bundles because of how the compiler determines the dependencies of a route module, or because you accidentally try to use it in code that needs to ship to the client. You can force it out by adding `*.server.ts` on the end of the file name. +There are a few ways to isolate server-only code in Remix. +The simplest approach is to use [`.server`][file_convention_server] and [`.client`][file_convention_client] modules. -For example, we could name a module `app/user.server.ts` instead of `app/user.ts` to ensure that the code in that module is never bundled into the client — even if you try to use it in the component. +#### `.server` modules -Additionally, you may depend on client libraries that are unsafe to even bundle on the server — maybe it tries to access [`window`][window_global] by simply being imported. You can likewise remove these modules from the server build by appending `*.client.ts` to the file name. +While not strictly necessary, [`.server` modules][file_convention_server] are a good way to explicitly mark entire modules as server-only. +The build will fail if any code in a `.server` file or `.server` directory accidentally ends up in the client module graph. + +```txt +app +├── .server 👈 marks all files in this directory as server-only +│ ├── auth.ts +│ └── db.ts +├── cms.server.ts 👈 marks this file as server-only +├── root.tsx +└── routes + └── _index.tsx +``` + +`.server` modules must be within your Remix app directory. + +`.server` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.server` files. + +#### `.client` modules + +You may depend on client libraries that are unsafe to even bundle on the server — maybe it tries to access [`window`][window_global] by simply being imported. + +You can remove the contents of these modules from the server build by appending `*.client.ts` to the file name or nesting them within a `.client` directory. + +`.client` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.client` files. + +#### vite-env-only + +If you want to mix server-only code and client-safe code in the same module, you +can use [vite-env-only][vite-env-only]. +This Vite plugin allows you to explicitly mark any expression as server-only so that it gets +replaced with `undefined` in the client. + +For example, once you've added the plugin to your [Vite config][vite-config], you can wrap any server-only exports with `serverOnly$`: + +```tsx +import { serverOnly$ } from "vite-env-only"; + +import { db } from "~/.server/db"; + +export const getPosts = serverOnly$(async () => { + return db.posts.findMany(); +}); + +export const PostPreview = ({ title, description }) => { + return ( +
+

{title}

+

{description}

+
+ ); +}; +``` + +This example would be compiled into the following code for the client: + +```tsx +export const getPosts = undefined; + +export const PostPreview = ({ title, description }) => { + return ( +
+

{title}

+

{description}

+
+ ); +}; +``` [action]: ../route/action [headers]: ../route/headers @@ -113,3 +182,8 @@ Additionally, you may depend on client libraries that are unsafe to even bundle [file_convention_client]: ../file-conventions/-client [file_convention_server]: ../file-conventions/-server [window_global]: https://developer.mozilla.org/en-US/docs/Web/API/Window/window +[server-bundles]: ../future/server-bundles +[vite-config]: ../file-conventions/vite-configuration +[vite-env-only]: https://github.com/pcattori/vite-env-only +[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite +[remix-vite]: ../future/vite diff --git a/docs/file-conventions/-client.md b/docs/file-conventions/-client.md index 828165d1383..6a4a5f76536 100644 --- a/docs/file-conventions/-client.md +++ b/docs/file-conventions/-client.md @@ -1,11 +1,11 @@ --- -title: "*.client.ts extension" +title: ".client modules" toc: false --- -# `*.client.ts` +# `.client` modules -While uncommon, you may have a file or dependency that uses module side effects in the browser. You can use `*.client.ts` on file names to force them out of server bundles. +While uncommon, you may have a file or dependency that uses module side effects in the browser. You can use `*.client.ts` on file names or nest files within `.client` directories to force them out of server bundles. ```ts filename=feature-check.client.ts // this would break the server @@ -23,6 +23,10 @@ console.log(supportsVibrationAPI); // client: true | false ``` +`.client` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.client` files. + Refer to the Route Module section in the sidebar for more information. [use_effect]: https://react.dev/reference/react/useEffect +[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite +[remix-vite]: ../future/vite diff --git a/docs/file-conventions/-server.md b/docs/file-conventions/-server.md index 32cea0f7d6e..57530879e99 100644 --- a/docs/file-conventions/-server.md +++ b/docs/file-conventions/-server.md @@ -1,10 +1,31 @@ --- -title: "*.server.ts extension" +title: ".server modules" toc: false --- -# `*.server.ts` +# `.server` modules -While not always necessary, you can use `*.server.ts` on file names to force them out of client bundles. Usually the compiler is fine, but if you've got a server dependency with module side effects, move it into a `your-name.server.ts` file to ensure it is removed from client bundles. +While not strictly necessary, `.server` modules are a good way to explicitly mark entire modules as server-only. +The build will fail if any code in a `.server` file or `.server` directory accidentally ends up in the client module graph. + +```txt +app +├── .server 👈 marks all files in this directory as server-only +│ ├── auth.ts +│ └── db.ts +├── cms.server.ts 👈 marks this file as server-only +├── root.tsx +└── routes + └── _index.tsx +``` + +`.server` modules must be within your Remix app directory. Refer to the Route Module section in the sidebar for more information. + +`.server` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.server` files. + +When using the [Classic Remix Compiler][classic-remix-compiler], `.server` modules are replaced with empty modules and will not result in a compilation error. Note that this can result in runtime errors. + +[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite +[remix-vite]: ../future/vite diff --git a/docs/file-conventions/remix-config.md b/docs/file-conventions/remix-config.md index 9f2c17e900c..bd5c4638fae 100644 --- a/docs/file-conventions/remix-config.md +++ b/docs/file-conventions/remix-config.md @@ -1,9 +1,12 @@ --- title: remix.config.js +hidden: true --- # remix.config.js +`remix.config.js` is only relevant when using the [Classic Remix Compiler][classic-remix-compiler]. When using [Remix Vite][remix-vite], this file should not be present in your project. Instead, Remix configuration should be provided to the Remix plugin in your [Vite config][vite-config]. + This file has a few build and development configuration options, but does not actually run on your server. ```js filename=remix.config.js @@ -282,3 +285,6 @@ There are a few conventions that Remix uses you should be aware of. [use-fetchers]: ../hooks/use-fetchers [use-fetcher]: ../hooks/use-fetcher [relativesplatpath]: https://reactrouter.com/en/main/hooks/use-resolved-path#splat-paths +[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite +[remix-vite]: ../future/vite +[vite-config]: ./vite-configuration diff --git a/docs/file-conventions/routes.md b/docs/file-conventions/routes.md index f695323e82d..743a650a54b 100644 --- a/docs/file-conventions/routes.md +++ b/docs/file-conventions/routes.md @@ -4,7 +4,7 @@ title: Route File Naming # Route File Naming -While you can configure routes in [`remix.config.js`][remix_config], most routes are created with this file system convention. Add a file, get a route. +While you can configure routes via [the "routes" plugin option][routes_config], most routes are created with this file system convention. Add a file, get a route. Please note that you can use either `.js`, `.jsx`, `.ts` or `.tsx` file extensions. We'll stick with `.tsx` in the examples to avoid duplication. @@ -381,7 +381,7 @@ Our general recommendation for scale is to make every route a folder and put the ## More Flexibility -While we like this file convention, we recognize that at a certain scale many organizations won't like it. You can always define your routes programmatically in [`remix.config.js`][remix_config]. +While we like this file convention, we recognize that at a certain scale many organizations won't like it. You can always define your routes programmatically in [`vite.config.ts`][routes_config]. There's also the [`remix-flat-routes`][flat_routes] third-party package with configurable options beyond the defaults in Remix. @@ -393,7 +393,7 @@ There's also the [`remix-flat-routes`][flat_routes] third-party package with con [index_route]: ../discussion/routes#index-routes [nested_routing]: ../discussion/routes#what-is-nested-routing [nested_routes]: #nested-routes -[remix_config]: ./remix-config#routes +[routes_config]: ./vite-config#routes [dot_delimiters]: #dot-delimiters [dynamic_segments]: #dynamic-segments [flat_routes]: https://github.com/kiliman/remix-flat-routes diff --git a/docs/file-conventions/vite-config.md b/docs/file-conventions/vite-config.md new file mode 100644 index 00000000000..71473e6bab9 --- /dev/null +++ b/docs/file-conventions/vite-config.md @@ -0,0 +1,155 @@ +--- +title: vite.config.ts +--- + +# vite.config.ts + +If your project is still using the [Classic Remix Compiler][classic-remix-compiler], you should refer to the [remix.config.js documentation][remix-config] instead. + +Remix uses [Vite] to compile your application. You'll need to provide a Vite config file with the Remix Vite plugin. Here's the minimum configuration you'll need: + +```ts filename=vite.config.ts +import { vitePlugin as remix } from "@remix-run/dev"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [remix()], +}); +``` + +Vite supports using a `.js` file for your config, but we recommend using TypeScript to help ensure your configuration is valid. + +## Remix Vite Plugin Config + +```js filename=vite.config.ts +import { vitePlugin as remix } from "@remix-run/dev"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ + remix({ + basename: "/", + buildDirectory: "build", + future: { + /* any enabled future flags */ + }, + ignoredRouteFiles: ["**/*.css"], + routes(defineRoutes) { + return defineRoutes((route) => { + route("/somewhere/cool/*", "catchall.tsx"); + }); + }, + serverBuildFile: "index.js", + }), + ], +}); +``` + +#### appDirectory + +The path to the `app` directory, relative to the project root. Defaults to +`"app"`. + +#### future + +The `future` config lets you opt-into future breaking changes via [Future Flags][future-flags]. The following future flags currently exist in Remix v2 and will become the default behavior in Remix v3: + +- **`v3_fetcherPersist`**: Change fetcher persistence/cleanup behavior in 2 ways ([RFC][fetcherpersist-rfc]): + - Fetchers are no longer removed on unmount, and remain exposed via [`useFetchers`][use-fetchers] until they return to an `idle` state + - Fetchers that complete while still mounted no longer persist in [`useFetchers`][use-fetchers] since you can access those fetchers via [`useFetcher`][use-fetcher] +- **`v3_relativeSplatPath`**: Fixes buggy relative path resolution in splat routes. Please see the [React Router docs][relativesplatpath] for more information. +- **`v3_throwAbortReason`**: When a server-side request is aborted, Remix will throw the `request.signal.reason` instead of an error such as `new Error("query() call aborted...")` + +#### ignoredRouteFiles + +This is an array of globs (via [minimatch][minimatch]) that Remix will match to +files while reading your `app/routes` directory. If a file matches, it will be +ignored rather than treated like a route module. This is useful for ignoring +CSS/test files you wish to colocate. + +#### routes + +A function for defining custom routes, in addition to those already defined +using the filesystem convention in `app/routes`. Both sets of routes will be merged. + +```ts filename=vite.config.ts +import { vitePlugin as remix } from "@remix-run/dev"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ + remix({ + routes: async (defineRoutes) => { + // If you need to do async work, do it before calling `defineRoutes`, we use + // the call stack of `route` inside to set nesting. + + return defineRoutes((route) => { + // A common use for this is catchall routes. + // - The first argument is the React Router path to match against + // - The second is the relative filename of the route handler + route("/some/path/*", "catchall.tsx"); + + // if you want to nest routes, use the optional callback argument + route("some/:path", "some/route/file.js", () => { + // - path is relative to parent path + // - filenames are still relative to the app directory + route("relative/path", "some/other/file"); + }); + }); + }, + }), + ], +}); +``` + +#### serverModuleFormat + +The output format of the server build, which can either be `"cjs"` or `"esm"`. +Defaults to `"esm"`. + +#### buildDirectory + +The path to the build directory, relative to the project root. Defaults to +`"build"`. + +#### basename + +An optional basename for your route paths, passed through to the [React Router "basename" option][rr-basename]. Please note that this is different from your _asset_ paths. You can can configure the [base public path][vite-public-base-path] for your assets via the [Vite "base" option][vite-base]. + +#### buildEnd + +A function that is called after the full Remix build is complete. + +#### manifest + +Whether to write a `.remix/manifest.json` file to the build directory. Defaults +to `false`. + +#### presets + +An array of [presets] to ease integration with other tools and hosting providers. + +#### serverBuildFile + +The name of the server file generated in the server build directory. Defaults to `"index.js"`. + +#### serverBundles + +A function for assigning addressable routes to [server bundles][server-bundles]. + +You may also want to enable the `manifest` option since, when server bundles are enabled, it contains mappings between routes and server bundles. + +[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite +[remix-config]: ./remix-config +[vite]: https://vitejs.dev +[future-flags]: ../start/future-flags +[fetcherpersist-rfc]: https://github.com/remix-run/remix/discussions/7698 +[use-fetchers]: ../hooks/use-fetchers +[use-fetcher]: ../hooks/use-fetcher +[relativesplatpath]: https://reactrouter.com/en/main/hooks/use-resolved-path#splat-paths +[minimatch]: https://npm.im/minimatch +[presets]: ../future/presets +[server-bundles]: ../future/server-bundles +[rr-basename]: https://reactrouter.com/routers/create-browser-router#basename +[vite-public-base-path]: https://vitejs.dev/config/shared-options.html#base +[vite-base]: https://vitejs.dev/config/shared-options.html#base diff --git a/docs/future/vite.md b/docs/future/vite.md index dc7ba442e5c..10201267dfd 100644 --- a/docs/future/vite.md +++ b/docs/future/vite.md @@ -6,6 +6,14 @@ title: Vite [Vite][vite] is a powerful, performant and extensible development environment for JavaScript projects. In order to improve and extend Remix's bundling capabilities, we now support Vite as an alternative compiler. In the future, Vite will become the default compiler for Remix. +## Classic Remix Compiler vs. Remix Vite + +The existing Remix compiler, accessed via the `remix build` and `remix dev` CLI commands and configured via `remix.config.js`, is now referred to as the "Classic Remix Compiler". + +The Remix Vite plugin and the `remix vite:build` and `remix vite:dev` CLI commands are collectively referred to as "Remix Vite". + +Moving forwards, documentation will assume usage of Remix Vite unless otherwise stated. + ## Getting started We've got a few different Vite-based templates to get you started. @@ -25,68 +33,7 @@ These templates include a `vite.config.ts` file which is where the Remix Vite pl ## Configuration -The Vite plugin does not use [`remix.config.js`][remix-config]. Instead, the plugin accepts options directly. - -For example, to configure `ignoredRouteFiles`: - -```ts filename=vite.config.ts lines=[7] -import { vitePlugin as remix } from "@remix-run/dev"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [ - remix({ - ignoredRouteFiles: ["**/*.css"], - }), - ], -}); -``` - -All other bundling-related options are now [configured with Vite][vite-config]. This means you have much greater control over the bundling process. - -#### Supported Remix config options - -The following subset of Remix config options are supported: - -- [appDirectory][app-directory] -- [future][future] -- [ignoredRouteFiles][ignored-route-files] -- [routes][routes] -- [serverModuleFormat][server-module-format] - -The Vite plugin also accepts the following additional options: - -#### buildDirectory - -The path to the build directory, relative to the project root. Defaults to -`"build"`. - -#### basename - -An optional basename for your route paths, passed through to the [React Router "basename" option][rr-basename]. Please note that this is different from your _asset_ paths. You can can configure the [base public path][vite-public-base-path] for your assets via the [Vite "base" option][vite-base]. - -#### buildEnd - -A function that is called after the full Remix build is complete. - -#### manifest - -Whether to write a `.remix/manifest.json` file to the build directory. Defaults -to `false`. - -#### presets - -An array of [presets] to ease integration with other tools and hosting providers. - -#### serverBuildFile - -The name of the server file generated in the server build directory. Defaults to `"index.js"`. - -#### serverBundles - -A function for assigning addressable routes to [server bundles][server-bundles]. - -You may also want to enable the `manifest` option since, when server bundles are enabled, it contains mappings between routes and server bundles. +The Remix Vite plugin is configured via a `vite.config.ts` file at the root of your project. For more information, see our [Vite config documentation][vite-config]. ## Cloudflare @@ -239,73 +186,7 @@ export const onRequest = createPagesFunctionHandler({ ## Splitting up client and server code -Remix lets you write code that [runs on both the client and the server][server-vs-client]. -Out-of-the-box, Vite doesn't support mixing server-only code with client-safe code in the same module. -Remix is able to make an exception for routes because we know which exports are server-only and can remove them from the client. - -There are a few ways to isolate server-only code in Remix. -The simplest approach is to use `.server` modules. - -#### `.server` modules - -While not strictly necessary, `.server` modules are a good way to explicitly mark entire modules as server-only. -The build will fail if any code in a `.server` file or `.server` directory accidentally ends up in the client module graph. - -```txt -app -├── .server 👈 marks all files in this directory as server-only -│ ├── auth.ts -│ └── db.ts -├── cms.server.ts 👈 marks this file as server-only -├── root.tsx -└── routes - └── _index.tsx -``` - -`.server` modules must be within your Remix app directory. - -#### vite-env-only - -If you want to mix server-only code and client-safe code in the same module, you -can use [vite-env-only][vite-env-only]. -This Vite plugin allows you to explicitly mark any expression as server-only so that it gets -replaced with `undefined` in the client. - -For example, once you've added the plugin to your Vite config, you can wrap any server-only exports with `serverOnly$`: - -```tsx -import { serverOnly$ } from "vite-env-only"; - -import { db } from "~/.server/db"; - -export const getPosts = serverOnly$(async () => { - return db.posts.findMany(); -}); - -export const PostPreview = ({ title, description }) => { - return ( -
-

{title}

-

{description}

-
- ); -}; -``` - -This example would be compiled into the following code for the client: - -```tsx -export const getPosts = undefined; - -export const PostPreview = ({ title, description }) => { - return ( -
-

{title}

-

{description}

-
- ); -}; -``` +Vite handles mixed use of client and server code differently to the Classic Remix compiler. For more information, see our documentation on [splitting up client and server code][splitting-up-client-and-server-code]. ## New build output paths @@ -318,8 +199,6 @@ This also means that the following configuration defaults have been changed: - [publicPath][public-path] has been replaced by [Vite's "base" option][vite-base] which defaults to `"/"` rather than `"/build/"`. - [serverBuildPath][server-build-path] has been replaced by `serverBuildFile` which defaults to `"index.js"`. This file will be written into the server directory within your configured `buildDirectory`. -## Additional features & plugins - One of the reasons that Remix is moving to Vite is, so you have less to learn when adopting Remix. This means that, for any additional bundling features you'd like to use, you should reference [Vite documentation][vite] and the [Vite plugin community][vite-plugins] rather than the Remix documentation. @@ -1211,19 +1090,11 @@ Finally, we were inspired by how other frameworks implemented Vite support: - [SolidStart][solidstart] - [SvelteKit][sveltekit] -We're definitely late to the Vite party, but we're excited to be here now! - [vite]: https://vitejs.dev [template-vite-cloudflare]: https://github.com/remix-run/remix/tree/main/templates/vite-cloudflare -[remix-config]: ../file-conventions/remix-config -[app-directory]: ../file-conventions/remix-config#appdirectory -[future]: ../file-conventions/remix-config#future -[ignored-route-files]: ../file-conventions/remix-config#ignoredroutefiles [public-path]: ../file-conventions/remix-config#publicpath -[routes]: ../file-conventions/remix-config#routes [server-build-path]: ../file-conventions/remix-config#serverbuildpath -[server-module-format]: ../file-conventions/remix-config#servermoduleformat -[vite-config]: https://vitejs.dev/config +[vite-config]: ../file-conventions/vite-config.md [vite-plugins]: https://vitejs.dev/plugins [vite-features]: https://vitejs.dev/guide/features [supported-remix-config-options]: #configuration @@ -1298,3 +1169,4 @@ We're definitely late to the Vite party, but we're excited to be here now! [presets]: ./presets [fix-up-css-imports-referenced-in-links]: #fix-up-css-imports-referenced-in-links [vite-plugin-react]: https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react +[splitting-up-client-and-server-code]: ../discussion/server-vs-client.md diff --git a/docs/guides/data-loading.md b/docs/guides/data-loading.md index 4afdd479af8..833ad163b06 100644 --- a/docs/guides/data-loading.md +++ b/docs/guides/data-loading.md @@ -47,7 +47,7 @@ export default function Products() { The component renders on the server and in the browser. The loader _only runs on the server_. That means our hard-coded products array doesn't get included in the browser bundles, and it's safe to use server-only for APIs and SDKs for things like database, payment processing, content management systems, etc. -If your server-side modules end up in client bundles, move the imports for those modules to a file named `{something}.server.ts` with the `.server.ts` suffix to ensure they are excluded. +If your server-side modules end up in client bundles, refer to our guide on [server vs. client code execution][server-vs-client-code]. ## Route Params @@ -764,3 +764,4 @@ export default function RouteComp() { [url]: https://developer.mozilla.org/en-US/docs/Web/API/URL [use-submit]: ../hooks/use-submit [useloaderdata]: ../hooks/use-loader-data +[server-vs-client-code]: ../discussion/server-vs-client diff --git a/docs/guides/gotchas.md b/docs/guides/gotchas.md index ac9aaf17109..4bc42abd0e6 100644 --- a/docs/guides/gotchas.md +++ b/docs/guides/gotchas.md @@ -8,8 +8,58 @@ Rendering your app on the server and in the browser with React has some inherent This document should help you get over these bumps. +## `typeof window` checks + +Because the same JavaScript code can run in the browser as well as the server, sometimes you need to have a part of your code that only runs in one context or the other: + +```ts bad +if (typeof window === "undefined") { + // running in a server environment +} else { + // running in a browser environment +} +``` + +This works fine in a Node.js environment, however, Deno actually supports `window`! So if you really want to check whether you're running in the browser, it's better to check for `document` instead: + +```ts good +if (typeof document === "undefined") { + // running in a server environment +} else { + // running in a browser environment +} +``` + +This will work for all JS environments (Node.js, Deno, Workers, etc.). + +## Browser extensions injecting code + +You may run into this warning in the browser: + +``` +Warning: Did not expect server HTML to contain a