Skip to content

Commit

Permalink
Merge branch 'dev' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeAskew authored May 31, 2023
2 parents 8fe00b9 + 08aedc4 commit 1d7249d
Show file tree
Hide file tree
Showing 132 changed files with 2,552 additions and 784 deletions.
5 changes: 5 additions & 0 deletions .changeset/bubbled-response-cookies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/server-runtime": patch
---

Automatically include set-cookie headers from bubbled thrown responses
5 changes: 5 additions & 0 deletions .changeset/error-response-resource-route.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/server-runtime": patch
---

Properly handle thrown `ErrorResponse` instances inside resource routes
5 changes: 5 additions & 0 deletions .changeset/expose-error-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/server-runtime": minor
---

Add `errorHeaders` parameter to the leaf `headers()` function to expose headers from thrown responses that bubble up to ancestor route boundaries. If the throwing route contains the boundary, then `errorHeaders` will be the same object as `loaderHeaders`/`actionHeaders` for that route.
7 changes: 7 additions & 0 deletions .changeset/gorgeous-fireants-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@remix-run/dev": patch
---

Fix Tailwind performance issue when `postcss.config.js` contains `plugins: { tailwindcss: {} }` and `remix.config.js` contains both `tailwind: true` and `postcss: true`.

Note that this was _not_ an issue when the plugin function had been explicitly called, i.e. `plugins: [tailwindcss()]`. Remix avoids adding the Tailwind plugin to PostCSS if it's already present but we were failing to detect when the plugin function hadn't been called — either because the plugin function itself had been passed, i.e. `plugins: [require('tailwindcss')]`, or the plugin config object syntax had been used, i.e. `plugins: { tailwindcss: {} }`.
9 changes: 9 additions & 0 deletions .changeset/great-geese-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@remix-run/react": minor
"@remix-run/dev": patch
---

Faster server export removal for routes when `unstable_dev` is enabled.

Also, only render modulepreloads on SSR.
Do not render modulepreloads when hydrated.
6 changes: 3 additions & 3 deletions .changeset/headers-args-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
Add `HeadersArgs` type to be consistent with loaders/actions/meta and allows for using a `function` declaration in addition to an arrow function expression

```tsx
import type { HeadersArgs } from '@remix-run/node'; // or cloudflare/deno
import type { HeadersArgs } from "@remix-run/node"; // or cloudflare/deno

export function headers({ loaderHeaders }: HeadersArgs) {
return {
"x-my-custom-thing": loaderHeaders.get("x-my-custom-thing") || "fallback"
}
"x-my-custom-thing": loaderHeaders.get("x-my-custom-thing") || "fallback",
};
}
```
25 changes: 25 additions & 0 deletions .changeset/lemon-beers-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@remix-run/server-runtime": minor
"@remix-run/react": minor
---

Force Typescript to simplify type produced by `Serialize`.

As a result, the following types and functions have simplified return types:

- SerializeFrom
- useLoaderData
- useActionData
- useFetcher

```ts
type Data = { hello: string; when: Date };

// BEFORE
type Unsimplified = SerializeFrom<Data>;
// ^? SerializeObject<UndefinedToOptional<{ hello: string; when: Date }>>

// AFTER
type Simplified = SerializeFrom<Data>;
// ^? { hello: string; when: string }
```
89 changes: 89 additions & 0 deletions .changeset/ninety-hornets-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
"@remix-run/dev": minor
---

built-in tls support

New options:

- `--tls-key` / `tlsKey`: TLS key
- `--tls-cert` / `tlsCert`: TLS Certificate

If both TLS options are set, `scheme` defaults to `https`

## Example

Install [mkcert](https://github.com/FiloSottile/mkcert) and create a local CA:

```sh
brew install mkcert
mkcert -install
```

Then make sure you inform `node` about your CA certs:

```sh
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
```

👆 You'll probably want to put that env var in your scripts or `.bashrc`/`.zshrc`

Now create `key.pem` and `cert.pem`:

```sh
mkcert -key-file key.pem -cert-file cert.pem localhost
```

See `mkcert` docs for more details.

Finally, pass in the paths to the key and cert via flags:

```sh
remix dev --tls-key=key.pem --tls-cert=cert.pem
```

or via config:

```js
module.exports = {
future: {
unstable_dev: {
tlsKey: "key.pem",
tlsCert: "cert.pem",
},
},
};
```

That's all that's needed to set up the Remix Dev Server with TLS.

🚨 Make sure to update your app server for TLS as well.

For example, with `express`:

```ts
import express from "express";
import https from "node:https";
import fs from "node:fs";

let app = express();

// ...code setting up your express app...

let appServer = https.createServer(
{
key: fs.readFileSync("key.pem"),
cert: fs.readFileSync("cert.pem"),
},
app
);

appServer.listen(3000, () => {
console.log("Ready on https://localhost:3000");
});
```

## Known limitations

`remix-serve` does not yet support TLS.
That means this only works for custom app server using the `-c` flag for now.
5 changes: 5 additions & 0 deletions .changeset/rude-geese-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/dev": patch
---

better error message when `remix-serve` is not found
5 changes: 5 additions & 0 deletions .changeset/serious-wolves-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/dev": patch
---

restore color for app server output
9 changes: 9 additions & 0 deletions .changeset/stale-spoons-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@remix-run/dev": patch
---

- Fix route ranking bug with pathless layout route next to a sibling index route

- Under the hood this is done by removing the trailing slash from all generated `path` values since the number of slash-delimited segments counts towards route ranking so the trailing slash incorrectly increases the score for routes

- Support sibling pathless layout routes by removing pathless layout routes from the unique route path checks in conventional route generation since they inherently trigger duplicate paths
5 changes: 5 additions & 0 deletions .changeset/strong-dolphins-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/dev": patch
---

fix dev server crashes caused by ungraceful hdr error handling
5 changes: 5 additions & 0 deletions .changeset/v2-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/server-runtime": minor
---

Added a new `future.v2_headers` future flag to opt into automatic inheriting of ancestor route `headers` functions so you do not need to export a `headers` function from every possible leaf route if you don't wish to.
23 changes: 23 additions & 0 deletions .changeset/wicked-pandas-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"@remix-run/dev": minor
"@remix-run/react": minor
"@remix-run/server-runtime": minor
---

Reuse dev server port for WebSocket (Live Reload,HMR,HDR)

As a result the `webSocketPort`/`--websocket-port` option has been obsoleted.
Additionally, scheme/host/port options for the dev server have been renamed.

Available options are:

| Option | flag | config | default |
| ---------- | ------------------ | ---------------- | --------------------------------- |
| Command | `-c` / `--command` | `command` | `remix-serve <server build path>` |
| Scheme | `--scheme` | `scheme` | `http` |
| Host | `--host` | `host` | `localhost` |
| Port | `--port` | `port` | Dynamically chosen open port |
| No restart | `--no-restart` | `restart: false` | `restart: true` |

Note that scheme/host/port options are for the _dev server_, not your app server.
You probably don't need to use scheme/host/port option if you aren't configuring networking (e.g. for Docker or SSL).
10 changes: 5 additions & 5 deletions docs/guides/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,11 @@ Now we can tell it which files to generate classes from:
import type { Config } from "tailwindcss";

export default {
content: ["./app/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [],
content: ["./app/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [],
} satisfies Config;
```

Expand Down
1 change: 1 addition & 0 deletions docs/pages/api-development-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Here's the current future flags in Remix v1 today:
| ------------------------ | --------------------------------------------------------------------- |
| `unstable_dev` | Enable the new development server (including HMR/HDR support) |
| `v2_errorBoundary` | Combine `ErrorBoundary`/`CatchBoundary` into a single `ErrorBoundary` |
| `v2_headers` | Leverage ancestor `headers` if children do not export `headers` |
| `v2_meta` | Enable the new API for your `meta` functions |
| `v2_normalizeFormMethod` | Normalize `useNavigation().formMethod` to be an uppercase HTTP Method |
| `v2_routeConvention` | Enable the flat routes style of file-based routing |
Expand Down
8 changes: 8 additions & 0 deletions docs/pages/v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ routes

For more background on this change, see the [original "flat routes" proposal][flat-routes].

## Route `headers`

In Remix v2, the behavior for route `headers` functions is changing slightly. You can opt-into this new behavior ahead of time via the `future.v2_headers` flag in `remix.config.js`.

In v1, Remix would only use the result of the leaf "rendered" route `headers` function. It was your responsibility to add a `headers` function to every potential leaf and merge in `parentHeaders` accordingly. This can get tedious quickly and is also easy to forget to add a `headers` function when you add a new route, even if you want it to just share the same headers from it's parent.

In v2, Remix will use the deepest `headers` function that it finds in the rendered routes. This more easily allows you to share headers across routes from a common ancestor. Then as needed you can add `headers` functions to deeper routes if they require specific behavior.

## Route `meta`

In Remix v2, the signature for route `meta` functions and how Remix handles meta tags under the hood have changed.
Expand Down
33 changes: 31 additions & 2 deletions docs/route/headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const headers: HeadersFunction = ({
actionHeaders,
loaderHeaders,
parentHeaders,
errorHeaders,
}) => ({
"X-Stretchy-Pants": "its for fun",
"Cache-Control": "max-age=300, s-maxage=3600",
Expand All @@ -33,7 +34,11 @@ export const headers: HeadersFunction = ({

Note: `actionHeaders` & `loaderHeaders` are an instance of the [Web Fetch API][headers] `Headers` class.

Because Remix has nested routes, there's a battle of the headers to be won when nested routes match. In this case, the deepest route wins. Consider these files in the routes directory:
If an action or a loader threw a `Response` and we're rendering a boundary, any headers from the thrown `Response` will be available in `errorHeaders`. This allows you to access headers from a child loader that threw in a parent error boundary.

## Nested Routes

Because Remix has nested routes, there's a battle of the headers to be won when nested routes match. The default behavior is that Remix only leverages the resulting headers from the leaf rendered route. Consider these files in the routes directory:

```
├── users.tsx
Expand All @@ -53,7 +58,11 @@ If we are looking at `/users/123/profile` then three routes are rendering:
</Users>
```

If all three define `headers`, the deepest module wins, in this case `profile.tsx`.
If all three define `headers`, the deepest module wins, in this case `profile.tsx`. However, if your `profile.tsx` loader threw and bubbled to a boundary in `userId.tsx` - then `userId.tsx`'s `headers` function would be used as it is the leaf rendered route.

<docs-info>
We realize that it can be tedious and error-prone to have to define `headers` on every possible leaf route so we're changing the current behavior in v2 behind the [`future.v2_headers`][v2_headers] flag.
</docs-info>

We don't want surprise headers in your responses, so it's your job to merge them if you'd like. Remix passes in the `parentHeaders` to your `headers` function. So `users.tsx` headers get passed to `$userId.tsx`, and then `$userId.tsx` headers are passed to `profile.tsx` headers.

Expand Down Expand Up @@ -118,5 +127,25 @@ export default function handleRequest(

Just keep in mind that doing this will apply to _all_ document requests, but does not apply to `data` requests (for client-side transitions for example). For those, use [`handleDataRequest`][handledatarequest].

## v2 Behavior

Since it can be tedious and error-prone to define a `header` function in every single possible leaf route, we're changing the behavior slightly in v2 and you can opt-into the new behavior via the `future.v2_headers` [Future Flag][future-flags] in `remix.config.js`.

When enabling this flag, Remix will now use the deepest `headers` function it finds in the renderable matches (up to and including the boundary route if an error is present). You'll still need to handle merging together headers as shown above for any `headers` functions above this route.

This means that, re-using the example above:

```
├── users.tsx
└── users
├── $userId.tsx
└── $userId
└── profile.tsx
```

If a user is looking at `/users/123/profile` and `profile.tsx` does not export a `headers` function, then Remix will use the return value of `$userId.tsx`'s `headers` function. If that file doesn't export one, then it will use the result of the one in `users.tsx`, and so on.

[headers]: https://developer.mozilla.org/en-US/docs/Web/API/Headers
[handledatarequest]: ../file-conventions/entry.server
[v2_headers]: #v2-behavior
[future-flags]: ../pages/api-development-strategy
4 changes: 3 additions & 1 deletion integration/abort-signal-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ let appFixture: AppFixture;

test.beforeAll(async () => {
fixture = await createFixture({
future: { v2_routeConvention: true },
config: {
future: { v2_routeConvention: true },
},
files: {
"app/routes/_index.jsx": js`
import { json } from "@remix-run/node";
Expand Down
10 changes: 6 additions & 4 deletions integration/action-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ test.describe("actions", () => {

test.beforeAll(async () => {
fixture = await createFixture({
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
v2_normalizeFormMethod: true,
config: {
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
v2_normalizeFormMethod: true,
},
},
files: {
"app/routes/urlencoded.jsx": js`
Expand Down
4 changes: 3 additions & 1 deletion integration/bug-report-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ let appFixture: AppFixture;

test.beforeAll(async () => {
fixture = await createFixture({
future: { v2_routeConvention: true },
config: {
future: { v2_routeConvention: true },
},
////////////////////////////////////////////////////////////////////////////
// 💿 Next, add files to this object, just like files in a real app,
// `createFixture` will make an app and run your tests against it.
Expand Down
12 changes: 8 additions & 4 deletions integration/catch-boundary-data-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ let LAYOUT_DATA = "root data";

test.beforeAll(async () => {
fixture = await createFixture({
future: { v2_routeConvention: true },
config: {
future: { v2_routeConvention: true },
},
files: {
"app/root.jsx": js`
import { json } from "@remix-run/node";
Expand Down Expand Up @@ -236,9 +238,11 @@ test("renders self boundary with layout data available on transition", async ({
test.describe("v2_errorBoundary", () => {
test.beforeAll(async () => {
fixture = await createFixture({
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
config: {
future: {
v2_routeConvention: true,
v2_errorBoundary: true,
},
},
files: {
"app/root.jsx": js`
Expand Down
Loading

0 comments on commit 1d7249d

Please sign in to comment.