-
Add support for
routes.ts
behindfuture.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 forroutes.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 inroutes.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)
- Add
@deprecated
annotations tojson
/defer
utilities
- Add
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Revert
future.v3_optimizeDeps
back tofuture.unstable_optimizeDeps
as it was not intended to stabilize in Remix v2 (#10099) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Stabilize the
future.unstable_optimizeDeps
flag intofuture.v3_optimizeDeps
(#10092) - 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)
future.unstable_singleFetch
->future.v3_singleFetch
future.unstable_lazyRouteDiscovery
->future.v3_lazyRouteDiscovery
-
Stop passing
request.signal
as therenderToReadableStream
signal
to abort server rendering for cloudflare/deno runtimes because by the time thatrequest
is 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: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 closedReadableStream
. - This has likely not shown up in any production scenarios because cloudflare/deno production runtimes are (correctly) not aborting the
request.signal
on successful renders - The built-in
entry.server
files no longer pass asignal
torenderToReadableStream
because 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.server
viaremix 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
-
Fix adapter logic for aborting
request.signal
so we don't incorrectly abort on theclose
event for successful requests (#10046) -
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Properly abort
request.signal
duringvite dev
when the node response is closed (#9976) - CSS imports with
?inline
,?inline-css
and?raw
are no longer incorrectly injected during SSR in development (#9910) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- New
future.unstable_optimizeDeps
flag for automatic dependency optimization (#9921)- 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 theremix-dot-server
plugin
- You can now opt-in to automatic dependency optimization during development by using the
- Handle circular dependencies in modulepreload manifest generation (#9917)
- 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) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Rename
future.unstable_fogOfWar
tofuture.unstable_lazyRouteDiscovery
for clarity (#9763)
- Handle absolute Vite base URLs (#9700)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Upgrade
express
dependency to^4.19.2
(#9184) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Fix
dest already exists
error when runningremix vite:build
(#9305) - Vite: Fix issue resolving critical CSS during development when route files are located outside of the app directory. (#9194)
- Remove
@remix-run/node
from Vite plugin'soptimizeDeps.include
list since it was unnecessary and resulted in Vite warnings when not depending on this package. (#9287) - Clean up redundant
?client-route=1
imports in development (#9395) - Ensure Babel config files are not referenced when applying the
react-refresh
Babel transform within the Remix Vite plugin (#9241) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- 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'sssr.external
option (#9301) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
-
New
future.unstable_singleFetch
flag (#8773)- Naked objects returned from loaders/actions are no longer automatically converted to JSON responses. They'll be streamed as-is via
turbo-stream
soDate
's will becomeDate
throughuseLoaderData()
- You can return naked objects with
Promise
's without needing to usedefer()
- including nestedPromise
's- If you need to return a custom status code or custom response headers, you can still use the
defer
utility
- If you need to return a custom status code or custom response headers, you can still use the
<RemixServer abortDelay>
is no longer used. Instead, you shouldexport const streamTimeout
fromentry.server.tsx
and the remix server runtime will use that as the delay to abort the streamed response- If you export your own streamTimeout, you should decouple that from aborting the react
renderToPipeableStream
. You should always ensure that react is aborted afer the stream is aborted so that abort rejections can be flushed down
- If you export your own streamTimeout, you should decouple that from aborting the react
- Actions no longer automatically revalidate on 4xx/5xx responses (via RR
future.unstable_skipActionErrorRevalidation
flag) - you can return a 2xx to opt-into revalidation or useshouldRevalidate
- Naked objects returned from loaders/actions are no longer automatically converted to JSON responses. They'll be streamed as-is via
- Improve
getDependenciesToBundle
resolution in monorepos (#8848) - Fix SPA mode when single fetch is enabled by using streaming entry.server (#9063)
- Vite: added sourcemap support for transformed routes (#8970)
- Update links printed to the console by the Remix CLI/Dev Server to point to updated docs locations (#9176)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Support reading from Vite config when running
remix reveal
andremix routes
CLI commands (#8916) - Add Vite commands to Remix CLI
--help
output (#8939) - Vite: Fix support for
build.sourcemap
option in Vite config (#8965) - Clean up redundant client route query strings on route JavaScript files in production builds (#8969)
- Vite: Fix error when using Vite's
server.fs.allow
option without a client entry file (#8966) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Pass resolved
viteConfig
to Remix Vite plugin'sbuildEnd
hook (#8885)
- Mark
Layout
as browser safe route export inesbuild
compiler (#8842) - Vite: Silence build warnings when dependencies include "use client" directives (#8897)
- Vite: Fix
serverBundles
issue where multiple browser manifests are generated (#8864) - Support custom Vite
build.assetsDir
option (#8843) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Vite: Fix error when building projects with
.css?url
imports (#8829) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
-
Allow an optional
Layout
export from the root route (#8709) -
Vite: Cloudflare Proxy as a Vite plugin (#8749)
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"], - }, - }, });
remixCloudflareDevProxy
must come before theremix
plugin so that it can override Vite's dev server middleware to be compatible with Cloudflare's proxied environment.Because it is a Vite plugin,
remixCloudflareDevProxy
can setssr.resolve.externalConditions
to beworkerd
-compatible for you.remixCloudflareDevProxy
accepts agetLoadContext
function that replaces the oldgetRemixDevLoadContext
. If you were using anightly
version that requiredgetBindingsProxy
orgetPlatformProxy
, that is no longer required. Any options you were passing togetBindingsProxy
orgetPlatformProxy
should now be passed toremixCloudflareDevProxy
instead.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.
-
Vite: Stabilize the Remix Vite plugin, Cloudflare preset, and all related types by removing all
unstable_
/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! 🙏
-
Vite: Stabilize "SPA Mode" by renaming the Remix vite plugin config from
unstable_ssr -> ssr
(#8692) -
Vite: Add a new
basename
option to the Vite plugin, allowing users to set the internal React Routerbasename
in order to to serve their applications underneath a subpath (#8145)
-
Vite: fix server exports dead-code elimination for routes outside of app directory (#8795)
-
Always prepend DOCTYPE in SPA mode entry.server.tsx, can opt out via remix reveal (#8725)
-
Fix build issue in SPA mode when using a
basename
(#8720) -
Vite: Validate that the MDX Rollup plugin, if present, is placed before Remix in Vite config (#8690)
-
Vite: reliably detect non-root routes in Windows (#8806)
Sometimes route
file
will be unnormalized Windows path with\
instead of/
. -
Vite: Pass
remixUserConfig
to presetremixConfig
hook (#8797) -
Vite: Fix issue resolving critical CSS during development when the current working directory differs from the project root (#8752)
-
Vite: Ensure CSS file URLs that are only referenced in the server build are available on the client (#8796)
-
Vite: Require version 5.1.0 to support
.css?url
imports (#8723) -
Fix type error in Remix config for synchronous
routes
function (#8745) -
Vite: Support Vite v5.1.0's
.css?url
imports (#8684) -
Always ignore route files starting with
.
(#8801) -
Vite: Enable use of
vite preview
to preview Remix SPA applications (#8624)- In the SPA template,
npm run start
has been renamed tonpm run preview
which usesvite preview
instead of a standalone HTTP server such ashttp-server
orserv-cli
- In the SPA template,
-
Vite: Remove the ability to pass
publicPath
as 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
base
config so we now set the RemixpublicPath
from the Vitebase
config
-
Vite: Fix issue where client route file requests fail if search params have been parsed and serialized before reaching the Remix Vite plugin (#8740)
-
Vite: Enable HMR for .md and .mdx files (#8711)
-
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Add
future.v3_throwAbortReason
flag to throwrequest.signal.reason
when a request is aborted instead of anError
such asnew Error("query() call aborted: GET /path")
(#8251)
-
Vite: Add
manifest
option to Vite plugin to enable writing a.remix/manifest.json
file to the build directory (#8575)This is a breaking change for consumers of the Vite plugin's "server bundles" feature.
The
build/server/bundles.json
file has been superseded by the more generalbuild/.remix/manifest.json
. While the old server bundles manifest was always written to disk when generating server bundles, the build manifest file must be explicitly enabled via themanifest
option. -
Vite: Provide
Unstable_ServerBundlesFunction
andUnstable_VitePluginConfig
types (#8654) -
Vite: add
--sourcemapClient
and--sourcemapServer
flags toremix vite:build
(#8613)-
--sourcemapClient
-
--sourcemapClient=inline
-
--sourcemapClient=hidden
-
--sourcemapServer
-
--sourcemapServer=inline
-
--sourcemapServer=hidden
See https://vitejs.dev/config/build-options.html#build-sourcemap
-
-
Vite: Validate IDs returned from the
serverBundles
function to ensure they only contain alphanumeric characters, hyphens and underscores (#8598) -
Vite: fix "could not fast refresh" false alarm (#8580)
HMR is already functioning correctly but was incorrectly logging that it "could not fast refresh" on internal client routes. Now internal client routes correctly register Remix exports like
meta
for fast refresh, which removes the false alarm. -
Vite: Cloudflare Pages support (#8531)
To get started with Cloudflare, you can use the [
unstable-vite-cloudflare
][template-vite-cloudflare] template:npx create-remix@latest --template remix-run/remix/templates/unstable-vite-cloudflare
Or read the new docs at Future > Vite > Cloudflare and Future > Vite > Migrating > Migrating Cloudflare Functions.
-
Vite: Remove undocumented backwards compatibility layer for Vite v4 (#8581)
-
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.
-
Vite: Add
presets
option to ease integration with different platforms and tools. (#8514) -
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.import { - LiveReload, Outlet, Scripts, } export default function App() { return ( <html> <head> </head> <body> <Outlet /> <Scripts /> - <LiveReload /> </body> </html> ) }
-
Vite: Add
buildEnd
hook (#8620) -
Vite: add dev load context option to Cloudflare preset (#8649)
-
Vite: Add
mode
field into generated server build (#8539) -
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
totrue
in your Vite config.export default defineConfig({ build: { manifest: true }, // ... });
-
Vite: reduce network calls for route modules during HMR (#8591)
-
Vite: Add new
buildDirectory
option with a default value of"build"
. This replaces the oldassetsBuildDirectory
andserverBuildDirectory
options which defaulted to"build/client"
and"build/server"
respectively. (#8575)This is a breaking change for consumers of the Vite plugin that were using the
assetsBuildDirectory
andserverBuildDirectory
options.The Remix Vite plugin now builds into a single directory containing
client
andserver
directories. If you've customized your build output directories, you'll need to migrate to the newbuildDirectory
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", }) ], });
-
Vite: Remove
unstable
prefix fromserverBundles
option. (#8596) -
Vite: Write Vite manifest files to
build/.vite
directory rather than being nested withinbuild/client
andbuild/server
directories. (#8599)This is a breaking change for consumers of Vite's
manifest.json
files.Vite manifest files are now written to the Remix build directory. Since all Vite manifests are now in the same directory, they're no longer named
manifest.json
. Instead, they're namedbuild/.vite/client-manifest.json
andbuild/.vite/server-manifest.json
, orbuild/.vite/server-{BUNDLE_ID}-manifest.json
when using server bundles. -
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Add
isSpaMode
to@remix-run/dev/server-build
virtual module (#8492) - Automatically prepend
<!DOCTYPE html>
if not present to fix quirks mode warnings for SPA template (#8495) - Vite: Errors for server-only code point to new docs (#8488)
- Vite: Fix HMR race condition when reading changed file contents (#8479)
- Vite: Tree-shake unused route exports in the client build (#8468)
- Vite: Performance profiling (#8493)
- Run
remix vite:build --profile
to generate a.cpuprofile
that can be shared or uploaded to speedscope.app - In dev, press
p + enter
to start a new profiling session or stop the current session - If you need to profile dev server startup, run
remix vite:dev --profile
to initialize the dev server with a running profiling session - For more, see the new docs: Vite > Performance
- Run
- Vite: Improve performance of dev server requests by invalidating Remix's virtual modules on relevant file changes rather than on every request (#8164)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
-
Add unstable support for "SPA Mode" (#8457)
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.
-
Add
unstable_serverBundles
option to Vite plugin to support splitting server code into multiple request handlers. (#8332)This is an advanced feature designed for hosting provider integrations. 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.
Example usage:
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"; }, }), ], });
-
Fix issue with
isbot
v4 released on 1/1/2024 (#8415)remix dev
will now add"isbot": "^4"
topackage.json
instead of usinglatest
- Update built-in
entry.server
files to work with bothisbot@3
andisbot@4
for backwards-compatibility with Remix apps that have pinnedisbot
to v3 - Templates are updated to use
isbot@4
moving forward viacreate-remix
-
Vite: Fix HMR issues when altering exports for non-rendered routes (#8157)
-
Vite: Default
NODE_ENV
to"production"
when runningremix vite:build
command (#8405) -
Vite: Remove Vite plugin config option
serverBuildPath
in favor of separateserverBuildDirectory
andserverBuildFile
options (#8332) -
Vite: Loosen strict route exports restriction, reinstating support for non-Remix route exports (#8420)
-
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
-
Vite: Error messages when
.server
files are referenced by client (#8267)- Previously, referencing a
.server
module from client code resulted in an error message like:The requested module '/app/models/answer.server.ts' does not provide an export named 'isDateType'
- This was confusing because
answer.server.ts
does provide theisDateType
export, but Remix was replacing.server
modules with empty modules (export {}
) for the client build - Now, Remix explicitly fails at compile time when a
.server
module is referenced from client code and includes dedicated error messages depending on whether the import occurs in a route or a non-route module - The error messages also include links to relevant documentation
- Previously, referencing a
-
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 callingssrLoadModule
in development.-import { unstable_viteServerBuildModuleId } from "@remix-run/dev"; // ... app.all( "*", createRequestHandler({ build: vite - ? () => vite.ssrLoadModule(unstable_viteServerBuildModuleId) + ? () => vite.ssrLoadModule("virtual:remix/server-build") : await import("./build/server/index.js"), }) );
-
Vite: Fix errors for non-existent
index.html
importer (#8353) -
Add
vite:dev
andvite:build
commands to the Remix CLI. (#8211)In order to handle upcoming Remix features where your plugin options can impact the number of Vite builds required, you should now run your Vite
dev
andbuild
processes via the Remix CLI.{ "scripts": { - "dev": "vite dev", - "build": "vite build && vite build --ssr" + "dev": "remix vite:dev", + "build": "remix vite:build" } }
-
Vite: Preserve names for exports from
.client
modules (#8200)Unlike
.server
modules, the main idea is not to prevent code from leaking into the server build since the client build is already public. Rather, the goal is to isolate the SSR render from client-only code. Routes need to import code from.client
modules without compilation failing and then rely on runtime checks or otherwise ensure that execution only happens within a client-only context (e.g. event handlers,useEffect
).Replacing
.client
modules with empty modules would cause the build to fail as ESM named imports are statically analyzed. So instead, we preserve the named export but replace each exported value withundefined
. 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. -
Disable watch mode in Vite child compiler during build (#8342)
-
Vite: Show warning when source maps are enabled in production build (#8222)
-
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
-
Vite: exclude modules within
.server
directories from client build (#8154) -
Add support for
clientLoader
/clientAction
/HydrateFallback
route exports (RFC) (#8173)Remix now supports loaders/actions that run on the client (in addition to, or instead of the loader/action that runs on the server). 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:
- Leveraging a data source local to the browser (i.e.,
localStorage
) - Managing a client-side cache of server data (like
IndexedDB
) - Bypassing the Remix server in a BFF setup and hitting your API directly from the browser
- Migrating a React Router SPA to a Remix application
By default,
clientLoader
will not run on hydration, and will only run on subsequent client side navigations.If you wish to run your client loader on hydration, you can set
clientLoader.hydrate=true
to force Remix to execute it on initial page load. Keep in mind that Remix will still SSR your route component so you should ensure that there is no new required data being added by yourclientLoader
.If your
clientLoader
needs to run on hydration and adds data you require to render the route component, you can export aHydrateFallback
component that will render during SSR, and then your route component will not render until theclientLoader
has executed on hydration.clientAction
is simpler thanclientLoader
because it has no hydration use-cases.clientAction
will only run on client-side navigations.For more information, please refer to the
clientLoader
andclientAction
documentation. - Leveraging a data source local to the browser (i.e.,
-
Vite: Strict route exports (#8171)
With Vite, Remix gets stricter about which exports are allowed from 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, see https://remix.run/docs/en/main/future/vite#strict-route-exports
-
Add a new
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 Router6.21.0
Release Notes and theuseResolvedPath
docs. (#8216)
-
Upgrade Vite peer dependency range to v5 (#8172)
-
Support HMR for routes with
handle
export in Vite dev (#8022) -
Fix flash of unstyled content for non-Express custom servers in Vite dev (#8076)
-
Bundle CSS imported in client entry file in Vite plugin (#8143)
-
Change Vite build output paths to fix a conflict between how Vite and the Remix compiler each manage the
public
directory. (#8077)This is a breaking change for projects using the unstable Vite plugin.
The server is now compiled into
build/server
rather thanbuild
, and the client is now compiled intobuild/client
rather thanpublic
.For more information on the changes and guidance on how to migrate your project, refer to the updated Remix Vite documentation.
-
Remove undocumented
legacyCssImports
option from Vite plugin due to issues with?url
imports of CSS files not being processed correctly in Vite (#8096) -
Vite: fix access to default
entry.{client,server}.tsx
within pnpm workspace on Windows (#8057) -
Remove
unstable_createViteServer
andunstable_loadViteServerBuild
which were only minimal wrappers around Vite'screateServer
andssrLoadModule
functions when using a custom server. (#8120)This is a breaking change for projects using the unstable Vite plugin with a custom server.
Instead, we now provide
unstable_viteServerBuildModuleId
so that custom servers interact with Vite directly rather than via Remix APIs, for example:-import { - unstable_createViteServer, - unstable_loadViteServerBuild, -} from "@remix-run/dev"; +import { unstable_viteServerBuildModuleId } from "@remix-run/dev";
Creating the Vite server in middleware mode:
const vite = process.env.NODE_ENV === "production" ? undefined - : await unstable_createViteServer(); + : await import("vite").then(({ createServer }) => + createServer({ + server: { + middlewareMode: true, + }, + }) + );
Loading the Vite server build in the request handler:
app.all( "*", createRequestHandler({ build: vite - ? () => unstable_loadViteServerBuild(vite) + ? () => vite.ssrLoadModule(unstable_viteServerBuildModuleId) : await import("./build/server/index.js"), }) );
-
Pass request handler errors to
vite.ssrFixStacktrace
in Vite dev to ensure stack traces correctly map to the original source code (#8066) -
Vite: Preserve names for exports from .client imports (#8200)
Unlike
.server
modules, the main idea is not to prevent code from leaking into the server build since the client build is already public. Rather, the goal is to isolate the SSR render from client-only code. Routes need to import code from.client
modules without compilation failing and then rely on runtime checks to determine if the code is running on the server or client.Replacing
.client
modules with empty modules would cause the build to fail as ESM named imports are statically analyzed. So instead, we preserve the named export but replace each exported value with an empty object. That way, the import is valid at build time and the standard runtime checks can be used to determine if then code is running on the server or client. -
Add
@remix-run/node
to Vite'soptimizeDeps.include
array (#8177) -
Improve Vite plugin performance (#8121)
- Parallelize detection of route module exports
- Disable
server.preTransformRequests
in Vite child compiler since it's only used to process route modules
-
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()], });
-
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.
-
Fix
request instanceof Request
checks when using Vite dev server (#8062) -
Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Support
nonce
prop onLiveReload
component in Vite dev (#8014) - Ensure code-split JS files in the server build's assets directory aren't cleaned up after Vite build (#8042)
- Fix redundant copying of assets from
public
directory in Vite build (#8039)- This ensures that static assets aren't duplicated in the server build directory
- This also fixes an issue where the build would break if
assetsBuildDirectory
was deeply nested within thepublic
directory
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Support rendering of
LiveReload
component afterScripts
in Vite dev (#7919) - fix(vite): fix "react-refresh/babel" resolution for custom server with pnpm (#7904)
- Support JSX usage in
.jsx
files without manualReact
import in Vite (#7888) - Support optional rendering of
LiveReload
component in Vite dev (#7919) - Fix Vite production builds when plugins that have different local state between
development
andproduction
modes are present, e.g.@mdx-js/rollup
. (#7911) - Cache resolution of Remix Vite plugin options (#7908)
- Support Vite 5 (#7846)
- Allow
process.env.NODE_ENV
values other than"development"
in Vite dev (#7980) - Attach CSS from shared chunks to routes in Vite build (#7952)
- fix(vite): 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)
- fix(vite): deduplicate
@remix-run/react
(#7926)- Pre-bundle Remix dependencies to avoid Remix router duplicates.
- Our remix-react-proxy plugin does not process default client and
- server entry files since those come from within
node_modules
. - That means that before Vite pre-bundles dependencies (e.g. first time dev server is run) mismatching Remix routers cause
Error: You must render this element inside a <Remix> element
.
- Fix React Fast Refresh error on load when using
defer
in Vite dev server (#7842) - Handle multiple "Set-Cookie" headers in Vite dev server (#7843)
- Fix flash of unstyled content on initial page load in Vite dev when using a custom Express server (#7937)
- Emit assets that were only referenced in the server build into the client assets directory in Vite build (#7892, cherry-picked in
8cd31d65
) - Populate
process.env
from.env
files on the server in Vite dev (#7958) - Fix
FutureConfig
type (#7895) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Unstable Vite support for Node-based Remix apps (#7590)
remix build
👉vite build && vite build --ssr
remix dev
👉vite dev
- Other runtimes (e.g. Deno, Cloudflare) not yet supported.
- See "Future > Vite" in the Remix Docs for details
- Add a new
future.v3_fetcherPersist
flag to change the persistence behavior of fetchers. Instead of being immediately cleaned up when unmounted in the UI, fetchers will persist until they return to anidle
state (RFC) (#7704)- For more details, please refer to the React Router 6.18.0 release notes
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Sourcemap takes into account special chars in output file (#7574)
- Updated dependencies:
@remix-run/[email protected]
- Fix types for MDX files when using pnpm (#7491)
- Update
getDependenciesToBundle
to handle ESM packages without main exports (#7272)- Note that these packages must expose
package.json
in theirexports
field so that their path can be resolved
- Note that these packages must expose
- Fix server builds where
serverBuildPath
extension is.cjs
(#7180) - Updated dependencies:
@remix-run/[email protected]
-
The
create-remix
CLI has been rewritten to feature a cleaner interface, Git repo initialization and optionalremix.init
script execution. The interactive template prompt and official Remix stack/template shorthands have also been removed so that community/third-party templates are now on a more equal footing. (#6887)- The code for
create-remix
has been moved out of the Remix CLI since it's not intended for use within an existing Remix application - This means that the
remix create
command is no longer available.
- The code for
-
Enable built-in PostCSS and Tailwind support by default. (#6909)
- These tools are now automatically used within the Remix compiler if PostCSS and/or Tailwind configuration files are present in your project.
- If you have a custom PostCSS and/or Tailwind setup outside of Remix, you can disable these features in your
remix.config.js
via thepostcss:false
and/ortailwind:false
flags
-
Drop React 17 support (#7121)
-
Require Node >=18.0.0 (#6939)
-
Compile server build to Node 18 (#7292)
- This allows features like top-level
await
to be used within a Remix app
- This allows features like top-level
-
Remove default Node.js polyfills - you must now opt-into polyfills via the
serverNodeBuiltinsPolyfill
andbrowserNodeBuiltinsPolyfill
configs (#7269) -
Remove
v2_errorBoundary
flag andCatchBoundary
implementation (#6906) -
Remove
v2_normalizeFormMethod
future flag - allformMethod
values will be normalized in v2 (#6875) -
Remove
v2_routeConvention
flag - the flat route file convention is now standard (#6969) -
Remove
v2_headers
flag - it is now the default behavior to use the deepestheaders
function in the route tree (#6979) -
The route
meta
API now defaults to the new "V2 Meta" API (#6958)- Please refer to the (docs and Preparing for V2 guide for more information.
-
Default to
serverModuleFormat: "esm"
and updateremix-serve
to use dynamic import to support ESM and CJS build outputs (#6949) -
Remove
serverBuildTarget
config option (#6896) -
Remove deprecated
REMIX_DEV_HTTP_ORIGIN
env var - useREMIX_DEV_ORIGIN
instead (#6963) -
Remove
devServerBroadcastDelay
config option (#7063) -
Remove deprecated
devServerPort
option - use--port
/dev.port
instead (#7078) -
Remove deprecated
REMIX_DEV_SERVER_WS_PORT
env var - useremix dev
's '--port
/port
option instead (#6965) -
Stop passing
isTypeScript
toremix.init
script (#7099) -
Remove
replace-remix-magic-imports
codemod (#6899) -
Remove deprecated
--no-restart
/restart
cli args/flags - use--manual
/manual
instead (#6962) -
Remove deprecated
--scheme
/scheme
and--host
/host
cli args/flags - useREMIX_DEV_ORIGIN
instead (#6962) -
Promote the
future.v2_dev
flag inremix.config.js
to a root leveldev
config (#7002) -
Remove
browserBuildDirectory
config option (#6900) -
Remove
serverBuildDirectory
config option ([#6897](https://github.com/remix-run/remix/pull/- Removecodemod
command (#6918) 6897)) -
Removed support for "magic exports" from the
remix
package. This package can be removed from yourpackage.json
and you should update all imports to use the source@remix-run/*
packages: (#6895)- import type { ActionArgs } from "remix"; - import { json, useLoaderData } from "remix"; + import type { ActionArgs } from "@remix-run/node"; + import { json } from "@remix-run/node"; + import { useLoaderData } from "@remix-run/react";
-
Warn users about obsolete future flags in
remix.config.js
(#7048) -
Detect built mode via
build.mode
(#6964)- Prevents mode mismatch between built Remix server entry and user-land server
- Additionally, all runtimes (including non-Node runtimes) can use
build.mode
to determine if HMR should be performed
-
Support
bun
package manager (#7074) -
The
serverNodeBuiltinsPolyfill
option (along with the newly addedbrowserNodeBuiltinsPolyfill
) now supports defining global polyfills in addition to module polyfills (#7269)-
For example, to polyfill Node's
Buffer
global:module.exports = { serverNodeBuiltinsPolyfill: { globals: { Buffer: true, }, // You'll probably need to polyfill the "buffer" module // too since the global polyfill imports this: modules: { buffer: true, }, }, };
-
-
Fix importing of PNGs, SVGs, and other assets from packages in
node_modules
(#6813, #7182) -
Decouple the
@remix-run/dev
package from the contents of the@remix-run/css-bundle
package. (#6982)- The contents of the
@remix-run/css-bundle
package are now entirely managed by the Remix compiler - Even though it's still recommended that your Remix dependencies all share the same version, this change ensures that there are no runtime errors when upgrading
@remix-run/dev
without upgrading@remix-run/css-bundle
- The contents of the
-
Allow non-development modes for
remix watch
(#7117) -
Stop
remix dev
whenesbuild
is not running (#7158) -
Do not interpret JSX in
.ts
files (#7306)-
While JSX is supported in
.js
files for compatibility with existing apps and libraries,.ts
files should not contain JSX. By not interpreting.ts
files as JSX,.ts
files can contain single-argument type generics without needing a comma to disambiguate from JSX:// this works in .ts files const id = <T>(x: T) => x; // ^ single-argument type generic
// this doesn't work in .tsx files const id = <T,>(x: T) => x; // ^ is this a JSX element? or a single-argument type generic?
// this works in .tsx files const id = <T,>(x: T) => x; // ^ comma: this is a generic, not a JSX element const component = <h1>hello</h1>; // ^ no comma: this is a JSX element
-
-
Enhance obsolete flag warning for
future.v2_dev
if it was an object, and prompt users to lift it to the rootdev
config (#7427) -
Allow decorators in app code (#7176)
-
Allow JSX in
.js
files during HMR (#7112) -
Kill app server when remix dev terminates (#7280)
-
Support dependencies that import polyfill packages for Node built-ins via a trailing slash (e.g. importing the
buffer
package withvar Buffer = require('buffer/').Buffer
as recommended in their README) (#7198)- These imports were previously marked as external
- This meant that they were left as dynamic imports in the client bundle and would throw a runtime error in the browser (e.g.
Dynamic require of "buffer/" is not supported
)
-
Surface errors when PostCSS config is invalid (#7391)
-
Restart dev server when Remix config changes (#7269)
-
Remove outdated ESM import warnings (#6916)
- Most of the time these warnings were false positives.
- Instead, we now rely on built-in Node warnings for ESM imports.
-
Do not trigger rebuilds when
.DS_Store
changes (#7172) -
Remove warnings for stabilized flags: (#6905)
unstable_cssSideEffectImports
unstable_cssModules
unstable_vanillaExtract
-
Allow any mode (
NODE_ENV
) (#7113) -
Replace the deprecated
xdm
package with@mdx-js/mdx
(#4054) -
Write a
version.txt
sentinel file after server build is completely written (#7299) -
Updated dependencies:
@remix-run/[email protected]
- Show deprecation warning when using
devServerBroadcastDelay
anddevServerPort
config options (#7064) - Updated dependencies:
@remix-run/[email protected]
- Update
proxy-agent
to resolve npm audit security vulnerability (#7027) - Updated dependencies:
@remix-run/[email protected]
- Add a heartbeat ping to prevent the WebSocket connection from being closed due to inactivity when using a proxy like Cloudflare (#6904, #6927)
- Treeshake out HMR code from production builds (#6894)
- Updated dependencies:
@remix-run/[email protected]
-
improved networking options for
v2_dev
(#6724)deprecate the
--scheme
and--host
options and replace them with theREMIX_DEV_ORIGIN
environment variable -
Output esbuild metafiles for bundle analysis (#6772)
Written to server build directory (
build/
by default):metafile.css.json
metafile.js.json
(browser JS)metafile.server.json
(server JS)
Metafiles can be uploaded to https://esbuild.github.io/analyze/ for analysis.
-
Add
serverNodeBuiltinsPolyfill
config option. Inremix.config.js
you can now disable polyfills of Node.js built-in modules for non-Node.js server platforms, or opt into a subset of polyfills. (#6814, #6859, #6877)// Disable all polyfills exports.serverNodeBuiltinsPolyfill = { modules: {} }; // Enable specific polyfills exports.serverNodeBuiltinsPolyfill = { modules: { crypto: true, // Provide a JSPM polyfill fs: "empty", // Provide an empty polyfill }, };
-
ignore missing react-dom/client for react 17 (#6725)
-
Warn if not using
v2_dev
(#6818)Also, rename
--no-restart
to--manual
to match intention and documentation.--no-restart
remains an alias for--manual
in v1 for backwards compatibility. -
ignore errors when killing already dead processes (#6773)
-
Always rewrite css-derived assets during builds (#6837)
-
fix sourcemaps for
v2_dev
(#6762) -
Do not clear screen when dev server starts (#6719)
On some terminal emulators, "clearing" only scrolls the next line to the top. on others, it erases the scrollback.
Instead, let users call
clear
themselves (clear && remix dev
) if they want to clear. -
Updated dependencies:
@remix-run/[email protected]
- Ignore missing
react-dom/client
for React 17 (#6725) - Updated dependencies:
@remix-run/[email protected]
- fix docs links for msw and mkcert (#6672)
- fix
remix dev -c
: kill all descendant processes of specified command when restarting (#6663) - Add caching to regular stylesheet compilation (#6638)
- Rename
Architect (AWS Lambda)
->Architect
in thecreate-remix
CLI to avoid confusion for other methods of deploying to AWS (i.e., SST) (#6484) - Improve CSS bundle build performance by skipping unused Node polyfills (#6639)
- Improve performance of CSS bundle build by skipping compilation of Remix/React packages that are known not to contain CSS imports (#6654)
- Cache CSS side-effect imports transform when using HMR (#6622)
- Fix bug with pathless layout routes beneath nested path segments (#6649)
- Add caching to PostCSS for CSS Modules (#6604)
- Add caching to PostCSS for side-effect imports (#6554)
- cache getRouteModuleExports calls to significantly speed up build and HMR rebuild times (#6629)
- group rebuild logs with surrounding whitespace (#6607)
- instructions for integrating with msw (#6669)
- Update minimum version of
esbuild-plugins-node-modules-polyfill
to 1.0.16 to ensure that the plugin is cached (#6652) - Updated dependencies:
@remix-run/[email protected]
- Replace
esbuild-plugin-polyfill-node
withesbuild-plugins-node-modules-polyfill
(#6562) - Lazily generate CSS bundle when import of
@remix-run/css-bundle
is detected (#6535) - Updated dependencies:
@remix-run/[email protected]
-
built-in tls support (#6483)
New options:
--tls-key
/tlsKey
: TLS key--tls-cert
/tlsCert
: TLS Certificate
If both TLS options are set,
scheme
defaults tohttps
Install mkcert and create a local CA:
brew install mkcert mkcert -install
Then make sure you inform
node
about your CA certs:export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
👆 You'll probably want to put that env var in your scripts or
.bashrc
/.zshrc
Now create
key.pem
andcert.pem
:mkcert -key-file key.pem -cert-file cert.pem localhost
See
mkcert
docs for more details.Finally, pass in the paths to the key and cert via flags:
remix dev --tls-key=key.pem --tls-cert=cert.pem
or via config:
module.exports = { future: { unstable_dev: { tlsKey: "key.pem", tlsCert: "cert.pem", }, }, };
That's all that's needed to set up the Remix Dev Server with TLS.
🚨 Make sure to update your app server for TLS as well.
For example, with
express
:import fs from "node:fs"; import https from "node:https"; import express from "express"; const app = express(); // ...code setting up your express app... const appServer = https.createServer( { key: fs.readFileSync("key.pem"), cert: fs.readFileSync("cert.pem"), }, app ); appServer.listen(3000, () => { console.log("Ready on https://localhost:3000"); });
remix-serve
does not yet support TLS. That means this only works for custom app server using the-c
flag for now. -
Reuse dev server port for WebSocket (Live Reload,HMR,HDR) (#6476)
As a result the
webSocketPort
/--websocket-port
option has been obsoleted. Additionally, scheme/host/port options for the dev server have been renamed.Available options are:
Option flag config default Command -c
/--command
command
remix-serve <server build path>
Scheme --scheme
scheme
http
Host --host
host
localhost
Port --port
port
Dynamically chosen open port No restart --no-restart
restart: false
restart: true
Note that scheme/host/port options are for the dev server, not your app server. You probably don't need to use scheme/host/port option if you aren't configuring networking (e.g. for Docker or SSL).
-
Add caching to PostCSS for regular stylesheets (#6505)
-
Fix warnings when importing CSS files with
future.unstable_dev
enabled (#6506) -
Fix Tailwind performance issue when
postcss.config.js
containsplugins: { tailwindcss: {} }
andremix.config.js
contains bothtailwind: true
andpostcss: true
. (#6468)Note that this was not an issue when the plugin function had been explicitly called, i.e.
plugins: [tailwindcss()]
. Remix avoids adding the Tailwind plugin to PostCSS if it's already present but we were failing to detect when the plugin function hadn't been called — either because the plugin function itself had been passed, i.e.plugins: [require('tailwindcss')]
, or the plugin config object syntax had been used, i.e.plugins: { tailwindcss: {} }
. -
Faster server export removal for routes when
unstable_dev
is enabled. (#6455)Also, only render modulepreloads on SSR. Do not render modulepreloads when hydrated.
-
Add
HeadersArgs
type to be consistent with loaders/actions/meta and allows for using afunction
declaration in addition to an arrow function expression (#6247)import type { HeadersArgs } from "@remix-run/node"; // or cloudflare/deno export function headers({ loaderHeaders }: HeadersArgs) { return { "x-my-custom-thing": loaderHeaders.get("x-my-custom-thing") || "fallback", }; }
-
better error message when
remix-serve
is not found (#6477) -
restore color for app server output (#6485)
-
Fix route ranking bug with pathless layout route next to a sibling index route (#4421)
- Under the hood this is done by removing the trailing slash from all generated
path
values since the number of slash-delimited segments counts towards route ranking so the trailing slash incorrectly increases the score for routes
- Under the hood this is done by removing the trailing slash from all generated
-
Support sibling pathless layout routes by removing pathless layout routes from the unique route path checks in conventional route generation since they inherently trigger duplicate paths (#4421)
-
fix dev server crashes caused by ungraceful hdr error handling (#6467)
-
Updated dependencies:
@remix-run/[email protected]
- Cross-module
loader
change detection for HDR (#6299) - Normalize path for dev server
PATH
envvar so that it works cross-platform (e.g. Windows) (#6310) - Fix CSS imports in JS files that use JSX (#6309)
- Kill app server when dev server exits (#6395)
- Wait until app server is killed before starting a new app server (#6289)
- Ensure CSS bundle changes result in a new manifest hash (#6374)
- Normalize file paths before testing if a changed file is a route entry (#6293)
- Fix race where app server responds with updated manifest version before dev server is listening for it (#6294)
- dev server now listens for updated versions before writing the server changes, guaranteeing that it is listening before the app server gets a chance to send its 'ready' message
- Only process
.css.ts
/.css.js
files with Vanilla Extract if@vanilla-extract/css
is installed (#6345) - Stop modifying a user's
tsconfig.json
when running usinggetConfig
(remix dev
,remix routes
,remix build
, etc) (#6156) - Cancel previous build when rebuild is kicked off to prevent rebuilds from hanging (#6295)
- Update minimum version of Babel dependencies to avoid errors parsing decorators (#6390)
- Support asset imports when detecting loader changes for HDR (#6396)
- Updated dependencies:
@remix-run/[email protected]
-
Enable support for CSS Modules, Vanilla Extract and CSS side-effect imports (#6046)
These CSS bundling features were previously only available via
future.unstable_cssModules
,future.unstable_vanillaExtract
andfuture.unstable_cssSideEffectImports
options inremix.config.js
, but they have now been stabilized.In order to use these features, check out our guide to CSS bundling in your project.
-
Stabilize built-in PostCSS support via the new
postcss
option inremix.config.js
. As a result, thefuture.unstable_postcss
option has also been deprecated. (#5960)The
postcss
option isfalse
by default, but when set totrue
will enable processing of all CSS files using PostCSS ifpostcss.config.js
is present.If you followed the original PostCSS setup guide for Remix, you may have a folder structure that looks like this, separating your source files from its processed output:
. ├── app │ └── styles (processed files) │ ├── app.css │ └── routes │ └── index.css └── styles (source files) ├── app.css └── routes └── index.css
After you've enabled the new
postcss
option, you can delete the processed files fromapp/styles
folder and move your source files fromstyles
toapp/styles
:. ├── app │ └── styles (source files) │ ├── app.css │ └── routes │ └── index.css
You should then remove
app/styles
from your.gitignore
file since it now contains source files rather than processed output.You can then update your
package.json
scripts to remove any usage ofpostcss
since Remix handles this automatically. For example, if you had followed the original setup guide:{ "scripts": { - "dev:css": "postcss styles --base styles --dir app/styles -w", - "build:css": "postcss styles --base styles --dir app/styles --env production", - "dev": "concurrently \"npm run dev:css\" \"remix dev\"" + "dev": "remix dev" } }
-
Stabilize built-in Tailwind support via the new
tailwind
option inremix.config.js
. As a result, thefuture.unstable_tailwind
option has also been deprecated. (#5960)The
tailwind
option isfalse
by default, but when set totrue
will enable built-in support for Tailwind functions and directives in your CSS files iftailwindcss
is installed.If you followed the original Tailwind setup guide for Remix and want to make use of this feature, you should first delete the generated
app/tailwind.css
.Then, if you have a
styles/tailwind.css
file, you should move it toapp/tailwind.css
.rm app/tailwind.css mv styles/tailwind.css app/tailwind.css
Otherwise, if you don't already have an
app/tailwind.css
file, you should create one with the following contents:@tailwind base; @tailwind components; @tailwind utilities;
You should then remove
/app/tailwind.css
from your.gitignore
file since it now contains source code rather than processed output.You can then update your
package.json
scripts to remove any usage oftailwindcss
since Remix handles this automatically. For example, if you had followed the original setup guide:{ // ... "scripts": { - "build": "run-s \"build:*\"", + "build": "remix build", - "build:css": "npm run generate:css -- --minify", - "build:remix": "remix build", - "dev": "run-p \"dev:*\"", + "dev": "remix dev", - "dev:css": "npm run generate:css -- --watch", - "dev:remix": "remix dev", - "generate:css": "npx tailwindcss -o ./app/tailwind.css", "start": "remix-serve build" } // ... }
-
The Remix dev server spins up your app server as a managed subprocess. (#6133) This keeps your development environment as close to production as possible. It also means that the Remix dev server is compatible with any app server.
By default, the dev server will use the Remix App Server, but you opt to use your own app server by specifying the command to run it via the
-c
/--command
flag:remix dev # uses `remix-serve <serve build path>` as the app server remix dev -c "node ./server.js" # uses your custom app server at `./server.js`
The dev server will:
- force
NODE_ENV=development
and warn you if it was previously set to something else - rebuild your app whenever your Remix app code changes
- restart your app server whenever rebuilds succeed
- handle live reload and HMR + Hot Data Revalidation
In order to manage your app server, the dev server needs to be told what server build is currently being used by your app server. This works by having the app server send a "I'm ready!" message with the Remix server build hash as the payload.
This is handled automatically in Remix App Server and is set up for you via calls to
broadcastDevReady
orlogDevReady
in the official Remix templates.If you are not using Remix App Server and your server doesn't call
broadcastDevReady
, you'll need to call it in your app server after it is up and running. For example, in an Express server:// server.js // <other imports> import { broadcastDevReady } from "@remix-run/node"; // Path to Remix's server build directory ('build/' by default) const BUILD_DIR = path.join(process.cwd(), "build"); // <code setting up your express server> app.listen(3000, () => { const build = require(BUILD_DIR); console.log("Ready: http://localhost:" + port); // in development, call `broadcastDevReady` _after_ your server is up and running if (process.env.NODE_ENV === "development") { broadcastDevReady(build); } });
Options priority order is: 1. flags, 2. config, 3. defaults.
Option flag config default Command -c
/--command
command
remix-serve <server build path>
HTTP(S) scheme --http-scheme
httpScheme
http
HTTP(S) host --http-host
httpHost
localhost
HTTP(S) port --http-port
httpPort
Dynamically chosen open port Websocket port --websocket-port
websocketPort
Dynamically chosen open port No restart --no-restart
restart: false
restart: true
🚨 The
--http-*
flags are only used for internal dev server <-> app server communication. Your app will run on your app server's normal URL.To set
unstable_dev
configuration, replaceunstable_dev: true
withunstable_dev: { <options> }
. For example, to set the HTTP(S) port statically:// remix.config.js module.exports = { future: { unstable_dev: { httpPort: 8001, }, }, };
You should only need to use the
--http-*
flags and--websocket-port
flag if you need fine-grain control of what scheme/host/port for the dev server. If you are setting up SSL or Docker networking, these are the flags you'll want to use.🚨 Remix will not set up SSL and custom host for you. The
--http-scheme
and--http-host
flag are for you to tell Remix how you've set things up. It is your task to set up SSL certificates and host files if you want those features.If you want to manage server changes yourself, you can use the
--no-restart
flag to tell the dev server to refrain from restarting your app server when builds succeed:remix dev -c "node ./server.js" --no-restart
For example, you could purge the
require
cache of your app server to keep it running while picking up server changes. If you do so, you should watch the server build path (build/
by default) for changes and only purge therequire
cache when changes are detected.🚨 If you use
--no-restart
, it is your responsibility to callbroadcastDevReady
when your app server has picked up server changes. For example, withchokidar
:// server.dev.js const BUILD_PATH = path.resolve(__dirname, "build"); const watcher = chokidar.watch(BUILD_PATH); watcher.on("change", () => { // 1. purge require cache purgeRequireCache(); // 2. load updated server build const build = require(BUILD_PATH); // 3. tell dev server that this app server is now ready broadcastDevReady(build); });
- force
- Fix absolute paths in CSS
url()
rules when using CSS Modules, Vanilla Extract and CSS side-effect imports (#5788) - look for @remix-run/serve in
devDependencies
when running remix dev (#6228) - add warning for v2 "cjs"->"esm"
serverModuleFormat
default change (#6154) - write mjs server output files (#6225)
- fix(react,dev): dev chunking and refresh race condition (#6201)
- Use correct require context in
bareImports
plugin. (#6181) - use minimatch for regex instead of glob-to-regexp (#6017)
- add
logDevReady
as replacement for platforms that can't initialize async I/O outside of the request response lifecycle. (#6204) - Use the "automatic" JSX runtime when processing MDX files. (#6098)
- forcibly kill app server during dev (#6197)
- show first compilation error instead of cancelation errors (#6202)
- Resolve imports from route modules across the graph back to the virtual module created by the v2 routes plugin. This fixes issues where we would duplicate portions of route modules that were imported. (#6098)
- Updated dependencies:
@remix-run/[email protected]
-
Added deprecation warning for
v2_normalizeFormMethod
(#5863) -
Added a new
future.v2_normalizeFormMethod
flag to normalize the exposeduseNavigation().formMethod
as an uppercase HTTP method to align with the previoususeTransition
behavior as well as thefetch()
behavior of normalizing to uppercase HTTP methods. (#5815)- When
future.v2_normalizeFormMethod === false
,useNavigation().formMethod
is lowercaseuseFetcher().formMethod
is uppercase
- When
future.v2_normalizeFormMethod === true
:useNavigation().formMethod
is uppercaseuseFetcher().formMethod
is uppercase
- When
-
Added deprecation warning for
browserBuildDirectory
inremix.config
(#5702) -
Added deprecation warning for
CatchBoundary
in favor offuture.v2_errorBoundary
(#5718) -
Added experimental support for Vanilla Extract caching, which can be enabled by setting
future.unstable_vanillaExtract: { cache: true }
inremix.config
. This is considered experimental due to the use of a brand new Vanilla Extract compiler under the hood. In order to use this feature, you must be using at leastv1.10.0
of@vanilla-extract/css
. (#5735) -
Added deprecation warning for
serverBuildDirectory
inremix.config
(#5704)
- Fixed issue to ensure changes to CSS inserted via
@remix-run/css-bundle
are picked up during HMR (#5823) - We now use
path.resolve
when re-exportingentry.client
(#5707) - Added support for
.mjs
and.cjs
extensions when detecting CSS side-effect imports (#5564) - Fixed resolution issues for pnpm users installing
react-refresh
(#5637) - Added deprecation warning for
future.v2_meta
(#5878) - Added optional entry file support for React 17 (#5681)
- Updated dependencies:
@remix-run/[email protected]
- dev server is resilient to build failures (#5795)
- Updated dependencies:
@remix-run/[email protected]
- remove premature deprecation warnings (#5790)
- Updated dependencies:
@remix-run/[email protected]
- Add types for importing
*.ico
files (#5430) - Allow
moduleResolution: "bundler"
in tsconfig.json (#5576) - Fix issue with x-route imports creating multiple entries in the module graph (#5721)
- Add
serverBuildTarget
deprecation warning (#5624) - Updated dependencies:
@remix-run/[email protected]
- Hot Module Replacement and Hot Data Revalidation (#5259)
- Requires
unstable_dev
future flag to be enabled - HMR provided through React Refresh
- Features:
- HMR for component and style changes
- HDR when loaders for current route change
- Known limitations for MVP:
- Only implemented for React via React Refresh
- No
import.meta.hot
API exposed yet - Revalidates all loaders on route when loader changes are detected
- Loader changes do not account for imported dependencies changing
- Requires
- Make
entry.client
andentry.server
files optional (#4600)- we'll use a bundled version of each unless you provide your own
-
Fixes flat route inconsistencies where
route.{ext}
wasn't always being treated likeindex.{ext}
when used in a folder (#5459)-
Route conflict no longer throw errors and instead display a helpful warning that we're using the first one we found.
⚠️ Route Path Collision: "/dashboard" The following routes all define the same URL, only the first one will be used 🟢️️ routes/dashboard/route.tsx ⭕️️ routes/dashboard.tsx
⚠️ Route Path Collision: "/" The following routes all define the same URL, only the first one will be used 🟢️️ routes/_landing._index.tsx ⭕️️ routes/_dashboard._index.tsx ⭕️ routes/_index.tsx
-
-
Log errors thrown during initial build in development. (#5441)
-
Sync
FutureConfig
interface between packages (#5398) -
Add file loader for importing
.csv
files (#3920) -
Updated dependencies:
@remix-run/[email protected]
- We are deprecating
serverBuildTarget
inremix.config
. See the release notes for v1.13.0 for more information. (#5354) - Add built-in support for PostCSS via the
future.unstable_postcss
feature flag (#5229) - Add built-in support for Tailwind via the
future.unstable_tailwind
feature flag (#5229)
- Mark Vanilla Extract files as side effects to ensure that files only containing global styles aren't tree-shaken (#5246)
- Support decorators in files using CSS side-effect imports (#5305)
- We made several Flat route fixes and enhancements. See the release notes for v1.13.0 for more information. (#5228)
- Updated dependencies:
@remix-run/[email protected]
- Added a new development server available in the Remix config under the
unstable_dev
flag. See the release notes for a full description. (#5133)
- Fixed issues with
v2_routeConvention
on Windows so that new and renamed files are properly included (#5266) - Server build should not be removed in
remix watch
andremix dev
(#5228) - The dev server will now clean up build directories whenever a rebuild starts (#5223)
- Updated dependencies:
@remix-run/[email protected]
- Fixed a bug with
v2_routeConvention
that preventedindex
modules from being recognized for route paths (195291a3d
) - Updated dependencies:
@remix-run/[email protected]
- Specify file loader for
.fbx
,.glb
,.gltf
,.hdr
, and.mov
files (#5030) - Added support for Vanilla Extract via the
unstable_vanillaExtract
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#5040) - Add support for CSS side-effect imports via the
unstable_cssSideEffectImports
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4919) - Add support for CSS Modules via the
unstable_cssModules
future flag. IMPORTANT: Features marked withunstable
are … unstable. While we're confident in the use cases they solve, the API and implementation may change without a major version bump. (#4852)
- Add new "flat" routing conventions. This convention will be the default in v2 but is available now under the
v2_routeConvention
future flag. (#4880) - Added support for
handle
in MDX frontmatter (#4865) - Updated dependencies:
@remix-run/[email protected]
- Update babel config to transpile down to node 14 (#5047)
- Updated dependencies:
@remix-run/[email protected]
- Fixed several issues with TypeScript to JavaScript conversion when running
create-remix
(#4891) - Resolve asset entry full path to support monorepo import of styles (#4855)
- Updated dependencies:
@remix-run/[email protected]
- Allow defining multiple routes for the same route module file (#3970)
- Added support and conventions for optional route segments (#4706)
- The Remix compiler now supports new Typescript 4.9 syntax (like the
satisfies
keyword) (#4754) - Optimize
parentRouteId
lookup indefineConventionalRoutes
. (#4800) - Fixed a bug in
.ts
->.js
conversion on Windows by using a relative unix-style path (#4718) - Updated dependencies:
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Added a missing type definition for the Remix config
future
option to the@remix-run/dev/server-build
virtual module (#4771) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Added support for a new route
meta
API to handle arrays of tags instead of an object. For details, check out the RFC. (#4610)
- Importing functions and types from the
remix
package is deprecated, and all exported modules will be removed in the next major release. For more details,see the release notes for 1.4.0 where these changes were first announced. (#4661) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Update
create-remix
to use the new examples repository when using--template example/<name>
(#4208) - Add support for setting
moduleResolution
tonode
,node16
ornodenext
intsconfig.json
. (#4034) - Add resources imported only by resource routes to
assetsBuildDirectory
(#3841) - Ensure that any assets referenced in CSS files are hashed and copied to the
assetsBuildDirectory
. (#4130) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Added support for importing
.gql
and.graphql
files as plain text (#3923) - Added support for importing
.zip
and.avif
files as resource URLs (#3985)
- Removed our compiler's React shim in favor of esbuild's new automatic JSX transform (#3860)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Added support for
.mjs
and.cjs
file extensions forremix.config
(#3675) - Added support for importing
.sql
files as text content (#3190) - Updated the compiler to make MDX builds deterministic (and a little faster!) (#3966)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Remove logical nullish assignment, which is incompatible with Node v14. (#3880)
- Don't show ESM warnings when consumed via dynamic import. (#3872)
- Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]
- Write server build output files so that only assets imported from resource routes are written to disk (#3817)
- Add support for exporting links in
.mdx
files (#3801) - Ensure that build hashing is deterministic (#2027)
- Fix types for
@remix-run/dev/server-build
virtual module (#3743) - Updated dependencies:
@remix-run/[email protected]
@remix-run/[email protected]