@remix-run/server-runtime
2.16.5
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.16.5.
2.16.4
Patch Changes
2.16.3
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.16.3.
2.16.2
Patch Changes
- Load ancestor pathless/index routes in lazy route discovery for upwards non-eager-discovery routing (#10535)
2.16.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.16.1.
2.16.0
Patch Changes
2.15.3
Patch Changes
- Avoid duplication of
Set-Cookie
headers could be duplicated if also returned from headers
(#10424)
- Properly handle status codes that cannot have a body in single fetch responses (204, etc.) (#10410)
2.15.2
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.15.2.
2.15.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.15.1.
2.15.0
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.15.0.
2.14.0
Minor Changes
- Deprecate
SerializeFrom
in favor of generics because it will be removed in React Router v7 (#10173)
Patch Changes
- Update externally-accessed resource routes warning to cover null usage as well (#10145)
2.13.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.13.1.
2.13.0
Minor Changes
- Stabilize React Router APIs in Remix (#9980)
- Adopt stabilized React Router APIs internally
- Single Fetch:
unstable_dataStrategy
-> dataStrategy
- Lazy Route Discovery:
unstable_patchRoutesOnNavigation
-> patchRoutesOnNavigation
- Stabilize public-facing APIs
- Single Fetch:
unstable_data()
-> data()
unstable_viewTransition
-> viewTransition
(Link
, Form
, navigate
, submit
)
unstable_flushSync>
-> <Link viewTransition>
(Link
, Form
, navigate
, submit
, useFetcher
)
- Stabilize future flags (#10072)
future.unstable_singleFetch
-> future.v3_singleFetch
future.unstable_lazyRouteDiscovery
-> future.v3_lazyRouteDiscovery
2.12.1
Patch Changes
- Fix single-fetch types when
loader
, action
, clientLoader
, or clientAction
return a mixture of bare objects, json(...)
, defer(...)
, and unstable_data(...)
. (#9999)
- Single Fetch: Re-export
interface Future
through @remix-run/node
/@remix-run/cloudflare
/@remix-run/deno
packages so that pnpm
doesn't complain about @remix-run/server-runtime
not being a dependency (#9982)
2.12.0
Patch Changes
Single Fetch: Do not try to encode a turbo-stream
body into 304 responses (#9941)
Single Fetch: fix revalidation behavior bugs (#9938)
- With Single Fetch, existing routes revalidate by default
- This means requests do not need special query params for granular route revalidations out of the box - i.e.,
GET /a/b/c.data
- There are two conditions that will trigger granular revalidation:
- If a route opts out of revalidation via
shouldRevalidate
, it will be excluded from the single fetch call
- If a route defines a
clientLoader
then it will be excluded from the single fetch call and if you call serverLoader()
from your clientLoader
, that will make a separarte HTTP call for just that route loader - i.e., GET /a/b/c.data?_routes=routes/a
for a clientLoader
in routes/a.tsx
- When one or more routes are excluded from the single fetch call, the remaining routes that have loaders are included as query params:
- For example, if A was excluded, and the
root
route and routes/b
had a loader
but routes/c
did not, the single fetch request would be GET /a/b/c.data?_routes=root,routes/a
Remove hydration URL check that was originally added for React 17 hydration issues and we no longer support React 17 (#9890)
- Reverts the logic originally added in Remix
v1.18.0
via https://github.com/remix-run/remix/pull/6409
- This was added to resolve an issue that could arise when doing quick back/forward history navigations while JS was loading which would cause a mismatch between the server matches and client matches: https://github.com/remix-run/remix/issues/1757
- This specific hydration issue would then cause this React v17 only looping issue: https://github.com/remix-run/remix/issues/1678
- The URL comparison that we added in
1.18.0
turned out to be subject to false positives of it's own which could also put the user in looping scenarios
- Remix v2 upgraded it's minimal React version to v18 which eliminated the v17 hydration error loop
- React v18 handles this hydration error like any other error and does not result in a loop
- So we can remove our check and thus avoid the false-positive scenarios in which it may also trigger a loop
Single Fetch: Improved typesafety (#9893)
If you were already using previously released unstable single-fetch types:
- Remove
"@remix-run/react/future/single-fetch.d.ts"
override from tsconfig.json
> compilerOptions
> types
- Remove
defineLoader
, defineAction
, defineClientLoader
, defineClientAction
helpers from your route modules
- Replace
UIMatch_SingleFetch
type helper with UIMatch
- Replace
MetaArgs_SingleFetch
type helper with MetaArgs
Then you are ready for the new typesafety setup:
declare module "@remix-run/server-runtime" {
interface Future {
unstable_singleFetch: true;
}
}
export default defineConfig({
plugins: [
remix({
future: {
unstable_singleFetch: true,
},
}),
],
});
For more information, see Guides > Single Fetch in our docs.
Single Fetch: Change content type on .data
requests to text/x-script
to allow Cloudflare compression (#9889)
Support 304 responses on document requests (#9955)
2.11.2
Patch Changes
- Single Fetch: Fix redirects when a
basename
is present (#9848)
- Fog of War: Simplify implementation now that React Router handles slug/splat edge cases and tracks previously discovered routes (see https://github.com/remix-run/react-router/pull/11883) (#9860)
- This changes the return signature of the internal
__manifest
endpoint since we no longer need the notFoundPaths
field
- Fog of War: Update to use renamed
unstable_patchRoutesOnNavigation
function in RR (see https://github.com/remix-run/react-router/pull/11888) (#9860)
- Single Fetch: Update
turbo-stream
to v2.3.0
(#9856)
- Stabilize object key order for serialized payloads
- Remove memory limitations payloads sizes
2.11.1
Patch Changes
- Revert #9695, stop infinite reload (
a7cffe57
)
2.11.0
Minor Changes
Patch Changes
- Change initial hydration route mismatch from a URL check to a matches check to be resistant to URL inconsistencies (#9695)
2.10.3
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.10.3.
2.10.2
Patch Changes
- Fix bug with
immutable
headers on raw native fetch
responses returned from loaders (#9693)
2.10.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.10.1.
2.10.0
Minor Changes
Patch Changes
- Properly handle thrown 4xx/5xx response stubs in single fetch (#9501)
- Change single fetch redirects to use a 202 status to avoid automatic caching (#9564)
- Fix error when returning
null
from a resource route in single fetch (#9488)
- Fix issues with returning or throwing a response stub from a resource route in single fetch (#9488)
- Update to `turbo-stream@2.2.0` for single fetch (#9562)
2.9.2
Patch Changes
- Don't log thrown response stubs via
handleError
in Single Fetch (#9369)
- Automatically wrap resource route naked object returns in
json()
for back-compat in v2 (and log deprecation warning) (#9349)
- Typesafety for single-fetch:
defineLoader
, defineClientLoader
, defineAction
, defineClientAction
(#9372, #9404)
- Pass
response
stub to resource route handlers when single fetch is enabled (#9349)
2.9.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.9.1.
2.9.0
Minor Changes
- New
future.unstable_singleFetch
flag (#8773)
- Naked objects returned from loaders/actions are no longer automatically converted to JSON responses. They'll be streamed as-is via
turbo-stream
so Date
's will become Date
through useLoaderData()
- You can return naked objects with
Promise
's without needing to use defer()
- including nested Promise
's
- If you need to return a custom status code or custom response headers, you can still use the
defer
utility
<RemixServer abortDelay>
is no longer used. Instead, you should export const streamTimeout
from entry.server.tsx
and the remix server runtime will use that as the delay to abort the streamed response
- If you export your own streamTimeout, you should decouple that from aborting the react
renderToPipeableStream
. You should always ensure that react is aborted afer the stream is aborted so that abort rejections can be flushed down
- Actions no longer automatically revalidate on 4xx/5xx responses (via RR
future.unstable_skipActionErrorRevalidation
flag) - you can return a 2xx to opt-into revalidation or use shouldRevalidate
- Add
ResponseStub
header interface for single fetch and deprecate the headers
export (#9142)
- The
headers
export is no longer used when single fetch is enabled
loader
/action
functions now receive a mutable response
parameter
type ResponseStub = { status: numbers | undefined, headers: Headers }
- To alter the status of a response, set the
status
field directly
- To set headers on the Response, you may use:
response.headers.set
response.headers.append
response.headers.delete
- Each
loader
/action
receives it's own unique response
instance so you cannot see what other loader
/action
functions have set (which would be subject to race conditions)
- If all status codes are unset or have values <200, the deepest status code will be used for the HTTP response
- If any status codes are set to a value >=300, the highest >=300 value will be used for the HTTP Response
- Remix tracks header operations and will replay them in order (action if present, then loaders top-down) after all handlers have completed on a fresh
Headers
instance that will be applied to the HTTP Response
headers.set
on any child handler will overwrite values from parent handlers
headers.append
can be used to set the same header from both a parent and child handler
headers.delete
can be used to delete a value set by a parent handler, but not a value set from a child handler
- Because single fetch supports naked object returns, and you no longer need to return a
Response
instance to set status/headers, the json
/redirect
/redirectDocument
/defer
utilities are considered deprecated when using Single Fetch
- You may still continue returning normal
Response
instances and they'll apply status codes in the same way, and will apply all headers via headers.set
- overwriting any same-named header values from parents
- If you need to append, you will need to switch from returning a
Response
instance to using the new response
parameter
Patch Changes
- Handle net new redirects created by handleDataRequest (#9104)
2.8.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.8.1.
2.8.0
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.8.0.
2.7.2
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.7.2.
2.7.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.7.1.
2.7.0
Minor Changes
- Allow an optional
Layout
export from the root route (#8709)
- Vite: Add a new
basename
option to the Vite plugin, allowing users to set the internal React Router basename
in order to to serve their applications underneath a subpath (#8145)
Patch Changes
- Add a more specific error if a user returns a
defer
response from a resource route (#8726)
2.6.0
Minor Changes
- Add
future.v3_throwAbortReason
flag to throw request.signal.reason
when a request is aborted instead of an Error
such as new Error("query() call aborted: GET /path")
(#8251)
Patch Changes
Vite: Cloudflare Pages support (#8531)
To get started with Cloudflare, you can use the [unstable-vite-cloudflare
][template-vite-cloudflare] template:
shellscript nonumber
npx create-remix@latest --template remix-run/remix/templates/unstable-vite-cloudflare
Or read the new docs at Future > Vite > Cloudflare and
Future > Vite > Migrating > Migrating Cloudflare Functions.
Unwrap thrown Response
's from entry.server
into ErrorResponse
's and preserve the status code (#8577)
2.5.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.5.1.
2.5.0
Minor Changes
- Updated
cookie
dependency to 0.6.0
to inherit support for the Partitioned
attribute (#8375)
Add unstable support for "SPA Mode" (#8457)
You can opt into SPA Mode by setting unstable_ssr: false
in your Remix Vite plugin config:
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [remix({ unstable_ssr: false })],
});
Development in SPA Mode is just like a normal Remix app, and still uses the Remix dev server for HMR/HDR:
remix vite:dev
Building in SPA Mode will generate an index.html
file in your client assets directory:
remix vite:build
To run your SPA, you serve your client assets directory via an HTTP server:
npx http-server build/client
For more information, please refer to the SPA Mode docs.
2.4.1
Patch Changes
- Add optional
error
to ServerRuntimeMetaArgs
type to align with MetaArgs
(#8238)
2.4.0
Minor Changes
Add support for clientLoader
/clientAction
/HydrateFallback
route exports (RFC). (#8173)
Remix now supports loaders/actions that run on the client (in addition to, or instead of the loader/action that runs on the server). While we still recommend server loaders/actions for the majority of your data needs in a Remix app - these provide some levers you can pull for more advanced use-cases such as:
- Leveraging a data source local to the browser (i.e.,
localStorage
)
- Managing a client-side cache of server data (like
IndexedDB
)
- Bypassing the Remix server in a BFF setup and hitting your API directly from the browser
- Migrating a React Router SPA to a Remix application
By default, clientLoader
will not run on hydration, and will only run on subsequent client side navigations.
If you wish to run your client loader on hydration, you can set clientLoader.hydrate=true
to force Remix to execute it on initial page load. Keep in mind that Remix will still SSR your route component so you should ensure that there is no new required data being added by your clientLoader
.
If your clientLoader
needs to run on hydration and adds data you require to render the route component, you can export a HydrateFallback
component that will render during SSR, and then your route component will not render until the clientLoader
has executed on hydration.
clientAction
is simpler than clientLoader
because it has no hydration use-cases. clientAction
will only run on client-side navigations.
For more information, please refer to the clientLoader
and clientAction
documentation.
Deprecate DataFunctionArgs
in favor of LoaderFunctionArgs
/ActionFunctionArgs
. This is aimed at keeping the types aligned across server/client loaders/actions now that clientLoader
/clientActon
functions have serverLoader
/serverAction
parameters which differentiate ClientLoaderFunctionArgs
/ClientActionFunctionArgs
. (#8173)
Add a new future.v3_relativeSplatPath
flag to implement a breaking bug fix to relative routing when inside a splat route. For more information, please see the React Router 6.21.0
Release Notes and the useResolvedPath
docs. (#8216)
Patch Changes
- Fix flash of unstyled content for non-Express custom servers in Vite dev (#8076)
- Pass request handler errors to
vite.ssrFixStacktrace
in Vite dev to ensure stack traces correctly map to the original source code (#8066)
2.3.1
No significant changes to this package were made in this release. See the repo CHANGELOG.md
for an overview of all changes in v2.3.1.
2.3.0
Minor Changes
- Updated
cookie
dependency from 0.4.1
to 0.5.0
to inherit support for Priority
attribute in Chrome (#6770)
2.2.0
Minor Changes
- Unstable Vite support for Node-based Remix apps (#7590)
remix build
👉 vite build && vite build --ssr
remix dev
👉 vite dev
- Other runtimes (e.g. Deno, Cloudflare) not yet supported.
- See "Future > Vite" in the Remix Docs for details
2.1.0
Patch Changes
- Emulate types for
JSON.parse(JSON.stringify(x))
in SerializeFrom
(#7605)
- Notably, type fields that are only assignable to
undefined
after serialization are now omitted since JSON.stringify |> JSON.parse
will omit them -- see test cases for examples
- Also fixes type errors when upgrading to v2 from 1.19
2.0.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v2.0.1.
2.0.0
Major Changes
- Require Node >=18.0.0 (#6939)
- The route
meta
API now defaults to the new "V2 Meta" API (#6958)
- Promote the
future.v2_dev
flag in remix.config.js
to a root level dev
config (#7002)
- Remove
v2_errorBoundary
flag and CatchBoundary
implementation (#6906)
- Remove
v2_normalizeFormMethod
future flag - all formMethod
values will be normalized in v2 (#6875)
- Remove
v2_routeConvention
flag - the flat route file convention is now standard (#6969)
- Remove
v2_headers
flag - it is now the default behavior to use the deepest headers
function in the route tree (#6979)
- Remove
imagesizes
& imagesrcset
properties from HtmlLinkDescriptor
, LinkDescriptor
& PrefetchPageDescriptor
types (#6936)
- Removed/adjusted types to prefer
unknown
over any
and to align with underlying React Router types (#7319, #7354):
- Renamed the
useMatches()
return type from RouteMatch
to UIMatch
- Renamed
LoaderArgs
/ActionArgs
to LoaderFunctionArgs
/ActionFunctionArgs
AppData
changed from any
to unknown
Location["state"]
(useLocation.state
) changed from any
to unknown
UIMatch["data"]
(useMatches()[i].data
) changed from any
to unknown
UIMatch["handle"]
(useMatches()[i].handle
) changed from { [k: string]: any }
to unknown
Fetcher["data"]
(useFetcher().data
) changed from any
to unknown
MetaMatch.handle
(used in meta()
) changed from any
to unknown
AppData
/RouteHandle
are no longer exported as they are just aliases for unknown
- Remove deprecated
REMIX_DEV_HTTP_ORIGIN
env var - use REMIX_DEV_ORIGIN
instead (#6963)
Removed support for "magic exports" from the remix
package. This package can be removed from your package.json
and you should update all imports to use the source @remix-run/*
packages: (#6895)
- import type { ActionArgs } from "remix";
- import { json, useLoaderData } from "remix";
+ import type { ActionArgs } from "@remix-run/node";
+ import { json } from "@remix-run/node";
+ import { useLoaderData } from "@remix-run/react";
Minor Changes
- Update Remix to use React Router
route.lazy
for module loading (#7133)
- Detect built mode via
build.mode
(#6964)
- Prevents mode mismatch between built Remix server entry and user-land server
- Additionally, all runtimes (including non-Node runtimes) can use
build.mode
to determine if HMR should be performed.
- Re-export the new
redirectDocument
method from React Router (#7040, #6842) (#7040)
Patch Changes
- Export proper
ErrorResponse
type for usage alongside isRouteErrorResponse
(#7244)
- Fix
destroySession
for sessions using a maxAge
cookie (#7252)
- The data in the cookie was always properly destroyed but when using
maxAge
, the cookie itself wasn't deleted because Max-Age
takes precedence over Expires
in the cookie spec
- Ensure
maxAge
/expires
options passed to commitSession
take precedence over the original cookie.expires
value (#6598, #7374)
- Fix
handleError
method to correctly receive ErrorResponse
instances on ?_data
and resource route requests (#7211)
- It now receives the
ErrorResponse
instance the same way a document request would
- Users can leverage
isRouteErrorResponse
to detect these error instances and log accordingly
- Update
createMemorySessionStorage
to use an internal hash value instead of an integer for the session id
(#7227)
- Fix false-positive resource route classification on document requests for routes that only export an
ErrorBoundary
(#7155)
- Correctly infer deferred types for top-level promises (#7104)
- Construct
Request
with duplex
option (#7234)
- Updated dependencies:
1.19.3
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.19.3.
1.19.2
Patch Changes
- Update to latest
@remix-run/web-*
packages (#7026)
1.19.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.19.1.
1.19.0
Minor Changes
Patch Changes
- Properly handle
?_data
HTTP/Network errors that don't reach the Remix server and ensure they bubble to the ErrorBoundary
(#6783)
- Support proper hydration of
Error
subclasses such as ReferenceError
/TypeError
in development mode (#6675)
- Properly return a 404 for a
?_data
request that doesn't match routes (#6820)
- Bump RR 6.14.2 (#6854)
- Updated dependencies:
1.18.1
Patch Changes
- Fix reload loops in scenarios where CDNs ignore search params (#6707)
- Avoid circular references and infinite recursion in types (#6736)
- "Pretty" or simplified Typescript types are evaluated by eagerly resolving types. For complex types with circular references, this can cause TS to recurse infinitely.
- To fix this, pretty types are reverted as a built-in DX feature of
useLoaderData
, useActionData
, etc...
- Updated dependencies:
1.18.0
Minor Changes
- stabilize v2 dev server (#6615)
Patch Changes
- Fix typing issues when using React 17 stemming from
@remix/server-runtime
including @types/react
as a devDependency
when it doesn't actually do anything React-specific and was just re-exporting ComponentType
in values such as CatchBoundaryComponent
/ErrorBoundaryComponent
/V2_ErrorBoundaryComponent
. These types are more correctly exported from @remix-run/react
which is React-aware so that is the correct place to be importing those types from. In order to avoid breaking existing builds, the types in @remix/server-runtime
have been loosened to any
and @deprecated
warnings have been added informing users to switch to the corresponding types in @remix-run/react
. (#5713)
- fix(types): better tuple serialization types (#6616)
- Move
@types/cookie
to dependencies
since we re-export types from there (#5713)
1.17.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.17.1.
1.17.0
Minor Changes
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. (#6425, #6475)
Add optional handleError
export for custom server-side error processing. This is a new optional export from your entry.server.tsx
that will be called with any encountered error on the Remix server (loader, action, or render error) (#6495, #6524):
export function handleError(
error: unknown,
{ request, params, context }: DataFunctionArgs
): void {
if (error instanceof Error) {
sendErrorToBugReportingService(error);
console.error(formatError(error));
} else {
const unknownError = new Error("Unknown Server Error");
sendErrorToBugReportingService(unknownError);
console.error(unknownError);
}
}
Force Typescript to simplify type produced by Serialize
. (#6449)
As a result, the following types and functions have simplified return types:
- SerializeFrom
- useLoaderData
- useActionData
- useFetcher
type Data = { hello: string; when: Date };
type Unsimplified = SerializeFrom<Data>;
type Simplified = SerializeFrom<Data>;
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. (#6431)
Reuse dev server port for WebSocket (Live Reload,HMR,HDR) (#6476)
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).
Patch Changes
Properly handle thrown ErrorResponse
instances inside resource routes (#6320)
Add HeadersArgs
type to be consistent with loaders/actions/meta and allows for using a function
declaration in addition to an arrow function expression (#6247)
import type { HeadersArgs } from "@remix-run/node";
export function headers({ loaderHeaders }: HeadersArgs) {
return {
"x-my-custom-thing": loaderHeaders.get("x-my-custom-thing") || "fallback",
};
}
Ensure un-sanitized server errors are logged on the server during document requests (#6495)
Updated dependencies:
1.16.1
Patch Changes
- Expose methods in the
SessionStorage
interface as arrow functions so destructuring is correctly part of the contract. (#6330)
- Fix
data
parameter typing on V2_MetaFunction
to include undefined
for scenarios in which the loader
threw to it's own boundary. (#6231)
- Updated dependencies:
1.16.0
Minor Changes
Enable support for CSS Modules, Vanilla Extract and CSS side-effect imports (#6046)
These CSS bundling features were previously only available via future.unstable_cssModules
, future.unstable_vanillaExtract
and future.unstable_cssSideEffectImports
options in remix.config.js
, but they have now been stabilized.
In order to use these features, check out our guide to CSS bundling in your project.
Stabilize built-in PostCSS support via the new postcss
option in remix.config.js
. As a result, the future.unstable_postcss
option has also been deprecated. (#5960)
The postcss
option is false
by default, but when set to true
will enable processing of all CSS files using PostCSS if postcss.config.js
is present.
If you followed the original PostCSS setup guide for Remix, you may have a folder structure that looks like this, separating your source files from its processed output:
.
├── app
│ └── styles (processed files)
│ ├── app.css
│ └── routes
│ └── index.css
└── styles (source files)
├── app.css
└── routes
└── index.css
After you've enabled the new postcss
option, you can delete the processed files from app/styles
folder and move your source files from styles
to app/styles
:
.
├── app
│ └── styles (source files)
│ ├── app.css
│ └── routes
│ └── index.css
You should then remove app/styles
from your .gitignore
file since it now contains source files rather than processed output.
You can then update your package.json
scripts to remove any usage of postcss
since Remix handles this automatically. For example, if you had followed the original setup guide:
{
"scripts": {
- "dev:css": "postcss styles --base styles --dir app/styles -w",
- "build:css": "postcss styles --base styles --dir app/styles --env production",
- "dev": "concurrently \"npm run dev:css\" \"remix dev\""
+ "dev": "remix dev"
}
}
Stabilize built-in Tailwind support via the new tailwind
option in remix.config.js
. As a result, the future.unstable_tailwind
option has also been deprecated. (#5960)
The tailwind
option is false
by default, but when set to true
will enable built-in support for Tailwind functions and directives in your CSS files if tailwindcss
is installed.
If you followed the original Tailwind setup guide for Remix and want to make use of this feature, you should first delete the generated app/tailwind.css
.
Then, if you have a styles/tailwind.css
file, you should move it to app/tailwind.css
.
rm app/tailwind.css
mv styles/tailwind.css app/tailwind.css
Otherwise, if you don't already have an app/tailwind.css
file, you should create one with the following contents:
@tailwind base;
@tailwind components;
@tailwind utilities;
You should then remove /app/tailwind.css
from your .gitignore
file since it now contains source code rather than processed output.
You can then update your package.json
scripts to remove any usage of tailwindcss
since Remix handles this automatically. For example, if you had followed the original setup guide:
{
"scripts": {
- "build": "run-s \"build:*\"",
+ "build": "remix build",
- "build:css": "npm run generate:css -- --minify",
- "build:remix": "remix build",
- "dev": "run-p \"dev:*\"",
+ "dev": "remix dev",
- "dev:css": "npm run generate:css -- --watch",
- "dev:remix": "remix dev",
- "generate:css": "npx tailwindcss -o ./app/tailwind.css",
"start": "remix-serve build"
}
}
The Remix dev server spins up your app server as a managed subprocess. (#6133)
This keeps your development environment as close to production as possible.
It also means that the Remix dev server is compatible with any app server.
By default, the dev server will use the Remix App Server, but you opt to use your own app server by specifying the command to run it via the -c
/--command
flag:
remix dev
remix dev -c "node ./server.js"
The dev server will:
- force
NODE_ENV=development
and warn you if it was previously set to something else
- rebuild your app whenever your Remix app code changes
- restart your app server whenever rebuilds succeed
- handle live reload and HMR + Hot Data Revalidation
App server coordination
In order to manage your app server, the dev server needs to be told what server build is currently being used by your app server.
This works by having the app server send a "I'm ready!" message with the Remix server build hash as the payload.
This is handled automatically in Remix App Server and is set up for you via calls to broadcastDevReady
or logDevReady
in the official Remix templates.
If you are not using Remix App Server and your server doesn't call broadcastDevReady
, you'll need to call it in your app server after it is up and running.
For example, in an Express server:
import { broadcastDevReady } from "@remix-run/node";
const BUILD_DIR = path.join(process.cwd(), "build");
app.listen(3000, () => {
const build = require(BUILD_DIR);
console.log("Ready: http://localhost:" + port);
if (process.env.NODE_ENV === "development") {
broadcastDevReady(build);
}
});
Options
Options priority order is: 1. flags, 2. config, 3. defaults.
| Option | flag | config | default |
| -------------- | ------------------ | ---------------- | --------------------------------- |
| Command | -c
/ --command
| command
| remix-serve <server build path>
|
| HTTP(S) scheme | --http-scheme
| httpScheme
| http
|
| HTTP(S) host | --http-host
| httpHost
| localhost
|
| HTTP(S) port | --http-port
| httpPort
| Dynamically chosen open port |
| Websocket port | --websocket-port
| websocketPort
| Dynamically chosen open port |
| No restart | --no-restart
| restart: false
| restart: true
|
🚨 The --http-*
flags are only used for internal dev server <-> app server communication.
Your app will run on your app server's normal URL.
To set unstable_dev
configuration, replace unstable_dev: true
with unstable_dev: { <options> }
.
For example, to set the HTTP(S) port statically:
module.exports = {
future: {
unstable_dev: {
httpPort: 8001,
},
},
};
SSL and custom hosts
You should only need to use the --http-*
flags and --websocket-port
flag if you need fine-grain control of what scheme/host/port for the dev server.
If you are setting up SSL or Docker networking, these are the flags you'll want to use.
🚨 Remix will not set up SSL and custom host for you.
The --http-scheme
and --http-host
flag are for you to tell Remix how you've set things up.
It is your task to set up SSL certificates and host files if you want those features.
--no-restart
and require
cache purging
If you want to manage server changes yourself, you can use the --no-restart
flag to tell the dev server to refrain from restarting your app server when builds succeed:
remix dev -c "node ./server.js" --no-restart
For example, you could purge the require
cache of your app server to keep it running while picking up server changes.
If you do so, you should watch the server build path (build/
by default) for changes and only purge the require
cache when changes are detected.
🚨 If you use --no-restart
, it is your responsibility to call broadcastDevReady
when your app server has picked up server changes.
For example, with chokidar
:
const BUILD_PATH = path.resolve(__dirname, "build");
const watcher = chokidar.watch(BUILD_PATH);
watcher.on("change", () => {
purgeRequireCache();
const build = require(BUILD_PATH);
broadcastDevReady(build);
});
Patch Changes
- add
logDevReady
as replacement for platforms that can't initialize async I/O outside of the request response lifecycle. (#6204)
- better type discrimination when unwrapping loader return types (#5516)
- pass
AppLoadContext
to handleRequest
(#5836)
- Updated dependencies:
1.15.0
Minor Changes
We have made a few changes to the API for route module meta
functions when using the future.v2_meta
flag. These changes are only breaking for users who have opted in. (#5746)
V2_HtmlMetaDescriptor
has been renamed to V2_MetaDescriptor
- The
meta
function's arguments have been simplified
parentsData
has been removed, as each route's loader data is available on the data
property of its respective match
object
export function meta({ parentsData }) {
return [{ title: parentsData["routes/some-route"].title }];
}
export function meta({ matches }) {
return [
{
title: matches.find((match) => match.id === "routes/some-route")
.data.title,
},
];
}
- The
route
property on route matches has been removed, as relevant match data is attached directly to the match object
export function meta({ matches }) {
const rootModule = matches.find((match) => match.route.id === "root");
}
export function meta({ matches }) {
const rootModule = matches.find((match) => match.id === "root");
}
- Added support for generating
<script type='application/ld+json' />
and meta-related <link />
tags to document head via the route meta
function when using the v2_meta
future flag
Added a new future.v2_normalizeFormMethod
flag to normalize the exposed useNavigation().formMethod
as an uppercase HTTP method to align with the previous useTransition
behavior as well as the fetch()
behavior of normalizing to uppercase HTTP methods. (#5815)
- When
future.v2_normalizeFormMethod === false
,
useNavigation().formMethod
is lowercase
useFetcher().formMethod
is uppercase
- When
future.v2_normalizeFormMethod === true
:
useNavigation().formMethod
is uppercase
useFetcher().formMethod
is uppercase
Added deprecation warning for CatchBoundary
in favor of future.v2_errorBoundary
(#5718)
Added experimental support for Vanilla Extract caching, which can be enabled by setting future.unstable_vanillaExtract: { cache: true }
in remix.config
. This is considered experimental due to the use of a brand new Vanilla Extract compiler under the hood. In order to use this feature, you must be using at least v1.10.0
of @vanilla-extract/css
. (#5735)
Patch Changes
- Bumped React Router dependencies to the latest version. See the release notes for more details. (
e14699547
)
- Added type deprecations for types now in React Router (#5679)
- Stopped logging server errors for aborted requests (#5602)
- We now ensure that stack traces are removed from all server side errors in production (#5541)
1.14.3
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.14.3.
1.14.2
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.14.2.
1.14.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.14.1.
1.14.0
Minor Changes
- Hot Module Replacement and Hot Data Revalidation (#5259)
- Requires
unstable_dev
future flag to be enabled
- HMR provided through React Refresh
- Features:
- HMR for component and style changes
- HDR when loaders for current route change
- Known limitations for MVP:
- Only implemented for React via React Refresh
- No
import.meta.hot
API exposed yet
- Revalidates all loaders on route when loader changes are detected
- Loader changes do not account for imported dependencies changing
Patch Changes
- Sync
FutureConfig
interface between packages (#5398)
- Updated dependencies:
1.13.0
Minor Changes
- Add built-in support for PostCSS via the
future.unstable_postcss
feature flag (#5229)
- Add built-in support for Tailwind via the
future.unstable_tailwind
feature flag (#5229)
Patch Changes
1.12.0
Minor Changes
- Added a new development server available in the Remix config under the
unstable_dev
flag. See the release notes for a full description. (#5133)
- Removed
react
& react-dom
from peerDependencies
(#4801)
Patch Changes
1.11.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.11.1.
1.11.0
Minor Changes
- Added support for Vanilla Extract via the
unstable_vanillaExtract
future flag. IMPORTANT: Features marked with unstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#5040)
- Add support for CSS side-effect imports via the
unstable_cssSideEffectImports
future flag. IMPORTANT: Features marked with unstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4919)
- Add support for CSS Modules via the
unstable_cssModules
future flag. IMPORTANT: Features marked with unstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4852)
Patch Changes
Added the v2_errorBoundary
future flag to opt into the next version of Remix's ErrorBoundary
behavior. This removes the separate CatchBoundary
and ErrorBoundary
and consolidates them into a single ErrorBoundary
, following the logic used by errorElement
in React Router. You can then use isRouteErrorResponse
to differentiate between thrown Response
/Error
instances. (#4918)
import { useCatch } from "@remix-run/react";
export function CatchBoundary() {
const caught = useCatch();
return (
<p>
{caught.status} {caught.data}
</p>
);
}
export function ErrorBoundary({ error }) {
return <p>{error.message}</p>;
}
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
export function ErrorBoundary() {
const error = useRouteError();
return isRouteErrorResponse(error) ? (
<p>
{error.status} {error.data}
</p>
) : (
<p>{error.message}</p>
);
}
Introduces the defer()
API from @remix-run/router
with support for server-rendering and HTTP streaming. This utility allows you to defer values returned from loader
functions by returning promises instead of resolved values. This has been refered to as "sending a promise over the wire". (#4920)
Informational Resources:
Documentation Resources (better docs specific to Remix are in the works):
1.10.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.10.1.
1.10.0
Minor Changes
- Update Remix to use new data APIs introduced in React Router v6.4 (#4900)
Patch Changes
- Export
V2_HtmlMetaDescriptor
and V2_MetaFunction
types from runtime packages (#4943)
- Fix
V2_MetaFunction
to return V2_HtmlMetaDescriptor[]
type (#4947)
1.9.0
Patch Changes
- Fix
TypedResponse
so that Typescript correctly shows errors for incompatible types in loader
and action
functions. (#4734)
- Fix error boundary tracking for multiple errors bubbling to the same boundary (#4829)
- Fixed an issue where a loader's
Request
object reflected method: "POST"
on document submissions (a74e51830
)
1.8.2
Patch Changes
- Remove
instanceof Response
checks in favor of isResponse
(#4782)
- Fix performance regression with creation of
@remix-run/router
static handler (#4790)
- Update dependency for
@remix-run/router
to v1.0.5
(bd84a9317
)
1.8.1
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.8.1.
1.8.0
Minor Changes
- We have been busy at work Layering Remix on top of React Router 6.4 and are excited to be releasing step 1 in this process that consists of performing all server-side data fetches/mutations through the new framework agnostic
@remix-run/router
. Server- and client-side rendering are still done the same as before, and will be updated in subsequent releases. (#4612)
- Importing functions and types from the
remix
package is deprecated, and all (#3284)
exported modules will be removed in the next major release. For more details,
see the release notes for 1.4.0
where these changes were first announced.
- Added support for a new route
meta
API to handle arrays of tags instead of an object. For details, check out the RFC. (#4610)
Patch Changes
Properly categorize internal framework-thrown error Responses as error boundary errors (#4385)
Previously there was some ambiguity around "thrown Responses go to the CatchBoundary
".
The CatchBoundary
exists to give the user a place to handle non-happy path code flows
such that they can throw Response
instances from their own code and handle them in a
CatchBoundary
. However, there are a handful of framework-internal errors that make
sense to have a non-500 status code, and the fact that these were being thrown as Response
instances
was causing them to go into the CatchBoundary
, even though they were not user-thrown.
With this change, anything thrown by the framework itself (Error
or Response
) will
go to the ErrorBoundary
, and any user-thrown Response
instances will go to the
CatchBoundary
. There is one exception to this rule, which is that framework-detected
404's will continue to go to the CatchBoundary
since users should have one single
location to handle 404 displays.
The primary affected use cases are scenarios such as:
- HTTP
OPTIONS
requests (405 Unsupported Method )
GET
requests to routes without loaders (400 Bad Request)
POST
requests to routes without actions (405 Method Not Allowed)
- Missing route id in
_data
parameters (403 Forbidden)
- Non-matching route id included in
_data
parameters (403 Forbidden)
1.7.6
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.7.6.
1.7.5
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.7.5.
1.7.4
Patch Changes
- Ignore pathless layout routes in action matches (#4376)
1.7.3
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.7.3.
1.7.2
Patch Changes
- Fix dependency conflicts with
type-fest
(87642b71b
)
1.7.1
Patch Changes
- Properly locked the dependency on
react-router-dom
to version 6.3.0 (#4203)
1.7.0
Minor Changes
- We've added a new type:
SerializeFrom
. This is used to infer the (#4013)
JSON-serialized return type of loaders and actions.
MetaFunction
type can now infer data
and parentsData
types from route loaders (#4022)
Patch Changes
- Improved performance for data serialization at runtime (#3889)
1.6.8
Patch Changes
We've added type safety for load context. AppLoadContext
is now an an interface mapping string
to unknown
, allowing users to extend it via module augmentation: (#1876)
declare module "@remix-run/server-runtime" {
interface AppLoadContext {
}
}
1.6.7
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.6.7.
1.6.6
No significant changes to this package were made in this release. See the releases page on GitHub for an overview of all changes in v1.6.6.
1.6.5
Patch Changes
We enhanced the type signatures of loader
/action
and
useLoaderData
/useActionData
to make it possible to infer the data type
from return type of its related server function.
To enable this feature, you will need to use the LoaderArgs
type from your
Remix runtime package instead of typing the function directly:
- import type { LoaderFunction } from "@remix-run/[runtime]";
+ import type { LoaderArgs } from "@remix-run/[runtime]";
- export const loader: LoaderFunction = async (args) => {
- return json<LoaderData>(data);
- }
+ export async function loader(args: LoaderArgs) {
+ return json(data);
+ }
Then you can infer the loader data by using typeof loader
as the type
variable in useLoaderData
:
- let data = useLoaderData() as LoaderData;
+ let data = useLoaderData<typeof loader>();
The API above is exactly the same for your route action
and useActionData
via the ActionArgs
type.
With this change you no longer need to manually define a LoaderData
type
(huge time and typo saver!), and we serialize all values so that
useLoaderData
can't return types that are impossible over the network, such
as Date
objects or functions.
See the discussions in #1254
and #3276 for more context.