- 
BREAKING CHANGE: Rework how middleware works in the router. This change has far-reaching implications.
Previously, the router would associate all middleware with a route. If no routes matched, middleware would not run. We partially addressed this in 0.7 by always running global middleware, even when no route matches. However, the router would still run its route matching algorithm before determining that no routes matched, so it could proceed to run global middleware and the default handler.
In this release,
router.use()has been replaced withcreateRouter({ middleware }). Middleware that is provided tocreateRouter()is "router middleware" (aka "global" middleware) that runs before the router tries to do any route matching. Router middleware may therefore modify the request context in ways that may affect route matching, including modifyingcontext.methodand/orcontext.url. Router middleware runs on every request, even when no routes match.Middleware is still supported at the route level on individual routes, but it is only invoked when that route matches. This is "route middleware" (or "inline" middleware) and runs downstream from router middleware.
To migrate, move middleware from
router.use()tocreateRouter({ middleware }).// before let router = createRouter() router.use(middleware) router.map(routes.home, () => new Response('Home')) // after let router = createRouter({ middleware: [middleware], }) router.map(routes.home, () => new Response('Home'))
 - 
BREAKING CHANGE: Rename
use=>middlewarein route handler definitions// before router.map(routes.home, { use: [middleware], handler() { return new Response('Home') }, }) // after router.map(routes.home, { middleware: [middleware], handler() { return new Response('Home') }, })
 - 
BREAKING CHANGE: Remove
router.mount()and support for sub-routers. We may add this back in a future release if there is demand for it. - 
BREAKING CHANGE: Move
FormDataparsing and method override handling out of the router and into separate middleware exports. SincemethodOverride()providescontext.method(used for route matching), it must be router (or "global") middleware. Also, it requirescontext.formData, so it must be after theformData()middleware in the middleware chain. This change also moves thecreateRouter({ parseFormData, methodOverride, uploadHandler })options to theformData()andmethodOverride()middlewares.// before let router = createRouter({ parseFormData: true, methodOverride: true, uploadHandler }) // after import { formData } from '@remix-run/fetch-router/form-data-middleware' import { methodOverride } from '@remix-run/fetch-router/method-override-middleware' let router = createRouter() router.use(formData({ uploadHandler })) router.use(methodOverride())
This change makes things a little more verbose but should ultimately lead to more flexible middleware composition and a smaller core build.