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:
Date: 2025-07-25
create-remix - Redirect users to create-react-router instead of create-remix (#10686, #10688)
Full Changelog: v2.16.8...v2.17.0
Date: 2025-05-29
create-remix - Update tar-fs (#10638)Full Changelog: v2.16.7...v2.16.8
Date: 2025-05-19
@remix-run/dev - Update vite-node (#10611)Full Changelog: v2.16.6...v2.16.7
Date: 2025-05-08
@remix-run/react - Upgrade turbo-stream to 2.4.1 (#9973)@remix-run/react - Fix window is not defined error in Single Fetch when server-rendering <PrefetchPageLinks> (#10601)@remix-run/serve - Remove redundant @remix-run/node/install import from remix-serve because it manually calls installGlobals separately (#10306)Full Changelog: v2.16.5...v2.16.6
Date: 2025-04-09
@remix-run/node - Bump undici to version 6.21.2 to address a security advisory (#10562)Full Changelog: v2.16.4...v2.16.5
Date: 2025-03-31
@remix-run/server-runtime - Bump cookie dependency from ^0.6.0 -> ^0.7.2 to fix security advisory (#10547)Full Changelog: v2.16.3...v2.16.4
Date: 2025-03-28
Fixed a security vulnerability that allowed URL manipulation and potential cache pollution via the Host and X-Forwarded-Host headers due to inadequate port sanitization.
@remix-run/express - Better validation of x-forwarded-host header to prevent potential security issues (#10553)Full Changelog: v2.16.2...v2.16.3
Date: 2025-03-19
@remix-run/react - Fix shouldRevalidate behavior for clientLoader-only routes in ssr:true apps (#10527)@remix-run/server-runtime - Load ancestor pathless/index routes in lazy route discovery for upwards non-eager-discovery routing (#10535)Full Changelog: v2.16.1...v2.16.2
Date: 2025-03-17
@remix-run/dev - Remove unused Vite file system watcher (#10510)@remix-run/dev - When future.v3_routeConfig is enabled, fix errors evaluating routes.ts when multiple copies of @remix-run/dev are present (#10524)@remix-run/dev - Fix Vite import analysis of @remix-run/react failing when the package is not marked as external (#10528)Full Changelog: v2.16.0...v2.16.1
Date: 2025-02-27
@remix-run/dev - Add Vite v6 support (#10351)@remix-run/dev - Clean up vite-node dev server when build finishes (#10477)@remix-run/react - Don't apply Single Fetch revalidation de-optimization when in SPA mode since there is no server HTTP request (#10479)@remix-run/react - When using Lazy Route Discovery (future.v3_lazyRouteDiscovery), Remix will now detect manifest version mismatches after a new deploy and trigger a document reload to sync up any active client sessions with the newly deployed version (#10498)
fetcher calls to undiscovered routes, this mismatch will trigger a document reload of the current path<Link> components, mismatches will result in a no-opFull Changelog: v2.15.3...v2.16.0
Date: 2025-01-30
@remix-run/react - Properly handle interrupted manifest requests in lazy route discovery (#10447)@remix-run/server-runtime - Avoid duplication of Set-Cookie headers if also returned from headers (#10424)@remix-run/server-runtime - Properly handle status codes that cannot have a body in single fetch responses (204, etc.) (#10410)Full Changelog: v2.15.2...v2.15.3
Date: 2024-12-20
@remix-run/dev - Allow suppression of future flag warnings by setting them to false (#10358)@remix-run/react - Throw unwrapped Single Fetch redirect to align with pre-Single Fetch behavior (#10317)Full Changelog: v2.15.1...v2.15.2
Date: 2024-12-09
create-remix - Move fs-extra from devDependencies to dependencies (#10300)Full Changelog: v2.15.0...v2.15.1
Date: 2024-11-19
Stabilize the future.v3_routeConfig future flag, replacing future.unstable_routeConfig. This enables support for routes.ts to assist with the migration to React Router v7. (#10236)
Note that if you had already enabled the future.unstable_routeConfig flag, your route config in app/routes.ts is no longer defined via the routes export and must now be defined via the default export.
import { type RouteConfig } from "@remix-run/route-config";
-export const routes: RouteConfig = [];
+export default [] satisfies RouteConfig;
Date: 2024-11-08
Deprecate SerializeFrom in favor of generics because it will be removed in React Router v7 (#10173)
Add deprecation warning to @remix-run/eslint-config (#10174)
Add support for routes.ts behind future.unstable_routeConfig flag to assist with the migration to React Router v7. (#10107)
Config-based routing is the new default in React Router v7, configured via the routes.ts file in the app directory. Support for routes.ts and its related APIs in Remix are designed as a migration path to help minimize the number of changes required when moving your Remix project over to React Router v7. While some new packages have been introduced within the @remix-run scope, these new packages only exist to keep the code in routes.ts as similar as possible to the equivalent code for React Router v7.
When the unstable_routeConfig future flag is enabled, Remix's built-in file system routing will be disabled and your project will opted into React Router v7's config-based routing.
To enable the flag, in your vite.config.ts file:
remix({
future: {
unstable_routeConfig: true,
},
});
A minimal routes.ts file to support Remix's built-in file system routing looks like this:
// app/routes.ts
import { flatRoutes } from "@remix-run/fs-routes";
import type { RouteConfig } from "@remix-run/route-config";
export const routes: RouteConfig = flatRoutes();
Log deprecation warnings for v3 future flags (#10126)
@deprecated annotations to json/defer utilities@remix-run/react - Fix defaultShouldRevalidate value when using Single Fetch (#10139)@remix-run/server-runtime - Update externally-accessed resource routes warning to cover null usage as well (#10145)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/fs-routes@remix-run/node@remix-run/react@remix-run/route-config@remix-run/routes-option-adapter@remix-run/serve@remix-run/server-runtime@remix-run/testingFull Changelog: v2.13.1...v2.14.0
Date: 2024-10-11
@remix-run/dev - Revert future.v3_optimizeDeps back to future.unstable_optimizeDeps as it was not intended to stabilize in Remix v2 (#10099)Full Changelog: v2.13.0...v2.13.1
Date: 2024-10-11
This release stabilizes a handful of "unstable" APIs in preparation for the pending React Router v7 release (see these posts for more info):
unstable_data ā data (for use with Single Fetch)unstable_flushSync ā flushSync (useSubmit, fetcher.load, fetcher.submit)unstable_viewTransition ā viewTransition (<Link>, <Form>, useNavigate, useSubmit)future.unstable_optimizeDeps ā future.v3_optimizeDeps (Docs)future.unstable_optimizeDeps in 2.13.1future.unstable_lazyRouteDiscovery ā future.v3_lazyRouteDiscovery (Docs)future.unstable_singleFetch ā future.v3_singleFetch (Docs)unstable_dataStrategy -> dataStrategyunstable_patchRoutesOnNavigation -> patchRoutesOnNavigationunstable_data() -> data()unstable_viewTransition -> viewTransition (Link, Form, navigate, submit)unstable_flushSync> -> <Link viewTransition> (Link, Form, navigate, submit, useFetcher)future.unstable_lazyRouteDiscovery -> future.v3_lazyRouteDiscoveryfuture.unstable_optimizeDeps -> future.v3_optimizeDepsfuture.unstable_singleFetch -> future.v3_singleFetch@remix-run/dev - Stop passing request.signal as the renderToReadableStream signal to abort server rendering for cloudflare/deno runtimes because by the time that request is aborted, aborting the rendering is useless because there's no way for React to flush down the unresolved boundaries (#10047)
remix vite:dev because we were incorrectly aborting requests after successful renders - which was causing us to abort a completed React render, and try to close an already closed ReadableStreamrequest.signal on successful rendersentry.server files no longer pass a signal to renderToReadableStream because adding a timeout-based abort signal to the default behavior would constitute a breaking changeentry.server via remix reveal entry.server, and the template entry.server files have been updated with an example approach for newly created Remix apps@remix-run/express - Fix adapter logic for aborting request.signal so we don't incorrectly abort on the close event for successful requests (#10046)@remix-run/react - Fix bug with clientLoader.hydrate in a layout route when hydrating with bubbled errors (#10063)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/testingFull Changelog: v2.12.1...v2.13.0
Date: 2024-09-19
@remix-run/dev - Properly abort request.signal during vite dev when the node response is closed (#9976)@remix-run/dev - CSS imports with ?inline, ?inline-css and ?raw are no longer incorrectly injected during SSR in development (#9910)@remix-run/server-runtime: Single Fetch: Fix types when loader, action, clientLoader, or clientAction return a mixture of bare objects, json(...), defer(...), and unstable_data(...). (#9999)@remix-run/node/@remix-run/cloudflare/@remix-run/deno - Single Fetch: Re-export interface Future through runtime packages so that pnpm doesn't complain about @remix-run/server-runtime not being a dependency (#9982)
vite.config.ts to augment @remix-run/node (or cloudflare/deno) instead of @remix-run/server-runtimeFull Changelog: v2.12.0...v2.12.1
Date: 2024-09-09
You can now opt-in to automatic dependency optimization during development by using the future.unstable_optimizeDeps future flag. For details, check out the docs at Guides > Dependency optimization. For users who were previously working around this limitation, you no longer need to explicitly add routes to Vite's optimizeDeps.entries nor do you need to disable the remix-dot-server plugin.
"@remix-run/react/future/single-fetch.d.ts" override from tsconfig.json > compilerOptions > typesdefineLoader, defineAction, defineClientLoader, defineClientAction helpers from your route modulesUIMatch_SingleFetch type helper with the original UIMatchMetaArgs_SingleFetch type helper with the original MetaArgsThen you are ready for the new type safety setup:
// vite.config.ts
declare module "@remix-run/server-runtime" {
interface Future {
unstable_singleFetch: true; // š enable _types_ for single-fetch
}
}
export default defineConfig({
plugins: [
remix({
future: {
unstable_singleFetch: true, // š enable single-fetch
},
}),
],
});
For more information, see Guides > Single Fetch in our docs.
With Single Fetch, re-used routes will now revalidate by default on GET navigations. This is aimed at improving caching of Single Fetch calls in the simple case while still allowing users to opt-into the previous behavior for more advanced use cases.
With this new behavior, requests do not need special query params for granular route revalidations out of the box - i.e., GET /a/b/c.data
There are two conditions that will trigger granular revalidation and will exclude certain routes from the single fetch call:
shouldRevalidateclientLoader
serverLoader() from your clientLoader, that will make a separate HTTP call for just that route loader - i.e., GET /a/b/c.data?_routes=routes/a for a clientLoader in routes/a.tsxWhen one or more routes are excluded from the Single Fetch call, the remaining routes that have loaders are included as query params. For example, when navigating to /a/b/c, if A was excluded, and the root route and routes/b had a loader but routes/c did not, the Single Fetch request would be GET /a/b/c.data?_routes=root,routes/b.
For more information, see Guides > Single Fetch in our docs.
@remix-run/dev - New future.unstable_optimizeDeps flag for automatic dependency optimization (#9921)@remix-run/dev - Handle circular dependencies in modulepreload manifest generation (#9917)@remix-run/dev - Fix dest already exists build errors by only moving SSR assets to the client build directory when they're not already present on disk (#9901)@remix-run/react - Clarify wording in default HydrateFallback console warning (#9899)@remix-run/react - Remove hydration URL check that was originally added for React 17 hydration issues and we no longer support React 17 (#9890)
v1.18.0 via #64091.18.0 turned out to be subject to false positives of it's own which could also put the user in looping scenarios@remix-run/react - Lazy Route Discovery: Sort /__manifest query parameters for better caching (#9888)@remix-run/react - Single Fetch: Improved type safety (#9893)@remix-run/react - Single Fetch: Fix revalidation behavior bugs (#9938)@remix-run/server-runtime - Do not render or try to include a body for 304 responses on document requests (#9955)@remix-run/server-runtime - Single Fetch: Do not try to encode a turbo-stream body into 304 responses (#9941)@remix-run/server-runtime - Single Fetch: Change content type on .data requests to text/x-script to allow Cloudflare compression (#9889)Full Changelog: v2.11.2...v2.12.0
Date: 2024-08-15
@remix-run/react - Fog of War: Simplify implementation now that React Router handles slug/splat edge cases and tracks previously discovered routes (see https://github.com/remix-run/react-router/pull/11883) (#9860)
/__manifest endpoint since we no longer need the notFoundPaths field@remix-run/react - Fog of War: Update to use renamed unstable_patchRoutesOnNavigation function in RR (see https://github.com/remix-run/react-router/pull/11888) (#9860)@remix-run/server-runtime - Single Fetch: Fix redirects when a basename is present (#9848)@remix-run/server-runtime - Single Fetch: Update turbo-stream to v2.3.0 (#9856)
Full Changelog: v2.11.1...v2.11.2
Date: 2024-08-05
@remix-run/react - Revert #9695, stop infinite reload (a7cffe57)Full Changelog: v2.11.0...v2.11.1
Date: 2024-08-01
unstable_fogOfWar future flag to unstable_lazyRouteDiscovery (unstable)We found that the future.unstable_fogOfWar flag name could be a bit confusing without the proper context (notably, the blog post), so we've renamed the flag to future.unstable_lazyRouteDiscovery for clarity. If you had opted into this feature already, please update the name of the flag in your vite.config.ts file (or remix.config.js).
response stub in Single Fetch (unstable)The original Single Fetch approach was based on an assumption that an eventual middleware implementation would require something like the ResponseStub API so users could mutate status/headers in middleware before/after handlers as well as during handlers. As part of Single Fetch, we wanted to align how response headers would be merged between document and data requests. Thinking response was the future API, we aligned document requests to use the response stub that data requests were using, and we stopped using the headers() function.
However, the realization/alignment between Michael and Ryan on the recent roadmap planning made us realize that the original assumption was incorrect. middleware won't need a response stub - as users can just mutate the Response they get from await next() directly.
Removing that assumption, and still wanting to align how headers get merged between document and data requests, it makes more sense to stick with the current headers() API and align Single Fetch data requests to use that existing API. This was we don't need to introduce any new header-related APIs which will make the adoption of Single Fetch much easier.
With this change:
headers() function will let you control header merging for both document and data requestsjson()/defer() without setting a custom status or headers, you can just remove those utility functions and return the raw data
return json({ data: "whatever" });return { data: "whatever" };status or headers via json/defer:
unstable_data utility that will let you send back status/headers alongside your raw data without having to encode it into a Responsejson and defer in the next major version, but both should still work in Single Fetch in v2 to allow for incremental adoption of the new behaviorā ļø If you've already adopted Single Fetch in it's unstable state and converted to response stub, you'll need to move those changes back to leveraging the headers() API.
@remix-run/dev - Fog of War: Rename future.unstable_fogOfWar to future.unstable_lazyRouteDiscovery for clarity (#9763)@remix-run/server-runtime - Add a new replace(url, init?) alternative to redirect(url, init?) that performs a history.replaceState instead of a history.pushState on client-side navigation redirects (#9764)@remix-run/server-runtime - Single Fetch: Add a new unstable_data() API as a replacement for json/defer when custom status/headers are needed (#9769)@remix-run/server-runtime - Single Fetch: Remove responseStub in favor of headers (#9769)@remix-run/dev - Handle absolute Vite base URLs (#9700)@remix-run/react - Change initial hydration route mismatch from a URL check to a matches check to be resistant to URL inconsistencies (#9695)@remix-run/react - Single Fetch: Ensure calls don't include any trailing slash from the pathname (i.e., /path/.data) (#9792)@remix-run/react - Single Fetch: Add undefined to the useRouteLoaderData type override (#9796)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/testingFull Changelog: v2.10.3...v2.11.0
Date: 2024-07-16
@remix-run/architect - Manually joining headers with semi-colons to avoid differences in Remix and node/undici Headers implementation (#9664)@remix-run/react - Log any errors encountered loading a route module prior to reloading the page (#8932)@remix-run/react - Single Fetch (unstable): Proxy request.signal through dataStrategy for loader calls to fix cancellation (#9738)@remix-run/react - Single Fetch (unstable): Adopt React Router's stabilized future.v7_skipActionErrorRevalidation under the hood (#9706)
shouldRevalidate parameter from unstable_actionStatus to actionStatusunstable_actionStatus parametercreate-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/testingFull Changelog: v2.10.2...v2.10.3
Date: 2024-07-04
@remix-run/react - Forward ref to Form (bdd04217)@remix-run/server-runtime - Fix bug with immutable headers on raw native fetch responses returned from loaders (#9693)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/testingFull Changelog: v2.10.1...v2.10.2
Date: 2024-07-03
@remix-run/react - Fog of War (unstable): Support route discovery from <Form> components (#9665)@remix-run/react - Fog of War (unstable): Don't discover links/forms with reloadDocument (#9686)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/testingFull Changelog: v2.10.0...v2.10.1
Date: 2024-06-25
The "Fog of War" feature in Remix, now available through the future.unstable_fogOfWar flag, is an optimization to reduce the up front size of the Remix route manifest. In most scenarios the Remix route manifest isn't prohibitively large so as to impact initial perf metrics, but at scale we've found that some apps can generate large manifests that are expensive to download and execute on app startup.
When Fog of War is enabled, Remix will only include the initially server-rendered routes in the manifest and then it will fetch manifest "patches" for outgoing links as the user navigates around. By default, to avoid waterfalls Remix fetches patches for all rendered links, so that in the ideal case they've already been patched in prior to being clicked. If a user clicks a link before this eager discovery completes, then a small waterfall will occur to first "discover" the route, and then navigate to the route.
Enabling this flag should require no application code changes. For more information, please see the documentation.
@remix-run/{dev|express|serve} - Upgrade express dependency to ^4.19.2 (#9184)@remix-run/react - Don't prefetch server loader data when clientLoader exists (#9580)@remix-run/react - Avoid hydration loops when Layout/ErrorBoundary renders also throw (#9566)@remix-run/react - Fix a hydration bug when using child routes and HydrateFallback components with a basename (#9584)@remix-run/{server-runtime|react} - Single Fetch: Update to turbo-stream@2.2.0 (#9562)@remix-run/server-runtime - Single Fetch: Properly handle thrown 4xx/5xx response stubs (#9501)@remix-run/server-runtime - Single Fetch: Change redirects to use a 202 status to avoid automatic caching (#9564)@remix-run/server-runtime - Single Fetch: Fix issues with returning or throwing a response stub from a resource route in single fetch (#9488)@remix-run/server-runtime - Single Fetch: Fix error when returning null from a resource route (#9488)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/testingFull Changelog: v2.9.2...v2.10.0
Date: 2024-05-10
In 2.9.2 we've enhanced the type-safety when opting into the future.unstable_singleFetch feature. Previously, we added the response stub to LoaderFunctionArgs and used type overrides for inference on useLoaderData, etc., but we found that it wasn't quite enough.
With this release we're introducing new functions to assist the type-inference when using single fetch - defineLoader/defineAction and their client-side counterparts defineClientLoader and nd defineClientAction. These are identity functions; they don't modify your loader or action at runtime. Rather, they exist solely for type-safety by providing types for args and by ensuring valid return types.
export const loader = defineLoader(({ request }) => {
// ^? Request
return { a: 1, b: () => 2 };
// ^ type error: `b` is not serializable
});
Note that defineLoader and defineAction are not technically necessary for defining loaders and actions if you aren't concerned with type-safety:
// this totally works! and typechecking is happy too!
export const loader = () => {
return { a: 1 };
};
This means that you can opt-in to defineLoader incrementally, one loader at a time.
Please see the Single Fetch docs for more information.
@remix-run/dev - Vite: Fix dest already exists error when running remix vite:build (#9305)@remix-run/dev - Vite: Fix issue resolving critical CSS during development when route files are located outside of the app directory (#9194)@remix-run/dev - Vite: Remove @remix-run/node from Vite plugin's optimizeDeps.include list since it was unnecessary and resulted in Vite warnings when not depending on this package (#9287)@remix-run/dev - Vite: Clean up redundant ?client-route=1 imports in development (#9395)@remix-run/dev - Vite: Ensure Babel config files are not referenced when applying the react-refresh Babel transform within the Remix Vite plugin (#9241)@remix-run/react - Type-safety for single-fetch: defineLoader, defineClientLoader, defineAction, defineClientAction (#9372)@remix-run/react - Single Fetch: Add undefined to useActionData type override (#9322)@remix-run/react - Single Fetch: Allow a nonce to be set on single fetch stream transfer inline scripts via <RemixServer> (#9364)@remix-run/server-runtime - Single Fetch: Don't log thrown response stubs via handleError (#9369)@remix-run/server-runtime - Single Fetch: Automatically wrap resource route naked object returns in json() for back-compat in v2 (and log deprecation warning) (#9349)@remix-run/server-runtime - Single Fetch: Pass response stub to resource route handlers (#9349)@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/testingFull Changelog: v2.9.1...v2.9.2
Date: 2024-04-24
@remix-run/dev - Fix issue where consumers who had added Remix packages to Vite's ssr.noExternal option were being overridden by the Remix Vite plugin adding Remix packages to Vite's ssr.external option (#9301)@remix-run/react - Ignore future/*.d.ts files from TS build (#9299)Full Changelog: v2.9.0...v2.9.1
Date: 2024-04-23
2.9.0 introduces a future.unstable_singleFetch flag to enable to Single Fetch behavior (RFC) in your Remix application. Please refer to the docs for the full detail but the high-level changes to be aware of include:
loader/action functions are no longer automatically serialized to JSON responses
turbo-stream which allows direct serialization of more complex types such as Promise, Date, Map instances, and moretsconfig.json's compilerOptions.types array to infer types properly when using Single Fetchheaders export is no longer used when Single Fetch is enabled in favor of a new response stub passed to your loader/action functionsjson/defer/redirect utilities are deprecated when using Single Fetch (but still work mostly the same)4xx/5xx responses - you can return a 2xx to opt-into revalidation or use shouldRevalidate[!IMPORTANT] Single Fetch requires using
undicias your fetch polyfill, or using the built-in fetch on Node 20+, because it relies on APIs available there but not in the@remix-run/web-fetchpolyfill. Please refer to the Undici section below for more details.
- If you are managing your own server and calling
installGlobals(), you will need to callinstallGlobals({ nativeFetch: true })to avoid runtime errors when using Single Fetch- If you are using
remix-serve, it will useundiciautomatically if Single Fetch is enabled
Remix 2.9.0 adds a new installGlobals({ nativeFetch: true }) flag to opt into using undici for the Web Fetch polyfills instead of the @remix-run/web-* packages. This change has a few primary benefits:
undici, so beware of "breaking bug fixes" and keep an eye on any advanced fetch API interactions you're performing in your appundici may have different behavior by design -- most notably, undici's garbage collection behavior differs and you are required to consume all fetch response bodies to avoid a memory leak in your appundici is the fetch implementation used by node internally, it should better prepare Remix apps to more smoothly drop the polyfill to use the built-in Node.js APIs on node 20+future.unstable_singleFetch flag (#8773, #9073, #9084, #9272)@remix-run/node - Add a new installGlobals({ nativeFetch: true }) flag to opt-into using undici as the fetch polyfill instead of @remix-run/web-* (#9106, #9111, #9198)@remix-run/server-runtime - Add ResponseStub header interface and deprecate the headers export when Single Fetch is enabled (#9142)create-remix - Allow . in repo name when using --template flag (#9026)@remix-run/dev - Improve getDependenciesToBundle resolution in monorepos (#8848)@remix-run/dev - Fix SPA mode when Single Fetch is enabled by using streaming entry.server (#9063)@remix-run/dev - Vite: added sourcemap support for transformed routes (#8970)@remix-run/dev - Update links printed to the console by the Remix CLI/Dev Server to point to updated docs locations (#9176)@remix-run/server-runtime - Handle redirects created by handleDataRequest (#9104)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/testingFull Changelog: v2.8.1...v2.9.0
Date: 2024-03-07
@remix-run/dev - Vite: Support reading from Vite config when running remix reveal and remix routes CLI commands (#8916)@remix-run/dev - Vite: Clean up redundant client route query strings on route JavaScript files in production builds (#8969)@remix-run/dev - Vite: Add vite commands to Remix CLI --help output (#8939)@remix-run/dev - Vite: Fix support for build.sourcemap option in Vite config (#8965)@remix-run/dev - Vite: Fix error when using Vite's server.fs.allow option without a client entry file (#8966)@remix-run/react - Strengthen the internal LayoutComponent type to accept limited children (#8910)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/testingFull Changelog: v2.8.0...v2.8.1
Date: 2024-02-28
@remix-run/dev - Vite: Pass resolved viteConfig to Remix Vite plugin's buildEnd hook (#8885)@remix-run/dev - Mark Layout as browser safe route export in esbuild compiler (#8842)@remix-run/dev - Vite: Silence build warnings when dependencies include "use client" directives (#8897)@remix-run/dev - Vite: Fix serverBundles issue where multiple browser manifests are generated (#8864)@remix-run/dev - Vite: Support custom build.assetsDir option (#8843)@remix-run/react - Fix the default root ErrorBoundary component so it leverages the user-provided Layout component (#8859)@remix-run/react - Fix the default root HydrateFallback component so it leverages any user-provided Layout component (#8892)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/testingFull Changelog: v2.7.2...v2.8.0
Date: 2024-02-21
@remix-run/dev - Vite: Fix error when building projects with .css?url imports (#8829)Date: 2024-02-20
@remix-run/cloudflare-pages - Fix breaking change and restore Cloudflare event context fields in getLoadContext argument for backwards compatibility (#8819)Date: 2024-02-20
We're excited to announce that support for Vite is now stable in Remix 2.7.0! Ever since the initial unstable release of Remix Vite, weāve been hard at work refining and extending it over the past few months with help from all of our early adopters and community contributors. This also means that Vite-only features such as SPA Mode, Server Bundles, and basename support are now officially stable as well š.
For more information, check out the blog post and the Vite docs.
Layout ExportWe've found that it's super common to create your own component in your root route to hold the shared layout/app shell between your Component/ErrorBoundary/HydrateFallback. This is so common (and can also cause some minor edge-case issues such as a FOUC on hydration) that we've incorporated this as a first-class API in 2.7.0.
You can now export an optional Layout component from your root route which will be provided your route component, ErrorBoundary, or HydrateFallback as it's children. For more information, please see the Layout docs and the RFC.
React Router has long supported a basename config that allows you to serve your app within a subpath such as http://localhost/myapp/* without having to include the /myapp segment in all of your route paths. This was originally omitted from Remix because v1 nested folders file-convention made it pretty easy to put your route files in a routes/myapp/ folder, giving you the same functionality. There has also been an open proposal from the community to add this functionality.
Two things have since changed that made us reconsider the lack of basename support:
myapp. compared to the nested folder conventionbase config which is often (and easily) confused with the concept of a React Router basename (when in reality it's more aligned with the old Remix publicPath config)In 2.7.0 we've added support for a basename in the Vite plugin config. For more information, please check out the basename docs.
Note: This is a Vite-only feature and is not available via the esbuild compiler.
ā ļø This is a breaking change for projects relying on Cloudflare support from the unstable Vite plugin
The Cloudflare preset (unstable_cloudflarePreset) as been removed and replaced with a new Vite plugin:
import {
unstable_vitePlugin as remix,
- unstable_cloudflarePreset as cloudflare,
+ cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from "@remix-run/dev";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
+ remixCloudflareDevProxy(),
+ remix(),
- remix({
- presets: [cloudflare()],
- }),
],
- ssr: {
- resolve: {
- externalConditions: ["workerd", "worker"],
- },
- },
});
A few notes on the new plugin:
remixCloudflareDevProxy must come before the remix plugin so that it can override Vite's dev server middleware to be compatible with Cloudflare's proxied environmentremixCloudflareDevProxy can set ssr.resolve.externalConditions to be workerd-compatible for youremixCloudflareDevProxy accepts a getLoadContext function that replaces the old getRemixDevLoadContextnightly version that required getBindingsProxy or getPlatformProxy, that is no longer requiredgetBindingsProxy or getPlatformProxy should now be passed to remixCloudflareDevProxy instead@remix-run/react - Allow an optional Layout export from the root route (#8709)@remix-run/cloudflare-pages - Make getLoadContext optional for Cloudflare Pages (#8701)
(context) => ({ env: context }), which is what we used to have in all the templates@remix-run/dev - Vite: Cloudflare Proxy as a Vite plugin (#8749)
@remix-run/dev - Vite: Add a new basename option to the Vite plugin, allowing users to set the internal React Router basename in order to to serve their applications underneath a subpath (#8145)@remix-run/dev - Vite: Stabilize the Remix Vite plugin, Cloudflare preset, and all related types by removing all unstable_ / Unstable_ prefixes (#8713)
@remix-run/dev - Vite: Stabilize "SPA Mode" by renaming the Remix vite plugin config from unstable_ssr -> ssr (#8692)@remix-run/express - Use req.originalUrl instead of req.url so that Remix sees the full URL (#8145)
@remix-run/react - Fix a bug with SPA mode when the root route had no children (#8747)@remix-run/server-runtime - Add a more specific error if a user returns a defer response from a resource route (#8726)@remix-run/dev - Always prepend DOCTYPE in SPA mode entry.server.tsx, can opt out via remix reveal (#8725)@remix-run/dev - Fix build issue in SPA mode when using a basename (#8720)@remix-run/dev - Fix type error in Remix config for synchronous routes function (#8745)@remix-run/dev - Vite: Fix issue where client route file requests fail if search params have been parsed and serialized before reaching the Remix Vite plugin (#8740)@remix-run/dev - Vite: Validate that the MDX Rollup plugin, if present, is placed before Remix in Vite config (#8690)@remix-run/dev - Vite: Fix issue resolving critical CSS during development when the current working directory differs from the project root (#8752)@remix-run/dev - Vite: Require version 5.1.0 to support .css?url imports (#8723)@remix-run/dev - Vite: Support Vite 5.1.0's .css?url imports (#8684)@remix-run/dev - Vite: Enable use of vite preview to preview Remix SPA applications (#8624)
npm run start has been renamed to npm run preview which uses vite preview instead of a standalone HTTP server such as http-server or serv-cli@remix-run/dev - Vite: Remove the ability to pass publicPath as an option to the Remix vite plugin (#8145)
publicPathbase config so we now set the Remix publicPath from the Vite base config@remix-run/dev - Vite: Enable HMR for .md and .mdx files (#8711)@remix-run/dev - Vite: reliably detect non-root routes in Windows (#8806)@remix-run/dev - Vite: Pass remixUserConfig to preset remixConfig hook (#8797)@remix-run/dev - Vite: Ensure CSS file URLs that are only referenced in the server build are available on the client (#8796)@remix-run/dev - Vite: fix server exports dead-code elimination for routes outside of app directory (#8795)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/testingFull Changelog: v2.6.0...v2.7.0
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 - Add future.v3_throwAbortReason flag to throw request.signal.reason when a request is aborted instead of an Error such as new Error("query() call aborted: GET /path") (#8251)@remix-run/server-runtime - Unwrap thrown Response's from entry.server into ErrorResponse's and preserve the status code (#8577)
@remix-run/dev - Vite: Add manifest option to Vite plugin to enable writing a .remix/manifest.json file to the build directory (#8575)
build/server/bundles.json file has been superseded by the more general build/.remix/manifest.jsonmanifest 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 if build.manifest is enabled within the Vite config (#8599)
ā ļø This is a breaking change for consumers of Vite's manifest.json files
To explicitly enable generation of Vite manifest files, you must set build.manifest to true in your Vite config:
export default defineConfig({
build: { manifest: true },
// ...
});
@remix-run/dev - Vite: Add new buildDirectory option with a default value of "build" (#8575)
ā ļø This is a breaking change for consumers of the Vite plugin that were using the assetsBuildDirectory and serverBuildDirectory options
This replaces the old assetsBuildDirectory and serverBuildDirectory options which defaulted to "build/client" and "build/server" respectively
The Remix Vite plugin now builds into a single directory containing client and server 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 to build/.vite directory rather than being nested within build/client and build/server directories (#8599)
manifest.json filesmanifest.jsonbuild/.vite/client-manifest.json and build/.vite/server-manifest.json, or build/.vite/server-{BUNDLE_ID}-manifest.json when using server bundles@remix-run/dev - Vite: Remove unstable prefix from serverBundles option (#8596)
@remix-run/dev - Vite: Add --sourcemapClient and --sourcemapServer flags to remix vite:build (#8613)
--sourcemapClient, --sourcemapClient=inline, or --sourcemapClient=hidden--sourcemapServer, --sourcemapServer=inline, or --sourcemapServer=hidden@remix-run/dev - Vite: Validate IDs returned from the serverBundles function to ensure they only contain alphanumeric characters, hyphens and underscores (#8598)
@remix-run/dev - Vite: Fix "could not fast refresh" false alarm (#8580)
meta for fast refresh, which removes the false alarm.@remix-run/dev - Vite: Cloudflare Pages support (#8531)
@remix-run/dev - Vite: Add getRemixDevLoadContext option to Cloudflare preset (#8649)
@remix-run/dev - Vite: Remove undocumented backwards compatibility layer for Vite v4 (#8581)
@remix-run/dev - Vite: Add presets option to ease integration with different platforms and tools (#8514)
@remix-run/dev - Vite: Add buildEnd hook (#8620)
@remix-run/dev - Vite: Add mode field into generated server build (#8539)
@remix-run/dev - Vite: Reduce network calls for route modules during HMR (#8591)
@remix-run/dev - Vite: Export Unstable_ServerBundlesFunction and Unstable_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/testingFull Changelog: v2.5.1...v2.6.0
Date: 2024-01-18
create-remix - high-contrast fg/bg for header colors (#8503)
bgWhite and whiteBright are the same color in many terminal colorthemes, which was causing it to render as illegible white-on-white@remix-run/dev - Add isSpaMode 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)
remix vite:build --profile to generate a .cpuprofile that can be shared or uploaded to speedscope.appp + enter to start a new profiling session or stop the current sessionremix vite:dev --profile to initialize the dev server with a running profiling session@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 leftover unstable_ prefix from Blocker/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/testingFull 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";
},
}),
],
});
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 with isbot@4 released on 1/1/2024 (#8415)
remix dev will now add "isbot": "^4" to package.json instead of using latestentry.server files to work with both isbot@3 and isbot@4 for backwards-compatibility with Remix apps that have pinned isbot@3isbot@4 moving forward via create-remix@remix-run/dev: Vite - Fix HMR issues when altering exports for non-rendered routes (#8157)@remix-run/dev: Vite - Default NODE_ENV to "production" when running remix vite:build command (#8405)@remix-run/dev: Vite - Remove Vite plugin config option serverBuildPath in favor of separate serverBuildDirectory and serverBuildFile 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 with import.meta.hot from the existing Remix compiler (#8459)@remix-run/server-runtime: Updated cookie dependency to 0.6.0 to inherit support for the Partitioned 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/testingFull Changelog: v2.4.1...v2.5.0
Date: 2023-12-22
@remix-run/dev: Vite - Remove unstable_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 calling ssrLoadModule 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 - Add vite:dev and vite: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 and build 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)
.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'answer.server.ts does provide the isDateType export, but Remix was replacing .server modules with empty modules (export {}) for the client build.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@remix-run/dev: Vite - Preserve names for exports from .client modules (#8200)
.server modules, the main idea is not to prevent code from leaking into the server build since the client build is already public.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).client modules with empty modules would cause the build to fail as ESM named imports are statically analyzed
undefined@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 server loader errors through serverLoader in hydrating clientLoader's (#8304)
@remix-run/react Re-export Response helpers (defer/json/redirect/redirectDocument) through @remix-run/react for use in clientLoader/clientAction (#8351)
@remix-run/server-runtime: Add optional error to ServerRuntimeMetaArgs type to align with MetaArgs (#8238)
create-remix: Switch to using @remix-run/web-fetch instead of node-fetch inside the create-remix CLI (#7345)
remix-serve: Use node fileURLToPath 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/testingFull 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:
future.v3_relativeSplatPathWe 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.
clientLoader/clientAction/HydrateFallback route exports (#8173)future.v3_relativeSplatPath flag to implement a breaking bug fix to relative routing when inside a splat route (#8216)DataFunctionArgs in favor of LoaderFunctionArgs/ActionFunctionArgs (#8173)
clientLoader/clientActon functions have serverLoader/serverAction parameters which differentiate ClientLoaderFunctionArgs/ClientActionFunctionArgs.server directories from client build (#8154)@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 to vite.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 the public directory (#8077)
build/server rather than build, and the client is now compiled into build/client rather than public@remix-run/dev: Upgrade Vite peer dependency range to v5 (#8172)
@remix-run/dev: Support HMR for routes with handle 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 undocumented legacyCssImports 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 default entry.{client,server}.tsx within pnpm workspaces on Windows (#8057)
@remix-run/dev: Remove unstable_createViteServer and unstable_loadViteServerBuild which were only minimal wrappers around Vite's createServer and ssrLoadModule 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 to vite.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)
.server modules, the main idea is not to prevent code from leaking into the server build since the client build is already public.client modules without compilation failing and then rely on runtime checks to determine if the code is running on the server or client.client modules with empty modules would cause the build to fail as ESM named imports are statically analyzed
@remix-run/dev: Add @remix-run/node to Vite's optimizeDeps.include array (#8177)
@remix-run/dev: Improve Vite plugin performance (#8121)
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-run/dev: Fix request 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/testingFull Changelog: v2.3.1...v2.4.0
Date: 2023-11-22
@remix-run/dev: Support nonce prop on LiveReload 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 from public directory in Vite build (#8039)
assetsBuildDirectory was deeply nested within the public directorycreate-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/testingFull Changelog: v2.3.0...v2.3.1
Date: 2023-11-16
useBlockerWe'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.
unstable_flushSync APIWe'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();
}
unstable_ prefix from the useBlocker hook (#7882)unstable_flushSync option to useNavigate/useSubmit/fetcher.load/fetcher.submit to opt-out of React.startTransition and into ReactDOM.flushSync for state updates (#7996)@remix-run/react: Add missing modulepreload for the manifest (#7684)@remix-run/server-runtime: Updated cookie dependency from 0.4.1 to 0.5.0 to inherit support for Priority attribute in Chrome (#6770)@remix-run/dev: Fix FutureConfig type (#7895)vite compiler:
LiveReload component in Vite dev (#7919)LiveReload component after Scripts in Vite dev (#7919)react-refresh/babel resolution for custom server with pnpm (#7904).jsx files without manual React import in Vite (#7888)development and production modes are present (e.g. @mdx-js/rollup) (#7911)process.env.NODE_ENV values other than "development" in Vite dev (#7980)/@fs (#7913)
server.fs.allow@remix-run/react (#7926)
remix-react-proxy plugin does not process default client and server entry files since those come from within node_modulesError: You must render this element inside a <Remix> elementdefer in Vite dev server (#7842)Set-Cookie headers in Vite dev server (#7843)process.env from .env files on the server in Vite dev (#7958)8cd31d65)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/testingFull 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
@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 developmentcreateRequestHandler: Now also allows the build argument to be a function that will be used to dynamically load new builds for each request during developmentnpm interopPer this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors:
useFetcher({ key: string }), which allows you to access the same fetcher instance from different components in your application without prop-drillinguseFetchers so that they can be looked up by keyForm and useSubmit now support optional navigate/fetcherKey props/params to allow kicking off a fetcher submission under the hood with an optionally user-specified key
<Form method="post" navigate={false} fetcherKey="my-key">submit(data, { method: "post", navigate: false, fetcherKey: "my-key" })useFetchers() or useFetcher({ key }) to look it up elsewherePer 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.
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 an idle stateuseFetchers() after completion - they served no purpose in there since you can access the data via useFetcher().dataidle state
useFetchers while in-flight so you can still access pending/optimistic data after unmountkey, then it's result will be processed, even if the originating fetcher was unmountedvite support (#7590)key APIs and navigate/fetcherKey params for navigational APIs (#10960)future.v3_fetcherPersist flag (#10962)@remix-run/express: Allow the Express adapter to work behind a proxy when using app.enable('trust proxy') (#7323)
req.get('host') to construct the Remix Request, but that does not respect X-Forwarded-Hostreq.hostname which will respect X-Forwarded-Host@remix-run/react: Fix warning that could be inadvertently logged when using route files with no default export (#7745)create-remix: Support local tarballs with a .tgz extension which allows direct support for pnpm pack tarballs (#7649)create-remix: Default the Remix app version to the version of create-remix being used (#7670)
npm create remix@nightlycreate-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/testingFull 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.
createRemixStubAfter 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.
ā ļø Please note that this did involve 1 small breaking change - the <RemixStub remixConfigFuture> prop has been renamed to <RemixStub future> to decouple the future prop from a specific file location.
@remix-run/testing createRemixStub helper (#7647)JSON.parse(JSON.stringify(x)) in SerializeFrom (#7605)
undefined after serialization are now omitted since JSON.stringify |> JSON.parse will omit them. See test cases for examplesmeta object when tagName is specified (#7594)route.lazy routes (#7576)useMatches wrapper to fix UIMatch typings (#7551)@remix-run/cloudflare - sourcemap takes into account special chars in output file (#7574)@remix-run/express - Flush headers for text/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/testingFull Changelog: v2.0.1...v2.1.0
Date: 2023-09-21
getDependenciesToBundle to handle ESM packages without main exports (#7272)
package.json in their exports field so that their path can be resolvedserverBuildPath extension is .cjs (#7180)remix-serve and manual mode (remix dev --manual) (#7487)
require cache, remix-serve now correctly re-imports new server changes in CJSbuild.assets being undefined and crashing when reading build.assets.versionUIMatch for handle field (#7464)route.lazy (#7498)ErrorResponse instead of just an Error when submitting to a route without an action (#7423)@remix-run/web-fetch (#7477)crypto.randomBytes to crypto.webcrypto.getRandomValues for file session storage ID generation (#7203)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.
Remix v2 has upgraded it's minimum version support for React and Node and now officially requires:
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)
future.v2_dev instead of just the boolean value (i.e., future.v2_dev.port), you can lift them into a root dev object in your remix.config.jsv2_errorBoundary - Removed CatchBoundary in favor of a singular ErrorBoundary (#6906)v2_headers - Altered the logic for headers in nested route scenarios (#6979)v2_meta - Altered the return format of meta() (#6958)v2_normalizeFormMethod - Normalize formMethod 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
browserBuildDirectory to assetsBuildDirectory (#6900)devServerBroadcastDelay (#7063)devServerPort to dev.port (000457e0)
1.x release, your config flag will be future.v2_dev.port, but on a stable 2.x release it will be dev.portserverModuleFormat from cjs to esm (#6949)serverBuildTarget (#6896)serverBuildDirectory to serverBuildPath (#6897)serverNodeBuiltinsPolyfill (#6911@remix-run/react
useTransition (#6870)fetcher.type and flattened fetcher.submission (#6874)
<fetcher.Form method="get"> is now more accurately categorized as state:"loading" instead of state:"submitting" to better align with the underlying GET requestimagesrcset/imagesizes (#6936)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
browserNodeBuiltinsPolyfill (#7269)postcss and tailwind flags (#6909)@remix-run/cloudflare
@remix-run/dev
REMIX_DEV_HTTP_ORIGIN in favor of REMIX_DEV_ORIGIN (#6963)REMIX_DEV_SERVER_WS_PORT in favor of dev.port or --port (#6965)--no-restart/restart flag in favor of --manual/manual (#6962)--scheme/scheme and --host/host in favor of REMIX_DEV_ORIGIN instead (#6962)codemod command (#6918)@remix-run/eslint-config
@remix-run/netlify
@remix-run/netlify adapter has been removed in favor of the Netlify official adapters (#7058)@remix-run/node
fetch is no longer polyfilled by default - apps must call installGlobals() 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)sourceMapSupport.install() to setup source map support@remix-run/react
unstable_shouldReload in favor of shouldRevalidate (#6865)@remix-run/serve
@remix-run/vercel
@remix-run/vercel adapter has been removed in favor of out of the box functionality provided by Vercel (#7035)create-remix
isTypeScript to remix.init script (#7099)remix
V2_ prefixes from future.v2_meta types as they are now the default behavior (#6958)
V2_MetaArgs -> MetaArgsV2_MetaDescriptor -> MetaDescriptorV2_MetaFunction -> MetaFunctionV2_MetaMatch -> MetaMatchV2_MetaMatches -> MetaMatchesV2_ServerRuntimeMetaArgs -> ServerRuntimeMetaArgsV2_ServerRuntimeMetaDescriptor -> ServerRuntimeMetaDescriptorV2_ServerRuntimeMetaFunction -> ServerRuntimeMetaFunctionV2_ServerRuntimeMetaMatch -> ServerRuntimeMetaMatchV2_ServerRuntimeMetaMatches -> ServerRuntimeMetaMatchesunknown over any and to align with underlying React Router types (#7319):
useMatches() return type from RouteMatch to UIMatchLoaderArgs/ActionArgs to LoaderFunctionArgs/ActionFunctionArgsAppData changed from any to unknownLocation["state"] (useLocation.state) changed from any to unknownUIMatch["data"] (useMatches()[i].data) changed from any to unknownUIMatch["handle"] (useMatches()[i].handle) changed from { [k: string]: any } to unknownFetcher["data"] (useFetcher().data) changed from any to unknownMetaMatch.handle (used in meta()) changed from any to unknownAppData/RouteHandle are no longer exported as they are just aliases for unknowncreate-remix CLI (#6887)
--template flag and our ever-growing list of available templates--overwrite flag (#7062)bun package manager (#7074)build.mode (#6964)serverNodeBuiltinsPolyfill.globals/browserNodeBuiltinsPolyfill.globals (#7269)redirectDocument utility to redirect via a fresh document load (#7040, #6842)error to meta params so you can render error titles, etc. (#7105)unstable_createRemixStub now supports adding meta/links functions on stubbed Remix routes (#7186)
unstable_createRemixStub no longer supports the element/errorElement properties on routes. You must use Component/ErrorBoundary to match what you would export from a Remix route module.route.lazy method internally to load route modules on navigations (#7133)@remix-run/node atob/btoa polyfills in favor of the built-in versions (#7206)@remix-run/dev package from the contents of the @remix-run/css-bundle package (#6982)
@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.remix-serve now picks an open port if 3000 is taken (#7278)
PORT env var is set, remix-serve will use that portremix-serve picks an open port (3000 unless that is already taken)react-router-dom@6.16.0@remix-run/router@1.9.0@remix-run/web-fetch@4.4.0@remix-run/web-file@3.1.0@remix-run/web-stream@1.1.0create-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