@wular/pnext 0.0.4 → 0.0.7
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/README.md +22 -16
- package/bin/pnext +6 -1
- package/config/lint/base.js +7 -7
- package/config/ts/base.json +2 -4
- package/config/ts/react.json +2 -6
- package/package.json +23 -2
- package/reference/compat.md +87 -22
- package/reference/config.md +40 -93
- package/reference/css.md +42 -33
- package/reference/dev.md +26 -33
- package/reference/env.md +18 -20
- package/reference/getting-started.md +132 -0
- package/reference/metadata.md +31 -46
- package/reference/navigation.md +65 -105
- package/reference/performance.md +21 -142
- package/reference/rendering.md +78 -75
- package/reference/routing.md +97 -107
- package/reference/typegen.md +27 -29
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +121 -114
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +52 -53
- package/src/api/navigation.ts +59 -58
- package/src/api/server.ts +152 -144
- package/src/api/suspense.ts +4 -4
- package/src/cli/adapters/vercel-warm.ts +126 -121
- package/src/cli/adapters/vercel.ts +437 -443
- package/src/cli/analyze.ts +333 -144
- package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
- package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
- package/src/cli/build.ts +976 -978
- package/src/cli/create.ts +72 -64
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +94 -85
- package/src/cli/migrate/package-json.ts +73 -71
- package/src/cli/migrate/report.ts +32 -33
- package/src/cli/migrate/{index.ts → run.ts} +48 -49
- package/src/cli/migrate/scan.ts +46 -46
- package/src/cli/migrate/spinner.ts +9 -9
- package/src/cli/migrate/tsconfig.ts +35 -35
- package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
- package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
- package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
- package/src/cli/start.ts +65 -66
- package/src/{typegen.ts → cli/typegen.ts} +59 -59
- package/src/client/build.ts +802 -768
- package/src/client/chunk-fold.ts +245 -240
- package/src/client/{paths.ts → chunk-name.ts} +6 -6
- package/src/client/entry.ts +162 -147
- package/src/client/prebuilt.ts +231 -223
- package/src/client/profile.ts +29 -29
- package/src/client/react-compiler.ts +20 -15
- package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
- package/src/client/reference-stub.ts +51 -51
- package/src/client/reference.ts +19 -19
- package/src/{api → client}/router/events.ts +32 -17
- package/src/{api → client}/router/history.ts +16 -16
- package/src/{api → client}/router/hub.ts +52 -53
- package/src/{api/router.ts → client/router/index.ts} +61 -60
- package/src/{api → client}/router/policies.ts +24 -24
- package/src/{api → client}/router/runtime.ts +2022 -1995
- package/src/{api → client}/router/types.ts +98 -98
- package/src/compat/actions/client-plugin.ts +42 -43
- package/src/compat/actions/client-stub.ts +14 -14
- package/src/compat/actions/{action-client.ts → client.ts} +194 -193
- package/src/compat/actions/config.ts +63 -64
- package/src/compat/actions/detect.ts +68 -68
- package/src/compat/actions/discovery.ts +105 -105
- package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
- package/src/compat/actions/early-submit.ts +1 -1
- package/src/compat/actions/endpoint.ts +198 -198
- package/src/compat/actions/extensions.ts +811 -0
- package/src/compat/actions/flight.ts +23 -23
- package/src/compat/actions/form-state.ts +34 -34
- package/src/compat/actions/hoist.ts +382 -236
- package/src/compat/actions/ids.ts +7 -12
- package/src/compat/actions/index.ts +8 -8
- package/src/compat/actions/instances.ts +46 -46
- package/src/compat/actions/origin.ts +47 -48
- package/src/compat/actions/protocol.ts +22 -22
- package/src/compat/actions/registry.ts +19 -19
- package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
- package/src/compat/actions/rewrite.ts +125 -125
- package/src/compat/actions/{action-router.ts → router.ts} +10 -10
- package/src/compat/actions/serve.ts +132 -136
- package/src/compat/actions/server-tag.ts +4 -4
- package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
- package/src/compat/actions/unrecognized-error.ts +4 -4
- package/src/compat/{index.ts → aliases.ts} +112 -109
- package/src/compat/bundler/bun-externals.ts +18 -18
- package/src/compat/bundler/cjs-exports.ts +271 -223
- package/src/compat/bundler/config.ts +116 -111
- package/src/compat/bundler/externals.ts +12 -12
- package/src/compat/bundler/import-meta-url.ts +19 -19
- package/src/compat/bundler/modularize-imports.ts +36 -33
- package/src/compat/bundler/new-url-asset.ts +22 -24
- package/src/compat/bundler/optimize-package-imports.ts +111 -107
- package/src/compat/bundler/polyfill.ts +28 -28
- package/src/compat/bundler/react-compiler.ts +35 -29
- package/src/compat/bundler/react-profiler.tsx +11 -11
- package/src/compat/bundler/relay-transform.ts +48 -47
- package/src/compat/bundler/require-context.ts +119 -113
- package/src/compat/bundler/resolve-extensions.ts +19 -19
- package/src/compat/bundler/source-cache.ts +25 -25
- package/src/compat/bundler/static-imports.ts +7 -7
- package/src/compat/bundler/symlink-imports.ts +46 -46
- package/src/compat/bundler/tsconfig-paths.ts +13 -15
- package/src/compat/bundler/wasm.ts +58 -60
- package/src/compat/bundler/webpack-loaders.ts +254 -241
- package/src/compat/bundler/worker.ts +101 -104
- package/src/compat/cache/build-flags.ts +29 -29
- package/src/compat/cache/build-prerender-errors.ts +40 -44
- package/src/compat/cache/custom-handler.ts +60 -53
- package/src/compat/cache/fetch-patch.ts +240 -240
- package/src/compat/cache/handler.ts +27 -31
- package/src/compat/cache/modern-handler.ts +148 -126
- package/src/compat/cache/resume-data-cache.ts +47 -45
- package/src/compat/cache/revalidate.ts +233 -232
- package/src/compat/cache/runtime-error.ts +35 -35
- package/src/compat/cache/use-cache-transform.ts +442 -417
- package/src/compat/cache/use-cache.ts +650 -614
- package/src/compat/cache-control.ts +140 -142
- package/src/compat/client/base-path.ts +21 -20
- package/src/compat/client/css-order.ts +18 -18
- package/src/compat/client/errors/bare-boundary.ts +11 -11
- package/src/compat/client/errors/control-flow.ts +23 -23
- package/src/compat/client/errors/error-boundary.ts +61 -61
- package/src/compat/client/errors/global-error.ts +101 -91
- package/src/compat/client/errors/install.ts +71 -72
- package/src/compat/client/errors/lazy.ts +23 -23
- package/src/compat/client/errors/primitive-throw.ts +47 -45
- package/src/compat/client/errors/soft-refresh.ts +4 -4
- package/src/compat/client/link-status.ts +33 -33
- package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
- package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
- package/src/compat/client/navigation-scroll.ts +63 -63
- package/src/compat/client/optimistic-routing.ts +93 -88
- package/src/compat/client/prefetch-cache.ts +23 -24
- package/src/compat/client/route-announcer.ts +35 -35
- package/src/compat/client/segment-cache-policy.ts +20 -20
- package/src/compat/client/segment-cache.ts +309 -315
- package/src/compat/client/segment-prefetch.ts +127 -132
- package/src/compat/client/trailing-slash.ts +5 -4
- package/src/compat/css/chunking.ts +113 -116
- package/src/compat/css/inline-css.ts +21 -21
- package/src/compat/css/lightningcss.ts +37 -38
- package/src/compat/css/modules.ts +161 -175
- package/src/compat/css/nonce.ts +7 -7
- package/src/compat/css/sass-plugin.ts +18 -21
- package/src/compat/css/sass.ts +150 -152
- package/src/compat/css/styled-jsx-runtime.ts +27 -27
- package/src/compat/css/styled-jsx.ts +21 -21
- package/src/compat/edge-runtime.ts +27 -27
- package/src/compat/{adapter → export}/build-complete.ts +72 -75
- package/src/compat/export/client.ts +29 -31
- package/src/compat/export/{index.ts → emit.ts} +111 -110
- package/src/compat/export/standalone.ts +62 -54
- package/src/compat/image-optimizer/cache.ts +51 -49
- package/src/compat/image-optimizer/detect.ts +52 -52
- package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
- package/src/compat/image-optimizer/source.ts +77 -80
- package/src/compat/lifecycle/after-scope.ts +26 -26
- package/src/compat/lifecycle/after.ts +48 -45
- package/src/compat/lifecycle/error-funnel.ts +98 -102
- package/src/compat/lifecycle/error-serialize.ts +30 -26
- package/src/compat/lifecycle/error-ui.ts +67 -32
- package/src/compat/lifecycle/instrumentation-client.ts +36 -38
- package/src/compat/lifecycle/instrumentation.ts +85 -85
- package/src/compat/lifecycle/node-console.ts +11 -11
- package/src/compat/lifecycle/testmode.ts +160 -132
- package/src/compat/mdx/compile.ts +60 -57
- package/src/compat/mdx/plugin.ts +11 -11
- package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
- package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
- package/src/compat/metadata.ts +75 -81
- package/src/compat/next/cache.ts +68 -69
- package/src/compat/next/canonical-url.ts +9 -9
- package/src/compat/next/client-cache.ts +19 -19
- package/src/compat/next/client-navigation.ts +112 -116
- package/src/compat/next/client-only.ts +1 -1
- package/src/compat/next/client-script.tsx +99 -93
- package/src/compat/next/client-server.ts +10 -10
- package/src/compat/next/config-loader.ts +176 -173
- package/src/compat/next/config.ts +7 -7
- package/src/compat/next/constants.cjs +6 -6
- package/src/compat/next/constants.ts +6 -6
- package/src/compat/next/custom-server.ts +26 -24
- package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
- package/src/compat/next/dynamic.tsx +21 -18
- package/src/compat/next/error.tsx +52 -52
- package/src/compat/next/font/cache.ts +74 -74
- package/src/compat/next/font/google.ts +2 -2
- package/src/compat/next/font/index.ts +1 -1
- package/src/compat/next/font/local.ts +3 -3
- package/src/compat/next/font/runtime-client.ts +17 -15
- package/src/compat/next/font/runtime.ts +443 -408
- package/src/compat/next/font/shared.ts +120 -108
- package/src/compat/next/form.tsx +63 -63
- package/src/compat/next/head.tsx +2 -2
- package/src/compat/next/headers.ts +103 -95
- package/src/compat/next/image/client.tsx +220 -0
- package/src/compat/next/image/config.ts +56 -58
- package/src/compat/next/image/optimizer.ts +40 -36
- package/src/compat/next/image/patterns.ts +37 -40
- package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
- package/src/compat/next/image/shared.ts +65 -57
- package/src/compat/next/image/static-metadata.ts +98 -107
- package/src/compat/next/image/validate.ts +79 -88
- package/src/compat/next/image.tsx +19 -23
- package/src/compat/next/index.ts +1 -1
- package/src/compat/next/legacy-image.tsx +59 -60
- package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
- package/src/compat/next/link.tsx +158 -158
- package/src/compat/next/navigation.cjs +12 -3
- package/src/compat/next/navigation.ts +48 -50
- package/src/compat/next/offline.ts +27 -27
- package/src/compat/next/og.ts +121 -124
- package/src/compat/next/preferred-region.ts +13 -14
- package/src/compat/next/redirects.ts +58 -56
- package/src/compat/next/resource-hints.ts +73 -76
- package/src/compat/next/rewrites.ts +130 -133
- package/src/compat/next/root-params.ts +45 -45
- package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
- package/src/compat/next/router.cjs +4 -2
- package/src/compat/next/router.ts +58 -61
- package/src/compat/next/script.tsx +108 -108
- package/src/compat/next/server-only.ts +1 -1
- package/src/compat/next/server.ts +19 -19
- package/src/compat/next/svgr.ts +18 -17
- package/src/compat/next/telemetry.ts +24 -24
- package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
- package/src/compat/next/user-agent.ts +53 -49
- package/src/compat/next/web-vitals.ts +22 -24
- package/src/compat/otel/api.ts +41 -41
- package/src/compat/otel/client-trace-metadata.ts +25 -27
- package/src/compat/otel/fetch-span.ts +29 -29
- package/src/compat/otel/tracer.ts +331 -331
- package/src/compat/pages/api.ts +456 -0
- package/src/compat/pages/client-plugin.ts +36 -36
- package/src/compat/pages/router-state.ts +34 -34
- package/src/compat/pages/{index.ts → router.ts} +130 -135
- package/src/compat/ppr/io.ts +12 -12
- package/src/compat/ppr/missing-root-params.ts +34 -38
- package/src/compat/ppr/root-params-scan.ts +66 -66
- package/src/compat/ppr/root-params-transform.ts +24 -26
- package/src/compat/ppr/root-params.ts +30 -30
- package/src/compat/ppr/segment-config-incompat.ts +6 -7
- package/src/compat/protocol.ts +71 -70
- package/src/compat/react/action-state.ts +47 -48
- package/src/compat/react/client-lite.ts +15 -15
- package/src/compat/react/client.ts +4 -4
- package/src/compat/react/compiler-runtime.ts +11 -11
- package/src/compat/react/dom-client.ts +44 -44
- package/src/compat/react/dom-react-server.ts +10 -16
- package/src/compat/react/dom-server.ts +10 -10
- package/src/compat/react/dom.ts +52 -52
- package/src/compat/react/hooks-extra.ts +34 -35
- package/src/compat/react/parity.ts +64 -61
- package/src/compat/react/preact.ts +81 -82
- package/src/compat/react/react-server.ts +28 -28
- package/src/compat/react/router-shim.ts +1 -1
- package/src/compat/react/server-component-use.ts +8 -8
- package/src/compat/react/server-inserted-html.ts +30 -31
- package/src/compat/react/server.ts +53 -55
- package/src/compat/react/use.ts +32 -32
- package/src/compat/react/view-transition.ts +20 -20
- package/src/compat/register/actions.ts +35 -824
- package/src/compat/register/boot.ts +41 -41
- package/src/compat/register/build-tier.ts +5 -5
- package/src/compat/register/build.ts +74 -70
- package/src/compat/register/bundler.ts +161 -156
- package/src/compat/register/cache.ts +20 -20
- package/src/compat/register/client-errors.ts +3 -3
- package/src/compat/register/config.ts +6 -6
- package/src/compat/register/css-extras.ts +30 -34
- package/src/compat/register/edge-runtime.ts +3 -3
- package/src/compat/register/errors.ts +10 -12
- package/src/compat/register/export.ts +16 -16
- package/src/compat/register/font.ts +11 -11
- package/src/compat/register/hooks.ts +2 -2
- package/src/compat/register/image.ts +40 -40
- package/src/compat/register/index.ts +59 -62
- package/src/compat/register/instrumentation-client.ts +10 -10
- package/src/compat/register/lifecycle.ts +25 -28
- package/src/compat/register/mdx.ts +10 -10
- package/src/compat/register/middleware.ts +226 -16
- package/src/compat/register/otel.ts +80 -88
- package/src/compat/register/pages-api.ts +10 -463
- package/src/compat/register/ppr.ts +16 -16
- package/src/compat/register/protocol.ts +17 -18
- package/src/compat/register/proxy.ts +49 -51
- package/src/compat/register/render.ts +79 -76
- package/src/compat/register/routing.ts +162 -159
- package/src/compat/register/segment.ts +24 -1897
- package/src/compat/register/static-image.ts +3 -3
- package/src/compat/register/{misc.ts → taint.ts} +9 -9
- package/src/compat/register/typed-routes.ts +14 -14
- package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
- package/src/compat/register/validation.ts +18 -18
- package/src/compat/segment/loading-boundary.ts +43 -45
- package/src/compat/segment/page-slot.ts +69 -69
- package/src/compat/segment/serve.ts +1884 -0
- package/src/compat/segment/tree.ts +113 -112
- package/src/compat/segment/vary-key.ts +38 -38
- package/src/compat/segment/vary-params.ts +138 -142
- package/src/compat/static-params.ts +14 -12
- package/src/compat/tsconfig-defaults.ts +87 -91
- package/src/compat/typecheck/{index.ts → check.ts} +234 -212
- package/src/compat/typecheck/worker.ts +15 -12
- package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
- package/src/compat/typed-routes/manifest.ts +174 -170
- package/src/compat/typed-routes/typegen.ts +127 -110
- package/src/compat/validation/errors.ts +16 -19
- package/src/compat/validation/prerender-diagnostics.ts +521 -504
- package/src/compat/validation/{index.ts → validate.ts} +647 -648
- package/src/compat-bootstrap.ts +16 -16
- package/src/config.ts +86 -69
- package/src/css/build.ts +230 -227
- package/src/css/postcss.ts +79 -80
- package/src/css/worker.ts +14 -15
- package/src/dev/client-actions.ts +10 -10
- package/src/dev/client-chunk-store.ts +27 -27
- package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
- package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
- package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
- package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
- package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
- package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
- package/src/dev/server.ts +804 -820
- package/src/env.ts +46 -43
- package/src/extensions.ts +491 -478
- package/src/index.ts +8 -8
- package/src/internal.ts +20 -23
- package/src/{islands → render}/boundary-error.ts +3 -3
- package/src/render/hooks.ts +71 -71
- package/src/render/island-context.ts +14 -14
- package/src/render/metadata.ts +310 -310
- package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
- package/src/{ppr.ts → render/ppr.ts} +244 -245
- package/src/render/renderer.ts +2087 -2082
- package/src/render/resource-hints.ts +16 -17
- package/src/render/slots.tsx +224 -235
- package/src/{islands → render}/static-children.ts +9 -12
- package/src/{islands → render}/static-slots.ts +37 -37
- package/src/{cache/context.ts → request/cache.ts} +20 -20
- package/src/request/context.ts +107 -107
- package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
- package/src/resolve/engine.ts +90 -77
- package/src/resolve/imports.ts +475 -463
- package/src/resolve/scan-facts.ts +318 -296
- package/src/resolve/source-text.ts +37 -37
- package/src/{dynamic → resolve}/tree-shake.ts +132 -128
- package/src/routing/forwarded.ts +19 -19
- package/src/routing/handler.ts +84 -91
- package/src/routing/href.ts +87 -70
- package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
- package/src/{proxy.ts → routing/proxy.ts} +306 -312
- package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
- package/src/routing/routes.ts +827 -815
- package/src/routing/slots.ts +164 -160
- package/src/runtime/loader.ts +954 -0
- package/src/{dev → runtime}/module-cache.ts +309 -287
- package/src/{dev → runtime}/module-generations.ts +9 -9
- package/src/{dev → runtime}/module-transform.ts +81 -72
- package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
- package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
- package/src/runtime/vendor.ts +428 -406
- package/src/styles.d.ts +9 -0
- package/src/types.ts +324 -335
- package/src/utils/ansi.ts +5 -5
- package/src/utils/{source.ts → code.ts} +15 -12
- package/src/utils/content-type.ts +3 -3
- package/src/utils/decode.ts +2 -2
- package/src/utils/dev-profile.ts +13 -13
- package/src/utils/error-log.ts +6 -6
- package/src/utils/esbuild.ts +18 -18
- package/src/utils/fs-cache.ts +13 -13
- package/src/utils/fs.ts +57 -49
- package/src/utils/html.ts +20 -24
- package/src/utils/native-require.ts +8 -8
- package/src/utils/serialize.ts +139 -146
- package/src/utils/verbose.ts +18 -18
- package/reference/overview.md +0 -35
- package/src/cli/analyze-print.ts +0 -181
- package/src/compat/middleware/manifest.ts +0 -210
- package/src/compat/next/image-client.tsx +0 -215
- package/src/compat/next/link-usage.ts +0 -29
- package/src/css/index.ts +0 -2
- package/src/render/index.ts +0 -1
- package/src/style-modules.d.ts +0 -9
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
isRedirectError,
|
|
21
21
|
isUnauthorizedError,
|
|
22
22
|
type PNextRedirectError,
|
|
23
|
-
} from '../../../api/navigation'
|
|
24
|
-
import { isPostpone } from '../../../
|
|
25
|
-
import { softNavigate } from '../../../
|
|
23
|
+
} from '../../../api/navigation'
|
|
24
|
+
import { isPostpone } from '../../../render/postpone'
|
|
25
|
+
import { softNavigate } from '../../../client/router'
|
|
26
26
|
|
|
27
27
|
/** True for a Next control-flow error that a boundary must re-throw, not render. */
|
|
28
28
|
export function isControlFlowError(error: unknown): boolean {
|
|
@@ -32,7 +32,7 @@ export function isControlFlowError(error: unknown): boolean {
|
|
|
32
32
|
isForbiddenError(error) ||
|
|
33
33
|
isUnauthorizedError(error) ||
|
|
34
34
|
isPostpone(error)
|
|
35
|
-
)
|
|
35
|
+
)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -42,8 +42,8 @@ export function isControlFlowError(error: unknown): boolean {
|
|
|
42
42
|
*/
|
|
43
43
|
export function handleControlFlowError(error: unknown): boolean {
|
|
44
44
|
if (isRedirectError(error)) {
|
|
45
|
-
applyRedirect(error)
|
|
46
|
-
return true
|
|
45
|
+
applyRedirect(error)
|
|
46
|
+
return true
|
|
47
47
|
}
|
|
48
48
|
if (isNotFoundError(error) || isForbiddenError(error) || isUnauthorizedError(error)) {
|
|
49
49
|
// Re-render the current URL server-side: the same control-flow call fires
|
|
@@ -52,41 +52,41 @@ export function handleControlFlowError(error: unknown): boolean {
|
|
|
52
52
|
// avoids a jump. Fall back to a full reload if the soft-nav itself fails.
|
|
53
53
|
if (process.browser || typeof window !== 'undefined') {
|
|
54
54
|
void softNavigate(location.href, { replace: true, scroll: false }).catch(() => {
|
|
55
|
-
location.reload()
|
|
56
|
-
})
|
|
55
|
+
location.reload()
|
|
56
|
+
})
|
|
57
57
|
}
|
|
58
|
-
return true
|
|
58
|
+
return true
|
|
59
59
|
}
|
|
60
60
|
if (isPostpone(error)) {
|
|
61
61
|
// A postpone escaping to the client has nothing to resume against here; a
|
|
62
62
|
// reload re-renders from the server. Treated as handled so it never lands
|
|
63
63
|
// in an error boundary as a "real" error.
|
|
64
|
-
if (process.browser || typeof window !== 'undefined') location.reload()
|
|
65
|
-
return true
|
|
64
|
+
if (process.browser || typeof window !== 'undefined') location.reload()
|
|
65
|
+
return true
|
|
66
66
|
}
|
|
67
|
-
return false
|
|
67
|
+
return false
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function applyRedirect(error: PNextRedirectError): void {
|
|
71
|
-
if (!process.browser && typeof window === 'undefined') return
|
|
72
|
-
const target = error.location
|
|
73
|
-
let sameOrigin = false
|
|
71
|
+
if (!process.browser && typeof window === 'undefined') return
|
|
72
|
+
const target = error.location
|
|
73
|
+
let sameOrigin = false
|
|
74
74
|
try {
|
|
75
|
-
sameOrigin = new URL(target, location.href).origin === location.origin
|
|
75
|
+
sameOrigin = new URL(target, location.href).origin === location.origin
|
|
76
76
|
} catch {
|
|
77
|
-
sameOrigin = false
|
|
77
|
+
sameOrigin = false
|
|
78
78
|
}
|
|
79
|
-
const replace = error.status === 303 || error.status === 307 || error.status === 308
|
|
79
|
+
const replace = error.status === 303 || error.status === 307 || error.status === 308
|
|
80
80
|
if (sameOrigin) {
|
|
81
81
|
void softNavigate(target, { replace }).catch(() => {
|
|
82
|
-
hardNavigate(target, replace)
|
|
83
|
-
})
|
|
82
|
+
hardNavigate(target, replace)
|
|
83
|
+
})
|
|
84
84
|
} else {
|
|
85
|
-
hardNavigate(target, replace)
|
|
85
|
+
hardNavigate(target, replace)
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function hardNavigate(target: string, replace: boolean): void {
|
|
90
|
-
if (replace) location.replace(target)
|
|
91
|
-
else location.assign(target)
|
|
90
|
+
if (replace) location.replace(target)
|
|
91
|
+
else location.assign(target)
|
|
92
92
|
}
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
//
|
|
17
17
|
// When no route error component is available the boundary mounts global-error.
|
|
18
18
|
|
|
19
|
-
import { Component, h, type ComponentChildren, type ComponentType } from 'preact'
|
|
20
|
-
import { isControlFlowError, handleControlFlowError } from './control-flow'
|
|
21
|
-
import { isNotFoundError } from '../../../api/navigation'
|
|
22
|
-
import { normalizeBoundaryError } from './primitive-throw'
|
|
19
|
+
import { Component, h, type ComponentChildren, type ComponentType } from 'preact'
|
|
20
|
+
import { isControlFlowError, handleControlFlowError } from './control-flow'
|
|
21
|
+
import { isNotFoundError } from '../../../api/navigation'
|
|
22
|
+
import { normalizeBoundaryError } from './primitive-throw'
|
|
23
23
|
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
// KNOWN GAP (preact core, not fully fixable from an options hook): a CLIENT
|
|
@@ -30,25 +30,25 @@ import { normalizeBoundaryError } from './primitive-throw';
|
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
31
31
|
|
|
32
32
|
export type RouteErrorComponent = ComponentType<{
|
|
33
|
-
error: unknown
|
|
34
|
-
reset: () => void
|
|
35
|
-
unstable_retry?: () => void
|
|
36
|
-
}
|
|
37
|
-
export type RouteNotFoundComponent = ComponentType<Record<string, never
|
|
33
|
+
error: unknown
|
|
34
|
+
reset: () => void
|
|
35
|
+
unstable_retry?: () => void
|
|
36
|
+
}>
|
|
37
|
+
export type RouteNotFoundComponent = ComponentType<Record<string, never>>
|
|
38
38
|
|
|
39
39
|
interface BoundaryProps {
|
|
40
40
|
/** The route's nearest error.js component; when absent the boundary escalates. */
|
|
41
|
-
errorComponent?: RouteErrorComponent
|
|
42
|
-
notFoundComponent?: RouteNotFoundComponent
|
|
41
|
+
errorComponent?: RouteErrorComponent
|
|
42
|
+
notFoundComponent?: RouteNotFoundComponent
|
|
43
43
|
/**
|
|
44
44
|
* Next's default 404 UI, handed in by the generated runtime - and emitted by it ONLY when some route
|
|
45
45
|
* can reach this fallback (no not-found.* of its own). An app whose boundary routes all have one
|
|
46
46
|
* never ships error-ui.ts.
|
|
47
47
|
*/
|
|
48
|
-
builtInNotFound?: RouteNotFoundComponent
|
|
48
|
+
builtInNotFound?: RouteNotFoundComponent
|
|
49
49
|
/** Soft-refresh invoked by reset() after clearing the error. */
|
|
50
|
-
onReset?: () => void
|
|
51
|
-
children?: unknown
|
|
50
|
+
onReset?: () => void
|
|
51
|
+
children?: unknown
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
interface BoundaryState {
|
|
@@ -56,9 +56,9 @@ interface BoundaryState {
|
|
|
56
56
|
// `null`/a string reaches error.js unwrapped (Next passes the raw value on the
|
|
57
57
|
// client channel), so `hasError` — NOT truthiness of `error` — gates rendering:
|
|
58
58
|
// a falsy `undefined`/`null` throw is still a caught error, not "no error".
|
|
59
|
-
error: unknown
|
|
60
|
-
hasError: boolean
|
|
61
|
-
notFound: boolean
|
|
59
|
+
error: unknown
|
|
60
|
+
hasError: boolean
|
|
61
|
+
notFound: boolean
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -67,9 +67,9 @@ interface BoundaryState {
|
|
|
67
67
|
* is ever attached (digests are a server-error-only signal).
|
|
68
68
|
*/
|
|
69
69
|
export function toClientError(value: unknown): Error {
|
|
70
|
-
if (value instanceof Error) return value
|
|
70
|
+
if (value instanceof Error) return value
|
|
71
71
|
// `throw undefined` / `throw null` / `throw 'msg'` → message is String(value).
|
|
72
|
-
return new Error(String(value))
|
|
72
|
+
return new Error(String(value))
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// A boundary that catches (or escalates) a real error marks it here so the
|
|
@@ -77,47 +77,47 @@ export function toClientError(value: unknown): Error {
|
|
|
77
77
|
// by the nearest-boundary path and must NOT also drive it to global-error.
|
|
78
78
|
// WeakSet-keyed (only object throws are markable; a primitive throw that reaches
|
|
79
79
|
// the window is treated as unhandled, matching "the boundary couldn't hold it").
|
|
80
|
-
const handledErrors = new WeakSet<object>()
|
|
80
|
+
const handledErrors = new WeakSet<object>()
|
|
81
81
|
|
|
82
82
|
export function markErrorHandled(error: unknown): void {
|
|
83
|
-
if (error !== null && typeof error === 'object') handledErrors.add(error)
|
|
83
|
+
if (error !== null && typeof error === 'object') handledErrors.add(error)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export function wasErrorHandled(error: unknown): boolean {
|
|
87
|
-
return error !== null && typeof error === 'object' && handledErrors.has(error)
|
|
87
|
+
return error !== null && typeof error === 'object' && handledErrors.has(error)
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export class ClientErrorBoundary extends Component<BoundaryProps, BoundaryState> {
|
|
91
|
-
state: BoundaryState = { error: null, hasError: false, notFound: false }
|
|
91
|
+
state: BoundaryState = { error: null, hasError: false, notFound: false }
|
|
92
92
|
|
|
93
93
|
static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {
|
|
94
|
-
if (isNotFoundError(error)) return { notFound: true, hasError: false, error: null }
|
|
94
|
+
if (isNotFoundError(error)) return { notFound: true, hasError: false, error: null }
|
|
95
95
|
// Control-flow errors must not be captured as state — let componentDidCatch
|
|
96
96
|
// re-throw so they propagate past this boundary.
|
|
97
|
-
if (isControlFlowError(error)) return {}
|
|
97
|
+
if (isControlFlowError(error)) return {}
|
|
98
98
|
// Pass the RAW thrown value to error.js (no Error wrapping): a client
|
|
99
99
|
// `throw undefined`/`null`/'msg' renders as `${error}` = 'undefined'/'null'/'msg'.
|
|
100
|
-
return { error: normalizeBoundaryError(error), hasError: true }
|
|
100
|
+
return { error: normalizeBoundaryError(error), hasError: true }
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
componentDidCatch(error: unknown): void {
|
|
104
104
|
if (isNotFoundError(error)) {
|
|
105
|
-
markErrorHandled(error)
|
|
106
|
-
return
|
|
105
|
+
markErrorHandled(error)
|
|
106
|
+
return
|
|
107
107
|
}
|
|
108
108
|
if (isControlFlowError(error)) {
|
|
109
109
|
// Re-throw past this boundary: React/Next semantics for control errors.
|
|
110
110
|
// The install layer's window handler catches the propagated error and
|
|
111
111
|
// performs the navigation; we still throw so no error UI renders here.
|
|
112
|
-
handleControlFlowError(error)
|
|
113
|
-
throw error
|
|
112
|
+
handleControlFlowError(error)
|
|
113
|
+
throw error
|
|
114
114
|
}
|
|
115
115
|
// A real error the boundary can render (it has a local error.js): mark it so the window-listener
|
|
116
116
|
// last resort ignores it. When there is NO errorComponent this boundary re-throws in render()
|
|
117
117
|
// instead of rendering anything - leave the error UNMARKED so an outer VDOM boundary can still
|
|
118
118
|
// catch it, and so the window-listener last resort recognizes a truly-uncaught error and mounts
|
|
119
119
|
// global-error.
|
|
120
|
-
if (this.props.errorComponent) markErrorHandled(error)
|
|
120
|
+
if (this.props.errorComponent) markErrorHandled(error)
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
@@ -127,8 +127,8 @@ export class ClientErrorBoundary extends Component<BoundaryProps, BoundaryState>
|
|
|
127
127
|
* holding one of those nodes (a click in flight, a test's element handle) loses it.
|
|
128
128
|
*/
|
|
129
129
|
reset = (): void => {
|
|
130
|
-
this.setState({ error: null, hasError: false, notFound: false })
|
|
131
|
-
}
|
|
130
|
+
this.setState({ error: null, hasError: false, notFound: false })
|
|
131
|
+
}
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* Re-run the SERVER render, then re-render: recovers data-dependent failures. A CLIENT-component
|
|
@@ -138,59 +138,59 @@ export class ClientErrorBoundary extends Component<BoundaryProps, BoundaryState>
|
|
|
138
138
|
* round trip.
|
|
139
139
|
*/
|
|
140
140
|
unstable_retry = (): void => {
|
|
141
|
-
const digest = (this.state.error as { digest?: unknown } | null)?.digest
|
|
142
|
-
this.setState({ error: null, hasError: false, notFound: false })
|
|
143
|
-
if (typeof digest === 'string' && digest.length > 0) this.props.onReset?.()
|
|
144
|
-
}
|
|
141
|
+
const digest = (this.state.error as { digest?: unknown } | null)?.digest
|
|
142
|
+
this.setState({ error: null, hasError: false, notFound: false })
|
|
143
|
+
if (typeof digest === 'string' && digest.length > 0) this.props.onReset?.()
|
|
144
|
+
}
|
|
145
145
|
|
|
146
146
|
// A client-side notFound() that renders a LOCAL not-found.js has no server
|
|
147
147
|
// round trip, so the `<meta name="robots" content="noindex">` the server
|
|
148
148
|
// would emit for a not-found render is missing. Mirror it on the client:
|
|
149
149
|
// inject the tag while the local boundary is showing, remove it on recovery.
|
|
150
|
-
private addedNoindex = false
|
|
150
|
+
private addedNoindex = false
|
|
151
151
|
|
|
152
152
|
private syncNotFoundRobots(): void {
|
|
153
|
-
if (typeof document === 'undefined') return
|
|
154
|
-
const shouldShow = this.state.notFound && Boolean(this.props.notFoundComponent)
|
|
153
|
+
if (typeof document === 'undefined') return
|
|
154
|
+
const shouldShow = this.state.notFound && Boolean(this.props.notFoundComponent)
|
|
155
155
|
if (shouldShow && !this.addedNoindex) {
|
|
156
156
|
// Don't stomp an existing robots tag (SSR/metadata already set one).
|
|
157
157
|
if (!document.querySelector('meta[name="robots"]')) {
|
|
158
|
-
const meta = document.createElement('meta')
|
|
159
|
-
meta.setAttribute('name', 'robots')
|
|
160
|
-
meta.setAttribute('content', 'noindex')
|
|
161
|
-
meta.setAttribute('data-pnext-notfound-robots', '')
|
|
162
|
-
document.head.appendChild(meta)
|
|
163
|
-
this.addedNoindex = true
|
|
158
|
+
const meta = document.createElement('meta')
|
|
159
|
+
meta.setAttribute('name', 'robots')
|
|
160
|
+
meta.setAttribute('content', 'noindex')
|
|
161
|
+
meta.setAttribute('data-pnext-notfound-robots', '')
|
|
162
|
+
document.head.appendChild(meta)
|
|
163
|
+
this.addedNoindex = true
|
|
164
164
|
}
|
|
165
165
|
} else if (!shouldShow && this.addedNoindex) {
|
|
166
|
-
document.querySelector('meta[name="robots"][data-pnext-notfound-robots]')?.remove()
|
|
167
|
-
this.addedNoindex = false
|
|
166
|
+
document.querySelector('meta[name="robots"][data-pnext-notfound-robots]')?.remove()
|
|
167
|
+
this.addedNoindex = false
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
componentDidMount(): void {
|
|
172
|
-
this.syncNotFoundRobots()
|
|
172
|
+
this.syncNotFoundRobots()
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
componentDidUpdate(): void {
|
|
176
|
-
this.syncNotFoundRobots()
|
|
176
|
+
this.syncNotFoundRobots()
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
componentWillUnmount(): void {
|
|
180
180
|
if (this.addedNoindex) {
|
|
181
|
-
document.querySelector('meta[name="robots"][data-pnext-notfound-robots]')?.remove()
|
|
182
|
-
this.addedNoindex = false
|
|
181
|
+
document.querySelector('meta[name="robots"][data-pnext-notfound-robots]')?.remove()
|
|
182
|
+
this.addedNoindex = false
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
render(): ComponentChildren {
|
|
187
187
|
if (this.state.notFound) {
|
|
188
|
-
const NotFoundComponent = this.props.notFoundComponent ?? this.props.builtInNotFound
|
|
189
|
-
return NotFoundComponent ? h(NotFoundComponent, {}) : null
|
|
188
|
+
const NotFoundComponent = this.props.notFoundComponent ?? this.props.builtInNotFound
|
|
189
|
+
return NotFoundComponent ? h(NotFoundComponent, {}) : null
|
|
190
190
|
}
|
|
191
|
-
if (!this.state.hasError) return this.props.children
|
|
192
|
-
const { error } = this.state
|
|
193
|
-
const ErrorComponent = this.props.errorComponent
|
|
191
|
+
if (!this.state.hasError) return this.props.children
|
|
192
|
+
const { error } = this.state
|
|
193
|
+
const ErrorComponent = this.props.errorComponent
|
|
194
194
|
if (!ErrorComponent) {
|
|
195
195
|
// Preserve primitive throws for global-error.js directly (window `error`
|
|
196
196
|
// loses raw null/undefined/string). Bubble Error objects to the next outer
|
|
@@ -198,11 +198,11 @@ export class ClientErrorBoundary extends Component<BoundaryProps, BoundaryState>
|
|
|
198
198
|
if (error === null || typeof error !== 'object') {
|
|
199
199
|
// global-error rides the deferred tier (see ./lazy) — a primitive throw
|
|
200
200
|
// with no error.js is the one path that reaches it from a render.
|
|
201
|
-
void import('./global-error').then(m => m.escalateToGlobalError(error))
|
|
202
|
-
return null
|
|
201
|
+
void import('./global-error').then(m => m.escalateToGlobalError(error))
|
|
202
|
+
return null
|
|
203
203
|
}
|
|
204
|
-
throw error as Error
|
|
204
|
+
throw error as Error
|
|
205
205
|
}
|
|
206
|
-
return h(ErrorComponent, { error, reset: this.reset, unstable_retry: this.unstable_retry })
|
|
206
|
+
return h(ErrorComponent, { error, reset: this.reset, unstable_retry: this.unstable_retry })
|
|
207
207
|
}
|
|
208
208
|
}
|
|
@@ -11,21 +11,21 @@
|
|
|
11
11
|
//
|
|
12
12
|
// Client-escaped errors carry NO digest, so the built-in fallback shows the no-digest message.
|
|
13
13
|
|
|
14
|
-
import { h, render, type ComponentType } from 'preact'
|
|
15
|
-
import { softNavigate } from '../../../
|
|
14
|
+
import { h, render, type ComponentType } from 'preact'
|
|
15
|
+
import { softNavigate } from '../../../client/router'
|
|
16
16
|
|
|
17
|
-
export type GlobalErrorComponent = ComponentType<{ error: unknown; reset: () => void }
|
|
17
|
+
export type GlobalErrorComponent = ComponentType<{ error: unknown; reset: () => void }>
|
|
18
18
|
|
|
19
|
-
let globalErrorMounted = false
|
|
19
|
+
let globalErrorMounted = false
|
|
20
20
|
|
|
21
21
|
// The app-root global-error.js component, registered by installClientErrors so the in-tree
|
|
22
22
|
// ClientErrorBoundary can escalate straight to it WITHOUT bouncing a re-throw through the window
|
|
23
23
|
// `error` channel - that channel drops the value for a thrown undefined/null (the ErrorEvent's `.error`
|
|
24
24
|
// is undefined), so a primitive escape would be lost.
|
|
25
|
-
let registeredGlobalError: GlobalErrorComponent | undefined
|
|
25
|
+
let registeredGlobalError: GlobalErrorComponent | undefined
|
|
26
26
|
|
|
27
27
|
export function registerGlobalErrorComponent(component?: GlobalErrorComponent): void {
|
|
28
|
-
registeredGlobalError = component
|
|
28
|
+
registeredGlobalError = component
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -35,35 +35,35 @@ export function registerGlobalErrorComponent(component?: GlobalErrorComponent):
|
|
|
35
35
|
* global-error.js unwrapped, so `${error}` renders 'undefined'/'null').
|
|
36
36
|
*/
|
|
37
37
|
export function escalateToGlobalError(error: unknown): void {
|
|
38
|
-
mountGlobalError(error, registeredGlobalError)
|
|
38
|
+
mountGlobalError(error, registeredGlobalError)
|
|
39
39
|
// A client error that escapes every route boundary is, to the page, an UNCAUGHT error: Next still
|
|
40
40
|
// reports it to the window so window.onerror and Playwright's pageerror observe the original.
|
|
41
41
|
// mountGlobalError swaps the document silently, so surface the throw explicitly here. Skip
|
|
42
42
|
// primitive-sentinel escapes and anything non-Error - only a real Error carries a meaningful pageerror.
|
|
43
43
|
if ((process.browser || typeof window !== 'undefined') && error instanceof Error) {
|
|
44
|
-
reportUncaught(error)
|
|
44
|
+
reportUncaught(error)
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Errors already surfaced via reportUncaught: the later natural unhandled
|
|
49
49
|
// rejection of the same value is a duplicate and gets suppressed (install.ts).
|
|
50
|
-
const reportedUncaught = new WeakSet<Error>()
|
|
50
|
+
const reportedUncaught = new WeakSet<Error>()
|
|
51
51
|
|
|
52
52
|
export function wasReportedUncaught(error: unknown): boolean {
|
|
53
|
-
return error instanceof Error && reportedUncaught.has(error)
|
|
53
|
+
return error instanceof Error && reportedUncaught.has(error)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Report an escaped error to the window as an uncaught exception. Prefer the
|
|
57
57
|
// standard `reportError`; fall back to a synthetic 'error' event for engines
|
|
58
58
|
// without it. Wrapped so a reporting failure never masks the global-error UI.
|
|
59
59
|
function reportUncaught(error: Error): void {
|
|
60
|
-
reportedUncaught.add(error)
|
|
60
|
+
reportedUncaught.add(error)
|
|
61
61
|
try {
|
|
62
62
|
if (typeof reportError === 'function') {
|
|
63
|
-
reportError(error)
|
|
64
|
-
return
|
|
63
|
+
reportError(error)
|
|
64
|
+
return
|
|
65
65
|
}
|
|
66
|
-
window.dispatchEvent(new ErrorEvent('error', { error, message: error.message }))
|
|
66
|
+
window.dispatchEvent(new ErrorEvent('error', { error, message: error.message }))
|
|
67
67
|
} catch {
|
|
68
68
|
// ignore — the global-error document is already shown.
|
|
69
69
|
}
|
|
@@ -75,47 +75,47 @@ function reportUncaught(error: Error): void {
|
|
|
75
75
|
* top-level replacement). A soft refresh via reset() clears the flag.
|
|
76
76
|
*/
|
|
77
77
|
export function mountGlobalError(error: unknown, component?: GlobalErrorComponent): void {
|
|
78
|
-
if (typeof document === 'undefined' || globalErrorMounted) return
|
|
79
|
-
globalErrorMounted = true
|
|
78
|
+
if (typeof document === 'undefined' || globalErrorMounted) return
|
|
79
|
+
globalErrorMounted = true
|
|
80
80
|
|
|
81
|
-
document.documentElement.id = '__next_error__'
|
|
82
|
-
const root = document.createElement('div')
|
|
83
|
-
document.body.replaceChildren(root)
|
|
81
|
+
document.documentElement.id = '__next_error__'
|
|
82
|
+
const root = document.createElement('div')
|
|
83
|
+
document.body.replaceChildren(root)
|
|
84
84
|
|
|
85
85
|
const reset = () => {
|
|
86
|
-
globalErrorMounted = false
|
|
87
|
-
render(null, root)
|
|
86
|
+
globalErrorMounted = false
|
|
87
|
+
render(null, root)
|
|
88
88
|
// Re-render the current URL from the server (recovers server + client errors).
|
|
89
89
|
void softNavigate(location.href, { replace: true, scroll: false }).catch(() => {
|
|
90
|
-
location.reload()
|
|
91
|
-
})
|
|
92
|
-
}
|
|
90
|
+
location.reload()
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
93
|
|
|
94
94
|
if (component) {
|
|
95
95
|
try {
|
|
96
96
|
// A user global-error.js owns the whole document (<html>/<body>); render its
|
|
97
97
|
// subtree in place. If it THROWS during render, fall back to the built-in.
|
|
98
|
-
render(h(component, { error, reset }), root)
|
|
99
|
-
return
|
|
98
|
+
render(h(component, { error, reset }), root)
|
|
99
|
+
return
|
|
100
100
|
} catch {
|
|
101
|
-
globalErrorMounted = true
|
|
101
|
+
globalErrorMounted = true // keep mounted; render the fallback below.
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
renderBuiltinFallback(root, error)
|
|
105
|
+
renderBuiltinFallback(root, error)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// Next's DefaultGlobalError document text/markup. A client-escaped error has no
|
|
109
109
|
// digest, so it always shows the non-server "Reload to try again, or go back."
|
|
110
110
|
// message and no ERROR <digest> footer.
|
|
111
111
|
function renderBuiltinFallback(root: HTMLElement, error: unknown): void {
|
|
112
|
-
const digest = (error as { digest?: unknown } | null | undefined)?.digest
|
|
113
|
-
const isServerError = typeof digest === 'string' && digest.length > 0
|
|
112
|
+
const digest = (error as { digest?: unknown } | null | undefined)?.digest
|
|
113
|
+
const isServerError = typeof digest === 'string' && digest.length > 0
|
|
114
114
|
const message = isServerError
|
|
115
115
|
? 'A server error occurred. Reload to try again.'
|
|
116
|
-
: 'Reload to try again, or go back.'
|
|
116
|
+
: 'Reload to try again, or go back.'
|
|
117
117
|
|
|
118
|
-
ensureThemeStyle()
|
|
118
|
+
ensureThemeStyle()
|
|
119
119
|
Object.assign(root.style, {
|
|
120
120
|
fontFamily:
|
|
121
121
|
'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',
|
|
@@ -123,29 +123,32 @@ function renderBuiltinFallback(root: HTMLElement, error: unknown): void {
|
|
|
123
123
|
display: 'flex',
|
|
124
124
|
alignItems: 'center',
|
|
125
125
|
justifyContent: 'center',
|
|
126
|
-
} as Partial<CSSStyleDeclaration>)
|
|
126
|
+
} as Partial<CSSStyleDeclaration>)
|
|
127
127
|
|
|
128
|
-
const card = document.createElement('div')
|
|
128
|
+
const card = document.createElement('div')
|
|
129
129
|
Object.assign(card.style, {
|
|
130
130
|
marginTop: '-32px',
|
|
131
131
|
maxWidth: '325px',
|
|
132
132
|
padding: '32px 28px',
|
|
133
133
|
textAlign: 'left',
|
|
134
|
-
} as Partial<CSSStyleDeclaration>)
|
|
135
|
-
|
|
136
|
-
const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
|
137
|
-
icon.setAttribute('width', '32')
|
|
138
|
-
icon.setAttribute('height', '32')
|
|
139
|
-
icon.setAttribute('viewBox', '-0.2 -1.5 32 32')
|
|
140
|
-
icon.setAttribute('fill', 'none')
|
|
141
|
-
icon.style.marginBottom = '24px'
|
|
142
|
-
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
143
|
-
path.setAttribute(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
134
|
+
} as Partial<CSSStyleDeclaration>)
|
|
135
|
+
|
|
136
|
+
const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
|
137
|
+
icon.setAttribute('width', '32')
|
|
138
|
+
icon.setAttribute('height', '32')
|
|
139
|
+
icon.setAttribute('viewBox', '-0.2 -1.5 32 32')
|
|
140
|
+
icon.setAttribute('fill', 'none')
|
|
141
|
+
icon.style.marginBottom = '24px'
|
|
142
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
143
|
+
path.setAttribute(
|
|
144
|
+
'd',
|
|
145
|
+
'M16.9328 0C18.0839.000116771 19.1334.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C.527541 29-.439628 27.4588.201371 26.1309L11.9973 1.69531C12.4979.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z',
|
|
146
|
+
)
|
|
147
|
+
path.setAttribute('fill', 'var(--next-error-title)')
|
|
148
|
+
icon.append(path)
|
|
149
|
+
|
|
150
|
+
const title = document.createElement('h1')
|
|
151
|
+
title.textContent = 'This page couldn’t load'
|
|
149
152
|
Object.assign(title.style, {
|
|
150
153
|
fontSize: '24px',
|
|
151
154
|
fontWeight: '500',
|
|
@@ -153,50 +156,50 @@ function renderBuiltinFallback(root: HTMLElement, error: unknown): void {
|
|
|
153
156
|
lineHeight: '32px',
|
|
154
157
|
margin: '0 0 12px 0',
|
|
155
158
|
color: 'var(--next-error-title)',
|
|
156
|
-
} as Partial<CSSStyleDeclaration>)
|
|
159
|
+
} as Partial<CSSStyleDeclaration>)
|
|
157
160
|
|
|
158
|
-
const body = document.createElement('p')
|
|
159
|
-
body.textContent = message
|
|
161
|
+
const body = document.createElement('p')
|
|
162
|
+
body.textContent = message
|
|
160
163
|
Object.assign(body.style, {
|
|
161
164
|
fontSize: '14px',
|
|
162
165
|
fontWeight: '400',
|
|
163
166
|
lineHeight: '21px',
|
|
164
167
|
margin: '0 0 20px 0',
|
|
165
168
|
color: 'var(--next-error-message)',
|
|
166
|
-
} as Partial<CSSStyleDeclaration>)
|
|
169
|
+
} as Partial<CSSStyleDeclaration>)
|
|
167
170
|
|
|
168
|
-
const buttonGroup = document.createElement('div')
|
|
169
|
-
Object.assign(buttonGroup.style, { display: 'flex', gap: '8px', alignItems: 'center' })
|
|
170
|
-
const reloadForm = document.createElement('form')
|
|
171
|
-
reloadForm.style.margin = '0'
|
|
171
|
+
const buttonGroup = document.createElement('div')
|
|
172
|
+
Object.assign(buttonGroup.style, { display: 'flex', gap: '8px', alignItems: 'center' })
|
|
173
|
+
const reloadForm = document.createElement('form')
|
|
174
|
+
reloadForm.style.margin = '0'
|
|
172
175
|
reloadForm.addEventListener('submit', event => {
|
|
173
|
-
event.preventDefault()
|
|
174
|
-
location.reload()
|
|
175
|
-
})
|
|
176
|
-
const reload = document.createElement('button')
|
|
177
|
-
reload.type = 'submit'
|
|
178
|
-
reload.textContent = 'Reload'
|
|
179
|
-
Object.assign(reload.style, buttonStyle(false))
|
|
180
|
-
reloadForm.append(reload)
|
|
181
|
-
buttonGroup.append(reloadForm)
|
|
176
|
+
event.preventDefault()
|
|
177
|
+
location.reload()
|
|
178
|
+
})
|
|
179
|
+
const reload = document.createElement('button')
|
|
180
|
+
reload.type = 'submit'
|
|
181
|
+
reload.textContent = 'Reload'
|
|
182
|
+
Object.assign(reload.style, buttonStyle(false))
|
|
183
|
+
reloadForm.append(reload)
|
|
184
|
+
buttonGroup.append(reloadForm)
|
|
182
185
|
if (!isServerError) {
|
|
183
|
-
const back = document.createElement('button')
|
|
184
|
-
back.type = 'button'
|
|
185
|
-
back.textContent = 'Back'
|
|
186
|
-
Object.assign(back.style, buttonStyle(true))
|
|
186
|
+
const back = document.createElement('button')
|
|
187
|
+
back.type = 'button'
|
|
188
|
+
back.textContent = 'Back'
|
|
189
|
+
Object.assign(back.style, buttonStyle(true))
|
|
187
190
|
back.addEventListener('click', () => {
|
|
188
|
-
if (window.history.length > 1) window.history.back()
|
|
189
|
-
else window.location.href = '/'
|
|
190
|
-
})
|
|
191
|
-
buttonGroup.append(back)
|
|
191
|
+
if (window.history.length > 1) window.history.back()
|
|
192
|
+
else window.location.href = '/'
|
|
193
|
+
})
|
|
194
|
+
buttonGroup.append(back)
|
|
192
195
|
}
|
|
193
|
-
card.append(icon, title, body, buttonGroup)
|
|
194
|
-
root.append(card)
|
|
196
|
+
card.append(icon, title, body, buttonGroup)
|
|
197
|
+
root.append(card)
|
|
195
198
|
if (isServerError) {
|
|
196
199
|
// Next's DefaultGlobalError digest footer (`ERROR <digest>`), fixed to the
|
|
197
200
|
// bottom so operators can correlate the redacted UI with server logs.
|
|
198
|
-
const footer = document.createElement('p')
|
|
199
|
-
footer.textContent = `ERROR ${digest}
|
|
201
|
+
const footer = document.createElement('p')
|
|
202
|
+
footer.textContent = `ERROR ${digest}`
|
|
200
203
|
Object.assign(footer.style, {
|
|
201
204
|
position: 'fixed',
|
|
202
205
|
bottom: '32px',
|
|
@@ -209,30 +212,37 @@ function renderBuiltinFallback(root: HTMLElement, error: unknown): void {
|
|
|
209
212
|
fontWeight: '400',
|
|
210
213
|
margin: '0',
|
|
211
214
|
color: 'var(--next-error-digest)',
|
|
212
|
-
} as Partial<CSSStyleDeclaration>)
|
|
213
|
-
root.append(footer)
|
|
215
|
+
} as Partial<CSSStyleDeclaration>)
|
|
216
|
+
root.append(footer)
|
|
214
217
|
}
|
|
215
|
-
if (typeof document.title !== 'undefined') document.title = '500: This page couldn’t load'
|
|
218
|
+
if (typeof document.title !== 'undefined') document.title = '500: This page couldn’t load'
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
function buttonStyle(secondary: boolean): Partial<CSSStyleDeclaration> {
|
|
219
222
|
return {
|
|
220
|
-
display: 'inline-flex',
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
display: 'inline-flex',
|
|
224
|
+
alignItems: 'center',
|
|
225
|
+
justifyContent: 'center',
|
|
226
|
+
height: '32px',
|
|
227
|
+
padding: '0 12px',
|
|
228
|
+
fontSize: '14px',
|
|
229
|
+
fontWeight: '500',
|
|
230
|
+
lineHeight: '20px',
|
|
231
|
+
borderRadius: '6px',
|
|
232
|
+
cursor: 'pointer',
|
|
223
233
|
color: secondary ? 'var(--next-error-btn-secondary-text)' : 'var(--next-error-btn-text)',
|
|
224
234
|
background: secondary ? 'var(--next-error-btn-secondary-bg)' : 'var(--next-error-btn-bg)',
|
|
225
235
|
border: secondary ? 'var(--next-error-btn-secondary-border)' : 'var(--next-error-btn-border)',
|
|
226
|
-
}
|
|
236
|
+
}
|
|
227
237
|
}
|
|
228
238
|
|
|
229
|
-
const THEME_STYLE_ID = '__pnext_global_error_theme__'
|
|
239
|
+
const THEME_STYLE_ID = '__pnext_global_error_theme__'
|
|
230
240
|
|
|
231
241
|
function ensureThemeStyle(): void {
|
|
232
|
-
if (document.getElementById(THEME_STYLE_ID)) return
|
|
233
|
-
const style = document.createElement('style')
|
|
234
|
-
style.id = THEME_STYLE_ID
|
|
242
|
+
if (document.getElementById(THEME_STYLE_ID)) return
|
|
243
|
+
const style = document.createElement('style')
|
|
244
|
+
style.id = THEME_STYLE_ID
|
|
235
245
|
style.textContent =
|
|
236
|
-
':root{--next-error-bg:#fff;--next-error-text:#171717;--next-error-title:#171717;--next-error-message:#171717;--next-error-digest:#666666;--next-error-btn-text:#fff;--next-error-btn-bg:#171717;--next-error-btn-border:none;--next-error-btn-secondary-text:#171717;--next-error-btn-secondary-bg:transparent;--next-error-btn-secondary-border:1px solid rgba(0,0,0,.08)}@media (prefers-color-scheme:dark){:root{--next-error-bg:#0a0a0a;--next-error-text:#ededed;--next-error-title:#ededed;--next-error-message:#ededed;--next-error-digest:#a0a0a0;--next-error-btn-text:#0a0a0a;--next-error-btn-bg:#ededed;--next-error-btn-border:none;--next-error-btn-secondary-text:#ededed;--next-error-btn-secondary-bg:transparent;--next-error-btn-secondary-border:1px solid rgba(255,255,255,.14)}}body{margin:0;color:var(--next-error-text);background:var(--next-error-bg);}'
|
|
237
|
-
document.head.append(style)
|
|
246
|
+
':root{--next-error-bg:#fff;--next-error-text:#171717;--next-error-title:#171717;--next-error-message:#171717;--next-error-digest:#666666;--next-error-btn-text:#fff;--next-error-btn-bg:#171717;--next-error-btn-border:none;--next-error-btn-secondary-text:#171717;--next-error-btn-secondary-bg:transparent;--next-error-btn-secondary-border:1px solid rgba(0,0,0,.08)}@media (prefers-color-scheme:dark){:root{--next-error-bg:#0a0a0a;--next-error-text:#ededed;--next-error-title:#ededed;--next-error-message:#ededed;--next-error-digest:#a0a0a0;--next-error-btn-text:#0a0a0a;--next-error-btn-bg:#ededed;--next-error-btn-border:none;--next-error-btn-secondary-text:#ededed;--next-error-btn-secondary-bg:transparent;--next-error-btn-secondary-border:1px solid rgba(255,255,255,.14)}}body{margin:0;color:var(--next-error-text);background:var(--next-error-bg);}'
|
|
247
|
+
document.head.append(style)
|
|
238
248
|
}
|