This page lists all releases/release notes for Remix back to v2.0.0
. For releases prior to v2, please refer to the Github Releases Page.
We manage release notes in this file instead of the paginated Github Releases Page for 2 reasons:
- Pagination in the Github UI means that you cannot easily search release notes for a large span of releases at once
- The paginated Github interface also cuts off longer releases notes without indication in list view, and you need to click into the detail view to see the full set of release notes
Table of Contents
Date: 2024-02-01
As we continue moving towards stabilizing the Vite plugin, we've introduced a few breaking changes to the unstable Vite plugin in this release. Please read the @remix-run/dev
changes below closely and update your app accordingly if you've opted into using the Vite plugin.
We've also removed the unstable_
prefix from the serverBundles
option as we're now confident in the API (#8596).
🎉 And last, but certainly not least - we've added much anticipated Cloudflare support in #8531! To get started with Cloudflare, you can use the unstable-vite-cloudflare
template:
npx create-remix@latest --template remix-run/remix/templates/unstable-vite-cloudflare
For more information, please refer to the docs at Future > Vite > Cloudflare and Future > Vite > Migrating > Migrating Cloudflare Functions.
@remix-run/server-runtime
- Addfuture.v3_throwAbortReason
flag to throwrequest.signal.reason
when a request is aborted instead of anError
such asnew Error("query() call aborted: GET /path")
(#8251)
-
@remix-run/server-runtime
- Unwrap thrownResponse
's fromentry.server
intoErrorResponse
's and preserve the status code (#8577) -
@remix-run/dev
- Vite: Addmanifest
option to Vite plugin to enable writing a.remix/manifest.json
file to the build directory (#8575)⚠️ This is a breaking change for consumers of the Vite plugin's "server bundles" feature- The
build/server/bundles.json
file has been superseded by the more generalbuild/.remix/manifest.json
- While the old server bundles manifest was always written to disk when generating server bundles, the build manifest file must be explicitly enabled via the
manifest
option
-
@remix-run/dev
- Vite: Rely on Vite plugin ordering (#8627)-
⚠️ This is a breaking change for projects using the unstable Vite plugin -
The Remix plugin expects to process JavaScript or TypeScript files, so any transpilation from other languages must be done first.
-
For example, that means putting the MDX plugin before the Remix plugin:
import mdx from "@mdx-js/rollup"; import { unstable_vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [ + mdx(), remix() - mdx(), ], });
-
Previously, the Remix plugin misused
enforce: "post"
from Vite's plugin API to ensure that it ran last -
However, this caused other unforeseen issues
-
Instead, we now rely on standard Vite semantics for plugin ordering
-
The official Vite React SWC plugin also relies on plugin ordering for MDX
-
-
@remix-run/dev
- Vite: Remove interop with<LiveReload />
, rely on<Scripts />
instead (#8636)-
⚠️ This is a breaking change for projects using the unstable Vite plugin -
Vite provides a robust client-side runtime for development features like HMR, making the
<LiveReload />
component obsolete -
In fact, having a separate dev scripts component was causing issues with script execution order
-
To work around this, the Remix Vite plugin used to override
<LiveReload />
into a bespoke implementation that was compatible with Vite -
Instead of all this indirection, now the Remix Vite plugin instructs the
<Scripts />
component to automatically include Vite's client-side runtime and other dev-only scripts -
To adopt this change, you can remove the LiveReload component from your
root.tsx
component:import { - LiveReload, Outlet, Scripts, } export default function App() { return ( <html> <head> </head> <body> <Outlet /> <Scripts /> - <LiveReload /> </body> </html> ) }
-
-
@remix-run/dev
- Vite: Only write Vite manifest files ifbuild.manifest
is enabled within the Vite config (#8599)-
⚠️ This is a breaking change for consumers of Vite'smanifest.json
files -
To explicitly enable generation of Vite manifest files, you must set
build.manifest
totrue
in your Vite config:export default defineConfig({ build: { manifest: true }, // ... });
-
-
@remix-run/dev
- Vite: Add newbuildDirectory
option with a default value of"build"
(#8575)-
⚠️ This is a breaking change for consumers of the Vite plugin that were using theassetsBuildDirectory
andserverBuildDirectory
options -
This replaces the old
assetsBuildDirectory
andserverBuildDirectory
options which defaulted to"build/client"
and"build/server"
respectively -
The Remix Vite plugin now builds into a single directory containing
client
andserver
directories -
If you've customized your build output directories, you'll need to migrate to the new
buildDirectory
option, e.g.:import { unstable_vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [ remix({ - serverBuildDirectory: "dist/server", - assetsBuildDirectory: "dist/client", + buildDirectory: "dist", }) ], });
-
-
@remix-run/dev
- Vite: Write Vite manifest files tobuild/.vite
directory rather than being nested withinbuild/client
andbuild/server
directories (#8599)⚠️ This is a breaking change for consumers of Vite'smanifest.json
files- Vite manifest files are now written to the Remix build directory
- Since all Vite manifests are now in the same directory, they're no longer named
manifest.json
- Instead, they're named
build/.vite/client-manifest.json
andbuild/.vite/server-manifest.json
, orbuild/.vite/server-{BUNDLE_ID}-manifest.json
when using server bundles
-
@remix-run/dev
- Vite: Removeunstable
prefix fromserverBundles
option (#8596) -
@remix-run/dev
- Vite: Add--sourcemapClient
and--sourcemapServer
flags toremix vite:build
(#8613)--sourcemapClient
,--sourcemapClient=inline
, or--sourcemapClient=hidden
--sourcemapServer
,--sourcemapServer=inline
, or--sourcemapServer=hidden
- See https://vitejs.dev/config/build-options.html#build-sourcemap
-
@remix-run/dev
- Vite: Validate IDs returned from theserverBundles
function to ensure they only contain alphanumeric characters, hyphens and underscores (#8598) -
@remix-run/dev
- Vite: Fix "could not fast refresh" false alarm (#8580)- HMR is already functioning correctly but was incorrectly logging that it "could not fast refresh" on internal client routes
- Now internal client routes correctly register Remix exports like
meta
for fast refresh, which removes the false alarm.
-
@remix-run/dev
- Vite: Cloudflare Pages support (#8531) -
@remix-run/dev
- Vite: AddgetRemixDevLoadContext
option to Cloudflare preset (#8649) -
@remix-run/dev
- Vite: Remove undocumented backwards compatibility layer for Vite v4 (#8581) -
@remix-run/dev
- Vite: Addpresets
option to ease integration with different platforms and tools (#8514) -
@remix-run/dev
- Vite: AddbuildEnd
hook (#8620) -
@remix-run/dev
- Vite: Addmode
field into generated server build (#8539) -
@remix-run/dev
- Vite: Reduce network calls for route modules during HMR (#8591) -
@remix-run/dev
- Vite: ExportUnstable_ServerBundlesFunction
andUnstable_VitePluginConfig
types (#8654)
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: v2.5.1...v2.6.0
Date: 2024-01-18
create-remix
- high-contrast fg/bg for header colors (#8503)bgWhite
andwhiteBright
are the same color in many terminal colorthemes, which was causing it to render as illegible white-on-white
@remix-run/dev
- AddisSpaMode
to@remix-run/dev/server-build
virtual module (#8492)@remix-run/dev
- SPA Mode: Automatically prepend<!DOCTYPE html>
if not present to fix quirks mode warnings for SPA template (#8495)@remix-run/dev
- Vite: Errors for server-only code point to new docs (#8488)@remix-run/dev
- Vite: Fix HMR race condition when reading changed file contents (#8479)@remix-run/dev
- Vite: Tree-shake unused route exports in the client build (#8468)@remix-run/dev
- Vite: Performance profiling (#8493)- Run
remix vite:build --profile
to generate a.cpuprofile
that can be shared or uploaded to speedscope.app - In dev, press
p + enter
to start a new profiling session or stop the current session - If you need to profile dev server startup, run
remix vite:dev --profile
to initialize the dev server with a running profiling session - For more, see the new Vite > Performance docs
- Run
@remix-run/dev
- Vite: Improve performance of dev server requests by invalidating Remix's virtual modules on relevant file changes rather than on every request (#8164)@remix-run/react
- Remove leftoverunstable_
prefix fromBlocker
/BlockerFunction
types (#8530)@remix-run/react
- Only use active matches in<Meta>
/<Links>
in SPA mode (#8538)
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: v2.5.0...v2.5.1
Date: 2024-01-11
SPA Mode (RFC) allows you to generate your Remix app as a standalone SPA served from a static index.html
file. You can opt into SPA Mode by setting unstable_ssr: false
in your Remix Vite plugin config:
// vite.config.ts
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.
This is an advanced feature designed for hosting provider integrations where you may want to split server code into multiple request handlers. When compiling your app into multiple server bundles, there will need to be a custom routing layer in front of your app directing requests to the correct bundle. This feature is currently unstable and only designed to gather early feedback.
You can control the server bundles generated by your Remix Vite build by setting the unstable_serverBundles
option in your vite config:
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
remix({
unstable_serverBundles: ({ branch }) => {
const isAuthenticatedRoute = branch.some(
(route) => route.id === "routes/_authenticated"
);
return isAuthenticatedRoute ? "authenticated" : "unauthenticated";
},
}),
],
});
- Add unstable support for "SPA Mode" (#8457)
- Add
unstable_serverBundles
option to Vite plugin to support splitting server code into multiple request handlers (#8332)
create-remix
: Only update*
versions for Remix dependencies (#8458)remix-serve
: Don't try to load sourcemaps if they don't exist on disk (#8446)@remix-run/dev
: Fix issue withisbot@4
released on 1/1/2024 (#8415)remix dev
will now add"isbot": "^4"
topackage.json
instead of usinglatest
- Update built-in
entry.server
files to work with bothisbot@3
andisbot@4
for backwards-compatibility with Remix apps that have pinnedisbot@3
- Templates are updated to use
isbot@4
moving forward viacreate-remix
@remix-run/dev
: Vite - Fix HMR issues when altering exports for non-rendered routes (#8157)@remix-run/dev
: Vite - DefaultNODE_ENV
to"production"
when runningremix vite:build
command (#8405)@remix-run/dev
: Vite - Remove Vite plugin config optionserverBuildPath
in favor of separateserverBuildDirectory
andserverBuildFile
options (#8332)@remix-run/dev
: Vite - Loosen strict route exports restriction, reinstating support for non-Remix route exports (#8420)@remix-run/react
: Vite - Fix type conflict withimport.meta.hot
from the existing Remix compiler (#8459)@remix-run/server-runtime
: Updatedcookie
dependency to0.6.0
to inherit support for thePartitioned
attribute (#8375)
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: v2.4.1...v2.5.0
Date: 2023-12-22
-
@remix-run/dev
: Vite - Removeunstable_viteServerBuildModuleId
in favor of manually referencing virtual module name"virtual:remix/server-build"
(#8264)-
⚠️ This is a breaking change for projects using the unstable Vite plugin with a custom server -
This change was made to avoid issues where
@remix-run/dev
could be inadvertently required in your server's production dependencies. -
Instead, you should manually write the virtual module name
"virtual:remix/server-build"
when callingssrLoadModule
in development.-import { unstable_viteServerBuildModuleId } from "@remix-run/dev"; // ... app.all( "*", createRequestHandler({ build: vite - ? () => vite.ssrLoadModule(unstable_viteServerBuildModuleId) + ? () => vite.ssrLoadModule("virtual:remix/server-build") : await import("./build/server/index.js"), }) );
-
-
@remix-run/dev
: Vite - Addvite:dev
andvite:build
commands to the Remix CLI (#8211)-
In order to handle upcoming Remix features where your plugin options can impact the number of Vite builds required, you should now run your Vite
dev
andbuild
processes via the Remix CLI.{ "scripts": { - "dev": "vite dev", - "build": "vite build && vite build --ssr" + "dev": "remix vite:dev", + "build": "remix vite:build" } }
-
-
@remix-run/dev
: Vite - Error messages when.server
files are referenced by client (#8267)- Previously, referencing a
.server
module from client code resulted in an error message like:The requested module '/app/models/answer.server.ts' does not provide an export named 'isDateType'
- This was confusing because
answer.server.ts
does provide theisDateType
export, but Remix was replacing.server
modules with empty modules (export {}
) for the client build - Now, Remix explicitly fails at compile time when a
.server
module is referenced from client code and includes dedicated error messages depending on whether the import occurs in a route or a non-route module - The error messages also include links to relevant documentation
- Previously, referencing a
-
@remix-run/dev
: Vite - Preserve names for exports from.client
modules (#8200)- Unlike
.server
modules, the main idea is not to prevent code from leaking into the server build since the client build is already public - Rather, the goal is to isolate the SSR render from client-only code
- Routes need to import code from
.client
modules without compilation failing and then rely on runtime checks or otherwise ensure that execution only happens within a client-only context (e.g. event handlers,useEffect
) - Replacing
.client
modules with empty modules would cause the build to fail as ESM named imports are statically analyzed- So instead, we preserve the named export but replace each exported value with
undefined
- That way, the import is valid at build time and standard runtime checks can be used to determine if the code is running on the server or client
- So instead, we preserve the named export but replace each exported value with
- Unlike
-
@remix-run/dev
: Vite - Disable watch mode in Vite child compiler during build (#8342) -
@remix-run/dev
: Vite - Show warning when source maps are enabled in production build (#8222) -
@remix-run/react
: Propagate serverloader
errors throughserverLoader
in hydratingclientLoader
's (#8304) -
@remix-run/react
Re-exportResponse
helpers (defer
/json
/redirect
/redirectDocument
) through@remix-run/react
for use inclientLoader
/clientAction
(#8351) -
@remix-run/server-runtime
: Add optionalerror
toServerRuntimeMetaArgs
type to align withMetaArgs
(#8238) -
create-remix
: Switch to using@remix-run/web-fetch
instead ofnode-fetch
inside thecreate-remix
CLI (#7345) -
remix-serve
: Use nodefileURLToPath
to convert source map URL to path (#8321)
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: v2.4.0...v2.4.1
Date: 2023-12-13
We're excited to land the Client Data RFC in this release! The final API differs slightly from the RFC, so please check out the docs for use-cases and final APIs:
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:
- Skip the Hop: Query a data API directly from the browser, using loaders simply for SSR
- Fullstack State: Augment server data with client data for your full set of loader data
- One or the Other: Sometimes you use server loaders, sometimes you use client loaders, but not both on one route
- Client Cache: Cache server loader data in the client and avoid some server calls
- Migration: Ease your migration from React Router -> Remix SPA -> Remix SSR
We introduced a 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
Remix now excludes modules within .server
directories from client build.
Remix now enforces strict route exports, and will will throw an error if you have unsupported exports in your route modules. Previously, the Remix compiler would allow any export from routes. While this was convenient, it was also a common source of bugs that were hard to track down because they only surfaced at runtime. For more information, please see the docs.
- Add support for
clientLoader
/clientAction
/HydrateFallback
route exports (#8173) - Add a new
future.v3_relativeSplatPath
flag to implement a breaking bug fix to relative routing when inside a splat route (#8216) - Deprecate
DataFunctionArgs
in favor ofLoaderFunctionArgs
/ActionFunctionArgs
(#8173)- This is aimed at keeping the types aligned across server/client loaders/actions now that
clientLoader
/clientActon
functions haveserverLoader
/serverAction
parameters which differentiateClientLoaderFunctionArgs
/ClientActionFunctionArgs
- This is aimed at keeping the types aligned across server/client loaders/actions now that
- Vite: Exclude modules within
.server
directories from client build (#8154) - Vite: Strict route exports (#8171)
-
@remix-run/server-runtime
: Fix flash of unstyled content for non-Express custom servers in Vite dev (#8076) -
@remix-run/server-runtime
: Pass request handler errors tovite.ssrFixStacktrace
in Vite dev to ensure stack traces correctly map to the original source code (#8066) -
remix-serve
: Fix source map loading when file has?t=timestamp
suffix (rebuilds) (#8174) -
@remix-run/dev
: Change Vite build output paths to fix a conflict between how Vite and the Remix compiler each manage thepublic
directory (#8077)⚠️ This is a breaking change for projects using the unstable Vite plugin- The server is now compiled into
build/server
rather thanbuild
, and the client is now compiled intobuild/client
rather thanpublic
- For more information on the changes and guidance on how to migrate your project, refer to the updated Remix Vite documentation
-
@remix-run/dev
: Upgrade Vite peer dependency range to v5 (#8172) -
@remix-run/dev
: Support HMR for routes withhandle
export in Vite dev (#8022) -
@remix-run/dev
: Fix flash of unstyled content for non-Express custom servers in Vite dev (#8076) -
@remix-run/dev
: Bundle CSS imported in client entry file in Vite plugin (#8143) -
@remix-run/dev
: Remove undocumentedlegacyCssImports
option from Vite plugin due to issues with?url
imports of CSS files not being processed correctly in Vite (#8096) -
@remix-run/dev
: Vite: fix access to defaultentry.{client,server}.tsx
withinpnpm
workspaces on Windows (#8057) -
@remix-run/dev
: Removeunstable_createViteServer
andunstable_loadViteServerBuild
which were only minimal wrappers around Vite'screateServer
andssrLoadModule
functions when using a custom server (#8120)-
⚠️ This is a breaking change for projects using the unstable Vite plugin with a custom server -
Instead, we now provide
unstable_viteServerBuildModuleId
so that custom servers interact with Vite directly rather than via Remix APIs, for example:-import { - unstable_createViteServer, - unstable_loadViteServerBuild, -} from "@remix-run/dev"; +import { unstable_viteServerBuildModuleId } from "@remix-run/dev";
Creating the Vite server in middleware mode:
const vite = process.env.NODE_ENV === "production" ? undefined - : await unstable_createViteServer(); + : await import("vite").then(({ createServer }) => + createServer({ + server: { + middlewareMode: true, + }, + }) + );
Loading the Vite server build in the request handler:
app.all( "*", createRequestHandler({ build: vite - ? () => unstable_loadViteServerBuild(vite) + ? () => vite.ssrLoadModule(unstable_viteServerBuildModuleId) : await import("./build/server/index.js"), }) );
-
-
@remix-run/dev
: Pass request handler errors tovite.ssrFixStacktrace
in Vite dev to ensure stack traces correctly map to the original source code (#8066) -
@remix-run/dev
: Vite: Preserve names for exports from.client
imports (#8200)- Unlike
.server
modules, the main idea is not to prevent code from leaking into the server build since the client build is already public - Rather, the goal is to isolate the SSR render from client-only code
- Routes need to import code from
.client
modules without compilation failing and then rely on runtime checks to determine if the code is running on the server or client - Replacing
.client
modules with empty modules would cause the build to fail as ESM named imports are statically analyzed- So instead, we preserve the named export but replace each exported value with an empty object
- That way, the import is valid at build time and the standard runtime checks can be used to determine if then code is running on the server or client
- Unlike
-
@remix-run/dev
: Add@remix-run/node
to Vite'soptimizeDeps.include
array (#8177) -
@remix-run/dev
: Improve Vite plugin performance (#8121)- Parallelize detection of route module exports
- Disable
server.preTransformRequests
in Vite child compiler since it's only used to process route modules
-
@remix-run/dev
: Remove automatic global Node polyfill installation from the built-in Vite dev server and instead allow explicit opt-in (#8119)-
⚠️ This is a breaking change for projects using the unstable Vite plugin without a custom server -
If you're not using a custom server, you should call
installGlobals
in your Vite config instead.import { unstable_vitePlugin as remix } from "@remix-run/dev"; +import { installGlobals } from "@remix-run/node"; import { defineConfig } from "vite"; +installGlobals(); export default defineConfig({ plugins: [remix()], });
-
-
@remix-run/dev
: Vite: Errors at build-time when client imports .server default export (#8184)- Remix already stripped .server file code before ensuring that server code never makes it into the client
- That results in errors when client code tries to import server code, which is exactly what we want!
- But those errors were happening at runtime for default imports
- A better experience is to have those errors happen at build-time so that you guarantee that your users won't hit them
-
@remix-run/dev
: Fixrequest instanceof Request
checks when using Vite dev server (#8062)
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: v2.3.1...v2.4.0
Date: 2023-11-22
@remix-run/dev
: Supportnonce
prop onLiveReload
component in Vite dev (#8014)@remix-run/dev
: Ensure code-split JS files in the server build's assets directory aren't cleaned up after Vite build (#8042)@remix-run/dev
: Fix redundant copying of assets frompublic
directory in Vite build (#8039)- This ensures that static assets aren't duplicated in the server build directory
- This also fixes an issue where the build would break if
assetsBuildDirectory
was deeply nested within thepublic
directory
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: v2.3.0...v2.3.1
Date: 2023-11-16
We've removed the unstable_
prefix from the useBlocker
hook as it's been in use for enough time that we are confident in the API. We do not plan to remove the prefix from unstable_usePrompt
due to differences in how browsers handle window.confirm
that prevent React Router from guaranteeing consistent/correct behavior.
We've added a new unstable_flushSync
option to the imperative APIs (useSubmit
, useNavigate
, fetcher.submit
, fetcher.load
) to let users opt-into synchronous DOM updates for pending/optimistic UI.
function handleClick() {
submit(data, { flushSync: true });
// Everything is flushed to the DOM so you can focus/scroll to your pending/optimistic UI
setFocusAndOrScrollToNewlyAddedThing();
}
- Remove the
unstable_
prefix from theuseBlocker
hook (#7882) - Add
unstable_flushSync
option touseNavigate
/useSubmit
/fetcher.load
/fetcher.submit
to opt-out ofReact.startTransition
and intoReactDOM.flushSync
for state updates (#7996)
@remix-run/react
: Add missingmodulepreload
for the manifest (#7684)@remix-run/server-runtime
: Updatedcookie
dependency from0.4.1
to0.5.0
to inherit support forPriority
attribute in Chrome (#6770)@remix-run/dev
: FixFutureConfig
type (#7895)- Lots of small fixes for the unstable
vite
compiler:- Support optional rendering of the
LiveReload
component in Vite dev (#7919) - Support rendering of the
LiveReload
component afterScripts
in Vite dev (#7919) - Fix
react-refresh/babel
resolution for custom server withpnpm
(#7904) - Support JSX usage in
.jsx
files without manualReact
import in Vite (#7888) - Fix Vite production builds when plugins that have different local state between
development
andproduction
modes are present (e.g.@mdx-js/rollup
) (#7911) - Cache resolution of Remix Vite plugin options (#7908)
- Support Vite 5 (#7846)
- Allow
process.env.NODE_ENV
values other than"development"
in Vite dev (#7980) - Attach CSS from shared chunks to routes in Vite build (#7952)
- Let Vite handle serving files outside of project root via
/@fs
(#7913)- This fixes errors when using default client entry or server entry in a pnpm project where those files may be outside of the project root, but within the workspace root
- By default, Vite prevents access to files outside the workspace root (when using workspaces) or outside of the project root (when not using workspaces) unless user explicitly opts into it via Vite's
server.fs.allow
- Improve performance of LiveReload proxy in Vite dev (#7883)
- Deduplicate
@remix-run/react
(#7926)- Pre-bundle Remix dependencies to avoid Remix router duplicates
- Our
remix-react-proxy
plugin does not process default client and server entry files since those come from withinnode_modules
- That means that before Vite pre-bundles dependencies (e.g. first time dev server is run) mismatching Remix routers cause
Error: You must render this element inside a <Remix> element
- Fix React Fast Refresh error on load when using
defer
in Vite dev server (#7842) - Handle multiple
Set-Cookie
headers in Vite dev server (#7843) - Fix flash of unstyled content on initial page load in Vite dev when using a custom Express server (#7937)
- Populate
process.env
from.env
files on the server in Vite dev (#7958) - Emit assets that were only referenced in the server build into the client assets directory in Vite build (#7892, cherry-picked in
8cd31d65
)
- Support optional rendering of the
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: v2.2.0...v2.3.0
Date: 2023-10-31
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.
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
- Deno support is untested, but should work through Deno's Node/
Per this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors:
- 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
anduseSubmit
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
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.
- 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
- Unstable
vite
support (#7590) - New fetcher
key
APIs andnavigate
/fetcherKey
params for navigational APIs (#10960) - New
future.v3_fetcherPersist
flag (#10962)
@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.
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: v2.1.0...v2.2.0
Date: 2023-10-16
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.
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.
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.
<RemixStub remixConfigFuture>
prop has been renamed to <RemixStub future>
to decouple the future
prop from a specific file location.
- Added unstable support for the View Transition API (#10916)
- Stabilized the
@remix-run/testing
createRemixStub
helper (#7647)
- 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)
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: v2.0.1...v2.1.0
Date: 2023-09-21
- 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)
Full Changelog: v2.0.0...v2.0.1
Date: 2023-09-15
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
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
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
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)
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
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)
- Removed
V2_
prefixes fromfuture.v2_meta
types as they are now the default behavior (#6958)V2_MetaArgs
->MetaArgs
V2_MetaDescriptor
->MetaDescriptor
V2_MetaFunction
->MetaFunction
V2_MetaMatch
->MetaMatch
V2_MetaMatches
->MetaMatches
V2_ServerRuntimeMetaArgs
->ServerRuntimeMetaArgs
V2_ServerRuntimeMetaDescriptor
->ServerRuntimeMetaDescriptor
V2_ServerRuntimeMetaFunction
->ServerRuntimeMetaFunction
V2_ServerRuntimeMetaMatch
->ServerRuntimeMetaMatch
V2_ServerRuntimeMetaMatches
->ServerRuntimeMetaMatches
- The following types were adjusted to prefer
unknown
overany
and to align with underlying React Router types (#7319):- Renamed the
useMatches()
return type fromRouteMatch
toUIMatch
- Renamed
LoaderArgs
/ActionArgs
toLoaderFunctionArgs
/ActionFunctionArgs
AppData
changed fromany
tounknown
Location["state"]
(useLocation.state
) changed fromany
tounknown
UIMatch["data"]
(useMatches()[i].data
) changed fromany
tounknown
UIMatch["handle"]
(useMatches()[i].handle
) changed from{ [k: string]: any }
tounknown
Fetcher["data"]
(useFetcher().data
) changed fromany
tounknown
MetaMatch.handle
(used inmeta()
) changed fromany
tounknown
AppData
/RouteHandle
are no longer exported as they are just aliases forunknown
- Renamed the
- New
create-remix
CLI (#6887)- Most notably, this removes the dropdown to choose your template/stack in favor of the
--template
flag and our ever-growing list of available templates - Adds a new
--overwrite
flag (#7062) - Supports the
bun
package manager (#7074)
- Most notably, this removes the dropdown to choose your template/stack in favor of the
- Detect built mode via
build.mode
(#6964) - Support polyfilling node globals via
serverNodeBuiltinsPolyfill.globals
/browserNodeBuiltinsPolyfill.globals
(#7269) - New
redirectDocument
utility to redirect via a fresh document load (#7040, #6842) - Add
error
tometa
params so you can render error titles, etc. (#7105) unstable_createRemixStub
now supports addingmeta
/links
functions on stubbed Remix routes (#7186)unstable_createRemixStub
no longer supports theelement
/errorElement
properties on routes. You must useComponent
/ErrorBoundary
to match what you would export from a Remix route module.
- Remix now uses React Router's
route.lazy
method internally to load route modules on navigations (#7133) - Removed the
@remix-run/node
atob
/btoa
polyfills in favor of the built-in versions (#7206) - Decouple the
@remix-run/dev
package from the contents of the@remix-run/css-bundle
package (#6982)- The contents of the
@remix-run/css-bundle
package are now entirely managed by the Remix compiler. Even though it's still recommended that your Remix dependencies all share the same version, this change ensures that there are no runtime errors when upgrading@remix-run/dev
without upgrading@remix-run/css-bundle
.
- The contents of the
remix-serve
now picks an open port if 3000 is taken (#7278)- If
PORT
env var is set,remix-serve
will use that port - Otherwise,
remix-serve
picks an open port (3000 unless that is already taken)
- If
[email protected]
@remix-run/[email protected]
@remix-run/[email protected]
@remix-run/[email protected]
@remix-run/[email protected]
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