This page lists all releases/release notes for Remix v2.x releases. 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
- Remix v2 Releases
- v2.17.4
- v2.17.3
- v2.17.2
- v2.17.1
- v2.17.0
- v2.16.8
- v2.16.7
- v2.16.6
- v2.16.5
- v2.16.4
- v2.16.3
- v2.16.2
- v2.16.1
- v2.16.0
- v2.15.3
- v2.15.2
- v2.15.1
- v2.15.0
- v2.14.0
- v2.13.1
- v2.13.0
- v2.12.1
- v2.12.0
- v2.11.2
- v2.11.1
- v2.11.0
- v2.10.3
- v2.10.2
- v2.10.1
- v2.10.0
- v2.9.2
- v2.9.1
- v2.9.0
- v2.8.1
- v2.8.0
- 2.7.2
- 2.7.1
- v2.7.0
- v2.6.0
- v2.5.1
- v2.5.0
- v2.4.1
- v2.4.0
- v2.3.1
- v2.3.0
- v2.2.0
- v2.1.0
- v2.0.1
- v2.0.0
Date: 2026-01-12
- Update internal React Router versions to pick up security patches in 6.30.3
Full Changelog: v2.17.3...v2.17.4
Date: 2026-01-07
This release addresses 2 security vulnerabilities:
- CSRF in React Router Action/Server Action Request Processing
- React Router SSR XSS in ScrollRestoration
@remix-run/dev- Updatevalibotto address CVE (GHSA-vqpr-j7v3-hqw9)@remix-run/react- Escape HTML during SSR for in<ScrollRestoration>keys@remix-run/server-runtime- Add additional layer of CSRF protection by rejecting submissions to UI routes from external origins
Full Changelog: v2.17.2...v2.17.3
Date: 2025-10-29
This release addresses 1 security vulnerability:
@remix-run/deno- Validate format of incoming session ids increateFileSessionStorage@remix-run/node- Validate format of incoming session ids increateFileSessionStorage
Full Changelog: v2.17.1...v2.17.2
Date: 2025-09-17
This release addresses 1 security vulnerability:
remix-serve- Updatecompressionandmorgandependencies to latest versions@remix-run/eslint-config- Update deprecation warning with proper link to sample v2 eslint config file@remix-run/react- Escape HTML inmeta()JSON-LD content
Full Changelog: v2.17.0...v2.17.1
Date: 2025-07-25
create-remix- Redirect users tocreate-react-routerinstead ofcreate-remix(#10686, #10688)- Remix v2 is in maintenance mode so we don't want new Remix apps to be created
Full Changelog: v2.16.8...v2.17.0
Date: 2025-05-29
create-remix- Updatetar-fs(#10638)
Full Changelog: v2.16.7...v2.16.8
Date: 2025-05-19
@remix-run/dev- Updatevite-node(#10611)
Full Changelog: v2.16.6...v2.16.7
Date: 2025-05-08
@remix-run/react- Upgradeturbo-streamto2.4.1(#9973)@remix-run/react- Fixwindow is not definederror in Single Fetch when server-rendering<PrefetchPageLinks>(#10601)@remix-run/serve- Remove redundant@remix-run/node/installimport fromremix-servebecause it manually callsinstallGlobalsseparately (#10306)
Full Changelog: v2.16.5...v2.16.6
Date: 2025-04-09
@remix-run/node- Bumpundicito version6.21.2to address a security advisory (#10562)
Full Changelog: v2.16.4...v2.16.5
Date: 2025-03-31
@remix-run/server-runtime- Bumpcookiedependency from^0.6.0 -> ^0.7.2to 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 ofx-forwarded-hostheader to prevent potential security issues (#10553)
Full Changelog: v2.16.2...v2.16.3
Date: 2025-03-19
@remix-run/react- FixshouldRevalidatebehavior forclientLoader-only routes inssr:trueapps (#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- Whenfuture.v3_routeConfigis enabled, fix errors evaluatingroutes.tswhen multiple copies of@remix-run/devare present (#10524)@remix-run/dev- Fix Vite import analysis of@remix-run/reactfailing 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)- On navigations to undiscovered routes, this mismatch will trigger a document reload of the destination path
- On
fetchercalls to undiscovered routes, this mismatch will trigger a document reload of the current path - While performing Eager Route Discovery on rendered
<Link>components, mismatches will result in a no-op
Full 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 ofSet-Cookieheaders if also returned fromheaders(#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 tofalse(#10358)@remix-run/react- Throw unwrapped Single Fetchredirectto align with pre-Single Fetch behavior (#10317)
Full Changelog: v2.15.1...v2.15.2
Date: 2024-12-09
create-remix- Movefs-extrafromdevDependenciestodependencies(#10300)
Full Changelog: v2.15.0...v2.15.1
Date: 2024-11-19
-
Stabilize the
future.v3_routeConfigfuture flag, replacingfuture.unstable_routeConfig. This enables support forroutes.tsto assist with the migration to React Router v7. (#10236)Note that if you had already enabled the
future.unstable_routeConfigflag, your route config inapp/routes.tsis no longer defined via theroutesexport 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
SerializeFromin 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.tsbehindfuture.unstable_routeConfigflag 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.tsfile in the app directory. Support forroutes.tsand 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-runscope, these new packages only exist to keep the code inroutes.tsas similar as possible to the equivalent code for React Router v7.When the
unstable_routeConfigfuture 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.tsfile:remix({ future: { unstable_routeConfig: true, }, });
A minimal
routes.tsfile 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)
- Add
@deprecatedannotations tojson/deferutilities
- Add
@remix-run/react- FixdefaultShouldRevalidatevalue when using Single Fetch (#10139)@remix-run/server-runtime- Update externally-accessed resource routes warning to covernullusage 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/testing
Full Changelog: v2.13.1...v2.14.0
Date: 2024-10-11
@remix-run/dev- Revertfuture.v3_optimizeDepsback tofuture.unstable_optimizeDepsas 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)⚠️ This flag was not intended to stabilize in Remix v2 and was reverted back tofuture.unstable_optimizeDepsin2.13.1
future.unstable_lazyRouteDiscovery→future.v3_lazyRouteDiscovery(Docs)future.unstable_singleFetch→future.v3_singleFetch(Docs)
- Stabilize React Router APIs in Remix (#9980)
- Adopt stabilized React Router APIs internally
- Single Fetch:
unstable_dataStrategy->dataStrategy - Lazy Route Discovery:
unstable_patchRoutesOnNavigation->patchRoutesOnNavigation
- Single Fetch:
- Stabilize public-facing APIs
- Single Fetch:
unstable_data()->data() unstable_viewTransition->viewTransition(Link,Form,navigate,submit)unstable_flushSync>-><Link viewTransition>(Link,Form,navigate,submit,useFetcher)
- Single Fetch:
- Adopt stabilized React Router APIs internally
- Stabilize future flags (#10072, #10092)
future.unstable_lazyRouteDiscovery->future.v3_lazyRouteDiscoveryfuture.unstable_optimizeDeps->future.v3_optimizeDepsfuture.unstable_singleFetch->future.v3_singleFetch
@remix-run/dev- Stop passingrequest.signalas therenderToReadableStreamsignalto abort server rendering for cloudflare/deno runtimes because by the time thatrequestis aborted, aborting the rendering is useless because there's no way for React to flush down the unresolved boundaries (#10047)- This has been incorrect for some time, but only recently exposed due to a bug in how we were aborting requests when running via
remix vite:devbecause we were incorrectly aborting requests after successful renders - which was causing us to abort a completed React render, and try to close an already closedReadableStream - This has likely not shown up in any production scenarios because cloudflare/deno production runtimes are (correctly) not aborting the
request.signalon successful renders - The built-in
entry.serverfiles no longer pass asignaltorenderToReadableStreambecause adding a timeout-based abort signal to the default behavior would constitute a breaking change - Users can configure this abort behavior via their own
entry.serverviaremix reveal entry.server, and the template entry.server files have been updated with an example approach for newly created Remix apps
- This has been incorrect for some time, but only recently exposed due to a bug in how we were aborting requests when running via
@remix-run/express- Fix adapter logic for abortingrequest.signalso we don't incorrectly abort on thecloseevent for successful requests (#10046)@remix-run/react- Fix bug withclientLoader.hydratein 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/testing
Full Changelog: v2.12.1...v2.13.0
Date: 2024-09-19
@remix-run/dev- Properly abortrequest.signalduringvite devwhen the node response is closed (#9976)@remix-run/dev- CSS imports with?inline,?inline-cssand?raware no longer incorrectly injected during SSR in development (#9910)@remix-run/server-runtime: Single Fetch: Fix types whenloader,action,clientLoader, orclientActionreturn a mixture of bare objects,json(...),defer(...), andunstable_data(...). (#9999)@remix-run/node/@remix-run/cloudflare/@remix-run/deno- Single Fetch: Re-exportinterface Futurethrough runtime packages so thatpnpmdoesn't complain about@remix-run/server-runtimenot being a dependency (#9982)- If you've already opted into Single Fetch, you can change your Single Fetch type augmentation in
vite.config.tsto augment@remix-run/node(orcloudflare/deno) instead of@remix-run/server-runtime
- If you've already opted into Single Fetch, you can change your Single Fetch type augmentation in
Full 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.
- If you were already using single-fetch types:
- Remove the
"@remix-run/react/future/single-fetch.d.ts"override fromtsconfig.json>compilerOptions>types - Remove
defineLoader,defineAction,defineClientLoader,defineClientActionhelpers from your route modules - Replace
UIMatch_SingleFetchtype helper with the originalUIMatch - Replace
MetaArgs_SingleFetchtype helper with the originalMetaArgs
- Remove the
Then 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:
- If a route opts out of revalidation via
shouldRevalidate - If a route defines a
clientLoader- If you call
serverLoader()from yourclientLoader, that will make a separate HTTP call for just that route loader - i.e.,GET /a/b/c.data?_routes=routes/afor aclientLoaderinroutes/a.tsx
- If you call
When one or more routes are excluded from the Single Fetch call, the remaining routes that have loaders are included as query params. For example, 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- Newfuture.unstable_optimizeDepsflag for automatic dependency optimization (#9921)
@remix-run/dev- Handle circular dependencies in modulepreload manifest generation (#9917)@remix-run/dev- Fixdest already existsbuild 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 defaultHydrateFallbackconsole 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)- Reverts the logic originally added in Remix
v1.18.0via #6409 - This was added to resolve an issue that could arise when doing quick back/forward history navigations while JS was loading which would cause a mismatch between the server matches and client matches: #1757
- This specific hydration issue would then cause this React v17 only looping issue: #1678
- The URL comparison that we added in
1.18.0turned out to be subject to false positives of it's own which could also put the user in looping scenarios - Remix v2 upgraded it's minimal React version to v18 which eliminated the v17 hydration error loop
- React v18 handles this hydration error like any other error and does not result in a loop
- So we can remove our check and thus avoid the false-positive scenarios in which it may also trigger a loop
- Reverts the logic originally added in Remix
@remix-run/react- Lazy Route Discovery: Sort/__manifestquery 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 aturbo-streambody into 304 responses (#9941)@remix-run/server-runtime- Single Fetch: Change content type on.datarequests totext/x-scriptto 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 remix-run/react-router#11883) (#9860)⚠️ This changes the return signature of the internal/__manifestendpoint since we no longer need thenotFoundPathsfield
@remix-run/react- Fog of War: Update to use renamedunstable_patchRoutesOnNavigationfunction in RR (see remix-run/react-router#11888) (#9860)@remix-run/server-runtime- Single Fetch: Fix redirects when abasenameis present (#9848)@remix-run/server-runtime- Single Fetch: Updateturbo-streamtov2.3.0(#9856)- Stabilize object key order for serialized payloads
- Remove memory limitations payloads sizes
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
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).
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:
- The
headers()function will let you control header merging for both document and data requests - In most cases, if you were returning
json()/defer()without setting a customstatusorheaders, you can just remove those utility functions and return the raw data- ❌
return json({ data: "whatever" }); - ✅
return { data: "whatever" };
- ❌
- If you were returning a custom
statusorheadersviajson/defer:- We've added a new API-compatible
unstable_datautility that will let you send backstatus/headersalongside your raw data without having to encode it into aResponse
- We've added a new API-compatible
- We will be removing both
jsonanddeferin the next major version, but both should still work in Single Fetch in v2 to allow for incremental adoption of the new behavior
response stub, you'll need to move those changes back to leveraging the headers() API.
@remix-run/dev- Fog of War: Renamefuture.unstable_fogOfWartofuture.unstable_lazyRouteDiscoveryfor clarity (#9763)@remix-run/server-runtime- Add a newreplace(url, init?)alternative toredirect(url, init?)that performs ahistory.replaceStateinstead of ahistory.pushStateon client-side navigation redirects (#9764)@remix-run/server-runtime- Single Fetch: Add a newunstable_data()API as a replacement forjson/deferwhen customstatus/headersare needed (#9769)@remix-run/server-runtime- Single Fetch: RemoveresponseStubin favor ofheaders(#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: Addundefinedto theuseRouteLoaderDatatype 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/testing
Full 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): Proxyrequest.signalthroughdataStrategyforloadercalls to fix cancellation (#9738)@remix-run/react- Single Fetch (unstable): Adopt React Router's stabilizedfuture.v7_skipActionErrorRevalidationunder the hood (#9706)- This stabilizes the
shouldRevalidateparameter fromunstable_actionStatustoactionStatus ⚠️ This might be a breaking change for your app if you have opted into single fetch and theunstable_actionStatusparameter
- This stabilizes 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.10.2...v2.10.3
Date: 2024-07-04
@remix-run/react- ForwardreftoForm(bdd04217)@remix-run/server-runtime- Fix bug withimmutableheaders on raw nativefetchresponses 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/testing
Full 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 withreloadDocument(#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/testing
Full 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}- Upgradeexpressdependency to^4.19.2(#9184)@remix-run/react- Don't prefetch serverloaderdata whenclientLoaderexists (#9580)@remix-run/react- Avoid hydration loops whenLayout/ErrorBoundaryrenders also throw (#9566)@remix-run/react- Fix a hydration bug when using child routes andHydrateFallbackcomponents with abasename(#9584)@remix-run/{server-runtime|react}- Single Fetch: Update toturbo-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 returningnullfrom 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/testing
Full 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: Fixdest already existserror when runningremix 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/nodefrom Vite plugin'soptimizeDeps.includelist 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=1imports in development (#9395)@remix-run/dev- Vite: Ensure Babel config files are not referenced when applying thereact-refreshBabel 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: AddundefinedtouseActionDatatype override (#9322)@remix-run/react- Single Fetch: Allow anonceto be set on single fetch stream transfer inline scripts via<RemixServer>(#9364)@remix-run/server-runtime- Single Fetch: Don't log thrown response stubs viahandleError(#9369)@remix-run/server-runtime- Single Fetch: Automatically wrap resource route naked object returns injson()for back-compat in v2 (and log deprecation warning) (#9349)@remix-run/server-runtime- Single Fetch: Passresponsestub 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/testing
Full 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'sssr.noExternaloption were being overridden by the Remix Vite plugin adding Remix packages to Vite'sssr.externaloption (#9301)@remix-run/react- Ignorefuture/*.d.tsfiles 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:
- Naked objects returned from
loader/actionfunctions are no longer automatically serialized to JSON responses- Instead, they'll be streamed as-is via
turbo-streamwhich allows direct serialization of more complex types such asPromise,Date,Mapinstances, and more - You will need to modify your
tsconfig.json'scompilerOptions.typesarray to infer types properly when using Single Fetch
- Instead, they'll be streamed as-is via
- The
headersexport is no longer used when Single Fetch is enabled in favor of a newresponsestub passed to yourloader/actionfunctions - The
json/defer/redirectutilities are deprecated when using Single Fetch (but still work mostly the same) - Actions no longer automatically revalidate on
4xx/5xxresponses - you can return a2xxto opt-into revalidation or useshouldRevalidate
Important
Single Fetch requires using undici as 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-fetch polyfill. 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:
- It will allow us to stop maintaining our own web-std-io fork in future versions of Remix
- It should bring us more in-line with spec compliance
⚠️ It is possible that some non-spec-compliant bugs in our fork will be "fixed" by moving toundici, so beware of "breaking bug fixes" and keep an eye on any advancedfetchAPI interactions you're performing in your app⚠️ In some cases,undicimay 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 app
- Because
undiciis the fetch implementation used bynodeinternally, it should better prepare Remix apps to more smoothly drop the polyfill to use the built-in Node.js APIs onnode20+
- New
future.unstable_singleFetchflag (#8773, #9073, #9084, #9272) @remix-run/node- Add a newinstallGlobals({ nativeFetch: true })flag to opt-into usingundicias the fetch polyfill instead of@remix-run/web-*(#9106, #9111, #9198)@remix-run/server-runtime- AddResponseStubheader interface and deprecate theheadersexport when Single Fetch is enabled (#9142)
create-remix- Allow.in repo name when using--templateflag (#9026)@remix-run/dev- ImprovegetDependenciesToBundleresolution in monorepos (#8848)@remix-run/dev- Fix SPA mode when Single Fetch is enabled by using streamingentry.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 byhandleDataRequest(#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/testing
Full Changelog: v2.8.1...v2.9.0
Date: 2024-03-07
@remix-run/dev- Vite: Support reading from Vite config when runningremix revealandremix routesCLI 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--helpoutput (#8939)@remix-run/dev- Vite: Fix support forbuild.sourcemapoption in Vite config (#8965)@remix-run/dev- Vite: Fix error when using Vite'sserver.fs.allowoption without a client entry file (#8966)@remix-run/react- Strengthen the internalLayoutComponenttype 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/testing
Full Changelog: v2.8.0...v2.8.1
Date: 2024-02-28
@remix-run/dev- Vite: Pass resolvedviteConfigto Remix Vite plugin'sbuildEndhook (#8885)
@remix-run/dev- MarkLayoutas browser safe route export inesbuildcompiler (#8842)@remix-run/dev- Vite: Silence build warnings when dependencies include"use client"directives (#8897)@remix-run/dev- Vite: FixserverBundlesissue where multiple browser manifests are generated (#8864)@remix-run/dev- Vite: Support custombuild.assetsDiroption (#8843)@remix-run/react- Fix the default rootErrorBoundarycomponent so it leverages the user-providedLayoutcomponent (#8859)@remix-run/react- Fix the default rootHydrateFallbackcomponent so it leverages any user-providedLayoutcomponent (#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/testing
Full Changelog: v2.7.2...v2.8.0
Date: 2024-02-21
@remix-run/dev- Vite: Fix error when building projects with.css?urlimports (#8829)
Date: 2024-02-20
@remix-run/cloudflare-pages- Fix breaking change and restore Cloudflare event context fields ingetLoadContextargument 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.
We'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:
- We switched to a flat-file based convention in v2, and it gets far less ergonomic to have to prefix all of your route files with
myapp.compared to the nested folder convention - We moved to Vite which has it's own
baseconfig which is often (and easily) confused with the concept of a React Routerbasename(when in reality it's more aligned with the old RemixpublicPathconfig)
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.
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:
remixCloudflareDevProxymust come before theremixplugin so that it can override Vite's dev server middleware to be compatible with Cloudflare's proxied environment- Because it is a Vite plugin,
remixCloudflareDevProxycan setssr.resolve.externalConditionsto beworkerd-compatible for you remixCloudflareDevProxyaccepts agetLoadContextfunction that replaces the oldgetRemixDevLoadContext- If you were using a
nightlyversion that requiredgetBindingsProxyorgetPlatformProxy, that is no longer required - Any options you were passing to
getBindingsProxyorgetPlatformProxyshould now be passed toremixCloudflareDevProxyinstead - This API also better aligns with future plans to support Cloudflare with a framework-agnostic Vite plugin that makes use of Vite's (experimental) Runtime API.
@remix-run/react- Allow an optionalLayoutexport from the root route (#8709)@remix-run/cloudflare-pages- MakegetLoadContextoptional for Cloudflare Pages (#8701)- Defaults to
(context) => ({ env: context }), which is what we used to have in all the templates - This gives parity with the Cloudflare preset for the Remix Vite plugin and keeps our templates leaner
- Defaults to
@remix-run/dev- Vite: Cloudflare Proxy as a Vite plugin (#8749)⚠️ This is a breaking change for projects relying on Cloudflare support from the unstable Vite plugin
@remix-run/dev- Vite: Add a newbasenameoption to the Vite plugin, allowing users to set the internal React Routerbasenamein 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 allunstable_/Unstable_prefixes (#8713)- While this is a breaking change for existing Remix Vite plugin consumers, now that the plugin has stabilized, there will no longer be any breaking changes outside of a major release. Thank you to all of our early adopters and community contributors for helping us get here! 🙏
@remix-run/dev- Vite: Stabilize "SPA Mode" by renaming the Remix vite plugin config fromunstable_ssr -> ssr(#8692)
@remix-run/express- Usereq.originalUrlinstead ofreq.urlso that Remix sees the full URL (#8145)- Remix relies on the knowing the full URL to ensure that server and client code can function together, and does not support URL rewriting prior to the Remix handler
@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 adeferresponse from a resource route (#8726)@remix-run/dev- Always prependDOCTYPEin SPA modeentry.server.tsx, can opt out via remix reveal (#8725)@remix-run/dev- Fix build issue in SPA mode when using abasename(#8720)@remix-run/dev- Fix type error in Remix config for synchronousroutesfunction (#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 version5.1.0to support.css?urlimports (#8723)@remix-run/dev- Vite: Support Vite5.1.0's.css?urlimports (#8684)@remix-run/dev- Vite: Enable use ofvite previewto preview Remix SPA applications (#8624)- In the SPA template,
npm run starthas been renamed tonpm run previewwhich usesvite previewinstead of a standalone HTTP server such ashttp-serverorserv-cli
- In the SPA template,
@remix-run/dev- Vite: Remove the ability to passpublicPathas an option to the Remix vite plugin (#8145)⚠️ This is a breaking change for projects using the unstable Vite plugin with apublicPath- This is already handled in Vite via the
baseconfig so we now set the RemixpublicPathfrom the Vitebaseconfig
@remix-run/dev- Vite: Enable HMR for.mdand.mdxfiles (#8711)@remix-run/dev- Vite: reliably detect non-root routes in Windows (#8806)@remix-run/dev- Vite: PassremixUserConfigto presetremixConfighook (#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/testing
Full 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- Addfuture.v3_throwAbortReasonflag to throwrequest.signal.reasonwhen a request is aborted instead of anErrorsuch asnew Error("query() call aborted: GET /path")(#8251)
-
@remix-run/server-runtime- Unwrap thrownResponse's fromentry.serverintoErrorResponse's and preserve the status code (#8577) -
@remix-run/dev- Vite: Addmanifestoption to Vite plugin to enable writing a.remix/manifest.jsonfile to the build directory (#8575)⚠️ This is a breaking change for consumers of the Vite plugin's "server bundles" feature- The
build/server/bundles.jsonfile 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
manifestoption
-
@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.tsxcomponent: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.manifestis enabled within the Vite config (#8599)-
⚠️ This is a breaking change for consumers of Vite'smanifest.jsonfiles -
To explicitly enable generation of Vite manifest files, you must set
build.manifesttotruein your Vite config:export default defineConfig({ build: { manifest: true }, // ... });
-
-
@remix-run/dev- Vite: Add newbuildDirectoryoption with a default value of"build"(#8575)-
⚠️ This is a breaking change for consumers of the Vite plugin that were using theassetsBuildDirectoryandserverBuildDirectoryoptions -
This replaces the old
assetsBuildDirectoryandserverBuildDirectoryoptions which defaulted to"build/client"and"build/server"respectively -
The Remix Vite plugin now builds into a single directory containing
clientandserverdirectories -
If you've customized your build output directories, you'll need to migrate to the new
buildDirectoryoption, 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/.vitedirectory rather than being nested withinbuild/clientandbuild/serverdirectories (#8599)⚠️ This is a breaking change for consumers of Vite'smanifest.jsonfiles- 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.jsonandbuild/.vite/server-manifest.json, orbuild/.vite/server-{BUNDLE_ID}-manifest.jsonwhen using server bundles
-
@remix-run/dev- Vite: Removeunstableprefix fromserverBundlesoption (#8596) -
@remix-run/dev- Vite: Add--sourcemapClientand--sourcemapServerflags 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 theserverBundlesfunction 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
metafor fast refresh, which removes the false alarm.
-
@remix-run/dev- Vite: Cloudflare Pages support (#8531) -
@remix-run/dev- Vite: AddgetRemixDevLoadContextoption to Cloudflare preset (#8649) -
@remix-run/dev- Vite: Remove undocumented backwards compatibility layer for Vite v4 (#8581) -
@remix-run/dev- Vite: Addpresetsoption to ease integration with different platforms and tools (#8514) -
@remix-run/dev- Vite: AddbuildEndhook (#8620) -
@remix-run/dev- Vite: Addmodefield into generated server build (#8539) -
@remix-run/dev- Vite: Reduce network calls for route modules during HMR (#8591) -
@remix-run/dev- Vite: ExportUnstable_ServerBundlesFunctionandUnstable_VitePluginConfigtypes (#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)bgWhiteandwhiteBrightare the same color in many terminal colorthemes, which was causing it to render as illegible white-on-white
@remix-run/dev- AddisSpaModeto@remix-run/dev/server-buildvirtual 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 --profileto generate a.cpuprofilethat can be shared or uploaded to speedscope.app - In dev, press
p + enterto start a new profiling session or stop the current session - If you need to profile dev server startup, run
remix vite:dev --profileto 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/BlockerFunctiontypes (#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:devBuilding in SPA Mode will generate an index.html file in your client assets directory:
remix vite:buildTo run your SPA, you serve your client assets directory via an HTTP server:
npx http-server build/clientFor 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_serverBundlesoption 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@4released on 1/1/2024 (#8415)remix devwill now add"isbot": "^4"topackage.jsoninstead of usinglatest- Update built-in
entry.serverfiles to work with bothisbot@3andisbot@4for backwards-compatibility with Remix apps that have pinnedisbot@3 - Templates are updated to use
isbot@4moving forward viacreate-remix
@remix-run/dev: Vite - Fix HMR issues when altering exports for non-rendered routes (#8157)@remix-run/dev: Vite - DefaultNODE_ENVto"production"when runningremix vite:buildcommand (#8405)@remix-run/dev: Vite - Remove Vite plugin config optionserverBuildPathin favor of separateserverBuildDirectoryandserverBuildFileoptions (#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.hotfrom the existing Remix compiler (#8459)@remix-run/server-runtime: Updatedcookiedependency to0.6.0to inherit support for thePartitionedattribute (#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_viteServerBuildModuleIdin 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/devcould be inadvertently required in your server's production dependencies. -
Instead, you should manually write the virtual module name
"virtual:remix/server-build"when callingssrLoadModulein 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:devandvite:buildcommands 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
devandbuildprocesses 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.serverfiles are referenced by client (#8267)- Previously, referencing a
.servermodule 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.tsdoes provide theisDateTypeexport, but Remix was replacing.servermodules with empty modules (export {}) for the client build - Now, Remix explicitly fails at compile time when a
.servermodule 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.clientmodules (#8200)- Unlike
.servermodules, 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
.clientmodules 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
.clientmodules 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 serverloadererrors throughserverLoaderin hydratingclientLoader's (#8304) -
@remix-run/reactRe-exportResponsehelpers (defer/json/redirect/redirectDocument) through@remix-run/reactfor use inclientLoader/clientAction(#8351) -
@remix-run/server-runtime: Add optionalerrortoServerRuntimeMetaArgstype to align withMetaArgs(#8238) -
create-remix: Switch to using@remix-run/web-fetchinstead ofnode-fetchinside thecreate-remixCLI (#7345) -
remix-serve: Use nodefileURLToPathto 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/HydrateFallbackroute exports (#8173) - Add a new
future.v3_relativeSplatPathflag to implement a breaking bug fix to relative routing when inside a splat route (#8216) - Deprecate
DataFunctionArgsin favor ofLoaderFunctionArgs/ActionFunctionArgs(#8173)- This is aimed at keeping the types aligned across server/client loaders/actions now that
clientLoader/clientActonfunctions haveserverLoader/serverActionparameters which differentiateClientLoaderFunctionArgs/ClientActionFunctionArgs
- This is aimed at keeping the types aligned across server/client loaders/actions now that
- Vite: Exclude modules within
.serverdirectories 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.ssrFixStacktracein Vite dev to ensure stack traces correctly map to the original source code (#8066) -
remix-serve: Fix source map loading when file has?t=timestampsuffix (rebuilds) (#8174) -
@remix-run/dev: Change Vite build output paths to fix a conflict between how Vite and the Remix compiler each manage thepublicdirectory (#8077)⚠️ This is a breaking change for projects using the unstable Vite plugin- The server is now compiled into
build/serverrather thanbuild, and the client is now compiled intobuild/clientrather 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 withhandleexport 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 undocumentedlegacyCssImportsoption from Vite plugin due to issues with?urlimports of CSS files not being processed correctly in Vite (#8096) -
@remix-run/dev: Vite: fix access to defaultentry.{client,server}.tsxwithinpnpmworkspaces on Windows (#8057) -
@remix-run/dev: Removeunstable_createViteServerandunstable_loadViteServerBuildwhich were only minimal wrappers around Vite'screateServerandssrLoadModulefunctions 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_viteServerBuildModuleIdso 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.ssrFixStacktracein Vite dev to ensure stack traces correctly map to the original source code (#8066) -
@remix-run/dev: Vite: Preserve names for exports from.clientimports (#8200)- Unlike
.servermodules, 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
.clientmodules without compilation failing and then rely on runtime checks to determine if the code is running on the server or client - Replacing
.clientmodules 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/nodeto Vite'soptimizeDeps.includearray (#8177) -
@remix-run/dev: Improve Vite plugin performance (#8121)- Parallelize detection of route module exports
- Disable
server.preTransformRequestsin 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
installGlobalsin 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 Requestchecks 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: Supportnonceprop onLiveReloadcomponent 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 frompublicdirectory 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
assetsBuildDirectorywas deeply nested within thepublicdirectory
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 theuseBlockerhook (#7882) - Add
unstable_flushSyncoption touseNavigate/useSubmit/fetcher.load/fetcher.submitto opt-out ofReact.startTransitionand intoReactDOM.flushSyncfor state updates (#7996)
@remix-run/react: Add missingmodulepreloadfor the manifest (#7684)@remix-run/server-runtime: Updatedcookiedependency from0.4.1to0.5.0to inherit support forPriorityattribute in Chrome (#6770)@remix-run/dev: FixFutureConfigtype (#7895)- Lots of small fixes for the unstable
vitecompiler:- Support optional rendering of the
LiveReloadcomponent in Vite dev (#7919) - Support rendering of the
LiveReloadcomponent afterScriptsin Vite dev (#7919) - Fix
react-refresh/babelresolution for custom server withpnpm(#7904) - Support JSX usage in
.jsxfiles without manualReactimport in Vite (#7888) - Fix Vite production builds when plugins that have different local state between
developmentandproductionmodes are present (e.g.@mdx-js/rollup) (#7911) - Cache resolution of Remix Vite plugin options (#7908)
- Support Vite 5 (#7846)
- Allow
process.env.NODE_ENVvalues 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-proxyplugin 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
deferin Vite dev server (#7842) - Handle multiple
Set-Cookieheaders 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.envfrom.envfiles 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/devunstable_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 thebuildargument 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/
npminterop - 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
useFetchersso that they can be looked up bykey FormanduseSubmitnow support optionalnavigate/fetcherKeyprops/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 anidlestate - 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
idlestate- They will remain exposed via
useFetcherswhile 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
vitesupport (#7590) - New fetcher
keyAPIs andnavigate/fetcherKeyparams for navigational APIs (#10960) - New
future.v3_fetcherPersistflag (#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.hostnamewhich will respectX-Forwarded-Host
- Previously, this used
@remix-run/react: Fix warning that could be inadvertently logged when using route files with nodefaultexport (#7745)create-remix: Support local tarballs with a.tgzextension which allows direct support forpnpm packtarballs (#7649)create-remix: Default the Remix app version to the version ofcreate-remixbeing 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/testingcreateRemixStubhelper (#7647)
- Emulate types for
JSON.parse(JSON.stringify(x))inSerializeFrom(#7605)- Notably, type fields that are only assignable to
undefinedafter serialization are now omitted sinceJSON.stringify |> JSON.parsewill 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
metaobject whentagNameis specified (#7594) - Fix FOUC on subsequent client-side navigations to
route.lazyroutes (#7576) - Export the proper Remix
useMatcheswrapper to fixUIMatchtypings (#7551) @remix-run/cloudflare- sourcemap takes into account special chars in output file (#7574)@remix-run/express- Flush headers fortext/event-streamresponses (#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
getDependenciesToBundleto handle ESM packages without main exports (#7272)- Note that these packages must expose
package.jsonin theirexportsfield so that their path can be resolved
- Note that these packages must expose
- Fix server builds where
serverBuildPathextension is.cjs(#7180) - Fix HMR for CJS projects using
remix-serveand manual mode (remix dev --manual) (#7487)- By explicitly busting the
requirecache,remix-servenow 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.assetsbeing 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
UIMatchforhandlefield (#7464) - Fix resource routes being loaded through
route.lazy(#7498) - Throw a semantically correct 405
ErrorResponseinstead of just anErrorwhen submitting to a route without anaction(#7423) - Update to latest version of
@remix-run/web-fetch(#7477) - Switch from
crypto.randomBytestocrypto.webcrypto.getRandomValuesfor file session storage ID generation (#7203) - Use native
Blobclass 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.3Below 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_devinstead of just the boolean value (i.e.,future.v2_dev.port), you can lift them into a rootdevobject in yourremix.config.js
- If you had configurations in
v2_errorBoundary- RemovedCatchBoundaryin favor of a singularErrorBoundary(#6906)v2_headers- Altered the logic forheadersin nested route scenarios (#6979)v2_meta- Altered the return format ofmeta()(#6958)v2_normalizeFormMethod- NormalizeformMethodAPIs 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
browserBuildDirectorytoassetsBuildDirectory(#6900) - Removed
devServerBroadcastDelay(#7063) - Renamed
devServerPorttodev.port(000457e0)- Note that if you are opting into this in a
1.xrelease, your config flag will befuture.v2_dev.port, but on a stable2.xrelease it will bedev.port
- Note that if you are opting into this in a
- Changed the default
serverModuleFormatfromcjstoesm(#6949) - Removed
serverBuildTarget(#6896) - Changed
serverBuildDirectorytoserverBuildPath(#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.typeand 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
postcssandtailwindflags (#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_ORIGINin favor ofREMIX_DEV_ORIGIN(#6963) - Removed
REMIX_DEV_SERVER_WS_PORTin favor ofdev.portor--port(#6965) - Removed
--no-restart/restartflag in favor of--manual/manual(#6962) - Removed
--scheme/schemeand--host/hostin favor ofREMIX_DEV_ORIGINinstead (#6962) - Removed the
codemodcommand (#6918)
- Removed
@remix-run/eslint-config@remix-run/netlify- The
@remix-run/netlifyadapter has been removed in favor of the Netlify official adapters (#7058)
- The
@remix-run/nodefetchis no longer polyfilled by default - apps must callinstallGlobals()to install the polyfills (#7009)fetchand 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_shouldReloadin favor ofshouldRevalidate(#6865)
- Remove
@remix-run/serve@remix-run/vercel- The
@remix-run/verceladapter has been removed in favor of out of the box functionality provided by Vercel (#7035)
- The
create-remix- Stop passing
isTypeScripttoremix.initscript (#7099)
- Stop passing
remix- Removed magic exports (#6895)
- Removed
V2_prefixes fromfuture.v2_metatypes 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->ServerRuntimeMetaMatches
- The following types were adjusted to prefer
unknownoveranyand to align with underlying React Router types (#7319):- Renamed the
useMatches()return type fromRouteMatchtoUIMatch - Renamed
LoaderArgs/ActionArgstoLoaderFunctionArgs/ActionFunctionArgs AppDatachanged fromanytounknownLocation["state"](useLocation.state) changed fromanytounknownUIMatch["data"](useMatches()[i].data) changed fromanytounknownUIMatch["handle"](useMatches()[i].handle) changed from{ [k: string]: any }tounknownFetcher["data"](useFetcher().data) changed fromanytounknownMetaMatch.handle(used inmeta()) changed fromanytounknownAppData/RouteHandleare no longer exported as they are just aliases forunknown
- Renamed the
- New
create-remixCLI (#6887)- Most notably, this removes the dropdown to choose your template/stack in favor of the
--templateflag and our ever-growing list of available templates - Adds a new
--overwriteflag (#7062) - Supports the
bunpackage 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
redirectDocumentutility to redirect via a fresh document load (#7040, #6842) - Add
errortometaparams so you can render error titles, etc. (#7105) unstable_createRemixStubnow supports addingmeta/linksfunctions on stubbed Remix routes (#7186)unstable_createRemixStubno longer supports theelement/errorElementproperties on routes. You must useComponent/ErrorBoundaryto match what you would export from a Remix route module.
- Remix now uses React Router's
route.lazymethod internally to load route modules on navigations (#7133) - Removed the
@remix-run/nodeatob/btoapolyfills in favor of the built-in versions (#7206) - Decouple the
@remix-run/devpackage from the contents of the@remix-run/css-bundlepackage (#6982)- The contents of the
@remix-run/css-bundlepackage 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/devwithout upgrading@remix-run/css-bundle.
- The contents of the
remix-servenow picks an open port if 3000 is taken (#7278)- If
PORTenv var is set,remix-servewill use that port - Otherwise,
remix-servepicks an open port (3000 unless that is already taken)
- If
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.0
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