@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
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## Getting started
|
|
10
10
|
|
|
11
|
+
> pnext requires [Bun](https://bun.sh/get) - make sure it is installed first.
|
|
12
|
+
|
|
11
13
|
A new app:
|
|
12
14
|
|
|
13
15
|
```sh
|
|
@@ -22,11 +24,13 @@ bunx @wular/pnext migrate
|
|
|
22
24
|
|
|
23
25
|
Or by hand: `bun add -d @wular/pnext`, then `pnext dev`.
|
|
24
26
|
|
|
27
|
+
[Getting Started](./reference/getting-started.md) walks through all of it, from first page to build.
|
|
28
|
+
|
|
25
29
|
## Incremental by design
|
|
26
30
|
|
|
27
|
-
Server-rendered pages ship **0 KB** of JavaScript, or **~1 KB gzip** if you want client-side navigation and prefetching. Interactive pages hydrate on Preact for **~7.5 KB** of framework, **~12.5 KB** with React compatibility.
|
|
31
|
+
Server-rendered pages ship **0 KB** of JavaScript, or **~1 KB gzip** if you want client-side navigation and prefetching. Interactive pages hydrate on Preact for **~7.5 KB** of framework, **~12.5 KB** with React compatibility. Everything is instant, the first page in dev renders **10–12× faster** than Next.js on **3.5–4× less memory**, and production builds run **7–9× faster**. See [Performance](./reference/performance.md).
|
|
28
32
|
|
|
29
|
-
Core pnext is pure Preact. `compat.react` runs React components and libraries on it, and `compat.next` runs a whole Next.js App Router app unchanged. Start anywhere on that ladder and move when it suits you. The App Router compatibility is validated against Next's own test suite (4,400+ assertions passing). The `pages/` folder
|
|
33
|
+
Core pnext is pure Preact. `compat.react` runs React components and libraries on it, and `compat.next` runs a whole Next.js App Router app unchanged. Start anywhere on that ladder and move when it suits you. The App Router compatibility is validated against Next's own test suite (4,400+ assertions passing). The `pages/` folder or private internal utilities of Next.js or React are mostly not supported. See [Compatibility](./reference/compat.md).
|
|
30
34
|
|
|
31
35
|
## A quick tour
|
|
32
36
|
|
|
@@ -36,17 +40,17 @@ Routes live in `app/`. A `page.tsx` is a Server Component by default. It runs on
|
|
|
36
40
|
|
|
37
41
|
```tsx
|
|
38
42
|
// app/posts/[id]/page.tsx
|
|
39
|
-
import type { PageProps } from
|
|
43
|
+
import type { PageProps } from '#gen/app/posts/[id]/page'
|
|
40
44
|
|
|
41
45
|
export default async function Page({ params }: PageProps) {
|
|
42
|
-
const { id } = await params
|
|
43
|
-
const post = await db.post.findUnique({ where: { id } })
|
|
46
|
+
const { id } = await params
|
|
47
|
+
const post = await db.post.findUnique({ where: { id } })
|
|
44
48
|
return (
|
|
45
49
|
<article>
|
|
46
50
|
<h1>{post.title}</h1>
|
|
47
51
|
<p>{post.body}</p>
|
|
48
52
|
</article>
|
|
49
|
-
)
|
|
53
|
+
)
|
|
50
54
|
}
|
|
51
55
|
```
|
|
52
56
|
|
|
@@ -58,12 +62,14 @@ Mark a component with `"use client"` where you need state, effects, or event han
|
|
|
58
62
|
|
|
59
63
|
```tsx
|
|
60
64
|
// app/counter.tsx
|
|
61
|
-
|
|
62
|
-
import { useState } from
|
|
65
|
+
'use client'
|
|
66
|
+
import { useState } from 'preact/hooks'
|
|
63
67
|
|
|
64
68
|
export function Counter({ initial }: { initial: number }) {
|
|
65
|
-
const [count, setCount] = useState(initial)
|
|
66
|
-
return
|
|
69
|
+
const [count, setCount] = useState(initial)
|
|
70
|
+
return (
|
|
71
|
+
<button onClick={() => setCount(count + 1)}>Count {count}</button>
|
|
72
|
+
)
|
|
67
73
|
}
|
|
68
74
|
```
|
|
69
75
|
|
|
@@ -74,14 +80,14 @@ Client Components hydrate on Preact for ~7.5 KB of framework, or ~12.5 KB with [
|
|
|
74
80
|
Wrap slow server work in `<Suspense>`. The shell streams immediately and the content follows when it's ready:
|
|
75
81
|
|
|
76
82
|
```tsx
|
|
77
|
-
import { Suspense } from
|
|
83
|
+
import { Suspense } from '@wular/pnext'
|
|
78
84
|
|
|
79
85
|
export default function Page() {
|
|
80
86
|
return (
|
|
81
87
|
<Suspense fallback={<p>Loading comments…</p>}>
|
|
82
88
|
<Comments />
|
|
83
89
|
</Suspense>
|
|
84
|
-
)
|
|
90
|
+
)
|
|
85
91
|
}
|
|
86
92
|
```
|
|
87
93
|
|
|
@@ -92,20 +98,20 @@ A `route.ts` file is an HTTP handler:
|
|
|
92
98
|
```ts
|
|
93
99
|
// app/api/users/route.ts
|
|
94
100
|
export async function GET(request: NextRequest) {
|
|
95
|
-
return Response.json(await listUsers())
|
|
101
|
+
return Response.json(await listUsers())
|
|
96
102
|
}
|
|
97
103
|
```
|
|
98
104
|
|
|
99
105
|
- `proxy.ts` runs before route matching.
|
|
100
106
|
- `loading.tsx`, `error.tsx`, and `not-found.tsx` define per-segment fallbacks.
|
|
101
|
-
- `pnext build`
|
|
107
|
+
- `pnext build` makes the production build and `pnext start` serves it. Routes that never read the request are prerendered to static HTML.
|
|
102
108
|
|
|
103
109
|
## Learn more
|
|
104
110
|
|
|
105
111
|
Apps are file-routed from `app/`: `page.tsx` and `layout.tsx` are Server Components, `route.ts` files are HTTP handlers, `public/` is served from `/`. The reference covers the rest:
|
|
106
112
|
|
|
107
|
-
- [
|
|
108
|
-
- [
|
|
113
|
+
- [Getting Started](./reference/getting-started.md)
|
|
114
|
+
- [Development](./reference/dev.md)
|
|
109
115
|
- [Routing](./reference/routing.md)
|
|
110
116
|
- [Navigation](./reference/navigation.md)
|
|
111
117
|
- [Rendering](./reference/rendering.md)
|
package/bin/pnext
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
|
|
3
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
4
|
+
echo "pnext requires Bun. Install it from https://bun.sh/get" >&2
|
|
5
|
+
exit 1
|
|
6
|
+
fi
|
|
7
|
+
|
|
3
8
|
script=$0
|
|
4
9
|
|
|
5
10
|
# `dirname` is an external binary and `$(...)` forks a subshell, so spelling this
|
|
@@ -47,7 +52,7 @@ fi
|
|
|
47
52
|
# instead of showing "bun". The kernel takes the process name from the exec'd
|
|
48
53
|
# file's basename; argv0 tricks like `exec -a` never reach it.
|
|
49
54
|
#
|
|
50
|
-
# The cached names are hardlinks of a bun binary (see src/cli/named-bin.ts), so
|
|
55
|
+
# The cached names are hardlinks of a bun binary (see src/cli/boot/named-bin.ts), so
|
|
51
56
|
# `-ef` — same device and inode — proves a candidate is *this* bun and never
|
|
52
57
|
# execs a stale one left by an earlier version. Resolving it here in sh instead
|
|
53
58
|
# of asking named-bin.ts saves a whole bun process per command; on a miss we run
|
package/config/lint/base.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as path from 'node:path'
|
|
2
|
-
import { includeIgnoreFile } from '@eslint/compat'
|
|
1
|
+
import * as path from 'node:path'
|
|
2
|
+
import { includeIgnoreFile } from '@eslint/compat'
|
|
3
3
|
// @ts-ignore
|
|
4
|
-
import eslint from '@eslint/js'
|
|
5
|
-
import importPlugin from 'eslint-plugin-import'
|
|
6
|
-
import turboPlugin from 'eslint-plugin-turbo'
|
|
7
|
-
import tseslint from 'typescript-eslint'
|
|
4
|
+
import eslint from '@eslint/js'
|
|
5
|
+
import importPlugin from 'eslint-plugin-import'
|
|
6
|
+
import turboPlugin from 'eslint-plugin-turbo'
|
|
7
|
+
import tseslint from 'typescript-eslint'
|
|
8
8
|
|
|
9
9
|
export default tseslint.config(
|
|
10
10
|
includeIgnoreFile(path.join(import.meta.dirname, '../../.gitignore')),
|
|
@@ -45,4 +45,4 @@ export default tseslint.config(
|
|
|
45
45
|
linterOptions: { reportUnusedDisableDirectives: true },
|
|
46
46
|
languageOptions: { parserOptions: { projectService: true } },
|
|
47
47
|
},
|
|
48
|
-
)
|
|
48
|
+
)
|
package/config/ts/base.json
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
"esModuleInterop": true,
|
|
7
7
|
"incremental": false,
|
|
8
8
|
"isolatedModules": true,
|
|
9
|
-
"lib": [
|
|
10
|
-
"ESNext"
|
|
11
|
-
],
|
|
9
|
+
"lib": ["ESNext"],
|
|
12
10
|
"module": "ESNext",
|
|
13
11
|
"moduleResolution": "Bundler",
|
|
14
12
|
"moduleDetection": "force",
|
|
@@ -23,4 +21,4 @@
|
|
|
23
21
|
"allowJs": true,
|
|
24
22
|
"noEmit": true
|
|
25
23
|
}
|
|
26
|
-
}
|
|
24
|
+
}
|
package/config/ts/react.json
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wular/pnext",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
|
+
"description": "A fast little framework for server-first React apps, fully compatible with Next.js",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"bin": {
|
|
6
7
|
"pnext": "bin/pnext"
|
|
7
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/muzam1l/pnext.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/muzam1l/pnext",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/muzam1l/pnext/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"react",
|
|
19
|
+
"preact",
|
|
20
|
+
"framework",
|
|
21
|
+
"ssr",
|
|
22
|
+
"server-components",
|
|
23
|
+
"bun",
|
|
24
|
+
"nextjs"
|
|
25
|
+
],
|
|
8
26
|
"files": [
|
|
9
27
|
"bin",
|
|
10
28
|
"config",
|
|
@@ -27,7 +45,8 @@
|
|
|
27
45
|
"./config/*": "./config/*"
|
|
28
46
|
},
|
|
29
47
|
"scripts": {
|
|
30
|
-
"lint": "bun scripts/check-compat-boundary.ts && eslint . --max-warnings 0 && tsc --noEmit",
|
|
48
|
+
"lint": "bun scripts/check-compat-boundary.ts && prettier --check . && eslint . --max-warnings 0 && tsc --noEmit",
|
|
49
|
+
"format": "prettier --write .",
|
|
31
50
|
"bench": "bun bench/run.ts",
|
|
32
51
|
"clean": "rm -rf .turbo .pnext node_modules",
|
|
33
52
|
"prepublishOnly": "bun run lint",
|
|
@@ -53,8 +72,10 @@
|
|
|
53
72
|
"@eslint/js": "^9.38.0",
|
|
54
73
|
"@types/bun": "^1.3.0",
|
|
55
74
|
"eslint": "^9.38.0",
|
|
75
|
+
"eslint-config-prettier": "^10.1.8",
|
|
56
76
|
"eslint-plugin-import": "^2.32.0",
|
|
57
77
|
"eslint-plugin-turbo": "^2.5.8",
|
|
78
|
+
"prettier": "^3.9.6",
|
|
58
79
|
"typescript": "^5.9.3",
|
|
59
80
|
"typescript-eslint": "^8.46.2"
|
|
60
81
|
},
|
package/reference/compat.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Compatibility
|
|
2
2
|
|
|
3
|
-
pnext is Next.js-shaped. With `compat.next` on, App Router apps behave the way they do in Next: the `next/*` module surface, `next.config.js`, server actions, metadata,
|
|
3
|
+
pnext is Next.js-shaped. With `compat.next` on, App Router apps behave the way they do in Next: the `next/*` module surface, `next.config.js`, server actions, metadata, proxy and middleware, `'use cache'`, the `/_next/image` optimizer, and the `next/navigation` router. That is validated by running Next.js's own test suite against pnext, with 4,400+ assertions passing, rather than by hand-written parity claims.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
export default {
|
|
@@ -9,55 +9,120 @@ export default {
|
|
|
9
9
|
next: true, // the next/* surface + next.config.js; implies react
|
|
10
10
|
reactCompiler: true, // React Compiler for React-style Client Components; implies react
|
|
11
11
|
},
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
`compat.react` aliases `react`, `react-dom`, `react-dom/client`, `react-dom/server`, `react/jsx-runtime`, `react/jsx-dev-runtime`, and `react/compiler-runtime` onto Preact-backed shims.
|
|
15
|
+
`compat.react` aliases `react`, `react-dom`, `react-dom/client`, `react-dom/server`, `react/jsx-runtime`, `react/jsx-dev-runtime`, and `react/compiler-runtime` onto Preact-backed shims. React's `cache()` maps to pnext's request cache on the server. Importing `next/*` or `react` without the matching mode is a build error that names the flag to enable.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
To turn Next compatibility on without a config file, set `PNEXT_COMPAT=next`. See [Environment Variables](./env.md).
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## Migrating a Next.js app
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
```sh
|
|
22
|
+
bunx @wular/pnext migrate --dry-run
|
|
23
|
+
bunx @wular/pnext migrate
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Migration rewrites `package.json` and `tsconfig.json`, and creates a `pnext.config.ts` with `compat.next` enabled. It reports on your app source but never edits it.
|
|
27
|
+
|
|
28
|
+
## What differs from Next
|
|
29
|
+
|
|
30
|
+
These are the places pnext deliberately does not match Next. Read them before migrating. Together with the caveats in the feature notes below, this is the whole list.
|
|
22
31
|
|
|
23
|
-
|
|
32
|
+
### Preact, not React
|
|
33
|
+
|
|
34
|
+
The streaming renderers from `react-dom/server`, `renderToReadableStream` and `renderToPipeableStream`, throw. The synchronous `renderToString` and `renderToStaticMarkup` work. Client components run on Preact's reconciler, so code reaching into React internals is out of scope.
|
|
24
35
|
|
|
25
36
|
Direct Preact imports and Preact Signals need no compat and produce smaller bundles than `preact/compat`.
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
### No Flight payload
|
|
39
|
+
|
|
40
|
+
Soft navigation and server-action responses carry HTML, not a React Flight stream. Streaming, refresh, and revalidation-driven updates all work. Consuming the RSC payload as a wire format does not.
|
|
28
41
|
|
|
29
|
-
|
|
42
|
+
Server-rendered JSX can cross into a Client Component as `children` or through any other prop, including nested in arrays and plain objects. Both stay server-rendered static HTML and ship no code, as in Next. Elements inside `Map` and `Set` props are the one shape that throws.
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
### Pages Router is emulated
|
|
32
45
|
|
|
33
|
-
|
|
46
|
+
A `pages/` directory is materialized onto App Router routes, so `getStaticProps` and `getServerSideProps` pages and `pages/api` handlers run. `_app`, `_document`, and `_error` are ignored. `next/head` renders nothing, so use the metadata exports instead. `next/router` maps onto the app router where the concepts line up and no-ops elsewhere.
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
### No webpack or Turbopack
|
|
36
49
|
|
|
37
|
-
|
|
50
|
+
esbuild is the only bundler. A `webpack(config)` function in `next.config.js` is not executed, and pnext warns once at config load when one is present. Loader chains from `turbopack.rules`, plus `turbopack.resolveAlias`, `transpilePackages`, `modularizeImports`, and `optimizePackageImports`, are re-implemented on esbuild directly.
|
|
38
51
|
|
|
39
|
-
|
|
52
|
+
A `webpack()` function that references `@svgr/webpack`, by far the most common custom-loader use, is auto-detected. pnext then compiles `.svg` imports to inline Preact components, matching that loader's default output. Root SVG attributes are spread first, so props such as `className`, `width`, and `height` override them. Without that reference, `.svg` imports keep the normal static-asset URL behavior.
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
### Cache state is per process
|
|
42
55
|
|
|
43
|
-
|
|
56
|
+
`revalidatePath`, `revalidateTag`, `unstable_cache`, and `'use cache'` entries live in the server process by default, so a multi-instance deployment revalidates one instance. Configure `cacheHandler` in `next.config.js` for a shared store.
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
### Optional native dependencies
|
|
59
|
+
|
|
60
|
+
All three ship as `optionalDependencies`, so a normal install has them, the same as Next. These paths only matter when the optional install fails.
|
|
46
61
|
|
|
47
62
|
- `next/image`'s `/_next/image` optimizer needs `sharp`. The component, `images` config validation, and static imports work without it.
|
|
48
63
|
- `next/og`'s `ImageResponse` needs `satori` and `@resvg/resvg-js`. Without them, or without a usable font, it answers with a valid placeholder PNG instead of failing the request.
|
|
49
64
|
- `next/font/google` resolves the catalog through `next-font`. If it cannot, the build fails rather than falling back to a hosted font.
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
### Smaller surfaces
|
|
52
67
|
|
|
53
|
-
- `userAgent()` uses an in-house parser covering mainstream browsers, engines, CPUs, and devices
|
|
54
|
-
-
|
|
68
|
+
- `userAgent()` uses an in-house parser covering mainstream browsers, engines, CPUs, and devices, not the full ua-parser-js database.
|
|
69
|
+
- React's taint functions do not exist under Preact, so pnext does not export them. What it implements is the guarantee `experimental.taint` exists for: with the flag on, `process.env` is registered as tainted, and passing that object as a client-component prop at any depth throws. Development shows the message in the nearest error boundary and production shows React's redacted error text, matching Next. Tainting your own objects or values is not available.
|
|
70
|
+
- `ViewTransition` and `addTransitionType` are exported from the `react` entry so pages importing them render instead of throwing, and `next/link` accepts `transitionTypes`. Support stops there: the component is a passthrough that renders no DOM, and pnext does not drive `document.startViewTransition`, so declared names and types are recorded but no browser transition is played.
|
|
71
|
+
- Only these `next/dist/*` paths are shimmed. Any other deep import fails with an error naming this list.
|
|
55
72
|
- `next/dist/client/components/app-router-headers`
|
|
56
73
|
- `next/dist/server/web/spec-extension/unstable-cache`
|
|
57
74
|
- `next/dist/server/web/spec-extension/unstable-no-store`
|
|
58
75
|
- `next/dist/server/web/spec-extension/revalidate`
|
|
59
76
|
- `next/dist/server/app-render/work-unit-async-storage.external` (server only)
|
|
60
77
|
|
|
61
|
-
##
|
|
78
|
+
## Feature notes
|
|
79
|
+
|
|
80
|
+
The rest of the surface ships as well. Each note says where support stops short.
|
|
81
|
+
|
|
82
|
+
### redirects and rewrites
|
|
83
|
+
|
|
84
|
+
`redirects()` and `rewrites()` in `next.config.js` are both honored. Sources support the `:param`, `:param*`, `:param+`, `:param?`, and `:param(regex)` tokens, plus `has` and `missing` conditions on host, header, query, and cookie. Named capture groups feed their values into destination parameters.
|
|
85
|
+
|
|
86
|
+
Rewrites accept the array form and the object form with `beforeFiles`, `afterFiles`, and `fallback`, and entries setting `basePath: false` match the raw path. An external `http` or `https` destination is proxied through a server-side fetch. After a rewrite fires, `usePathname()` and `useSearchParams()` still report the URL the browser asked for.
|
|
87
|
+
|
|
88
|
+
Redirects use 308 for `permanent: true`, 307 for `permanent: false`, or an explicit `statusCode`, and they keep external destinations as redirects.
|
|
89
|
+
|
|
90
|
+
One partial: fallback rewrites apply only to requests that would otherwise 404, and in development that check consults the route table alone, since there is no built output to look at.
|
|
91
|
+
|
|
92
|
+
### after()
|
|
93
|
+
|
|
94
|
+
`after()` from `next/server` runs work once the response is fully sent. Each callback runs exactly once, when the response closes, on every path: stream end, a redirect, a not-found, a thrown error, or a client abort. Calls nested inside an `after()` task run too. When the host platform supplies the Vercel request context, each task is also handed to its `waitUntil` so a serverless invocation stays alive until the task settles. An `after()` task that throws during a build prerender fails the build rather than quietly degrading the route.
|
|
95
|
+
|
|
96
|
+
### next/form
|
|
97
|
+
|
|
98
|
+
`Form` renders a GET form and intercepts submission into a client-side navigation, building the destination URL from the form's fields. String actions get the basePath applied and are prefetched like a link, including a re-prefetch when a revalidation invalidates them. Function actions pass straight through as React form actions with no interception. A submitter that overrides the encoding, method, or target falls back to the browser's native submit, and file inputs are not submitted with a string action. Both cases warn in development.
|
|
99
|
+
|
|
100
|
+
### instrumentation and instrumentation-client
|
|
101
|
+
|
|
102
|
+
An `instrumentation` file at the project root or in `src/` is bundled and imported once at server start. Its `register()` is awaited before the first request is served, and its `onRequestError` export is wired into the error funnel. When the app contains any edge entity, meaning a proxy or middleware, or a route declaring an edge runtime, a second freshly loaded instance is registered with `NEXT_RUNTIME` set to `edge`, mirroring Next's separate edge boot.
|
|
103
|
+
|
|
104
|
+
An `instrumentation-client` file is bundled with any `instrumentationClientInject` entries ahead of it, in configured order, and loaded from the document head so it runs before hydration. Each module's `onRouterTransitionStart` export is called at the start of every soft navigation. Apps without such a file get no extra bundle and no extra head tag.
|
|
105
|
+
|
|
106
|
+
### OpenTelemetry
|
|
107
|
+
|
|
108
|
+
pnext emits Next's span taxonomy through the global `@opentelemetry/api` that your instrumentation file registers: a root request span carrying `next.route` and `http.status_code`, plus child spans for rendering, route handlers, `fetch`, middleware and proxy, and Pages Router data and API handlers. Incoming `traceparent` headers are extracted, and errors caught by the request funnel mark the root span.
|
|
109
|
+
|
|
110
|
+
`@opentelemetry/api` is an optional dependency resolved from your own `node_modules`, so pnext and your SDK share one API singleton. When the package is absent, every tracing helper is inert. Keys listed in `experimental.clientTraceMetadata` are injected into the document head as meta tags.
|
|
111
|
+
|
|
112
|
+
### MDX
|
|
113
|
+
|
|
114
|
+
`.mdx` and `.md` modules compile through `@mdx-js/mdx`, an optional dependency loaded on the first MDX compile, so an app that never imports MDX does not need it installed. `createMDX()` from `@next/mdx` is understood at config load, so the remark, rehype, and recma plugins you configure there run. MDX files become routes only when `pageExtensions` lists the extension, matching Next. An `mdx-components` file supplies the component provider, and without one MDX emits plain host elements. One caveat: MDX currently compiles in the client graph, so treat an MDX module as client code.
|
|
115
|
+
|
|
116
|
+
### Edge runtime
|
|
117
|
+
|
|
118
|
+
A route or proxy declaring an edge runtime, and a Pages Router handler configured for `edge` or `experimental-edge`, runs with `process.env.NEXT_RUNTIME` set to `edge`, the `EdgeRuntime` global defined, and a `process` object that hides `version` and `versions` so code branching on those detects the edge environment. This is an emulation inside the same Bun process rather than a separate isolate, so the Edge API subset is not enforced: Node built-ins stay reachable, and code that only works because of that will still fail on a real edge platform.
|
|
119
|
+
|
|
120
|
+
### Root params
|
|
121
|
+
|
|
122
|
+
`next/root-params` resolves parameters from the root dynamic segment. It works in layouts, pages, and `'use cache'` functions, and inside `generateStaticParams` when a parent `generateStaticParams` already provided the parameter. Calling it inside a server action, inside `unstable_cache`, or from a route handler throws with the same diagnostics Next produces. Reading one marks every segment of the response as varying.
|
|
123
|
+
|
|
124
|
+
### output: 'export' and output: 'standalone'
|
|
125
|
+
|
|
126
|
+
`output: 'export'` writes a static tree to `out/`, or to `distDir` when the app configures a custom one. The tree carries the HTML and the flat per-page artifacts the client router fetches when no pnext server is present, the client runtime under `_next/static/chunks/`, the build manifests, the `public/` tree, and the not-found page. Dynamic routes without `generateStaticParams`, pages forcing dynamic rendering, and route handlers with disallowed segment config are build errors, as they are in Next.
|
|
62
127
|
|
|
63
|
-
`
|
|
128
|
+
`output: 'standalone'` writes `.next/standalone/` with a `server.js` that boots on `PORT` and `HOSTNAME`, along with a `.nft.json` trace beside each page entry and a middleware manifest. Because pnext's production server runs under Bun, that launcher is a thin Node script that re-executes the real pnext server pointed back at the original build directory. The folder is therefore not a self-contained bundle you can ship on its own, because the build tree has to travel with it.
|
package/reference/config.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Config
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An optional `pnext.config.ts` in the project root, meaning the directory passed to the CLI.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
import type {
|
|
6
|
+
import type { PNextConfig } from '@wular/pnext'
|
|
7
7
|
|
|
8
8
|
export default {
|
|
9
9
|
outDir: '.pnext',
|
|
@@ -12,109 +12,56 @@ export default {
|
|
|
12
12
|
compat: {
|
|
13
13
|
next: true,
|
|
14
14
|
},
|
|
15
|
-
} satisfies
|
|
15
|
+
} satisfies PNextConfig
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
With `compat.next`, `next.config.js
|
|
18
|
+
This is the form `pnext create` scaffolds. With `compat.next`, pnext also loads `next.config.js`, and that file wins for the options both can set: `basePath`, `assetPrefix`, `outDir`, `trailingSlash`, `skipTrailingSlashRedirect`, and `productionBrowserSourceMaps`.
|
|
19
19
|
|
|
20
20
|
## Fields
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
| Field | Default | What it does |
|
|
23
|
+
| ----------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `outDir` | `'.pnext'` | Build output for HTML, client assets, cache files, and `manifest.json`. |
|
|
25
|
+
| `basePath` | `''` | Path prefix for an app served below the domain root. |
|
|
26
|
+
| `assetPrefix` | `basePath` | URL prefix for emitted assets. Set it when assets come from a CDN. |
|
|
27
|
+
| `trailingSlash` | `false` | Canonicalizes URLs to a trailing slash and redirects the form without one. |
|
|
28
|
+
| `skipTrailingSlashRedirect` | `false` | Serves both slash forms with no canonical redirect, preserving authored hrefs. |
|
|
29
|
+
| `productionBrowserSourceMaps` | `false` | Emits external `.js.map` files next to production client chunks. |
|
|
30
|
+
| `prefetch` | `'visible'` | Default prefetch mode for links that set none of their own. See [Navigation](./navigation.md#prefetching). |
|
|
31
|
+
| `workspaceRoot` | inferred | Monorepo root for resolving and reloading local workspace package imports. |
|
|
32
|
+
| `htmlLimitedBots` | see below | User agents that get blocking metadata in the head. Applies with `compat.next`. |
|
|
33
|
+
| `adapter` | unset | Narrows what a deployment adapter packs into its server function. |
|
|
34
|
+
| `compat` | all `false` | Turns on the React, Next, and React Compiler compatibility layers. |
|
|
23
35
|
|
|
24
|
-
|
|
36
|
+
Worth knowing:
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
- Development client output is already unminified, so it never emits sourcemaps.
|
|
39
|
+
- `workspaceRoot` is inferred from `package.json#workspaces` or `pnpm-workspace.yaml`, otherwise the app root. It does not change the app root used for `public/`, `.pnext/`, or `pnext.config.ts`. Set it only to override the inference.
|
|
40
|
+
- The `htmlLimitedBots` default is a regex covering Twitterbot, Slackbot, Bingbot, Discordbot, LinkedInBot, and the Google and Lighthouse renderers. Matching user agents receive metadata blocked in the head instead of streamed into the body.
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
## Compat modes
|
|
29
43
|
|
|
30
|
-
|
|
44
|
+
| Flag | Effect |
|
|
45
|
+
| ---------------------- | -------------------------------------------------------------------------- |
|
|
46
|
+
| `compat.react` | Aliases the React and React DOM entry points to Preact-backed shims. |
|
|
47
|
+
| `compat.next` | Adds the `next/*` surface, `next.config.js`, and Next App Router behavior. |
|
|
48
|
+
| `compat.reactCompiler` | Experimental React Compiler support for React-style Client Components. |
|
|
31
49
|
|
|
32
|
-
|
|
50
|
+
Both `compat.next` and `compat.reactCompiler` imply `compat.react`. Direct Preact imports stay smaller than any of them, so reach for compat when you are running React-style components. React Compiler is not intended for components built around Preact Signals. See [Compatibility](./compat.md).
|
|
33
51
|
|
|
34
|
-
|
|
52
|
+
## Deployment adapter
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
`exclude` and `keep` are string lists that adjust which directories and file suffixes an adapter packs. The Vercel adapter consumes them.
|
|
37
55
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
### `skipTrailingSlashRedirect`
|
|
47
|
-
|
|
48
|
-
Default: `false`
|
|
49
|
-
|
|
50
|
-
Serve both the slashed and unslashed URL without a canonical redirect, and leave
|
|
51
|
-
`<Link>` hrefs exactly as authored.
|
|
52
|
-
|
|
53
|
-
### `productionBrowserSourceMaps`
|
|
54
|
-
|
|
55
|
-
Default: `false`
|
|
56
|
-
|
|
57
|
-
Emit external `.js.map` browser sourcemaps next to each production client chunk,
|
|
58
|
-
linked by a `//# sourceMappingURL=` comment. Off by default (as in Next): maps
|
|
59
|
-
publish your first-party source to every visitor and cost real build time.
|
|
60
|
-
Development never emits them — dev client output is un-minified already.
|
|
61
|
-
|
|
62
|
-
### `htmlLimitedBots`
|
|
63
|
-
|
|
64
|
-
Default: a regex covering Twitterbot, Slackbot, Bingbot, Discordbot, LinkedInBot,
|
|
65
|
-
and the Google/Lighthouse renderers.
|
|
66
|
-
|
|
67
|
-
User agents matched by this pattern get metadata blocked in `<head>` rather than
|
|
68
|
-
streamed into the body. `compat.next` only.
|
|
69
|
-
|
|
70
|
-
### `adapter`
|
|
71
|
-
|
|
72
|
-
Default: unset
|
|
73
|
-
|
|
74
|
-
`exclude` and `keep` string lists overriding what a deployment adapter packs into
|
|
75
|
-
the server function. Entries are directory names (`storybook-static`) or file
|
|
76
|
-
suffixes (`.map`).
|
|
77
|
-
|
|
78
|
-
### `workspaceRoot`
|
|
79
|
-
|
|
80
|
-
Default: inferred from `package.json#workspaces` or `pnpm-workspace.yaml`, otherwise the app root.
|
|
81
|
-
|
|
82
|
-
Monorepo root used to resolve and reload local workspace package imports. This does not change where pnext reads `public/`, writes `.pnext/`, or loads `pnext.config.ts`.
|
|
83
|
-
|
|
84
|
-
### `compat.react`
|
|
85
|
-
|
|
86
|
-
Default: `false`
|
|
87
|
-
|
|
88
|
-
When `true`, pnext aliases `react`, `react-dom`, `react-dom/client`, `react-dom/server`, `react/jsx-runtime`, `react/jsx-dev-runtime`, and `react/compiler-runtime` onto Preact-backed shims.
|
|
89
|
-
|
|
90
|
-
Use this when moving React-style components into a pnext app. Direct Preact imports are still smaller; `preact/compat` adds compatibility code only when your app imports React APIs.
|
|
91
|
-
|
|
92
|
-
### `compat.next`
|
|
93
|
-
|
|
94
|
-
Default: `false`
|
|
95
|
-
|
|
96
|
-
Enables the `next/*` module surface, `next.config.js`, and the rest of the Next App Router behaviors for existing apps and shared packages. This implies `compat.react`.
|
|
97
|
-
|
|
98
|
-
See [Compatibility](./compat.md).
|
|
99
|
-
|
|
100
|
-
### `compat.reactCompiler`
|
|
101
|
-
|
|
102
|
-
Default: `false`
|
|
103
|
-
|
|
104
|
-
Experimental React Compiler support for React-style Client Components. This implies `compat.react`.
|
|
105
|
-
|
|
106
|
-
Use this for components written with React hooks and props-heavy render paths where compiler memoization can reduce rerenders. Direct Preact code still gives the smallest bundles, and React Compiler compat is not recommended for components built around Preact Signals.
|
|
107
|
-
|
|
108
|
-
## File Conventions
|
|
109
|
-
|
|
110
|
-
Routes are loaded from `app/` or `src/app/`. If both exist, `app/` wins. Under
|
|
111
|
-
`compat.next`, a `pages/` directory is materialized onto App Router routes; a
|
|
112
|
-
hybrid app keeps its native `app/` routes.
|
|
113
|
-
|
|
114
|
-
Static assets are loaded from `public/` at the project root.
|
|
115
|
-
|
|
116
|
-
## Workspace Root
|
|
56
|
+
```ts
|
|
57
|
+
export default {
|
|
58
|
+
adapter: {
|
|
59
|
+
exclude: ['storybook-static', '.map'],
|
|
60
|
+
keep: ['runtime-assets', '.wasm'],
|
|
61
|
+
},
|
|
62
|
+
} satisfies PNextConfig
|
|
63
|
+
```
|
|
117
64
|
|
|
118
|
-
|
|
65
|
+
## Where pnext looks for files
|
|
119
66
|
|
|
120
|
-
|
|
67
|
+
Routes come from `app/` or `src/app/`, and `app/` wins if both exist. Static assets come from `public/` at the project root. Under `compat.next`, a `pages/` directory is materialized onto App Router routes, and a hybrid app keeps its native `app/` routes.
|