@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
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
// Pages-router API/data serving implementation (COMPAT - may import core freely): Node req/res
|
|
2
|
+
// shims plus the API-route and data-fetch (`/_next/data`) dispatch. Registered by
|
|
3
|
+
// ../register/pages-api.ts, which wires the exports below into the extension registries.
|
|
4
|
+
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
6
|
+
import { Writable } from 'node:stream'
|
|
7
|
+
import path from 'node:path'
|
|
8
|
+
import { devServerModuleHref } from '../../runtime/modules'
|
|
9
|
+
import { pagesApiBundleTargetForRuntime } from '../../runtime/loader'
|
|
10
|
+
import { getRequestExtensions, type RequestInterceptor } from '../../extensions'
|
|
11
|
+
import { getRequestRuntime } from '../../routing/request-environment'
|
|
12
|
+
import { selectRouteForRequest } from '../../routing/routes'
|
|
13
|
+
import { serverBundleTargetForRuntime } from '../../runtime/loader'
|
|
14
|
+
import { setWorkUnitRoute } from '../../request/context'
|
|
15
|
+
import { canonicalUrlHref } from '../next/canonical-url'
|
|
16
|
+
import { markPathRevalidated, normalizeRevalidatePath } from '../cache/revalidate'
|
|
17
|
+
import { withPagesApiHandlerSpan } from '../otel/tracer'
|
|
18
|
+
import { toNextRequest } from '../../api/server'
|
|
19
|
+
|
|
20
|
+
type PagesApiHandler = (req: unknown, res: PagesApiResponse) => Promise<unknown>
|
|
21
|
+
|
|
22
|
+
interface PagesApiModule {
|
|
23
|
+
default?: PagesApiHandler
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface PagesApiResponse {
|
|
27
|
+
statusCode: number
|
|
28
|
+
on(event: 'close' | 'error', listener: (...args: unknown[]) => void): PagesApiResponse
|
|
29
|
+
write(chunk: unknown, encoding?: BufferEncoding, callback?: () => void): boolean
|
|
30
|
+
setHeader(name: string, value: string | number | readonly string[]): PagesApiResponse
|
|
31
|
+
getHeader(name: string): string | null
|
|
32
|
+
status(code: number): PagesApiResponse
|
|
33
|
+
json(value: unknown): PagesApiResponse
|
|
34
|
+
send(value?: unknown): PagesApiResponse
|
|
35
|
+
end(value?: unknown): PagesApiResponse
|
|
36
|
+
revalidate(path: string): Promise<void>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const pageExtensions = ['ts', 'tsx', 'js', 'jsx', 'mjs', 'mts']
|
|
40
|
+
|
|
41
|
+
/** The preview-mode id written into prerender-manifest.json (see register/pages-api.ts). */
|
|
42
|
+
export const PREVIEW_MODE_ID = 'pnext-preview-id'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pages-router data protocol (`/_next/data/<id>/<page>.json`, normalized to the page path by cli/start.ts
|
|
46
|
+
* with the `x-nextjs-data` marker): serve the page's data-fetch result as Next's data JSON -
|
|
47
|
+
* `{ pageProps }` from getServerSideProps/getStaticProps of the materialized pages route - instead of
|
|
48
|
+
* rendering HTML. When the request was rewritten, `x-nextjs-matched-path` reports the destination the
|
|
49
|
+
* data was served from, which the pages client router uses to resolve the rewrite.
|
|
50
|
+
*/
|
|
51
|
+
export const pagesDataInterceptor: RequestInterceptor = async request => {
|
|
52
|
+
if (request.headers.get('x-nextjs-data') !== '1') return undefined
|
|
53
|
+
const method = request.method.toUpperCase()
|
|
54
|
+
if (method !== 'GET' && method !== 'HEAD') return undefined
|
|
55
|
+
const runtime = getRequestRuntime()
|
|
56
|
+
if (!runtime) return undefined
|
|
57
|
+
const url = new URL(request.url)
|
|
58
|
+
// Un-normalized data URLs (skipMiddlewareUrlNormalize without a middleware
|
|
59
|
+
// rewrite) never match a route here; header-only marker requests for
|
|
60
|
+
// document paths fall through to the HTML render.
|
|
61
|
+
if (url.pathname.startsWith('/_next/')) return undefined
|
|
62
|
+
|
|
63
|
+
const selection = selectRouteForRequest(runtime.routes, url.pathname)
|
|
64
|
+
if (selection?.route.kind !== 'page') {
|
|
65
|
+
return dataResponse({ notFound: true }, 404, url)
|
|
66
|
+
}
|
|
67
|
+
const route = selection.route
|
|
68
|
+
if (!isMaterializedPagesRoute(route.file)) return undefined
|
|
69
|
+
|
|
70
|
+
const module = (await import(
|
|
71
|
+
await devServerModuleHref(
|
|
72
|
+
runtime.config,
|
|
73
|
+
route.file,
|
|
74
|
+
runtime.dev ? (runtime.devImportVersion ?? 'dev') : 'build',
|
|
75
|
+
{
|
|
76
|
+
conditionTarget: serverBundleTargetForRuntime(route.segmentConfig?.runtime),
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
)) as PagesDataModule
|
|
80
|
+
|
|
81
|
+
setWorkUnitRoute('data', 'dynamic')
|
|
82
|
+
const params = selection.params ?? {}
|
|
83
|
+
const query = { ...Object.fromEntries(url.searchParams), ...params }
|
|
84
|
+
if (typeof module.getServerSideProps === 'function') {
|
|
85
|
+
const result = await module.getServerSideProps({
|
|
86
|
+
params,
|
|
87
|
+
query,
|
|
88
|
+
req: pagesDataRequestShim(request, url),
|
|
89
|
+
res: pagesDataResponseShim(),
|
|
90
|
+
resolvedUrl: `${url.pathname}${url.search}`,
|
|
91
|
+
preview: false,
|
|
92
|
+
previewData: undefined,
|
|
93
|
+
})
|
|
94
|
+
return pagesDataResult(result, url)
|
|
95
|
+
}
|
|
96
|
+
if (typeof module.getStaticProps === 'function') {
|
|
97
|
+
const result = await module.getStaticProps({ params })
|
|
98
|
+
return pagesDataResult(result, url, true)
|
|
99
|
+
}
|
|
100
|
+
return dataResponse({ pageProps: {} }, 200, url)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface PagesDataFnResult {
|
|
104
|
+
props?: Record<string, unknown>
|
|
105
|
+
notFound?: boolean
|
|
106
|
+
redirect?: { destination: string; permanent?: boolean; statusCode?: number }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface PagesDataModule {
|
|
110
|
+
getServerSideProps?: (
|
|
111
|
+
context: Record<string, unknown>,
|
|
112
|
+
) => Promise<PagesDataFnResult> | PagesDataFnResult
|
|
113
|
+
getStaticProps?: (
|
|
114
|
+
context: Record<string, unknown>,
|
|
115
|
+
) => Promise<PagesDataFnResult> | PagesDataFnResult
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function pagesDataResult(result: PagesDataFnResult | undefined, url: URL, ssg = false): Response {
|
|
119
|
+
if (result?.notFound) return dataResponse({ notFound: true }, 404, url)
|
|
120
|
+
if (result?.redirect) {
|
|
121
|
+
const status = result.redirect.statusCode ?? (result.redirect.permanent ? 308 : 307)
|
|
122
|
+
return dataResponse(
|
|
123
|
+
{
|
|
124
|
+
pageProps: {
|
|
125
|
+
__N_REDIRECT: result.redirect.destination,
|
|
126
|
+
__N_REDIRECT_STATUS: status,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
200,
|
|
130
|
+
url,
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
return dataResponse(
|
|
134
|
+
{ pageProps: result?.props ?? {}, ...(ssg ? { __N_SSG: true } : { __N_SSP: true }) },
|
|
135
|
+
200,
|
|
136
|
+
url,
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function dataResponse(body: Record<string, unknown>, status: number, url: URL): Response {
|
|
141
|
+
const headers = new Headers({ 'content-type': 'application/json; charset=utf-8' })
|
|
142
|
+
// A rewrite happened when the canonical (as-requested, post-normalization)
|
|
143
|
+
// pathname differs from the URL the route was matched on.
|
|
144
|
+
const canonical = canonicalUrlHref()
|
|
145
|
+
if (canonical && new URL(canonical).pathname !== url.pathname) {
|
|
146
|
+
headers.set('x-nextjs-matched-path', url.pathname)
|
|
147
|
+
}
|
|
148
|
+
return new Response(JSON.stringify(body), { status, headers })
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// The materialized hybrid app hosts BOTH routers; only pages wrappers
|
|
152
|
+
// re-export from source-pages/, so sniff the (tiny, generated) wrapper body —
|
|
153
|
+
// app routes must never serve _next/data.
|
|
154
|
+
function isMaterializedPagesRoute(file: string): boolean {
|
|
155
|
+
if (!file.split(path.sep).join('/').includes('pnext-pages-compat/')) return false
|
|
156
|
+
try {
|
|
157
|
+
return readFileSync(file, 'utf8').includes('source-pages/')
|
|
158
|
+
} catch {
|
|
159
|
+
return false
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function pagesDataRequestShim(request: Request, url: URL) {
|
|
164
|
+
return {
|
|
165
|
+
method: request.method,
|
|
166
|
+
url: `${url.pathname}${url.search}`,
|
|
167
|
+
headers: Object.fromEntries(request.headers),
|
|
168
|
+
cookies: cookiesFromHeader(request.headers.get('cookie')),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function pagesDataResponseShim() {
|
|
173
|
+
const headers = new Headers()
|
|
174
|
+
let statusCode = 200
|
|
175
|
+
return {
|
|
176
|
+
get statusCode() {
|
|
177
|
+
return statusCode
|
|
178
|
+
},
|
|
179
|
+
set statusCode(value: number) {
|
|
180
|
+
statusCode = value
|
|
181
|
+
},
|
|
182
|
+
setHeader(name: string, value: string | number | readonly string[]) {
|
|
183
|
+
headers.set(name, Array.isArray(value) ? value.join(', ') : String(value))
|
|
184
|
+
return this
|
|
185
|
+
},
|
|
186
|
+
getHeader(name: string) {
|
|
187
|
+
return headers.get(name)
|
|
188
|
+
},
|
|
189
|
+
removeHeader(name: string) {
|
|
190
|
+
headers.delete(name)
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const pagesApiInterceptor: RequestInterceptor = async (request, { config }) => {
|
|
196
|
+
const url = new URL(request.url)
|
|
197
|
+
const file = pagesApiFile(config.root, url.pathname)
|
|
198
|
+
if (!file) return undefined
|
|
199
|
+
const imported = (await import(
|
|
200
|
+
await devServerModuleHref(config, file, 'build', {
|
|
201
|
+
conditionTarget: pagesApiBundleTargetForRuntime(apiRuntime(file)),
|
|
202
|
+
})
|
|
203
|
+
)) as PagesApiModule
|
|
204
|
+
if (typeof imported.default !== 'function') return undefined
|
|
205
|
+
|
|
206
|
+
const responder = createPagesApiResponse(request)
|
|
207
|
+
// Edge-runtime pages API handlers receive the real NextRequest (signal,
|
|
208
|
+
// nextUrl, text() — Request prototype getters a spread would lose); node
|
|
209
|
+
// handlers get the IncomingMessage-shaped shim.
|
|
210
|
+
const handlerRequest =
|
|
211
|
+
apiRuntime(file) === 'edge' ? toNextRequest(request) : createPagesApiRequest(request, url)
|
|
212
|
+
const finished = withPagesApiHandlerSpan(url.pathname, () =>
|
|
213
|
+
Promise.resolve(imported.default!(handlerRequest, responder.res)),
|
|
214
|
+
).catch(error => responder.fail(error))
|
|
215
|
+
// A handler that starts writing (res.write / pipeline) streams: the response returns at the first write
|
|
216
|
+
// and the body flows through until end or disconnect - a client disconnect destroys `res`, surfacing as
|
|
217
|
+
// its 'close' event, which is Node pages-API cancellation semantics. A handler that only buffers
|
|
218
|
+
// resolves on completion exactly as before.
|
|
219
|
+
const outcome = await Promise.race([responder.started.then(() => STREAM_STARTED), finished])
|
|
220
|
+
if (outcome !== STREAM_STARTED) {
|
|
221
|
+
if (outcome instanceof Response) return outcome
|
|
222
|
+
return responder.response(outcome)
|
|
223
|
+
}
|
|
224
|
+
return responder.streamResponse()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const STREAM_STARTED = Symbol('pnext.pagesApiStreamStarted')
|
|
228
|
+
|
|
229
|
+
function pagesApiFile(root: string, pathname: string): string | undefined {
|
|
230
|
+
if (pathname !== '/api' && !pathname.startsWith('/api/')) return undefined
|
|
231
|
+
let relative: string
|
|
232
|
+
try {
|
|
233
|
+
relative = decodeURIComponent(pathname === '/api' ? 'index' : pathname.slice('/api/'.length))
|
|
234
|
+
} catch {
|
|
235
|
+
return undefined
|
|
236
|
+
}
|
|
237
|
+
const baseDir = path.join(root, 'pages', 'api')
|
|
238
|
+
const base = path.resolve(baseDir, relative)
|
|
239
|
+
if (base !== baseDir && !base.startsWith(`${baseDir}${path.sep}`)) return undefined
|
|
240
|
+
for (const ext of pageExtensions) {
|
|
241
|
+
const file = `${base}.${ext}`
|
|
242
|
+
if (existsSync(file)) return file
|
|
243
|
+
const index = path.join(base, `index.${ext}`)
|
|
244
|
+
if (existsSync(index)) return index
|
|
245
|
+
}
|
|
246
|
+
return undefined
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function apiRuntime(file: string): string | undefined {
|
|
250
|
+
return /\bruntime\b\s*[:=]\s*(['"`])(?:edge|experimental-edge)\1/.test(readFileSync(file, 'utf8'))
|
|
251
|
+
? 'edge'
|
|
252
|
+
: undefined
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function createPagesApiRequest(request: Request, url: URL) {
|
|
256
|
+
const nextRequest = toNextRequest(request)
|
|
257
|
+
return {
|
|
258
|
+
...nextRequest,
|
|
259
|
+
method: request.method,
|
|
260
|
+
url: `${url.pathname}${url.search}`,
|
|
261
|
+
headers: Object.fromEntries(request.headers),
|
|
262
|
+
query: Object.fromEntries(url.searchParams),
|
|
263
|
+
cookies: cookiesFromHeader(request.headers.get('cookie')),
|
|
264
|
+
nextUrl: nextRequest.nextUrl,
|
|
265
|
+
text() {
|
|
266
|
+
return request.text()
|
|
267
|
+
},
|
|
268
|
+
json() {
|
|
269
|
+
return request.json()
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function createPagesApiResponse(request: Request) {
|
|
275
|
+
const headers = new Headers()
|
|
276
|
+
let statusCode = 200
|
|
277
|
+
let sent = false
|
|
278
|
+
let body: BodyInit | null = null
|
|
279
|
+
let started = false
|
|
280
|
+
let notifyStarted: () => void = () => undefined
|
|
281
|
+
const startedPromise = new Promise<void>(resolve => {
|
|
282
|
+
notifyStarted = resolve
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
let controller: ReadableStreamDefaultController<Uint8Array> | undefined
|
|
286
|
+
const streamBody = new ReadableStream<Uint8Array>({
|
|
287
|
+
start(c) {
|
|
288
|
+
controller = c
|
|
289
|
+
},
|
|
290
|
+
// The client disconnected mid-stream: destroy the res so the handler
|
|
291
|
+
// observes it as the response closing (Node pages-API semantics —
|
|
292
|
+
// `res.on('close', ...)` aborts its inner stream).
|
|
293
|
+
cancel() {
|
|
294
|
+
writable.destroy()
|
|
295
|
+
},
|
|
296
|
+
})
|
|
297
|
+
const start = () => {
|
|
298
|
+
if (!started) {
|
|
299
|
+
started = true
|
|
300
|
+
notifyStarted()
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const enqueue = (chunk: unknown) => {
|
|
304
|
+
const value = normalizeWriteChunk(chunk)
|
|
305
|
+
if (value === '') return
|
|
306
|
+
try {
|
|
307
|
+
controller?.enqueue(
|
|
308
|
+
typeof value === 'string' ? new TextEncoder().encode(value) : new Uint8Array(value),
|
|
309
|
+
)
|
|
310
|
+
} catch {
|
|
311
|
+
// Stream already closed/cancelled — drop the late chunk.
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// A REAL Writable: `stream.pipeline(source, res)` and event listeners need a
|
|
315
|
+
// genuine EventEmitter/stream destination, not a duck-typed object.
|
|
316
|
+
const writable = new Writable({
|
|
317
|
+
write(chunk, _encoding, callback) {
|
|
318
|
+
start()
|
|
319
|
+
enqueue(chunk)
|
|
320
|
+
callback()
|
|
321
|
+
},
|
|
322
|
+
final(callback) {
|
|
323
|
+
// Only a stream that actually wrote flags the streaming path: a plain
|
|
324
|
+
// res.end(value) is a BUFFERED response (its body rides `body`, not the
|
|
325
|
+
// stream) and must resolve through the handler-completion race.
|
|
326
|
+
try {
|
|
327
|
+
controller?.close()
|
|
328
|
+
} catch {
|
|
329
|
+
// Already closed.
|
|
330
|
+
}
|
|
331
|
+
callback()
|
|
332
|
+
},
|
|
333
|
+
destroy(error, callback) {
|
|
334
|
+
try {
|
|
335
|
+
controller?.close()
|
|
336
|
+
} catch {
|
|
337
|
+
// Already closed.
|
|
338
|
+
}
|
|
339
|
+
callback(error ?? null)
|
|
340
|
+
},
|
|
341
|
+
})
|
|
342
|
+
request.signal?.addEventListener?.('abort', () => writable.destroy(), { once: true })
|
|
343
|
+
|
|
344
|
+
const api = {
|
|
345
|
+
setHeader(name: string, value: string | number | readonly string[]) {
|
|
346
|
+
headers.set(name, Array.isArray(value) ? value.join(', ') : String(value))
|
|
347
|
+
return res
|
|
348
|
+
},
|
|
349
|
+
getHeader(name: string) {
|
|
350
|
+
return headers.get(name)
|
|
351
|
+
},
|
|
352
|
+
removeHeader(name: string) {
|
|
353
|
+
headers.delete(name)
|
|
354
|
+
},
|
|
355
|
+
status(code: number) {
|
|
356
|
+
statusCode = code
|
|
357
|
+
return res
|
|
358
|
+
},
|
|
359
|
+
json(value: unknown) {
|
|
360
|
+
if (!headers.has('content-type'))
|
|
361
|
+
headers.set('content-type', 'application/json; charset=utf-8')
|
|
362
|
+
body = JSON.stringify(value)
|
|
363
|
+
sent = true
|
|
364
|
+
return res
|
|
365
|
+
},
|
|
366
|
+
send(value?: unknown) {
|
|
367
|
+
body = bodyFromValue(value, headers)
|
|
368
|
+
sent = true
|
|
369
|
+
return res
|
|
370
|
+
},
|
|
371
|
+
end(value?: unknown) {
|
|
372
|
+
if (!sent) {
|
|
373
|
+
body = bodyFromValue(value, headers)
|
|
374
|
+
sent = true
|
|
375
|
+
}
|
|
376
|
+
if (value !== undefined && value !== null && started) {
|
|
377
|
+
// Mid-stream end(chunk): flush the tail through the stream.
|
|
378
|
+
enqueue(value)
|
|
379
|
+
}
|
|
380
|
+
;(Writable.prototype.end as (this: Writable) => Writable).call(writable)
|
|
381
|
+
return res
|
|
382
|
+
},
|
|
383
|
+
async revalidate(pathname: string) {
|
|
384
|
+
markPathRevalidated(pathname)
|
|
385
|
+
await getRequestExtensions().onDemandRevalidatePath(normalizeRevalidatePath(pathname))
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
const res = Object.assign(writable, api) as unknown as PagesApiResponse
|
|
389
|
+
Object.defineProperty(res, 'statusCode', {
|
|
390
|
+
get: () => statusCode,
|
|
391
|
+
set: (value: number) => {
|
|
392
|
+
statusCode = value
|
|
393
|
+
},
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
res,
|
|
398
|
+
started: startedPromise,
|
|
399
|
+
fail(error: unknown): never | undefined {
|
|
400
|
+
if (!started) throw error
|
|
401
|
+
try {
|
|
402
|
+
controller?.error(error)
|
|
403
|
+
} catch {
|
|
404
|
+
// Stream already settled.
|
|
405
|
+
}
|
|
406
|
+
return undefined
|
|
407
|
+
},
|
|
408
|
+
streamResponse() {
|
|
409
|
+
// Null-body statuses (204/304) must not carry a body stream.
|
|
410
|
+
if (statusCode === 204 || statusCode === 304) {
|
|
411
|
+
return new Response(null, { status: statusCode, headers })
|
|
412
|
+
}
|
|
413
|
+
return new Response(streamBody, { status: statusCode, headers })
|
|
414
|
+
},
|
|
415
|
+
response(result: unknown) {
|
|
416
|
+
if (result !== undefined && !sent) body = bodyFromValue(result, headers)
|
|
417
|
+
return new Response(statusCode === 204 || statusCode === 304 ? null : body, {
|
|
418
|
+
status: statusCode,
|
|
419
|
+
headers,
|
|
420
|
+
})
|
|
421
|
+
},
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function normalizeWriteChunk(chunk: unknown) {
|
|
426
|
+
if (chunk === null || chunk === undefined) return ''
|
|
427
|
+
if (typeof chunk === 'string') return chunk
|
|
428
|
+
if (chunk instanceof ArrayBuffer) return Buffer.from(chunk)
|
|
429
|
+
if (ArrayBuffer.isView(chunk))
|
|
430
|
+
return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)
|
|
431
|
+
if (typeof chunk === 'number' || typeof chunk === 'boolean' || typeof chunk === 'bigint') {
|
|
432
|
+
return String(chunk)
|
|
433
|
+
}
|
|
434
|
+
return JSON.stringify(chunk) ?? ''
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function bodyFromValue(value: unknown, headers: Headers): BodyInit | null {
|
|
438
|
+
if (value === undefined || value === null) return null
|
|
439
|
+
if (typeof value === 'string' || value instanceof Blob || value instanceof ArrayBuffer)
|
|
440
|
+
return value
|
|
441
|
+
if (value instanceof Uint8Array && value.buffer instanceof ArrayBuffer) {
|
|
442
|
+
return value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength)
|
|
443
|
+
}
|
|
444
|
+
if (!headers.has('content-type')) headers.set('content-type', 'application/json; charset=utf-8')
|
|
445
|
+
return JSON.stringify(value)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function cookiesFromHeader(header: string | null): Record<string, string> {
|
|
449
|
+
if (!header) return {}
|
|
450
|
+
return Object.fromEntries(
|
|
451
|
+
header
|
|
452
|
+
.split(';')
|
|
453
|
+
.map(part => part.trim().split('='))
|
|
454
|
+
.filter((parts): parts is [string, string] => parts.length === 2 && parts[0] !== ''),
|
|
455
|
+
)
|
|
456
|
+
}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
|
-
import { readFile } from 'node:fs/promises'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import type { Loader, OnLoadResult, Plugin } from 'esbuild'
|
|
5
|
-
import { build as esbuild } from '../../utils/esbuild'
|
|
6
|
-
import type { ResolvedConfig } from '../../config'
|
|
7
|
-
import { applyClientSourceTransforms, getBundlerExtensions } from '../../extensions'
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import type { Loader, OnLoadResult, Plugin } from 'esbuild'
|
|
5
|
+
import { build as esbuild } from '../../utils/esbuild'
|
|
6
|
+
import type { ResolvedConfig } from '../../config'
|
|
7
|
+
import { applyClientSourceTransforms, getBundlerExtensions } from '../../extensions'
|
|
8
8
|
|
|
9
|
-
const pageClientFacade = 'pnext-page-client.js'
|
|
10
|
-
const sideEffectImportPattern = /(?:^|\n)\s*import\s*(['"])([^'"]+)\1\s*;?/g
|
|
11
|
-
const styleImportPattern = /\.(?:css|scss|sass|less|styl)(?:\?|$)
|
|
9
|
+
const pageClientFacade = 'pnext-page-client.js'
|
|
10
|
+
const sideEffectImportPattern = /(?:^|\n)\s*import\s*(['"])([^'"]+)\1\s*;?/g
|
|
11
|
+
const styleImportPattern = /\.(?:css|scss|sass|less|styl)(?:\?|$)/
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Compile generated Pages facades from only the page component export. The relative-import hook is
|
|
15
15
|
* a catch-all that only ever fires from a facade, so an app with no `pages/` dir skips it.
|
|
16
16
|
*/
|
|
17
17
|
export function pagesClientModulePlugin(config: ResolvedConfig): Plugin {
|
|
18
|
-
const compiled = new Map<string, Promise<OnLoadResult>>()
|
|
19
|
-
const hasPages = existsSync(path.join(config.root, 'pages'))
|
|
18
|
+
const compiled = new Map<string, Promise<OnLoadResult>>()
|
|
19
|
+
const hasPages = existsSync(path.join(config.root, 'pages'))
|
|
20
20
|
return {
|
|
21
21
|
name: 'pnext-pages-client-module',
|
|
22
22
|
setup(build) {
|
|
23
|
-
if (!hasPages) return
|
|
23
|
+
if (!hasPages) return
|
|
24
24
|
build.onResolve({ filter: /^\.{1,2}\// }, args => {
|
|
25
|
-
if (path.basename(args.importer) !== pageClientFacade) return undefined
|
|
25
|
+
if (path.basename(args.importer) !== pageClientFacade) return undefined
|
|
26
26
|
return {
|
|
27
27
|
path: path.resolve(args.resolveDir, args.path),
|
|
28
28
|
namespace: 'pnext-pages-client-module',
|
|
29
|
-
}
|
|
30
|
-
})
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
31
|
build.onLoad({ filter: /.*/, namespace: 'pnext-pages-client-module' }, args => {
|
|
32
|
-
let output = compiled.get(args.path)
|
|
32
|
+
let output = compiled.get(args.path)
|
|
33
33
|
if (!output) {
|
|
34
|
-
output = compilePageClientModule(config, args.path)
|
|
35
|
-
compiled.set(args.path, output)
|
|
34
|
+
output = compilePageClientModule(config, args.path)
|
|
35
|
+
compiled.set(args.path, output)
|
|
36
36
|
}
|
|
37
|
-
return output
|
|
38
|
-
})
|
|
37
|
+
return output
|
|
38
|
+
})
|
|
39
39
|
},
|
|
40
|
-
}
|
|
40
|
+
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async function compilePageClientModule(
|
|
44
44
|
config: ResolvedConfig,
|
|
45
45
|
file: string,
|
|
46
46
|
): Promise<OnLoadResult> {
|
|
47
|
-
const rawSource = await readFile(file, 'utf8')
|
|
48
|
-
const source = applyClientSourceTransforms(rawSource, file, config.root)
|
|
47
|
+
const rawSource = await readFile(file, 'utf8')
|
|
48
|
+
const source = applyClientSourceTransforms(rawSource, file, config.root)
|
|
49
49
|
const sideEffectImports = new Set(
|
|
50
50
|
[...source.matchAll(sideEffectImportPattern)]
|
|
51
51
|
.map(match => match[2])
|
|
52
52
|
.filter((specifier): specifier is string => Boolean(specifier)),
|
|
53
|
-
)
|
|
53
|
+
)
|
|
54
54
|
const result = await esbuild({
|
|
55
55
|
stdin: {
|
|
56
56
|
contents: `export { default } from ${JSON.stringify(file)};`,
|
|
@@ -76,34 +76,34 @@ async function compilePageClientModule(
|
|
|
76
76
|
setup(build) {
|
|
77
77
|
build.onResolve({ filter: /.*/ }, args => {
|
|
78
78
|
if (args.path === file) {
|
|
79
|
-
return { path: file, namespace: 'pnext-pages-client-source' }
|
|
79
|
+
return { path: file, namespace: 'pnext-pages-client-source' }
|
|
80
80
|
}
|
|
81
81
|
return {
|
|
82
82
|
path: args.path,
|
|
83
83
|
external: true,
|
|
84
84
|
sideEffects: sideEffectImports.has(args.path) || styleImportPattern.test(args.path),
|
|
85
|
-
}
|
|
86
|
-
})
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
87
|
build.onLoad({ filter: /.*/, namespace: 'pnext-pages-client-source' }, () => ({
|
|
88
88
|
contents: source,
|
|
89
89
|
loader: pageLoader(file),
|
|
90
90
|
resolveDir: path.dirname(file),
|
|
91
|
-
}))
|
|
91
|
+
}))
|
|
92
92
|
},
|
|
93
93
|
},
|
|
94
94
|
],
|
|
95
|
-
})
|
|
96
|
-
const output = result.outputFiles[0]
|
|
97
|
-
if (!output) throw new Error(`Failed to compile Pages client module ${file}`)
|
|
95
|
+
})
|
|
96
|
+
const output = result.outputFiles[0]
|
|
97
|
+
if (!output) throw new Error(`Failed to compile Pages client module ${file}`)
|
|
98
98
|
return {
|
|
99
99
|
contents: output.text,
|
|
100
100
|
loader: 'js',
|
|
101
101
|
resolveDir: path.dirname(file),
|
|
102
|
-
}
|
|
102
|
+
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function pageLoader(file: string): Loader {
|
|
106
|
-
if (file.endsWith('.tsx')) return 'tsx'
|
|
107
|
-
if (file.endsWith('.ts')) return 'ts'
|
|
108
|
-
return 'jsx'
|
|
106
|
+
if (file.endsWith('.tsx')) return 'tsx'
|
|
107
|
+
if (file.endsWith('.ts')) return 'ts'
|
|
108
|
+
return 'jsx'
|
|
109
109
|
}
|