Change8

remix@3.0.0-beta.4

Breaking Changes
📦 remixView on GitHub →
2 breaking8 features🐛 2 fixes🔧 23 symbols

Summary

This pre-release introduces significant router enhancements, including route mounting capabilities and improved middleware contract enforcement, alongside better Node assertion compatibility.

⚠️ Breaking Changes

  • Middleware consumed through `remix/router` and `remix/fetch-router` must now explicitly continue the request chain by calling `next()` or return a `Response`. Middleware that returned `undefined` without calling `next()` now throws at runtime instead of implicitly continuing. Fix by ensuring middleware returns `next()` or a `Response`.
  • `MapTarget` and `MapHandler` are no longer re-exported from `remix/router` or `remix/fetch-router`. Use the public `Router`, `RouteBuilder`, `RouteInstaller`, `Action`, and `Controller` types instead.

Migration Steps

  1. Update context-loading middleware in `remix/router` or `remix/fetch-router` to explicitly return the downstream response, typically by calling `return next()`.
  2. Replace usage of re-exported `MapTarget` and `MapHandler` with the public `Router`, `RouteBuilder`, `RouteInstaller`, `Action`, and `Controller` types.

✨ New Features

  • Added `router.mount()` and the `RouteBuilder`/`RouteInstaller` types to `remix/router` and `remix/fetch-router` to allow building larger apps from smaller route groups.
  • Params from the mount pattern are available to mounted handlers; duplicate param names follow `route-pattern` behavior where the right-most param wins.
  • `RouterContext<typeof router>` extracts the request context provided by a router or route builder, allowing apps to keep root middleware inline.
  • `createAction()`, direct action objects, and `createController()` now infer middleware-provided values from plain inline middleware arrays, reducing the need for explicit generics.
  • `createMiddleware()` creates reusable middleware chains that preserve their tuple type without `as const` across inference boundaries.
  • The public type surface for re-exported router types is smaller, preserving route params, middleware context inference, and stored action/controller compatibility checks.
  • Exposed `remix/test` timeout and abort signal support through the main Remix package; tests/lifecycle hooks can pass `{ timeout, signal }`, and `t.signal` aborts on timeout.
  • String `skip`/`todo` reasons now flow through `remix/test` results and reporter output.

🐛 Bug Fixes

  • Improved Node compatibility for the `remix/assert` entrypoint: default export is callable as `assert.ok` alias, failure errors expose Node-style metadata, expected-error/message handling aligns closer to `node:assert/strict`, strict/deep equality handles `Object.is` and built-in object comparisons more consistently with Node.
  • Kept generated README mirrors in the published `remix` package so documentation remains available at `node_modules/remix/src/<subpath>/README.md`.

Affected Symbols