Skip to content

Commit

Permalink
docs: small updates
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelDeBoey committed Aug 25, 2023
1 parent b86ce25 commit efb25a0
Show file tree
Hide file tree
Showing 35 changed files with 648 additions and 578 deletions.
16 changes: 8 additions & 8 deletions docs/discussion/00-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ order: 0

These discussion topics are intended to be read in order. It gives you a linear path to Remix mastery instead of bouncing around from one doc to another. While useful independently, topics may refer to code and concepts from previous chapters.

Built on top of [React Router][reactrouter], Remix is four things:
Built on top of [React Router][react-router], Remix is four things:

1. A compiler
2. A server-side HTTP handler
Expand Down Expand Up @@ -44,7 +44,7 @@ app.all(
);
```

Express (or Node.js) is the actual server, Remix is just a handler on that server. The `"@remix-run/express"` package is called an adapter. Remix handlers are server agnostic. Adapters make them work for a specific server by converting the server's request/response API into the Fetch API on the way in, and then adapting the Fetch Response coming from Remix into the server's response API. Here's some pseudo code of what an adapter does:
Express (or Node.js) is the actual server, Remix is just a handler on that server. The `"@remix-run/express"` package is called an adapter. Remix handlers are server agnostic. Adapters make them work for a specific server by converting the server's request/response API into the Fetch API on the way in, and then adapting the Fetch Response coming from Remix into the server's response API. Here's some pseudocode of what an adapter does:

```ts
export function createRequestHandler({ build }) {
Expand Down Expand Up @@ -138,15 +138,15 @@ export async function action({ request }: ActionArgs) {

You can actually use Remix as just a server-side framework without using any browser JavaScript at all. The route conventions for data loading with `loader`, mutations with `action` and HTML forms, and components that render at URLs, can provide the core feature set of a lot of web projects.

In this way, **Remix scales down**. Not every page in your application needs a bunch of JavaScript in the browser and not every user interaction requires any extra flair than the browser's default behaviors. In Remix you can build it the simple way first, and then scale up without changing the fundamental model. Additionally, the majority of the app works before JavaScript loads in the browser, which makes Remix apps resilient to choppy network conditions by design.
In this way, **Remix scales down**. Not every page in your application needs a bunch of JavaScript in the browser and not every user interaction requires any extra flair than the browser's default behaviors. In Remix, you can build it the simple way first, and then scale up without changing the fundamental model. Additionally, the majority of the app works before JavaScript loads in the browser, which makes Remix apps resilient to choppy network conditions by design.

If you're not familiar with traditional back-end web frameworks, you can think of Remix routes as React components that are already their own API route and already know how to load and submit data to themselves on the server.

## Browser Framework

Once Remix has served the document to the browser, it "hydrates" the page with the browser build's JavaScript modules. This is where we talk a lot about Remix "emulating the browser".

When the user clicks a link, instead of making a round trip to the server for the entire document and all of the assets, Remix simply fetches the data for the next page and updates the UI. This has many performance benefits over making a full-document request:
When the user clicks a link, instead of making a round trip to the server for the entire document and all the assets, Remix simply fetches the data for the next page and updates the UI. This has many performance benefits over making a full-document request:

1. Assets don't need to be re-downloaded (or pulled from cache)
2. Assets don't need to be parsed by the browser again
Expand All @@ -158,15 +158,15 @@ This approach also has UX benefits like not resetting the scroll position of a s

Remix can also prefetch all resources for a page when the user is about to click a link. The browser framework knows about the compiler's asset manifest. It can match the URL of the link, read the manifest, and then prefetch all data, JavaScript modules, and even CSS resources for the next page. This is how Remix apps feel fast even when networks are slow.

Remix then provides client side APIs so you can create rich user experiences without changing the fundamental model of HTML and browsers.
Remix then provides client side APIs, so you can create rich user experiences without changing the fundamental model of HTML and browsers.

Taking our route module from before, here are a few small, but useful UX improvements to the form that you can only do with JavaScript in the browser:

1. Disable the button when the form is being submitted
2. Focus the input when server-side form validation fails
3. Animate in the error messages

```tsx nocopy lines=[4-6,8-12,23-26,30-32]
```tsx lines=[4-6,8-12,23-26,30-32] nocopy
export default function Projects() {
const projects = useLoaderData<typeof loader>();
const actionData = useActionData<typeof action>();
Expand Down Expand Up @@ -213,7 +213,7 @@ Because Remix reaches into the controller level of the backend, it can do this s

And while it doesn't reach as far back into the stack as server-side frameworks like Rails and Laravel, it does reach way farther up the stack into the browser to make the transition from the back end to the front end seamless.

For example. Building a plain HTML form and server-side handler in a back-end heavy web framework is just as easy to do as it is in Remix. But as soon as you want to cross over into an experience with animated validation messages, focus management, and pending UI, it requires a fundamental change in the code. Typically people build an API route and then bring in a splash of client-side JavaScript to connect the two. With Remix you simply add some code around the existing "server side view" without changing how it works fundamentally.
For example. Building a plain HTML form and server-side handler in a back-end heavy web framework is just as easy to do as it is in Remix. But as soon as you want to cross over into an experience with animated validation messages, focus management, and pending UI, it requires a fundamental change in the code. Typically, people build an API route and then bring in a splash of client-side JavaScript to connect the two. With Remix, you simply add some code around the existing "server side view" without changing how it works fundamentally.

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.

Expand All @@ -224,4 +224,4 @@ We borrowed an old term and called this Progressive Enhancement in Remix. Start
[vercel]: https://vercel.com
[netlify]: https://netlify.com
[arc]: https://arc.codes
[reactrouter]: https://reactrouter.com
[react-router]: https://reactrouter.com
8 changes: 4 additions & 4 deletions docs/discussion/01-runtimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Deploying a Remix application has four layers:
3. A server adapter like `@remix-run/express`
4. A web host or platform

Depending on your web host, you may have fewer layers. For example, deploying to Cloudflare Pages takes care of 2, 3, and 4 all at once. Deploying Remix inside of an express app will have all four, and using the "Remix App Server" combines 2 and 3!
Depending on your web host, you may have fewer layers. For example, deploying to Cloudflare Pages takes care of 2, 3, and 4 all at once. Deploying Remix inside an Express app will have all four, and using the "Remix App Server" combines 2 and 3!

You can wire all of these up yourself, or start with a Remix Template.

Expand Down Expand Up @@ -49,11 +49,11 @@ import { createCookieSessionStorage } from "remix";

## Adapters

Remix is not an HTTP server, but rather a handler inside of an existing HTTP server. Adapters allow the Remix handler to run inside the HTTP server. Some JavaScript runtimes, especially Node.js, have multiple ways to create an HTTP server. For example, in Node.js you can use Express.js, fastify, or raw `http.createServer`.
Remix is not an HTTP server, but rather a handler inside an existing HTTP server. Adapters allow the Remix handler to run inside the HTTP server. Some JavaScript runtimes, especially Node.js, have multiple ways to create an HTTP server. For example, in Node.js you can use Express.js, fastify, or raw `http.createServer`.

Each of these servers has its own Request/Response API. The adapter's job is to convert the incoming request to a Web Fetch Request, run the Remix handler, and then adapt the Web Fetch Response back to the host server's response API.

Here's some pseudo code that illustrates the flow.
Here's some pseudocode that illustrates the flow.

```tsx
// import the app build created by `remix build`
Expand Down Expand Up @@ -92,7 +92,7 @@ See [`@remix-run/serve`][serve]

## Templates

Remix is designed to be incredibly flexible with just enough opinions to connect the UI to the back end but it doesn't bring opinions on the database you use, how you cache data, or where and how your app is deployed.
Remix is designed to be incredibly flexible with just enough opinions to connect the UI to the back end, but it doesn't bring opinions on the database you use, how you cache data, or where and how your app is deployed.

Remix templates are starting points for app development with all of these extra opinions baked in, created by the community.

Expand Down
111 changes: 59 additions & 52 deletions docs/discussion/02-routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This strategy, combined with modern browsers' capability to handle multiple conc

## Conventional Route Configuration

Remix introduces a key convention to help streamline the routing process: the `routes` folder. When a developer introduces a file within this folder, Remix inherently understands it as a route. This convention simplifies the process of defining routes, associating them with URLs, and rendering the associated components.
Remix introduces a key convention to help streamline the routing process: the `app/routes` folder. When a developer introduces a file within this folder, Remix inherently understands it as a route. This convention simplifies the process of defining routes, associating them with URLs, and rendering the associated components.

Here's a sample directory that uses the routes folder convention:

Expand All @@ -41,19 +41,19 @@ app/
└── root.tsx
```

All the routes that start with `concerts.` will be child routes of `concerts.tsx`.
All the routes that start with `app/routes/concerts.` will be child routes of `app/routes/concerts.tsx`.

| URL | Matched Route | Layout |
| -------------------------- | ----------------------- | -------------- |
| `/` | `_index.tsx` | `root.tsx` |
| `/about` | `about.tsx` | `root.tsx` |
| `/concerts` | `concerts._index.tsx` | `concerts.tsx` |
| `/concerts/trending` | `concerts.trending.tsx` | `concerts.tsx` |
| `/concerts/salt-lake-city` | `concerts.$city.tsx` | `concerts.tsx` |
| URL | Matched Route | Layout |
| -------------------------- | ---------------------------------- | ------------------------- |
| `/` | `app/routes/_index.tsx` | `app/root.tsx` |
| `/about` | `app/routes/about.tsx` | `app/root.tsx` |
| `/concerts` | `app/routes/concerts._index.tsx` | `app/routes/concerts.tsx` |
| `/concerts/trending` | `app/routes/concerts.trending.tsx` | `app/routes/concerts.tsx` |
| `/concerts/salt-lake-city` | `app/routes/concerts.$city.tsx` | `app/routes/concerts.tsx` |

## Conventional Route Folders

For routes that require additional modules or assets, a folder inside of `routes/` with a `route.tsx` file can be used. This method:
For routes that require additional modules or assets, a folder inside of `app/routes` with a `route.tsx` file can be used. This method:

- **Co-locates Modules**: It gathers all elements connected to a particular route, ensuring logic, styles, and components are closely knit.
- **Simplifies Imports**: With related modules in one place, managing imports becomes straightforward, enhancing code maintainability.
Expand All @@ -62,68 +62,74 @@ For routes that require additional modules or assets, a folder inside of `routes
The same routes from above could instead be organized like this:

<!-- prettier-ignore -->
```
```markdown
app/
└── routes/
├── _index/
│   ├── signup-form.tsx
│   └── route.tsx
├── about/
│   ├── header.tsx
│   └── route.tsx
├── concerts/
│   ├── favorites-cookie.ts
│   └── route.tsx
├── concerts.$city/
│   └── route.tsx
├── concerts._index/
│   ├── featured.tsx
│   └── route.tsx
└── concerts.trending/
├── card.tsx
├── route.tsx
└── sponsored.tsx
├── routes/
│ ├── _index/
│ │ ├── signup-form.tsx
│ │ └── route.tsx
│ ├── about/
│ │ ├── header.tsx
│ │ └── route.tsx
│ ├── concerts/
│ │ ├── favorites-cookie.ts
│ │ └── route.tsx
│ ├── concerts.$city/
│ │ └── route.tsx
│ ├── concerts._index/
│ │ ├── featured.tsx
│ │ └── route.tsx
│ └── concerts.trending/
│ ├── card.tsx
│ ├── route.tsx
│ └── sponsored.tsx
└── root.tsx
```

You can read more about the specific patterns in the file names and other features in the [Route File Conventions][route-file-conventions] reference.

Only the folders directly beneath `routes/` will be registered as a route. Deeply nested folders are ignored. The file at `routes/about/header/route.tsx` will not create a route.
Only the folders directly beneath `app/routes` will be registered as a route. Deeply nested folders are ignored. The file at `app/routes/about/header/route.tsx` will not create a route.

<!-- prettier-ignore -->
```markdown bad lines=[4]
routes
└── about
├── header
│   └── route.tsx
└── route.tsx
app/
├── routes/
│ └── about/
│ ├── header/
│ │ └── route.tsx
│ └── route.tsx
└── root.tsx
```

## Manual Route Configuration

While the `routes/` folder offers a convenient convention for developers, Remix appreciates that one size doesn't fit all. There are times when the provided convention might not align with specific project requirements or a developer's preferences. In such cases, Remix allows for manual route configuration via the `remix.config`. This flexibility ensures developers can structure their application in a way that makes sense for their project.
While the `app/routes` folder offers a convenient convention for developers, Remix appreciates that one size doesn't fit all. There are times when the provided convention might not align with specific project requirements or a developer's preferences. In such cases, Remix allows for manual route configuration via [`remix.config.js`][remix-config]. This flexibility ensures developers can structure their application in a way that makes sense for their project.

A common way to structure an app is by top-level features folders. Consider that routes related to a particular theme, like concerts, likely share several modules. Organizing them under a single folder makes sense:

```text
<!-- prettier-ignore -->
```markdown
app/
├── about
│   └── route.tsx
├── concerts
│   ├── card.tsx
│   ├── city.tsx
│   ├── favorites-cookie.ts
│   ├── home.tsx
│   ├── layout.tsx
│   ├── sponsored.tsx
│   └── trending.tsx
└── home
├── header.tsx
└── route.tsx
├── about/
│ └── route.tsx
├── concerts/
│ ├── card.tsx
│ ├── city.tsx
│ ├── favorites-cookie.ts
│ ├── home.tsx
│ ├── layout.tsx
│ ├── sponsored.tsx
│ └── trending.tsx
├── home/
│ ├── header.tsx
│ └── route.tsx
└── root.tsx
```

To configure this structure into the same URLs as the previous examples, you can use the `routes` function in `remix.config.js`:

```js filename=remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
export default {
routes(defineRoutes) {
return defineRoutes((route) => {
Expand All @@ -139,6 +145,7 @@ export default {
};
```

Remix's route configuration approach blends convention with flexibility. You can use the `routes` folder for an easy, organized way to set up your routes. If you want more control, dislike the file names, or have unique needs, there's `remix.config`. It is expected that many apps forgo the routes folder convention in favor of `remix.config`.
Remix's route configuration approach blends convention with flexibility. You can use the `app/routes` folder for an easy, organized way to set up your routes. If you want more control, dislike the file names, or have unique needs, there's `remix.config.js`. It is expected that many apps forgo the routes folder convention in favor of `remix.config.js`.

[route-file-conventions]: ../file-conventions/routes
[remix-config]: ../file-conventions/remix-config
Loading

0 comments on commit efb25a0

Please sign in to comment.