Skip to content

Commit

Permalink
Update docs to make Vite the default (#9017)
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish committed Mar 11, 2024
1 parent 24fa52c commit ea795f9
Show file tree
Hide file tree
Showing 39 changed files with 659 additions and 386 deletions.
12 changes: 7 additions & 5 deletions docs/discussion/introduction.md
Expand Up @@ -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.
Expand All @@ -38,7 +38,9 @@ const app = express();

app.all(
"*",
remix.createRequestHandler({ build: require("./build") })
remix.createRequestHandler({
build: require("./build/server"),
})
);
```

Expand Down Expand Up @@ -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
Expand Down
86 changes: 80 additions & 6 deletions docs/discussion/server-vs-client.md
Expand Up @@ -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:

Expand Down Expand Up @@ -97,19 +97,93 @@ 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.

<docs-warning>`.server` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.server` files.</docs-warning>

#### `.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.

<docs-warning>`.client` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.client` files.</docs-warning>

#### vite-env-only

If you want to mix server-only code and client-safe code in the same module, you
can use <nobr>[vite-env-only][vite-env-only]</nobr>.
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 (
<article>
<h2>{title}</h2>
<p>{description}</p>
</article>
);
};
```

This example would be compiled into the following code for the client:

```tsx
export const getPosts = undefined;

export const PostPreview = ({ title, description }) => {
return (
<article>
<h2>{title}</h2>
<p>{description}</p>
</article>
);
};
```

[action]: ../route/action
[headers]: ../route/headers
[loader]: ../route/loader
[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
10 changes: 7 additions & 3 deletions 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
Expand All @@ -23,6 +23,10 @@ console.log(supportsVibrationAPI);
// client: true | false
```

<docs-warning>`.client` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.client` files.</docs-warning>

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
27 changes: 24 additions & 3 deletions 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.

<docs-warning>`.server` directories are only supported when using [Remix Vite][remix-vite]. The [Classic Remix Compiler][classic-remix-compiler] only supports `.server` files.</docs-warning>

<docs-warning>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.</docs-warning>

[classic-remix-compiler]: ../future/vite#classic-remix-compiler-vs-remix-vite
[remix-vite]: ../future/vite
6 changes: 6 additions & 0 deletions docs/file-conventions/remix-config.md
@@ -1,9 +1,12 @@
---
title: remix.config.js
hidden: true
---

# remix.config.js

<docs-warning>`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].</docs-warning>

This file has a few build and development configuration options, but does not actually run on your server.

```js filename=remix.config.js
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions docs/file-conventions/routes.md
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand All @@ -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
Expand Down

0 comments on commit ea795f9

Please sign in to comment.