Releases: remix-run/remix
v2.0.0
Remix v2
We're so excited to release Remix v2 to you and we really hope this upgrade is one of the smoothest framework upgrades you've ever experienced! That was our primary goal with v2 - something we aimed to achieve through a heavy use of deprecation warnings and Future Flags in Remix v1.
If you are on the latest 1.x
version and you've enabled all future flags and addressed all console warnings, then our hope is that you are 90% of the way to being upgraded for v2. There are always going to be a few things that we can't put behind a flag (like breaking type changes) or come up at the very last moment and don't have time to add as a warning or flag in 1.x
.
If you're not yet on the latest 1.x version we'd recommend first upgrading to that and resolving any flag/console warnings:
> npx upgrade-remix 1.19.3
Breaking Changes
Below is a very concise list of the breaking changes in v2.
- For the most thorough discussion of breaking changes, please read the Upgrading to v2 guide. This document provides a comprehensive walkthrough of the breaking changes that come along with v2 - and instructions on how to adapt your application to handle them
- For additional details, you can refer to the Changes by Package section below
Upgraded Dependency Requirements
Remix v2 has upgraded it's minimum version support for React and Node and now officially requires:
- React 18 (#7121)
- For information on upgrading to React 18, please see the React upgrade guide
- Node 18 or later (#6939, #7292)
- For information on upgrading to Node 18, please see the Node v18 announcement
- Please refer to the Remix documentation for an overview of when we drop support for Node versions
Removed Future Flags
The following future flags were removed and their behavior is now the default - you can remove all of these from your remix.config.js
file.
v2_dev
- New dev server with HMR+HDR (#7002)- If you had configurations in
future.v2_dev
instead of just the boolean value (i.e.,future.v2_dev.port
), you can lift them into a rootdev
object in yourremix.config.js
- If you had configurations in
v2_errorBoundary
- RemovedCatchBoundary
in favor of a singularErrorBoundary
(#6906)v2_headers
- Altered the logic forheaders
in nested route scenarios (#6979)v2_meta
- Altered the return format ofmeta()
(#6958)v2_normalizeFormMethod
- NormalizeformMethod
APIs to uppercase (#6875)v2_routeConvention
- Routes use a flat route convention by default now (#6969)
Breaking Changes/API Removals
With deprecation warnings
The following lists other breaking changes/API removals which had deprecation warnings in Remix v1. If you're on the latest 1.19.3
release without any console warnings, then you're probably good to go on all of these!
remix.config.js
- Renamed
browserBuildDirectory
toassetsBuildDirectory
(#6900) - Removed
devServerBroadcastDelay
(#7063) - Renamed
devServerPort
todev.port
(000457e0
)- Note that if you are opting into this in a
1.x
release, your config flag will befuture.v2_dev.port
, but on a stable2.x
release it will bedev.port
- Note that if you are opting into this in a
- Changed the default
serverModuleFormat
fromcjs
toesm
(#6949) - Removed
serverBuildTarget
(#6896) - Changed
serverBuildDirectory
toserverBuildPath
(#6897) - Node built-ins are no longer polyfilled on the server by default, you must opt-into polyfills via
serverNodeBuiltinsPolyfill
(#6911
- Renamed
@remix-run/react
- Removed
useTransition
(#6870) - Removed
fetcher.type
and flattenedfetcher.submission
(#6874)<fetcher.Form method="get">
is now more accurately categorized asstate:"loading"
instead ofstate:"submitting"
to better align with the underlying GET request
- Require camelCased versions of
imagesrcset
/imagesizes
(#6936)
- Removed
Without deprecation warnings
Unfortunately, we didn't manage to get a deprecation warning on every breaking change or API removal 🙃. Here's a list of remaining changes that you may need to look into to upgrade to v2:
remix.config.js
- Node built-ins are no longer polyfilled in the browser by default, you must opt-into polyfills via
browserNodeBuiltinsPolyfill
(#7269) - PostCSS/Tailwind will be enabled by default if config files exist in your app, you may disable this via the
postcss
andtailwind
flags (#6909)
- Node built-ins are no longer polyfilled in the browser by default, you must opt-into polyfills via
@remix-run/cloudflare
@remix-run/dev
- Removed
REMIX_DEV_HTTP_ORIGIN
in favor ofREMIX_DEV_ORIGIN
(#6963) - Removed
REMIX_DEV_SERVER_WS_PORT
in favor ofdev.port
or--port
(#6965) - Removed
--no-restart
/restart
flag in favor of--manual
/manual
(#6962) - Removed
--scheme
/scheme
and--host
/host
in favor ofREMIX_DEV_ORIGIN
instead (#6962) - Removed the
codemod
command (#6918)
- Removed
@remix-run/eslint-config
@remix-run/netlify
- The
@remix-run/netlify
adapter has been removed in favor of the Netlify official adapters (#7058)
- The
@remix-run/node
fetch
is no longer polyfilled by default - apps must callinstallGlobals()
to install the polyfills (#7009)fetch
and related APIs are no longer exported from@remix-run/node
- apps should use the versions in the global namespace (#7293)- Apps must call
sourceMapSupport.install()
to setup source map support
@remix-run/react
- Remove
unstable_shouldReload
in favor ofshouldRevalidate
(#6865)
- Remove
@remix-run/serve
@remix-run/vercel
- The
@remix-run/vercel
adapter has been removed in favor of out of the box functionality provided by Vercel (#7035)
- The
create-remix
- Stop passing
isTypeScript
toremix.init
script (#7099)
- Stop passing
remix
- Removed magic exports ([#6895](https://github.com/re...
v1.19.3
Patch Changes
- Show deprecation warning when using
devServerBroadcastDelay
anddevServerPort
config options (#7064)
Changes by Package 🔗
Full Changelog: 1.19.2...1.19.3
v1.19.2
Patch Changes
- Show deprecation warning on
@remix-run/netlify
usage, which is deprecated in favor of@netlify/remix-adapter
(#6937) - Update to latest
@remix-run/web-*
packages (#7026) - Install
source-map-support
in@remix-run/serve
(#7039) - Update
proxy-agent
to resolve npm audit security vulnerability (#7027)
Changes by Package 🔗
Full Changelog: 1.19.1...1.19.2
v1.19.1
Patch Changes
- Add a heartbeat ping to prevent the WebSocket connection from being closed due to inactivity when using a proxy like Cloudflare (#6904, #6927)
- Treeshake out HMR code from production builds (#6894)
Changes by Package 🔗
Full Changelog: 1.19.0...1.19.1
v1.19.0
New Features
Improved Networking Options
When using the new v2_dev
server, the --scheme
and --host
options have been deprecated and replaced with the REMIX_DEV_ORIGIN
environment variable. For more information, refer to the v2 dev server docs (#6724)
ESBuild metafiles
For bundle analysis, the esbuild
metafiles are now written to your server build directory (build/
by default) and can be uploaded to https://esbuild.github.io/analyze/ for analysis (#6772):
metafile.css.json
metafile.js.json
(browser JS)metafile.server.json
(server JS)
New serverNodeBuiltinsPolyfill
Config Option
When building for non-Node.js server platforms, you can now control which polyfills are included (or disbale them entirely) by setting serverNodeBuiltinsPolyfill
in remix.config.js
(#6814, #6859, #6877).
// Disable all polyfills
exports.serverNodeBuiltinsPolyfill = { modules: {} };
// Enable specific polyfills
exports.serverNodeBuiltinsPolyfill = {
modules: {
crypto: true, // Provide a JSPM polyfill
fs: "empty", // Provide an empty polyfill
},
};
serverNodeBuiltinsPolyfill
. In v2, Remix will no longer include polyfills by default. You can prepare for your eventual migration by explicitly setting this config value in your v1 app.
Other Notable Changes
- Exclude unimplemented polyfills from server build for non-Node.js server platforms (#6814)
- Ignore missing
react-dom/client
for react 17 (#6725) - Warn if not using
v2_dev
(#6818)- Rename
--no-restart
to--manual
to match intention and documentation --no-restart
remains an alias for--manual
in v1 for backwards compatibility
- Rename
- Ignore errors when killing already dead processes (#6773)
- Fix sourcemaps for
v2_dev
(#6762) - Do not clear screen when dev server starts (#6719)
- On some terminal emulators, "clearing" only scrolls the next line to the top, while on others it erases the scrollback
- Instead, let users call
clear
themselves (clear && remix dev
) if they want to clear
- Always rewrite css-derived assets during builds (#6837)
- Fix router race condition for HMR (#6767)
- Properly handle
?_data
HTTP/Network errors that don't reach the Remix server and ensure they bubble to theErrorBoundary
(#6783) - Support proper hydration of
Error
subclasses such asReferenceError
/TypeError
in development mode (#6675) - Properly return a 404 for a
?_data
request that doesn't match any routes (#6820) - Narrowed the type of
fetcher.formEncType
to useFormEncType
fromreact-router-dom
instead ofstring
(#6810) - Deferred promises that return
undefined
/void
now surface a serialization error (#6793) - Avoid re-prefetching stylesheets for active routes during a revalidation (#6679)
- Add generic type for
useRouteLoaderData()
(#5157) - Submitted empty file inputs are now correctly parsed out as empty
File
instances instead of being surfaced as an empty string viarequest.formData()
(via@remix-run/[email protected]
) (#6816) - Added some missing
react-router-dom
exports to@remix-run/react
(createPath
,matchPath
, etc.) (#6856) - Updated React Router dependencies:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.18.1...1.19.0
v1.18.1
Patch Changes
- Ignore missing
react-dom/client
for React 17 (#6725) - 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 React Router dependencies:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.18.0...1.18.1
v1.18.0
New Features
Stable V2 Dev Server
Great news! 1.18.0
officially stabilizes the "New Dev Server" complete with HMR/HDR 🎉. If you've previously opted into the unstable_dev
version, you'll need to update your remix.config.js
flag name from future.unstable_dev -> future.v2_dev
in 1.18.0
. If you've not yet opted in, we now consider the new dev server stable (no more API changes) so feel free to upgrade anytime to make your eventual migration to v2 smoother! You can read up on the new dev server in the docs.
JSON/Text Submissions
If you're not a huge fan of FormData
, Remix 1.18.0
updates to [email protected]
which brings along support for opt-in application/json
or text/plain
encoding in useSubmit
/fetcher.submit
, and adds corresponding navigation.json
/navigation.text
and fetcher.json
/fetcher.text
fields containing the respective submissions. For details please check out the React Router release notes or the useSubmit
docs. (#6570)
// Submit to your action using JSON
submit({ key: "value" }, { method: "post", encType: "application/json" });
// available in components via useNavigation().json and actions via request.json()
// Submit to your action using text
submit("plain text", { method: "post", encType: "text/plain" });
// available in components via useNavigation().text and actions via request.text()
Warning
Please be aware thatuseSubmit()
andfetcher.submit()
are not suitable for Progressive Enhancement, so switching to these to leverage JSON or Text submissions will break your app when JS is unable to load/execute. It's recommended to stick with normalFormData
submissions for critical aspects of your application.
Default Behavior
Please also note that to avoid a breaking change, the default behavior will still encode a simple key/value JSON object into a FormData
instance:
submit({ key: "value" }, { method: "post" });
// available in components via useNavigation().formData and actions via request.formData()
}
This behavior will likely change in the future when React Router releases v7, so it's best to make any JSON object submissions explicit with either encType: "application/x-www-form-urlencoded"
or encType: "application/json"
to ease your eventual v7 migration path.
Viewport-driven Prefetching
The Link
component can now automatically prefetch your route data and JS modules when they enter the viewport via the new <Link prefetch="viewport">
prop value. Similar to intent
this will add the relevant <link rel="prefetch">
tags to DOM when the link enters the viewport, and remove them when it exits (via an Intersection Observer). (#6433)
Updated ESLint Configurations
We've updated the @remix-run/eslint-config
to inherit the recommended set of rules from @typescript-eslint/recommended
instead of manually maintaining our own TS-related rules, so you may see some new lint warnings/errors (#6614)
Perf improvements 🏎️
We've invested heavily into performance the last couple weeks and are excited to share those speed gains with all of you 💪.
You could see modest improvement (~10% faster), but we've also personally witnessed build and rebuild times melt in some extreme cases. Here's a sample:
- 2x faster builds and 3x faster rebuilds for the Indie Stack
- 4x speed ups in a small, realistic app
- 10-20x speed ups for apps with hundreds of manually-defined routes 😱
All of these numbers depend on your hardware, OS, and your app so take them with a grain of salt 🧂. That said, none of our optimizations were hardware or OS-specific so here's hoping 🤞 that your DX gets a speed boost!
Pro-tip: if your project uses a large component library like MUI or AntD you could get BIG perf gains if you avoid named imports.
Other notable Changes
- Fix typing issues when using React 17 (#5713)
⚠️ Note that because@remix/server-runtime
doesn't actually do anything with React, the includedCatchBoundaryComponent
/ErrorBoundaryComponent
/V2_ErrorBoundaryComponent
types have been loosened toany
and marked@deprecated
. If you were using these types you should instead import them from the corresponding types in@remix-run/react
.
- Fix bug with pathless layout routes beneath nested path segments (#6649)
- Properly pass
<Scripts />
props (i.e.,nonce
) to inline script tags for deferred data (#6389) - Detect mismatches between the initially loaded URL and the URL at the time of hydration and trigger a hard reload if they don't match (#6409)
- Show deprecation warning when using
@remix-run/vercel
, since Vercel now provides built-in support for Remix apps (#5964) - improved logging for
remix build
andremix dev
(#6596) - fix
remix dev -c
: kill all descendant processes of specified command when restarting (#6663) - Updated React Router dependencies to the latest versions:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.17.1...1.18.0
v1.17.1
Patch Changes
- Replace
esbuild-plugin-polyfill-node
withesbuild-plugins-node-modules-polyfill
(#6562) - Lazily generate CSS bundle when import of
@remix-run/css-bundle
is detected (#6535) - Updated dependencies:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.17.0...1.17.1
v1.17.0
New Features
Suspense Support
Remix 1.17.0 updates to React Router 6.12.0 which wraps internal router state updates in React.startTransition
so you can better handle async/suspenseful components within your Remix app.
Error Reporting
If you want better control over your server-side error logging and the ability to report unhandled errors to an external service, you may now export a handleError
function from your entry.server.tsx
file and take full control over the logging and reporting of server-side errors. (#6495, #6524)
// entry.server.tsx
export function handleError(
error: unknown,
{ request, params, context }: DataFunctionArgs
): void {
if (error instanceof Error) {
sendErrorToBugReportingService(error);
console.error(formatError(error));
} else {
let unknownError = new Error("Unknown Server Error");
sendErrorToBugReportingService(unknownError);
console.error(unknownError);
}
}
future.v2_headers
flag
Previously, Remix relied on each leaf route to export it's own headers
function to generate headers for document requests. This was a bit tedious and easy to forget to include on new routes, and prohibited child routes from inheriting the headers
logic of any ancestor routes. We plan to change this behavior in v2 and have introduced the new behavior behind a future.v2_headers
flag. With this new flag enabled, Remix will now return the headers from the deepest headers
function found in the matched routes, which allows you to better inherit parent route headers
function implementations. If an error boundary is being rendered, the "matched" routes will only contain routes up to and including the error boundary route, but not below. (#6431)
Enhanced Header Management for Errored Document Requests
When rendering a CatchBoundary
(or v2 ErrorBoundary
) due to a thrown Response
from a loader
/action
, the headers
function now has a new errorHeaders
parameter that contains any headers from the thrown Response
. This allows you to include headers from bubbled responses in your document request response. If the throwing route contains the boundary, then errorHeaders
will be the same object as loaderHeaders
/actionHeaders
for that route. (#6425, #6475)
Dev server updates (future.unstable_dev
)
Built-in TLS Support
The new dev server now has built-in TLS support via 2 new CLI options (#6483):
--tls-key
/tlsKey
: TLS key--tls-cert
/tlsCert
: TLS Certificate
If both TLS options are set, scheme
defaults to https
.
Example
Install mkcert and create a local CA:
brew install mkcert
mkcert -install
Then make sure you inform node
about your CA certs:
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
:
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:
remix dev --tls-key=key.pem --tls-cert=cert.pem
or via config:
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
:
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.
Port Management
The new dev server will now reuse the dev server port for the 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).
Other notable changes
- Force Typescript to simplify type produced by
Serialize
(#6449) - Fix warnings when importing CSS files with
future.unstable_dev
enabled (#6506) - Fix Tailwind performance issue when
postcss.config.js
containsplugins: { tailwindcss: {} }
andremix.config.js
contains bothtailwind: true
andpostcss: true
(#6468) - Faster server export removal for routes when
unstable_dev
is enabled (#6455) - Better error message when
remix-serve
is not found (#6477) - Restore color for app server output (#6485)
- Support sibling pathless layout routes (#4421)
- Fix route ranking bug with pathless layout route next to a sibling index route (#4421)
- Fix dev server crashes caused by ungraceful HDR error handling (#6467)
- Add caching to PostCSS for regular stylesheets (#6505)
- Export
HeadersArgs
type (#6247) - Properly handle thrown
ErrorResponse
instances inside resource routes (#6320) - Ensure unsanitized server errors are logged on the server during document requests (#6495)
- Retry HDR revalidations in development mode to aid in 3rd party server race conditions (#6287)
- Fix
request.clone() instanceof Request
returning false (#6512) - Updated React Router dependencies to the latest versions:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.16.1...1.17.0
v1.16.1
Continuing the work to stabilize features for v2, this release brings improvements to unstable_dev
as well as a bunch of bug fixes.
Dev server power-ups 🦾🤖
We've made two huge improvements to 🔥 Hot Data Revalidation 🔥 in 1.16.1! For anyone who needs a refresher on HDR, its like HMR but for your server code. In Remix, that primarily means tracking loader
changes.
In 1.16.0, Remix would trigger HDR even if only UI code had changed. Now in 1.16.1, Remix only triggers HDR when loader
s have changed. (#6278)
Also, in 1.16.1, Remix now detects code changes that affect your loader anywhere in your app code. You can modify the loader
itself, or a function that the loader
calls, or hardcoded data. Remix now only triggers HDR to fetch new data from routes with loader
changes. For example, if you changed your /products/$id
loader, but not your /products
loader, Remix only refetches data for /products/$id
. (#6299)
If you want to dive deeper into how it works and get a mental model for the new dev server with HDR, check out 🎥 Pedro's talk at Remix Conf.
Dev server bug fixes
Thank you to everyone who's tried unstable_dev
❤️ .
You've given us invaluable feedback that let us identify and fix the following bugs:
- CSS-only changes now correctly trigger HMR (#6374)
- Fixed a regression that caused the old dev server to hang on rebuilds (#6295)
- Rebuilds no longer hang indefinitely for
unstable_dev
(#6294, #6295) - Fixed
No loader for {.svg,.png, etc...}
during HDR (#6396) - App server port no longer conflicts during rebuilds (#6289)
- Windows:
-c
/--command
option now has access tonode_modules/.bin
binaries (#6310) - Windows: App server process in no longer orphaned when dev server exits (#6395)
- Windows: Changes in route files are now detected correctly for HMR/HDR (#6293)
Other notable changes
- css: handle css imports in js files with jsx (#6309)
- css: only process
.css.{js,ts}
if@vanilla-extract/css
is installed (#6345) - lint: do not require display name in root route (#5450)
- types: Typesafe destructuring of
SessionStorage
(#6330) - types:
V2_MetaFunction
can beundefined
(#6231) - Remix commands no longer modify
tsconfig
(#6156) - re-export
useMatch
fromreact-router-dom
(#5257) - Updated React Router dependencies to the latest versions:
Changes by Package 🔗
@remix-run/cloudflare
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/node
@remix-run/react
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 1.16.0...1.16.1