Releases: remix-run/remix
v2.2.0
Minor Changes
Vite!
Remix 2.2.0
adds unstable support for Vite for Node-based apps! See our announcement blog post and the Future > Vite page in the Remix docs for more details. (#7590)
You can try it out today with two new (unstable) templates:
# minimal server
npx create-remix@latest --template remix-run/remix/templates/unstable-vite
# custom server (Express example)
npx create-remix@latest --template remix-run/remix/templates/unstable-vite-express
New APIs in @remix-run/dev
unstable_vitePlugin
: The new Remix Vite pluginunstable_createViteServer
: Creates a Vite server in middleware mode for interop with custom serversunstable_loadViteServerBuild
: Allows your custom server to delegate SSR requests to Vite during development
Changed APIs
createRequestHandler
: Now also allows thebuild
argument to be a function that will be used to dynamically load new builds for each request during development
Other Runtimes
- Deno support is untested, but should work through Deno's Node/
npm
interop - CloudFlare support is not yet available
New Fetcher APIs
Per this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors. (#10960)
- You may now specify your own fetcher identifier via
useFetcher({ key: string })
, which allows you to access the same fetcher instance from different components in your application without prop-drilling - Fetcher keys are now exposed on the fetchers returned from
useFetchers
so that they can be looked up bykey
Form
anduseSumbit
now support optionalnavigate
/fetcherKey
props/params to allow kicking off a fetcher submission under the hood with an optionally user-specifiedkey
<Form method="post" navigate={false} fetcherKey="my-key">
submit(data, { method: "post", navigate: false, fetcherKey: "my-key" })
- Invoking a fetcher in this way is ephemeral and stateless
- If you need to access the state of one of these fetchers, you will need to leverage
useFetchers()
oruseFetcher({ key })
to look it up elsewhere
Persistence Future Flag (future.v3_fetcherPersist
)
Per the same RFC as above, we've introduced a new future.v3_fetcherPersist
flag that allows you to opt-into the new fetcher persistence/cleanup behavior. Instead of being immediately cleaned up on unmount, fetchers will persist until they return to an idle
state. This makes pending/optimistic UI much easier in scenarios where the originating fetcher needs to unmount. (#10962)
- This is sort of a long-standing bug fix as the
useFetchers()
API was always supposed to only reflect in-flight fetcher information for pending/optimistic UI -- it was not intended to reflect fetcher data or hang onto fetchers after they returned to anidle
state - Keep an eye out for the following specific behavioral changes when opting into this flag and check your app for compatibility:
- Fetchers that complete while still mounted will no longer appear in
useFetchers()
after completion - they served no purpose in there since you can access the data viauseFetcher().data
- Fetchers that previously unmounted while in-flight will not be immediately aborted and will instead be cleaned up once they return to an
idle
state- They will remain exposed via
useFetchers
while in-flight so you can still access pending/optimistic data after unmount - If a fetcher is no longer mounted when it completes, then it's result will not be post processed - e.g., redirects will not be followed and errors will not bubble up in the UI
- However, if a fetcher was re-mounted elsewhere in the tree using the same
key
, then it's result will be processed, even if the originating fetcher was unmounted
- They will remain exposed via
- Fetchers that complete while still mounted will no longer appear in
Patch Changes
@remix-run/express
: Allow the Express adapter to work behind a proxy when usingapp.enable('trust proxy')
(#7323)- Previously, this used
req.get('host')
to construct the RemixRequest
, but that does not respectX-Forwarded-Host
- This now uses
req.hostname
which will respectX-Forwarded-Host
- Previously, this used
@remix-run/react
: Fix warning that could be inadvertently logged when using route files with nodefault
export (#7745)create-remix
: Support local tarballs with a.tgz
extension which allows direct support forpnpm pack
tarballs (#7649)create-remix
: Default the Remix app version to the version ofcreate-remix
being used (#7670)- This most notably enables easier usage of tags, e.g.
npm create remix@nightly
- This most notably enables easier usage of tags, e.g.
Updated Dependencies
Changes by Package
create-remix
@remix-run/architect
@remix-run/cloudflare
@remix-run/cloudflare-pages
@remix-run/cloudflare-workers
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/express
@remix-run/node
@remix-run/react
@remix-run/serve
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 2.1.0...2.2.0
v2.1.0
Minor Changes
View Transitions 🚀
We're excited to release experimental support for the the View Transitions API in Remix! You can now trigger navigational DOM updates to be wrapped in document.startViewTransition
to enable CSS animated transitions on SPA navigations in your application. (#10916)
The simplest approach to enabling a View Transition in your Remix app is via the new <Link unstable_viewTransition>
prop. This will cause the navigation DOM update to be wrapped in document.startViewTransition
which will enable transitions for the DOM update. Without any additional CSS styles, you'll get a basic cross-fade animation for your page.
If you need to apply more fine-grained styles for your animations, you can leverage the unstable_useViewTransitionState
hook which will tell you when a transition is in progress and you can use that to apply classes or styles:
function ImageLink(to, src, alt) {
const isTransitioning = unstable_useViewTransitionState(to);
return (
<Link to={to} unstable_viewTransition>
<img
src={src}
alt={alt}
style={{
viewTransitionName: isTransitioning ? "image-expand" : "",
}}
/>
</Link>
);
}
You can also use the <NavLink unstable_viewTransition>
shorthand which will manage the hook usage for you and automatically add a transitioning
class to the <a>
during the transition:
a.transitioning img {
view-transition-name: "image-expand";
}
<NavLink to={to} unstable_viewTransition>
<img src={src} alt={alt} />
</NavLink>
For an example usage of View Transitions, check out our fork of the Astro Records demo (which uses React Router but so does Remix 😉).
For more information on using the View Transitions API, please refer to the Smooth and simple transitions with the View Transitions API guide from the Google Chrome team.
Stable createRemixStub
🔒
After real-world experience, we're confident in the createRemixStub
API and ready to commit to it, so in 2.1.0
we've removed the unstable_
prefix. (#7647)
<RemixStub remixConfigFuture>
prop has been renamed to <RemixStub future>
to decouple the future
prop from a specific file location.
Patch Changes
- Emulate types for
JSON.parse(JSON.stringify(x))
inSerializeFrom
(#7605)- Notably, type fields that are only assignable to
undefined
after serialization are now omitted sinceJSON.stringify |> JSON.parse
will omit them. See test cases for examples - This fixes type errors when upgrading to v2 from 1.19
- Notably, type fields that are only assignable to
- Avoid mutating
meta
object whentagName
is specified (#7594) - Fix FOUC on subsequent client-side navigations to
route.lazy
routes (#7576) - Export the proper Remix
useMatches
wrapper to fixUIMatch
typings (#7551) @remix-run/cloudflare
- sourcemap takes into account special chars in output file (#7574)@remix-run/express
- Flush headers fortext/event-stream
responses (#7619)
Changes by Package
create-remix
@remix-run/architect
@remix-run/cloudflare
@remix-run/cloudflare-pages
@remix-run/cloudflare-workers
@remix-run/css-bundle
@remix-run/deno
@remix-run/dev
@remix-run/eslint-config
@remix-run/express
@remix-run/node
@remix-run/react
@remix-run/serve
@remix-run/server-runtime
@remix-run/testing
Full Changelog: 2.0.1...2.1.0
v2.0.1
Patch Changes
- Fix types for MDX files when using pnpm (#7491)
- Update
getDependenciesToBundle
to handle ESM packages without main exports (#7272)- Note that these packages must expose
package.json
in theirexports
field so that their path can be resolved
- Note that these packages must expose
- Fix server builds where
serverBuildPath
extension is.cjs
(#7180) - Fix HMR for CJS projects using
remix-serve
and manual mode (remix dev --manual
) (#7487)- By explicitly busting the
require
cache,remix-serve
now correctly re-imports new server changes in CJS - ESM projects were already working correctly and are not affected by this.
- By explicitly busting the
- Fix error caused by partially written server build (#7470)
- Previously, it was possible to trigger a reimport of the app server code before the new server build had completely been written. Reimporting the partially written server build caused issues related to
build.assets
being undefined and crashing when readingbuild.assets.version
- Previously, it was possible to trigger a reimport of the app server code before the new server build had completely been written. Reimporting the partially written server build caused issues related to
- Add second generic to
UIMatch
forhandle
field (#7464) - Fix resource routes being loaded through
route.lazy
(#7498) - Throw a semantically correct 405
ErrorResponse
instead of just anError
when submitting to a route without anaction
(#7423) - Update to latest version of
@remix-run/web-fetch
(#7477) - Switch from
crypto.randomBytes
tocrypto.webcrypto.getRandomValues
for file session storage ID generation (#7203) - Use native
Blob
class instead of polyfill (#7217)
Changes by Package 🔗
Full Changelog: 2.0.0...2.0.1
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/web-fetch@4.3.5
) (#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 react-router-dom@6.14.0
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