react-router 7.16.0 → 8.0.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -1
- package/dist/development/dom-export.d.ts +6 -172
- package/dist/development/dom-export.js +12 -1007
- package/dist/development/index-react-server-client.d.ts +7 -4
- package/dist/development/index-react-server-client.js +8 -52
- package/dist/development/index-react-server.d.ts +1645 -1635
- package/dist/development/index-react-server.js +2880 -3642
- package/dist/development/index.d.ts +43 -1475
- package/dist/development/index.js +37 -2621
- package/dist/development/lib/actions.js +62 -0
- package/dist/development/lib/components.d.ts +1022 -0
- package/dist/development/lib/components.js +835 -0
- package/dist/development/lib/context.d.ts +83 -0
- package/dist/development/lib/context.js +41 -0
- package/dist/development/lib/dom/dom.d.ts +119 -0
- package/dist/development/lib/dom/dom.js +143 -0
- package/dist/development/lib/dom/lib.d.ts +2042 -0
- package/dist/development/lib/dom/lib.js +1259 -0
- package/dist/development/lib/dom/server.d.ts +138 -0
- package/dist/development/lib/dom/server.js +301 -0
- package/dist/development/lib/dom/ssr/components.d.ts +196 -0
- package/dist/development/lib/dom/ssr/components.js +579 -0
- package/dist/development/lib/dom/ssr/data.js +29 -0
- package/dist/development/lib/dom/ssr/entry.d.ts +59 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.d.ts +27 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.js +83 -0
- package/dist/development/lib/dom/ssr/errors.d.ts +7 -0
- package/dist/development/lib/dom/ssr/errors.js +36 -0
- package/dist/development/lib/dom/ssr/fallback.js +28 -0
- package/dist/development/lib/dom/ssr/fog-of-war.d.ts +12 -0
- package/dist/development/lib/dom/ssr/fog-of-war.js +170 -0
- package/dist/development/lib/dom/ssr/hydration.d.ts +32 -0
- package/dist/development/lib/dom/ssr/hydration.js +29 -0
- package/dist/development/lib/dom/ssr/invariant.js +16 -0
- package/dist/development/lib/dom/ssr/links.js +170 -0
- package/dist/development/lib/dom/ssr/markup.js +24 -0
- package/dist/development/lib/dom/ssr/routeModules.d.ts +206 -0
- package/dist/development/lib/dom/ssr/routeModules.js +31 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +62 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.js +108 -0
- package/dist/development/lib/dom/ssr/routes.d.ts +33 -0
- package/dist/development/lib/dom/ssr/routes.js +303 -0
- package/dist/development/lib/dom/ssr/server.d.ts +45 -0
- package/dist/development/lib/dom/ssr/server.js +68 -0
- package/dist/development/lib/dom/ssr/single-fetch.d.ts +14 -0
- package/dist/development/lib/dom/ssr/single-fetch.js +346 -0
- package/dist/development/lib/dom-export/dom-router-provider.d.ts +9 -0
- package/dist/development/lib/dom-export/dom-router-provider.js +22 -0
- package/dist/development/lib/dom-export/hydrated-router.d.ts +125 -0
- package/dist/development/lib/dom-export/hydrated-router.js +153 -0
- package/dist/development/lib/errors.js +29 -0
- package/dist/development/lib/hooks.d.ts +947 -0
- package/dist/development/lib/hooks.js +1386 -0
- package/dist/development/lib/href.d.ts +20 -0
- package/dist/development/lib/href.js +50 -0
- package/dist/development/lib/router/history.d.ts +258 -0
- package/dist/development/lib/router/history.js +371 -0
- package/dist/development/lib/router/instrumentation.d.ts +86 -0
- package/dist/development/lib/router/instrumentation.js +213 -0
- package/dist/development/lib/router/links.d.ts +113 -0
- package/dist/development/lib/router/router.d.ts +663 -0
- package/dist/development/lib/router/router.js +2981 -0
- package/dist/development/lib/router/utils.d.ts +942 -0
- package/dist/development/lib/router/utils.js +791 -0
- package/dist/development/lib/rsc/browser.d.ts +137 -0
- package/dist/development/lib/rsc/browser.js +599 -0
- package/dist/development/lib/rsc/errorBoundaries.d.ts +11 -0
- package/dist/development/lib/rsc/errorBoundaries.js +90 -0
- package/dist/development/lib/rsc/html-stream/browser.d.ts +48 -0
- package/dist/development/lib/rsc/html-stream/browser.js +74 -0
- package/dist/development/lib/rsc/html-stream/server.js +78 -0
- package/dist/development/lib/rsc/route-modules.js +27 -0
- package/dist/development/lib/rsc/server.rsc.d.ts +219 -0
- package/dist/development/lib/rsc/server.ssr.d.ts +129 -0
- package/dist/development/lib/rsc/server.ssr.js +388 -0
- package/dist/development/lib/server-runtime/build.d.ts +66 -0
- package/dist/development/lib/server-runtime/cookies.d.ts +66 -0
- package/dist/development/lib/server-runtime/cookies.js +139 -0
- package/dist/development/lib/server-runtime/crypto.js +43 -0
- package/dist/development/lib/server-runtime/data.d.ts +13 -0
- package/dist/development/lib/server-runtime/data.js +25 -0
- package/dist/development/lib/server-runtime/dev.d.ts +9 -0
- package/dist/development/lib/server-runtime/dev.js +26 -0
- package/dist/development/lib/server-runtime/entry.js +20 -0
- package/dist/development/lib/server-runtime/errors.js +95 -0
- package/dist/development/lib/server-runtime/headers.js +73 -0
- package/dist/development/lib/server-runtime/invariant.js +19 -0
- package/dist/development/lib/server-runtime/mode.d.ts +12 -0
- package/dist/development/lib/server-runtime/mode.js +25 -0
- package/dist/development/lib/server-runtime/routeMatching.js +28 -0
- package/dist/development/lib/server-runtime/routes.d.ts +13 -0
- package/dist/development/lib/server-runtime/routes.js +74 -0
- package/dist/development/lib/server-runtime/server.d.ts +10 -0
- package/dist/development/lib/server-runtime/server.js +351 -0
- package/dist/development/lib/server-runtime/serverHandoff.js +17 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +25 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +45 -0
- package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +23 -0
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +52 -0
- package/dist/development/lib/server-runtime/sessions.d.ts +145 -0
- package/dist/development/lib/server-runtime/sessions.js +98 -0
- package/dist/development/lib/server-runtime/single-fetch.d.ts +7 -0
- package/dist/development/lib/server-runtime/single-fetch.js +215 -0
- package/dist/development/lib/server-runtime/urls.js +31 -0
- package/dist/development/lib/server-runtime/warnings.js +20 -0
- package/dist/development/lib/types/future.d.ts +9 -0
- package/dist/development/lib/types/internal.d.ts +26 -177
- package/dist/development/lib/types/internal.js +3 -2
- package/dist/{production/register-CNAx3TXj.d.ts → development/lib/types/register.d.ts} +9 -15
- package/dist/development/lib/types/route-data.d.ts +113 -0
- package/dist/development/lib/types/route-module-annotations.d.ts +149 -0
- package/dist/development/lib/types/route-module.d.ts +19 -0
- package/dist/development/lib/types/serializes-to.d.ts +13 -0
- package/dist/development/lib/types/utils.d.ts +11 -0
- package/dist/development/vendor/turbo-stream-v2/flatten.js +159 -0
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +178 -0
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +198 -0
- package/dist/development/vendor/turbo-stream-v2/utils.js +47 -0
- package/dist/production/dom-export.d.ts +6 -172
- package/dist/production/dom-export.js +12 -1007
- package/dist/production/index-react-server-client.d.ts +7 -4
- package/dist/production/index-react-server-client.js +8 -52
- package/dist/production/index-react-server.d.ts +1645 -1635
- package/dist/production/index-react-server.js +2871 -3642
- package/dist/production/index.d.ts +43 -1475
- package/dist/production/index.js +37 -2621
- package/dist/production/lib/actions.js +62 -0
- package/dist/production/lib/components.d.ts +1022 -0
- package/dist/production/lib/components.js +835 -0
- package/dist/production/lib/context.d.ts +83 -0
- package/dist/production/lib/context.js +41 -0
- package/dist/production/lib/dom/dom.d.ts +119 -0
- package/dist/production/lib/dom/dom.js +143 -0
- package/dist/production/lib/dom/lib.d.ts +2042 -0
- package/dist/production/lib/dom/lib.js +1259 -0
- package/dist/production/lib/dom/server.d.ts +138 -0
- package/dist/production/lib/dom/server.js +301 -0
- package/dist/production/lib/dom/ssr/components.d.ts +196 -0
- package/dist/production/lib/dom/ssr/components.js +579 -0
- package/dist/production/lib/dom/ssr/data.js +29 -0
- package/dist/production/lib/dom/ssr/entry.d.ts +59 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.d.ts +27 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.js +83 -0
- package/dist/production/lib/dom/ssr/errors.d.ts +7 -0
- package/dist/production/lib/dom/ssr/errors.js +36 -0
- package/dist/production/lib/dom/ssr/fallback.js +21 -0
- package/dist/production/lib/dom/ssr/fog-of-war.d.ts +12 -0
- package/dist/production/lib/dom/ssr/fog-of-war.js +170 -0
- package/dist/production/lib/dom/ssr/hydration.d.ts +32 -0
- package/dist/production/lib/dom/ssr/hydration.js +29 -0
- package/dist/production/lib/dom/ssr/invariant.js +16 -0
- package/dist/production/lib/dom/ssr/links.js +170 -0
- package/dist/production/lib/dom/ssr/markup.js +24 -0
- package/dist/production/lib/dom/ssr/routeModules.d.ts +206 -0
- package/dist/production/lib/dom/ssr/routeModules.js +31 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +62 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.js +108 -0
- package/dist/production/lib/dom/ssr/routes.d.ts +33 -0
- package/dist/production/lib/dom/ssr/routes.js +303 -0
- package/dist/production/lib/dom/ssr/server.d.ts +45 -0
- package/dist/production/lib/dom/ssr/server.js +68 -0
- package/dist/production/lib/dom/ssr/single-fetch.d.ts +14 -0
- package/dist/production/lib/dom/ssr/single-fetch.js +346 -0
- package/dist/production/lib/dom-export/dom-router-provider.d.ts +9 -0
- package/dist/production/lib/dom-export/dom-router-provider.js +22 -0
- package/dist/production/lib/dom-export/hydrated-router.d.ts +125 -0
- package/dist/production/lib/dom-export/hydrated-router.js +153 -0
- package/dist/production/lib/errors.js +29 -0
- package/dist/production/lib/hooks.d.ts +947 -0
- package/dist/production/lib/hooks.js +1371 -0
- package/dist/production/lib/href.d.ts +20 -0
- package/dist/production/lib/href.js +50 -0
- package/dist/production/lib/router/history.d.ts +258 -0
- package/dist/production/lib/router/history.js +371 -0
- package/dist/production/lib/router/instrumentation.d.ts +86 -0
- package/dist/production/lib/router/instrumentation.js +213 -0
- package/dist/production/lib/router/links.d.ts +113 -0
- package/dist/production/lib/router/router.d.ts +663 -0
- package/dist/production/lib/router/router.js +2981 -0
- package/dist/production/lib/router/utils.d.ts +942 -0
- package/dist/production/lib/router/utils.js +782 -0
- package/dist/production/lib/rsc/browser.d.ts +137 -0
- package/dist/production/lib/rsc/browser.js +599 -0
- package/dist/production/lib/rsc/errorBoundaries.d.ts +11 -0
- package/dist/production/lib/rsc/errorBoundaries.js +90 -0
- package/dist/production/lib/rsc/html-stream/browser.d.ts +48 -0
- package/dist/production/lib/rsc/html-stream/browser.js +74 -0
- package/dist/production/lib/rsc/html-stream/server.js +78 -0
- package/dist/production/lib/rsc/route-modules.js +27 -0
- package/dist/production/lib/rsc/server.rsc.d.ts +219 -0
- package/dist/production/lib/rsc/server.ssr.d.ts +129 -0
- package/dist/production/lib/rsc/server.ssr.js +388 -0
- package/dist/production/lib/server-runtime/build.d.ts +66 -0
- package/dist/production/lib/server-runtime/cookies.d.ts +66 -0
- package/dist/production/lib/server-runtime/cookies.js +139 -0
- package/dist/production/lib/server-runtime/crypto.js +43 -0
- package/dist/production/lib/server-runtime/data.d.ts +13 -0
- package/dist/production/lib/server-runtime/data.js +25 -0
- package/dist/production/lib/server-runtime/dev.d.ts +9 -0
- package/dist/production/lib/server-runtime/dev.js +26 -0
- package/dist/production/lib/server-runtime/entry.js +20 -0
- package/dist/production/lib/server-runtime/errors.js +95 -0
- package/dist/production/lib/server-runtime/headers.js +73 -0
- package/dist/production/lib/server-runtime/invariant.js +19 -0
- package/dist/production/lib/server-runtime/mode.d.ts +12 -0
- package/dist/production/lib/server-runtime/mode.js +25 -0
- package/dist/production/lib/server-runtime/routeMatching.js +28 -0
- package/dist/production/lib/server-runtime/routes.d.ts +13 -0
- package/dist/production/lib/server-runtime/routes.js +74 -0
- package/dist/production/lib/server-runtime/server.d.ts +10 -0
- package/dist/production/lib/server-runtime/server.js +351 -0
- package/dist/production/lib/server-runtime/serverHandoff.js +17 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +25 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +45 -0
- package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +23 -0
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +52 -0
- package/dist/production/lib/server-runtime/sessions.d.ts +145 -0
- package/dist/production/lib/server-runtime/sessions.js +98 -0
- package/dist/production/lib/server-runtime/single-fetch.d.ts +7 -0
- package/dist/production/lib/server-runtime/single-fetch.js +215 -0
- package/dist/production/lib/server-runtime/urls.js +31 -0
- package/dist/production/lib/server-runtime/warnings.js +20 -0
- package/dist/production/lib/types/future.d.ts +9 -0
- package/dist/production/lib/types/internal.d.ts +26 -177
- package/dist/production/lib/types/internal.js +3 -2
- package/dist/{development/register-CNAx3TXj.d.ts → production/lib/types/register.d.ts} +9 -15
- package/dist/production/lib/types/route-data.d.ts +113 -0
- package/dist/production/lib/types/route-module-annotations.d.ts +149 -0
- package/dist/production/lib/types/route-module.d.ts +19 -0
- package/dist/production/lib/types/serializes-to.d.ts +13 -0
- package/dist/production/lib/types/utils.d.ts +11 -0
- package/dist/production/vendor/turbo-stream-v2/flatten.js +159 -0
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +178 -0
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +198 -0
- package/dist/production/vendor/turbo-stream-v2/utils.js +47 -0
- package/docs/explanation/backend-for-frontend.md +50 -0
- package/docs/explanation/code-splitting.md +77 -0
- package/docs/explanation/concurrency.md +135 -0
- package/docs/explanation/form-vs-fetcher.md +292 -0
- package/docs/explanation/hot-module-replacement.md +137 -0
- package/docs/explanation/hydration.md +14 -0
- package/docs/explanation/index-query-param.md +86 -0
- package/docs/explanation/index.md +4 -0
- package/docs/explanation/lazy-route-discovery.md +78 -0
- package/docs/explanation/location.md +6 -0
- package/docs/explanation/progressive-enhancement.md +150 -0
- package/docs/explanation/race-conditions.md +88 -0
- package/docs/explanation/react-transitions.md +160 -0
- package/docs/explanation/route-matching.md +7 -0
- package/docs/explanation/server-client-execution.md +4 -0
- package/docs/explanation/sessions-and-cookies.md +465 -0
- package/docs/explanation/special-files.md +16 -0
- package/docs/explanation/state-management.md +524 -0
- package/docs/explanation/styling.md +87 -0
- package/docs/explanation/type-safety.md +82 -0
- package/docs/how-to/accessibility.md +44 -0
- package/docs/how-to/client-data.md +199 -0
- package/docs/how-to/data-strategy.md +317 -0
- package/docs/how-to/error-boundary.md +231 -0
- package/docs/how-to/error-reporting.md +134 -0
- package/docs/how-to/fetchers.md +307 -0
- package/docs/how-to/file-route-conventions.md +410 -0
- package/docs/how-to/file-uploads.md +217 -0
- package/docs/how-to/form-validation.md +120 -0
- package/docs/how-to/headers.md +164 -0
- package/docs/how-to/index.md +4 -0
- package/docs/how-to/instrumentation.md +556 -0
- package/docs/how-to/meta.md +40 -0
- package/docs/how-to/middleware.md +728 -0
- package/docs/how-to/navigation-blocking.md +233 -0
- package/docs/how-to/optimize-revalidation.md +12 -0
- package/docs/how-to/pre-rendering.md +225 -0
- package/docs/how-to/presets.md +103 -0
- package/docs/how-to/react-server-components.md +899 -0
- package/docs/how-to/resource-routes.md +126 -0
- package/docs/how-to/route-module-type-safety.md +100 -0
- package/docs/how-to/search-params.md +4 -0
- package/docs/how-to/security.md +30 -0
- package/docs/how-to/server-bundles.md +66 -0
- package/docs/how-to/spa.md +120 -0
- package/docs/how-to/status.md +63 -0
- package/docs/how-to/suspense.md +132 -0
- package/docs/how-to/using-handle.md +117 -0
- package/docs/how-to/view-transitions.md +237 -0
- package/docs/how-to/webhook.md +50 -0
- package/docs/index.md +39 -0
- package/docs/start/data/actions.md +138 -0
- package/docs/start/data/custom.md +198 -0
- package/docs/start/data/data-loading.md +44 -0
- package/docs/start/data/index.md +4 -0
- package/docs/start/data/installation.md +52 -0
- package/docs/start/data/navigating.md +12 -0
- package/docs/start/data/pending-ui.md +12 -0
- package/docs/start/data/route-object.md +248 -0
- package/docs/start/data/routing.md +281 -0
- package/docs/start/data/testing.md +8 -0
- package/docs/start/declarative/index.md +4 -0
- package/docs/start/declarative/installation.md +43 -0
- package/docs/start/declarative/navigating.md +133 -0
- package/docs/start/declarative/routing.md +237 -0
- package/docs/start/declarative/url-values.md +65 -0
- package/docs/start/framework/actions.md +175 -0
- package/docs/start/framework/data-loading.md +201 -0
- package/docs/start/framework/deploying.md +96 -0
- package/docs/start/framework/index.md +4 -0
- package/docs/start/framework/installation.md +42 -0
- package/docs/start/framework/navigating.md +182 -0
- package/docs/start/framework/pending-ui.md +142 -0
- package/docs/start/framework/rendering.md +59 -0
- package/docs/start/framework/route-module.md +527 -0
- package/docs/start/framework/routing.md +362 -0
- package/docs/start/framework/testing.md +133 -0
- package/docs/start/index.md +4 -0
- package/docs/start/modes.md +201 -0
- package/docs/upgrading/component-routes.md +363 -0
- package/docs/upgrading/future.md +31 -0
- package/docs/upgrading/index.md +4 -0
- package/docs/upgrading/remix.md +403 -0
- package/docs/upgrading/router-provider.md +442 -0
- package/docs/upgrading/v6.md +379 -0
- package/package.json +44 -87
- package/dist/development/browser-D3uq9sI1.d.ts +0 -318
- package/dist/development/browser-nIQ4Nsyi.d.mts +0 -318
- package/dist/development/chunk-IBI7OMNB.js +0 -1363
- package/dist/development/chunk-QUQL4437.mjs +0 -11529
- package/dist/development/chunk-S54KXAEJ.mjs +0 -2585
- package/dist/development/chunk-SRID2YZ2.js +0 -10229
- package/dist/development/chunk-XEJDWL2B.js +0 -188
- package/dist/development/context-m8rizgnE.d.mts +0 -1771
- package/dist/development/data-D4xhSy90.d.ts +0 -1732
- package/dist/development/data-U8FS-wNn.d.mts +0 -1732
- package/dist/development/dom-export.d.mts +0 -172
- package/dist/development/dom-export.mjs +0 -1008
- package/dist/development/index-react-server-client-BLiUx67a.d.ts +0 -3655
- package/dist/development/index-react-server-client-CdKROblb.d.mts +0 -2600
- package/dist/development/index-react-server-client.d.mts +0 -4
- package/dist/development/index-react-server-client.mjs +0 -59
- package/dist/development/index-react-server.d.mts +0 -2703
- package/dist/development/index-react-server.mjs +0 -3780
- package/dist/development/index.d.mts +0 -1478
- package/dist/development/index.mjs +0 -277
- package/dist/development/instrumentation-1q4YhLGP.d.ts +0 -715
- package/dist/development/lib/types/internal.d.mts +0 -184
- package/dist/development/lib/types/internal.mjs +0 -10
- package/dist/development/register-CqK96Zfk.d.mts +0 -30
- package/dist/production/browser-D3uq9sI1.d.ts +0 -318
- package/dist/production/browser-nIQ4Nsyi.d.mts +0 -318
- package/dist/production/chunk-EAQNHM3N.js +0 -188
- package/dist/production/chunk-NALGHHKE.mjs +0 -2585
- package/dist/production/chunk-Q65P7S7Y.mjs +0 -11529
- package/dist/production/chunk-SKEDDLRM.js +0 -1363
- package/dist/production/chunk-Y7DNFQZP.js +0 -10229
- package/dist/production/context-m8rizgnE.d.mts +0 -1771
- package/dist/production/data-D4xhSy90.d.ts +0 -1732
- package/dist/production/data-U8FS-wNn.d.mts +0 -1732
- package/dist/production/dom-export.d.mts +0 -172
- package/dist/production/dom-export.mjs +0 -1008
- package/dist/production/index-react-server-client-BLiUx67a.d.ts +0 -3655
- package/dist/production/index-react-server-client-CdKROblb.d.mts +0 -2600
- package/dist/production/index-react-server-client.d.mts +0 -4
- package/dist/production/index-react-server-client.mjs +0 -59
- package/dist/production/index-react-server.d.mts +0 -2703
- package/dist/production/index-react-server.mjs +0 -3780
- package/dist/production/index.d.mts +0 -1478
- package/dist/production/index.mjs +0 -277
- package/dist/production/instrumentation-1q4YhLGP.d.ts +0 -715
- package/dist/production/lib/types/internal.d.mts +0 -184
- package/dist/production/lib/types/internal.mjs +0 -10
- package/dist/production/register-CqK96Zfk.d.mts +0 -30
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Navigation Blocking
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Navigation Blocking
|
|
6
|
+
|
|
7
|
+
[MODES: framework, data]
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
<br/>
|
|
11
|
+
|
|
12
|
+
When users are in the middle of a workflow, like filling out an important form, you may want to prevent them from navigating away from the page.
|
|
13
|
+
|
|
14
|
+
This example will show:
|
|
15
|
+
|
|
16
|
+
- Setting up a route with a form and action called with a fetcher
|
|
17
|
+
- Blocking navigation when the form is dirty
|
|
18
|
+
- Showing a confirmation when the user tries to leave the page
|
|
19
|
+
|
|
20
|
+
## 1. Set up a route with a form
|
|
21
|
+
|
|
22
|
+
Add a route with the form, we'll use a "contact" route for this example:
|
|
23
|
+
|
|
24
|
+
```ts filename=routes.ts
|
|
25
|
+
import {
|
|
26
|
+
type RouteConfig,
|
|
27
|
+
index,
|
|
28
|
+
route,
|
|
29
|
+
} from "@react-router/dev/routes";
|
|
30
|
+
|
|
31
|
+
export default [
|
|
32
|
+
index("routes/home.tsx"),
|
|
33
|
+
route("contact", "routes/contact.tsx"),
|
|
34
|
+
] satisfies RouteConfig;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Add the form to the contact route module:
|
|
38
|
+
|
|
39
|
+
```tsx filename=routes/contact.tsx
|
|
40
|
+
import { useFetcher } from "react-router";
|
|
41
|
+
import type { Route } from "./+types/contact";
|
|
42
|
+
|
|
43
|
+
export async function action({
|
|
44
|
+
request,
|
|
45
|
+
}: Route.ActionArgs) {
|
|
46
|
+
let formData = await request.formData();
|
|
47
|
+
let email = formData.get("email");
|
|
48
|
+
let message = formData.get("message");
|
|
49
|
+
console.log(email, message);
|
|
50
|
+
return { ok: true };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default function Contact() {
|
|
54
|
+
let fetcher = useFetcher();
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<fetcher.Form method="post">
|
|
58
|
+
<p>
|
|
59
|
+
<label>
|
|
60
|
+
Email: <input name="email" type="email" />
|
|
61
|
+
</label>
|
|
62
|
+
</p>
|
|
63
|
+
<p>
|
|
64
|
+
<textarea name="message" />
|
|
65
|
+
</p>
|
|
66
|
+
<p>
|
|
67
|
+
<button type="submit">
|
|
68
|
+
{fetcher.state === "idle" ? "Send" : "Sending..."}
|
|
69
|
+
</button>
|
|
70
|
+
</p>
|
|
71
|
+
</fetcher.Form>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 2. Add dirty state and onChange handler
|
|
77
|
+
|
|
78
|
+
To track the dirty state of the form, we'll use a single boolean and a quick form onChange handler. You may want to track the dirty state differently but this works for this guide.
|
|
79
|
+
|
|
80
|
+
```tsx filename=routes/contact.tsx lines=[2,8-12]
|
|
81
|
+
export default function Contact() {
|
|
82
|
+
let [isDirty, setIsDirty] = useState(false);
|
|
83
|
+
let fetcher = useFetcher();
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<fetcher.Form
|
|
87
|
+
method="post"
|
|
88
|
+
onChange={(event) => {
|
|
89
|
+
let email = event.currentTarget.email.value;
|
|
90
|
+
let message = event.currentTarget.message.value;
|
|
91
|
+
setIsDirty(Boolean(email || message));
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
{/* existing code */}
|
|
95
|
+
</fetcher.Form>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 3. Block navigation when the form is dirty
|
|
101
|
+
|
|
102
|
+
```tsx filename=routes/contact.tsx lines=[1,6-8]
|
|
103
|
+
import { useBlocker } from "react-router";
|
|
104
|
+
|
|
105
|
+
export default function Contact() {
|
|
106
|
+
let [isDirty, setIsDirty] = useState(false);
|
|
107
|
+
let fetcher = useFetcher();
|
|
108
|
+
let blocker = useBlocker(
|
|
109
|
+
useCallback(() => isDirty, [isDirty]),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// ... existing code
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
While this will now block a navigation, there's no way for the user to confirm it.
|
|
117
|
+
|
|
118
|
+
## 4. Show confirmation UI
|
|
119
|
+
|
|
120
|
+
This uses a simple div, but you may want to use a modal dialog.
|
|
121
|
+
|
|
122
|
+
```tsx filename=routes/contact.tsx lines=[19-41]
|
|
123
|
+
export default function Contact() {
|
|
124
|
+
let [isDirty, setIsDirty] = useState(false);
|
|
125
|
+
let fetcher = useFetcher();
|
|
126
|
+
let blocker = useBlocker(
|
|
127
|
+
useCallback(() => isDirty, [isDirty]),
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<fetcher.Form
|
|
132
|
+
method="post"
|
|
133
|
+
onChange={(event) => {
|
|
134
|
+
let email = event.currentTarget.email.value;
|
|
135
|
+
let message = event.currentTarget.message.value;
|
|
136
|
+
setIsDirty(Boolean(email || message));
|
|
137
|
+
}}
|
|
138
|
+
>
|
|
139
|
+
{/* existing code */}
|
|
140
|
+
|
|
141
|
+
{blocker.state === "blocked" && (
|
|
142
|
+
<div>
|
|
143
|
+
<p>Wait! You didn't send the message yet:</p>
|
|
144
|
+
<p>
|
|
145
|
+
<button
|
|
146
|
+
type="button"
|
|
147
|
+
onClick={() => blocker.proceed()}
|
|
148
|
+
>
|
|
149
|
+
Leave
|
|
150
|
+
</button>{" "}
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
onClick={() => blocker.reset()}
|
|
154
|
+
>
|
|
155
|
+
Stay here
|
|
156
|
+
</button>
|
|
157
|
+
</p>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
</fetcher.Form>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If the user clicks "leave" then `blocker.proceed()` will proceed with the navigation. If they click "stay here" then `blocker.reset()` will clear the blocker and keep them on the current page.
|
|
166
|
+
|
|
167
|
+
## 5. Reset the blocker when the action resolves
|
|
168
|
+
|
|
169
|
+
If the user doesn't click either "leave" or "stay here", then submits the form, the blocker will still be active. Let's reset the blocker when the action resolves with an effect.
|
|
170
|
+
|
|
171
|
+
```tsx filename=routes/contact.tsx
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (fetcher.data?.ok) {
|
|
174
|
+
if (blocker.state === "blocked") {
|
|
175
|
+
blocker.reset();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}, [fetcher.data]);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 6. Clear the form when the action resolves
|
|
182
|
+
|
|
183
|
+
While unrelated to navigation blocking, let's clear the form when the action resolves with a ref.
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
let formRef = useRef<HTMLFormElement>(null);
|
|
187
|
+
|
|
188
|
+
// put it on the form
|
|
189
|
+
<fetcher.Form
|
|
190
|
+
ref={formRef}
|
|
191
|
+
method="post"
|
|
192
|
+
onChange={(event) => {
|
|
193
|
+
// ... existing code
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
{/* existing code */}
|
|
197
|
+
</fetcher.Form>;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
if (fetcher.data?.ok) {
|
|
203
|
+
// clear the form in the effect
|
|
204
|
+
formRef.current?.reset();
|
|
205
|
+
if (blocker.state === "blocked") {
|
|
206
|
+
blocker.reset();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}, [fetcher.data]);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Alternatively, if a navigation is currently blocked, instead of resetting the blocker, you can proceed through to the blocked navigation.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
if (fetcher.data?.ok) {
|
|
217
|
+
if (blocker.state === "blocked") {
|
|
218
|
+
// proceed with the blocked navigation
|
|
219
|
+
blocker.proceed();
|
|
220
|
+
} else {
|
|
221
|
+
formRef.current?.reset();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}, [fetcher.data]);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
In this case the user flow is:
|
|
228
|
+
|
|
229
|
+
- User fills out the form
|
|
230
|
+
- User forgets to click "send" and clicks a link instead
|
|
231
|
+
- The navigation is blocked, and the confirmation message is shown
|
|
232
|
+
- Instead of clicking "leave" or "stay here", the user submits the form
|
|
233
|
+
- The user is taken to the requested page
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Revalidation Optimization
|
|
3
|
+
hidden: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
[copy pasted]
|
|
7
|
+
|
|
8
|
+
During client-side transitions, React Router will optimize reloading of routes that are already rendering, like not reloading layout routes that aren't changing. In other cases, like form submissions or search param changes, React Router doesn't know which routes need to be reloaded, so it reloads them all to be safe. This ensures your UI always stays in sync with the state on your server.
|
|
9
|
+
|
|
10
|
+
This function lets apps further optimize by returning `false` when React Router is about to reload a route. If you define this function on a route module, React Router will defer to your function on every navigation and every revalidation after an action is called. Again, this makes it possible for your UI to get out of sync with your server if you do it wrong, so be careful.
|
|
11
|
+
|
|
12
|
+
`fetcher.load` calls also revalidate, but because they load a specific URL, they don't have to worry about route param or URL search param revalidations. `fetcher.load`'s only revalidate by default after action submissions and explicit revalidation requests via [`useRevalidator`][use-revalidator].
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pre-Rendering
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Pre-Rendering
|
|
6
|
+
|
|
7
|
+
[MODES: framework]
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
<br/>
|
|
11
|
+
|
|
12
|
+
Pre-Rendering allows you to speed up page loads for static content by rendering pages at build time instead of at runtime.
|
|
13
|
+
|
|
14
|
+
## Configuration
|
|
15
|
+
|
|
16
|
+
Pre-rendering is enabled via the `prerender` config in `react-router.config.ts`.
|
|
17
|
+
|
|
18
|
+
The simplest configuration is a boolean `true` which will pre-render all off the applications static paths based on `routes.ts`:
|
|
19
|
+
|
|
20
|
+
```ts filename=react-router.config.ts
|
|
21
|
+
import type { Config } from "@react-router/dev/config";
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
prerender: true,
|
|
25
|
+
} satisfies Config;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The boolean `true` will not include any dynamic paths (i.e., `/blog/:slug`) because the parameter values are unknown.
|
|
29
|
+
|
|
30
|
+
To configure specific paths including dynamic values, you can specify an array of paths:
|
|
31
|
+
|
|
32
|
+
```ts filename=react-router.config.ts
|
|
33
|
+
import type { Config } from "@react-router/dev/config";
|
|
34
|
+
|
|
35
|
+
let slugs = getPostSlugs();
|
|
36
|
+
|
|
37
|
+
export default {
|
|
38
|
+
prerender: [
|
|
39
|
+
"/",
|
|
40
|
+
"/blog",
|
|
41
|
+
...slugs.map((s) => `/blog/${s}`),
|
|
42
|
+
],
|
|
43
|
+
} satisfies Config;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If you need to perform more complex and/or asynchronous logic to determine the paths, you can also provide a function that returns an array of paths. This function provides you with a `getStaticPaths` method you can use to avoid manually adding all of the static paths in your application:
|
|
47
|
+
|
|
48
|
+
```ts filename=react-router.config.ts
|
|
49
|
+
import type { Config } from "@react-router/dev/config";
|
|
50
|
+
|
|
51
|
+
export default {
|
|
52
|
+
async prerender({ getStaticPaths }) {
|
|
53
|
+
let slugs = await getPostSlugsFromCMS();
|
|
54
|
+
return [
|
|
55
|
+
...getStaticPaths(), // "/" and "/blog"
|
|
56
|
+
...slugs.map((s) => `/blog/${s}`),
|
|
57
|
+
];
|
|
58
|
+
},
|
|
59
|
+
} satisfies Config;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Concurrency
|
|
63
|
+
|
|
64
|
+
By default, pages are pre-rendered one path at a time. You can enable concurrency to pre-render multiple paths in parallel which can speed up build times in many cases. You should experiment with the value that provides the best performance for your app.
|
|
65
|
+
|
|
66
|
+
To specify concurrency, move your `prerender` config down into a `prerender.paths` field and you can specify the concurrency in `prerender.concurrency`:
|
|
67
|
+
|
|
68
|
+
```ts filename=react-router.config.ts
|
|
69
|
+
import type { Config } from "@react-router/dev/config";
|
|
70
|
+
|
|
71
|
+
let slugs = getPostSlugs();
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
prerender: {
|
|
75
|
+
paths: [
|
|
76
|
+
"/",
|
|
77
|
+
"/blog",
|
|
78
|
+
...slugs.map((s) => `/blog/${s}`),
|
|
79
|
+
],
|
|
80
|
+
concurrency: 4,
|
|
81
|
+
},
|
|
82
|
+
} satisfies Config;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Pre-Rendering with/without a Runtime Server
|
|
86
|
+
|
|
87
|
+
Pre-Rendering can be used in two ways based on the `ssr` config value:
|
|
88
|
+
|
|
89
|
+
- Alongside a runtime SSR server with `ssr:true` (the default value)
|
|
90
|
+
- Deployed to a static file server with `ssr:false`
|
|
91
|
+
|
|
92
|
+
### Pre-rendering with `ssr:true`
|
|
93
|
+
|
|
94
|
+
When pre-rendering with `ssr:true`, you're indicating you will still have a runtime server but you are choosing to pre-render certain paths for quicker Response times.
|
|
95
|
+
|
|
96
|
+
```ts filename=react-router.config.ts
|
|
97
|
+
import type { Config } from "@react-router/dev/config";
|
|
98
|
+
|
|
99
|
+
export default {
|
|
100
|
+
// Can be omitted - defaults to true
|
|
101
|
+
ssr: true,
|
|
102
|
+
prerender: ["/", "/blog", "/blog/popular-post"],
|
|
103
|
+
} satisfies Config;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Data Loading and Pre-rendering
|
|
107
|
+
|
|
108
|
+
There is no extra application API for pre-rendering. Routes being pre-rendered use the same route `loader` functions as server rendering:
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
export async function loader({ request, params }) {
|
|
112
|
+
let post = await getPost(params.slug);
|
|
113
|
+
return post;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function Post({ loaderData }) {
|
|
117
|
+
return <div>{loaderData.title}</div>;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Instead of a request coming to your route on a deployed server, the build creates a `new Request()` and runs it through your app just like a server would.
|
|
122
|
+
|
|
123
|
+
When server rendering, requests to paths that have not been pre-rendered will be server rendered as usual.
|
|
124
|
+
|
|
125
|
+
#### Static File Output
|
|
126
|
+
|
|
127
|
+
The rendered result will be written out to your `build/client` directory. You'll notice two files for each path:
|
|
128
|
+
|
|
129
|
+
- `[url].html` HTML file for initial document requests
|
|
130
|
+
- `[url].data` file for client side navigation browser requests
|
|
131
|
+
|
|
132
|
+
The output of your build will indicate what files were pre-rendered:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
> react-router build
|
|
136
|
+
vite v5.2.11 building for production...
|
|
137
|
+
...
|
|
138
|
+
vite v5.2.11 building SSR bundle for production...
|
|
139
|
+
...
|
|
140
|
+
Prerender: Generated build/client/index.html
|
|
141
|
+
Prerender: Generated build/client/blog.data
|
|
142
|
+
Prerender: Generated build/client/blog/index.html
|
|
143
|
+
Prerender: Generated build/client/blog/my-first-post.data
|
|
144
|
+
Prerender: Generated build/client/blog/my-first-post/index.html
|
|
145
|
+
...
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
During development, pre-rendering doesn't save the rendered results to the public directory, this only happens for `react-router build`.
|
|
149
|
+
|
|
150
|
+
### Pre-rendering with `ssr:false`
|
|
151
|
+
|
|
152
|
+
The above examples assume you are deploying a runtime server but are pre-rendering some static pages to avoid hitting the server, resulting in faster loads.
|
|
153
|
+
|
|
154
|
+
To disable runtime SSR and configure pre-rendering to be served from a static file server, you can set the `ssr:false` config flag:
|
|
155
|
+
|
|
156
|
+
```ts filename=react-router.config.ts
|
|
157
|
+
import type { Config } from "@react-router/dev/config";
|
|
158
|
+
|
|
159
|
+
export default {
|
|
160
|
+
ssr: false, // disable runtime server rendering
|
|
161
|
+
prerender: true, // pre-render all static routes
|
|
162
|
+
} satisfies Config;
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If you specify `ssr:false` without a `prerender` config, React Router refers to that as [SPA Mode](./spa). In SPA Mode, we render a single HTML file that is capable of hydrating for _any_ of your application paths. It can do this because it only renders the `root` route into the HTML file and then determines which child routes to load based on the browser URL during hydration. This means you can use a `loader` on the root route, but not on any other routes because we don't know which routes to load until hydration in the browser.
|
|
166
|
+
|
|
167
|
+
If you want to pre-render paths with `ssr:false`, those matched routes _can_ have loaders because we'll pre-render all of the matched routes for those paths, not just the root. You cannot include `actions` or `headers` functions in any routes when `ssr:false` is set because there will be no runtime server to run them on.
|
|
168
|
+
|
|
169
|
+
#### Pre-rendering with a SPA Fallback
|
|
170
|
+
|
|
171
|
+
If you want `ssr:false` but don't want to pre-render _all_ of your routes - that's fine too! You may have some paths where you need the performance/SEO benefits of pre-rendering, but other pages where a SPA would be fine.
|
|
172
|
+
|
|
173
|
+
You can do this using the combination of config options as well - just limit your `prerender` config to the paths that you want to pre-render and React Router will also output a "SPA Fallback" HTML file that can be served to hydrate any other paths (using the same approach as [SPA Mode](./spa)).
|
|
174
|
+
|
|
175
|
+
This will be written to one of the following paths:
|
|
176
|
+
|
|
177
|
+
- `build/client/index.html` - If the `/` path is not pre-rendered
|
|
178
|
+
- `build/client/__spa-fallback.html` - If the `/` path is pre-rendered
|
|
179
|
+
|
|
180
|
+
```ts filename=react-router.config.ts
|
|
181
|
+
import type { Config } from "@react-router/dev/config";
|
|
182
|
+
|
|
183
|
+
export default {
|
|
184
|
+
ssr: false,
|
|
185
|
+
|
|
186
|
+
// SPA fallback will be written to build/client/index.html
|
|
187
|
+
prerender: ["/about-us"],
|
|
188
|
+
|
|
189
|
+
// SPA fallback will be written to build/client/__spa-fallback.html
|
|
190
|
+
prerender: ["/", "/about-us"],
|
|
191
|
+
} satisfies Config;
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
You can configure your deployment server to serve this file for any path that otherwise would 404. Some hosts do this by default, but others don't. As an example, a host may support a `_redirects` file to do this:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
# If you did not pre-render the `/` route
|
|
198
|
+
/* /index.html 200
|
|
199
|
+
|
|
200
|
+
# If you pre-rendered the `/` route
|
|
201
|
+
/* /__spa-fallback.html 200
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
If you're getting 404s at valid routes for your app, it's likely you need to configure your host.
|
|
205
|
+
|
|
206
|
+
Here's another example of how you can do this with the [`sirv-cli`](https://www.npmjs.com/package/sirv-cli#user-content-single-page-applications) tool:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
# If you did not pre-render the `/` route
|
|
210
|
+
sirv-cli build/client --single index.html
|
|
211
|
+
|
|
212
|
+
# If you pre-rendered the `/` route
|
|
213
|
+
sirv-cli build/client --single __spa-fallback.html
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### Invalid Exports
|
|
217
|
+
|
|
218
|
+
When pre-rendering with `ssr:false`, React Router will error at build time if you have invalid exports to help prevent some mistakes that can be easily overlooked.
|
|
219
|
+
|
|
220
|
+
- `headers`/`action` functions are prohibited in all routes because there will be no runtime server on which to run them
|
|
221
|
+
- When using `ssr:false` without a `prerender` config (SPA Mode), a `loader` is permitted on the root route only
|
|
222
|
+
- When using `ssr:false` with a `prerender` config, a `loader` is permitted on any route matched by a `prerender` path
|
|
223
|
+
- If you are using a `loader` on a pre-rendered route that has child routes, you will need to make sure the parent `loaderData` can be determined at run-time properly by either:
|
|
224
|
+
- Pre-rendering all child routes so that the parent `loader` can be called at build-time for each child route path and rendered into a `.data` file, or
|
|
225
|
+
- Use a `clientLoader` on the parent that can be called at run-time for non-pre-rendered child paths
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Presets
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Presets
|
|
6
|
+
|
|
7
|
+
[MODES: framework]
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
<br/>
|
|
11
|
+
|
|
12
|
+
The [React Router config][react-router-config] supports a `presets` option to ease integration with other tools and hosting providers.
|
|
13
|
+
|
|
14
|
+
[Presets][preset-type] can only do two things:
|
|
15
|
+
|
|
16
|
+
- Configure React Router config options on your behalf
|
|
17
|
+
- Validate the resolved config
|
|
18
|
+
|
|
19
|
+
The config returned by each preset is merged in the order the presets were defined. Any config directly specified in your React Router config will be merged last. This means that your config will always take precedence over any presets.
|
|
20
|
+
|
|
21
|
+
## Defining preset config
|
|
22
|
+
|
|
23
|
+
As a basic example, let's create a preset that configures a [server bundles function][server-bundles]:
|
|
24
|
+
|
|
25
|
+
```ts filename=my-cool-preset.ts
|
|
26
|
+
import type { Preset } from "@react-router/dev/config";
|
|
27
|
+
|
|
28
|
+
export function myCoolPreset(): Preset {
|
|
29
|
+
return {
|
|
30
|
+
name: "my-cool-preset",
|
|
31
|
+
reactRouterConfig: () => ({
|
|
32
|
+
serverBundles: ({ branch }) => {
|
|
33
|
+
const isAuthenticatedRoute = branch.some((route) =>
|
|
34
|
+
route.id.split("/").includes("_authenticated"),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return isAuthenticatedRoute
|
|
38
|
+
? "authenticated"
|
|
39
|
+
: "unauthenticated";
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Validating config
|
|
47
|
+
|
|
48
|
+
Keep in mind that other presets and user config can still override the values returned from your preset.
|
|
49
|
+
|
|
50
|
+
In our example preset, the `serverBundles` function could be overridden with a different, conflicting implementation. If we want to validate that the final resolved config contains the `serverBundles` function from our preset, we can use the `reactRouterConfigResolved` hook:
|
|
51
|
+
|
|
52
|
+
```ts filename=my-cool-preset.ts lines=[22-27]
|
|
53
|
+
import type {
|
|
54
|
+
Preset,
|
|
55
|
+
ServerBundlesFunction,
|
|
56
|
+
} from "@react-router/dev/config";
|
|
57
|
+
|
|
58
|
+
const serverBundles: ServerBundlesFunction = ({
|
|
59
|
+
branch,
|
|
60
|
+
}) => {
|
|
61
|
+
const isAuthenticatedRoute = branch.some((route) =>
|
|
62
|
+
route.id.split("/").includes("_authenticated"),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return isAuthenticatedRoute
|
|
66
|
+
? "authenticated"
|
|
67
|
+
: "unauthenticated";
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function myCoolPreset(): Preset {
|
|
71
|
+
return {
|
|
72
|
+
name: "my-cool-preset",
|
|
73
|
+
reactRouterConfig: () => ({ serverBundles }),
|
|
74
|
+
reactRouterConfigResolved: ({ reactRouterConfig }) => {
|
|
75
|
+
if (
|
|
76
|
+
reactRouterConfig.serverBundles !== serverBundles
|
|
77
|
+
) {
|
|
78
|
+
throw new Error("`serverBundles` was overridden!");
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The `reactRouterConfigResolved` hook should only be used when it would be an error to merge or override your preset's config.
|
|
86
|
+
|
|
87
|
+
## Using a preset
|
|
88
|
+
|
|
89
|
+
Presets are designed to be published to npm and used within your React Router config.
|
|
90
|
+
|
|
91
|
+
```ts filename=react-router.config.ts lines=[6]
|
|
92
|
+
import type { Config } from "@react-router/dev/config";
|
|
93
|
+
import { myCoolPreset } from "react-router-preset-cool";
|
|
94
|
+
|
|
95
|
+
export default {
|
|
96
|
+
// ...
|
|
97
|
+
presets: [myCoolPreset()],
|
|
98
|
+
} satisfies Config;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
[react-router-config]: https://api.reactrouter.com/v7/types/_react-router_dev.config.Config.html
|
|
102
|
+
[preset-type]: https://api.reactrouter.com/v7/types/_react-router_dev.config.Preset.html
|
|
103
|
+
[server-bundles]: ./server-bundles
|