@wular/pnext 0.0.1
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 +153 -0
- package/bin/pnext +67 -0
- package/config/lint/base.js +48 -0
- package/config/ts/base.json +26 -0
- package/config/ts/react.json +13 -0
- package/package.json +70 -0
- package/reference/compat.md +63 -0
- package/reference/config.md +120 -0
- package/reference/css.md +58 -0
- package/reference/dev.md +69 -0
- package/reference/env.md +40 -0
- package/reference/metadata.md +86 -0
- package/reference/navigation.md +149 -0
- package/reference/overview.md +35 -0
- package/reference/performance.md +97 -0
- package/reference/rendering.md +127 -0
- package/reference/routing.md +167 -0
- package/reference/typegen.md +64 -0
- package/src/api/cache.ts +80 -0
- package/src/api/client-cache.ts +9 -0
- package/src/api/client-navigation.ts +279 -0
- package/src/api/dynamic.tsx +102 -0
- package/src/api/link.tsx +119 -0
- package/src/api/navigation.ts +198 -0
- package/src/api/router/events.ts +53 -0
- package/src/api/router/history.ts +70 -0
- package/src/api/router/hub.ts +194 -0
- package/src/api/router/policies.ts +107 -0
- package/src/api/router/runtime.ts +5238 -0
- package/src/api/router/types.ts +299 -0
- package/src/api/router.ts +167 -0
- package/src/api/server.ts +323 -0
- package/src/api/suspense.ts +16 -0
- package/src/cache/context.ts +61 -0
- package/src/cli/adapters/vercel-warm.ts +375 -0
- package/src/cli/adapters/vercel.ts +1310 -0
- package/src/cli/analyze-print.ts +181 -0
- package/src/cli/analyze.ts +328 -0
- package/src/cli/boot-trace.ts +29 -0
- package/src/cli/build.ts +3114 -0
- package/src/cli/dev.ts +276 -0
- package/src/cli/index.ts +196 -0
- package/src/cli/named-bin.ts +119 -0
- package/src/cli/serve-ui.ts +160 -0
- package/src/cli/start.ts +1425 -0
- package/src/client/build.ts +2136 -0
- package/src/client/chunk-fold.ts +526 -0
- package/src/client/entry.ts +1525 -0
- package/src/client/paths.ts +22 -0
- package/src/client/prebuilt.ts +621 -0
- package/src/client/profile.ts +75 -0
- package/src/client/react-compiler.ts +94 -0
- package/src/client/reference-stub.ts +145 -0
- package/src/client/reference.ts +47 -0
- package/src/compat/actions/action-client.ts +531 -0
- package/src/compat/actions/action-dispatch.ts +676 -0
- package/src/compat/actions/action-router.ts +40 -0
- package/src/compat/actions/action-shared.ts +95 -0
- package/src/compat/actions/client-plugin.ts +135 -0
- package/src/compat/actions/client-stub.ts +65 -0
- package/src/compat/actions/config.ts +164 -0
- package/src/compat/actions/detect.ts +208 -0
- package/src/compat/actions/discovery.ts +244 -0
- package/src/compat/actions/early-submit.ts +40 -0
- package/src/compat/actions/endpoint.ts +602 -0
- package/src/compat/actions/flight.ts +52 -0
- package/src/compat/actions/form-state.ts +73 -0
- package/src/compat/actions/hoist.ts +485 -0
- package/src/compat/actions/ids.ts +39 -0
- package/src/compat/actions/index.ts +41 -0
- package/src/compat/actions/instances.ts +144 -0
- package/src/compat/actions/origin.ts +109 -0
- package/src/compat/actions/protocol.ts +125 -0
- package/src/compat/actions/registry.ts +74 -0
- package/src/compat/actions/rewrite.ts +282 -0
- package/src/compat/actions/serve.ts +414 -0
- package/src/compat/actions/server-tag.ts +21 -0
- package/src/compat/actions/unrecognized-error.ts +30 -0
- package/src/compat/adapter/build-complete.ts +257 -0
- package/src/compat/bundler/bun-externals.ts +53 -0
- package/src/compat/bundler/cjs-exports.ts +542 -0
- package/src/compat/bundler/config.ts +363 -0
- package/src/compat/bundler/externals.ts +34 -0
- package/src/compat/bundler/import-meta-url.ts +60 -0
- package/src/compat/bundler/modularize-imports.ts +119 -0
- package/src/compat/bundler/new-url-asset.ts +87 -0
- package/src/compat/bundler/optimize-package-imports.ts +273 -0
- package/src/compat/bundler/polyfill.ts +88 -0
- package/src/compat/bundler/react-compiler.ts +61 -0
- package/src/compat/bundler/react-profiler.tsx +25 -0
- package/src/compat/bundler/relay-transform.ts +116 -0
- package/src/compat/bundler/require-context.ts +281 -0
- package/src/compat/bundler/resolve-extensions.ts +75 -0
- package/src/compat/bundler/source-cache.ts +61 -0
- package/src/compat/bundler/static-imports.ts +25 -0
- package/src/compat/bundler/symlink-imports.ts +119 -0
- package/src/compat/bundler/tsconfig-paths.ts +50 -0
- package/src/compat/bundler/wasm.ts +153 -0
- package/src/compat/bundler/webpack-loaders.ts +685 -0
- package/src/compat/bundler/worker.ts +278 -0
- package/src/compat/cache/build-flags.ts +81 -0
- package/src/compat/cache/build-prerender-errors.ts +163 -0
- package/src/compat/cache/custom-handler.ts +159 -0
- package/src/compat/cache/fetch-patch.ts +745 -0
- package/src/compat/cache/handler.ts +100 -0
- package/src/compat/cache/modern-handler.ts +275 -0
- package/src/compat/cache/resume-data-cache.ts +143 -0
- package/src/compat/cache/revalidate.ts +759 -0
- package/src/compat/cache/runtime-error.ts +124 -0
- package/src/compat/cache/use-cache-transform.ts +961 -0
- package/src/compat/cache/use-cache.ts +1695 -0
- package/src/compat/cache-control.ts +269 -0
- package/src/compat/client/base-path.ts +64 -0
- package/src/compat/client/css-order.ts +36 -0
- package/src/compat/client/errors/control-flow.ts +92 -0
- package/src/compat/client/errors/error-boundary.ts +222 -0
- package/src/compat/client/errors/global-error.ts +238 -0
- package/src/compat/client/errors/install.ts +217 -0
- package/src/compat/client/errors/lazy.ts +53 -0
- package/src/compat/client/errors/primitive-throw.ts +126 -0
- package/src/compat/client/errors/soft-refresh.ts +14 -0
- package/src/compat/client/link-status.ts +86 -0
- package/src/compat/client/nav-compat-runtime.ts +57 -0
- package/src/compat/client/nav-compat.ts +42 -0
- package/src/compat/client/navigation-scroll.ts +154 -0
- package/src/compat/client/optimistic-routing.ts +206 -0
- package/src/compat/client/prefetch-cache.ts +111 -0
- package/src/compat/client/route-announcer.ts +72 -0
- package/src/compat/client/segment-cache-policy.ts +159 -0
- package/src/compat/client/segment-cache.ts +1077 -0
- package/src/compat/client/segment-prefetch.ts +375 -0
- package/src/compat/client/trailing-slash.ts +24 -0
- package/src/compat/css/chunking.ts +254 -0
- package/src/compat/css/inline-css.ts +73 -0
- package/src/compat/css/lightningcss.ts +90 -0
- package/src/compat/css/modules.ts +373 -0
- package/src/compat/css/nonce.ts +30 -0
- package/src/compat/css/sass-plugin.ts +65 -0
- package/src/compat/css/sass.ts +392 -0
- package/src/compat/css/styled-jsx-runtime.ts +80 -0
- package/src/compat/css/styled-jsx.ts +49 -0
- package/src/compat/edge-runtime.ts +71 -0
- package/src/compat/export/client.ts +112 -0
- package/src/compat/export/index.ts +272 -0
- package/src/compat/export/standalone.ts +207 -0
- package/src/compat/image-optimizer/cache.ts +119 -0
- package/src/compat/image-optimizer/detect.ts +143 -0
- package/src/compat/image-optimizer/index.ts +601 -0
- package/src/compat/image-optimizer/source.ts +243 -0
- package/src/compat/index.ts +458 -0
- package/src/compat/lifecycle/after-scope.ts +86 -0
- package/src/compat/lifecycle/after.ts +173 -0
- package/src/compat/lifecycle/error-funnel.ts +306 -0
- package/src/compat/lifecycle/error-serialize.ts +87 -0
- package/src/compat/lifecycle/error-ui.ts +167 -0
- package/src/compat/lifecycle/instrumentation-client.ts +138 -0
- package/src/compat/lifecycle/instrumentation.ts +277 -0
- package/src/compat/lifecycle/node-console.ts +19 -0
- package/src/compat/lifecycle/testmode.ts +263 -0
- package/src/compat/mdx/compile.ts +219 -0
- package/src/compat/mdx/next-mdx-stub.ts +46 -0
- package/src/compat/mdx/plugin.ts +37 -0
- package/src/compat/metadata-route-artifacts.ts +458 -0
- package/src/compat/metadata.ts +295 -0
- package/src/compat/middleware/manifest.ts +210 -0
- package/src/compat/misc/action-return.ts +173 -0
- package/src/compat/next/cache.ts +211 -0
- package/src/compat/next/canonical-url.ts +35 -0
- package/src/compat/next/client-cache.ts +57 -0
- package/src/compat/next/client-navigation.ts +313 -0
- package/src/compat/next/client-only.ts +3 -0
- package/src/compat/next/client-script.tsx +215 -0
- package/src/compat/next/client-server.ts +39 -0
- package/src/compat/next/config-loader.ts +569 -0
- package/src/compat/next/config.ts +29 -0
- package/src/compat/next/constants.cjs +6 -0
- package/src/compat/next/constants.ts +6 -0
- package/src/compat/next/custom-server.ts +236 -0
- package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
- package/src/compat/next/dynamic.tsx +46 -0
- package/src/compat/next/error.tsx +148 -0
- package/src/compat/next/font/cache.ts +171 -0
- package/src/compat/next/font/google.ts +2 -0
- package/src/compat/next/font/index.ts +8 -0
- package/src/compat/next/font/local.ts +5 -0
- package/src/compat/next/font/runtime-client.ts +71 -0
- package/src/compat/next/font/runtime.ts +974 -0
- package/src/compat/next/font/shared.ts +281 -0
- package/src/compat/next/form.tsx +156 -0
- package/src/compat/next/head.tsx +10 -0
- package/src/compat/next/headers.ts +247 -0
- package/src/compat/next/image/config.ts +196 -0
- package/src/compat/next/image/optimizer.ts +96 -0
- package/src/compat/next/image/patterns.ts +103 -0
- package/src/compat/next/image/shared.ts +141 -0
- package/src/compat/next/image/static-metadata.ts +283 -0
- package/src/compat/next/image/validate.ts +269 -0
- package/src/compat/next/image-client.tsx +215 -0
- package/src/compat/next/image-props.ts +575 -0
- package/src/compat/next/image-usage.ts +102 -0
- package/src/compat/next/image.tsx +56 -0
- package/src/compat/next/index.ts +1 -0
- package/src/compat/next/legacy-image.tsx +97 -0
- package/src/compat/next/link-usage.ts +29 -0
- package/src/compat/next/link-validation-transform.ts +200 -0
- package/src/compat/next/link.tsx +466 -0
- package/src/compat/next/navigation.cjs +21 -0
- package/src/compat/next/navigation.ts +188 -0
- package/src/compat/next/offline.ts +51 -0
- package/src/compat/next/og.ts +324 -0
- package/src/compat/next/optimistic-route-state.ts +188 -0
- package/src/compat/next/preferred-region.ts +39 -0
- package/src/compat/next/redirects.ts +131 -0
- package/src/compat/next/resource-hints.ts +136 -0
- package/src/compat/next/rewrites.ts +350 -0
- package/src/compat/next/root-params.ts +142 -0
- package/src/compat/next/router.cjs +49 -0
- package/src/compat/next/router.ts +143 -0
- package/src/compat/next/script.tsx +355 -0
- package/src/compat/next/server-only.ts +3 -0
- package/src/compat/next/server.ts +28 -0
- package/src/compat/next/svgr.ts +58 -0
- package/src/compat/next/telemetry.ts +77 -0
- package/src/compat/next/user-agent.ts +100 -0
- package/src/compat/next/web-vitals.ts +56 -0
- package/src/compat/otel/api.ts +95 -0
- package/src/compat/otel/client-trace-metadata.ts +71 -0
- package/src/compat/otel/fetch-span.ts +77 -0
- package/src/compat/otel/tracer.ts +944 -0
- package/src/compat/pages/client-plugin.ts +108 -0
- package/src/compat/pages/index.ts +527 -0
- package/src/compat/pages/router-state.ts +94 -0
- package/src/compat/ppr/io.ts +38 -0
- package/src/compat/ppr/missing-root-params.ts +105 -0
- package/src/compat/ppr/root-params-scan.ts +164 -0
- package/src/compat/ppr/root-params-transform.ts +75 -0
- package/src/compat/ppr/root-params.ts +129 -0
- package/src/compat/ppr/segment-config-incompat.ts +34 -0
- package/src/compat/protocol.ts +202 -0
- package/src/compat/react/client.ts +59 -0
- package/src/compat/react/compiler-runtime.ts +60 -0
- package/src/compat/react/dom-client.ts +115 -0
- package/src/compat/react/dom-react-server.ts +20 -0
- package/src/compat/react/dom-server.ts +40 -0
- package/src/compat/react/dom.ts +154 -0
- package/src/compat/react/preact.ts +522 -0
- package/src/compat/react/react-server.ts +84 -0
- package/src/compat/react/router-shim.ts +26 -0
- package/src/compat/react/server-component-use.ts +48 -0
- package/src/compat/react/server-inserted-html.ts +87 -0
- package/src/compat/react/server.ts +156 -0
- package/src/compat/react/view-transition.ts +60 -0
- package/src/compat/register/actions.ts +875 -0
- package/src/compat/register/boot.ts +141 -0
- package/src/compat/register/build-tier.ts +11 -0
- package/src/compat/register/build.ts +182 -0
- package/src/compat/register/bundler.ts +587 -0
- package/src/compat/register/cache.ts +85 -0
- package/src/compat/register/client-errors.ts +18 -0
- package/src/compat/register/config.ts +17 -0
- package/src/compat/register/css-extras.ts +120 -0
- package/src/compat/register/edge-runtime.ts +6 -0
- package/src/compat/register/errors.ts +46 -0
- package/src/compat/register/export.ts +23 -0
- package/src/compat/register/font.ts +36 -0
- package/src/compat/register/hooks.ts +34 -0
- package/src/compat/register/image.ts +133 -0
- package/src/compat/register/index.ts +111 -0
- package/src/compat/register/instrumentation-client.ts +35 -0
- package/src/compat/register/lifecycle.ts +86 -0
- package/src/compat/register/mdx.ts +48 -0
- package/src/compat/register/middleware.ts +36 -0
- package/src/compat/register/misc.ts +44 -0
- package/src/compat/register/otel.ts +288 -0
- package/src/compat/register/pages-api.ts +473 -0
- package/src/compat/register/ppr.ts +56 -0
- package/src/compat/register/protocol.ts +57 -0
- package/src/compat/register/proxy.ts +127 -0
- package/src/compat/register/render.ts +268 -0
- package/src/compat/register/routing.ts +410 -0
- package/src/compat/register/segment.ts +1903 -0
- package/src/compat/register/static-image.ts +21 -0
- package/src/compat/register/typed-routes.ts +35 -0
- package/src/compat/register/usecache.ts +131 -0
- package/src/compat/register/validation.ts +56 -0
- package/src/compat/segment/loading-boundary.ts +113 -0
- package/src/compat/segment/page-slot.ts +200 -0
- package/src/compat/segment/tree.ts +481 -0
- package/src/compat/segment/vary-key.ts +102 -0
- package/src/compat/segment/vary-params.ts +551 -0
- package/src/compat/static-params.ts +33 -0
- package/src/compat/tsconfig-defaults.ts +301 -0
- package/src/compat/typecheck/index.ts +1481 -0
- package/src/compat/typecheck/worker.ts +26 -0
- package/src/compat/typed-routes/index.ts +92 -0
- package/src/compat/typed-routes/manifest.ts +356 -0
- package/src/compat/typed-routes/typegen.ts +566 -0
- package/src/compat/validation/errors.ts +159 -0
- package/src/compat/validation/index.ts +1770 -0
- package/src/compat/validation/prerender-diagnostics.ts +1508 -0
- package/src/compat-bootstrap.ts +67 -0
- package/src/config.ts +218 -0
- package/src/css/build.ts +697 -0
- package/src/css/index.ts +2 -0
- package/src/css/postcss.ts +236 -0
- package/src/css/worker.ts +34 -0
- package/src/dev/client-actions.ts +35 -0
- package/src/dev/client-chunk-store.ts +92 -0
- package/src/dev/client-key-cache.ts +178 -0
- package/src/dev/global-css-cache.ts +212 -0
- package/src/dev/imports.ts +2430 -0
- package/src/dev/module-cache.ts +721 -0
- package/src/dev/module-generations.ts +38 -0
- package/src/dev/module-transform.ts +188 -0
- package/src/dev/node-module-bundle-cache.ts +63 -0
- package/src/dev/restart-cache.ts +10 -0
- package/src/dev/route-bundle-key-cache.ts +154 -0
- package/src/dev/route-facts-cache.ts +223 -0
- package/src/dev/server.ts +1710 -0
- package/src/dynamic/source.ts +307 -0
- package/src/dynamic/tree-shake.ts +262 -0
- package/src/env.ts +92 -0
- package/src/extensions.ts +1898 -0
- package/src/index.ts +34 -0
- package/src/internal.ts +43 -0
- package/src/islands/boundary-error.ts +8 -0
- package/src/islands/static-children.ts +37 -0
- package/src/islands/static-slots.ts +106 -0
- package/src/ppr-postpone.ts +24 -0
- package/src/ppr.ts +784 -0
- package/src/proxy.ts +752 -0
- package/src/render/hooks.ts +384 -0
- package/src/render/index.ts +1 -0
- package/src/render/island-context.ts +47 -0
- package/src/render/metadata.ts +857 -0
- package/src/render/renderer.ts +7391 -0
- package/src/render/resource-hints.ts +44 -0
- package/src/render/slots.tsx +679 -0
- package/src/request/context.ts +396 -0
- package/src/resolve/engine.ts +219 -0
- package/src/resolve/imports.ts +1104 -0
- package/src/resolve/scan-facts.ts +474 -0
- package/src/resolve/source-text.ts +86 -0
- package/src/routing/forwarded.ts +41 -0
- package/src/routing/handler.ts +271 -0
- package/src/routing/href.ts +203 -0
- package/src/routing/metadata.ts +1018 -0
- package/src/routing/request-runtime.ts +43 -0
- package/src/routing/routes.ts +2560 -0
- package/src/routing/slots.ts +432 -0
- package/src/runtime/server.ts +3453 -0
- package/src/runtime/vendor.ts +1160 -0
- package/src/style-modules.d.ts +9 -0
- package/src/typegen.ts +151 -0
- package/src/types.ts +725 -0
- package/src/utils/ansi.ts +9 -0
- package/src/utils/content-type.ts +31 -0
- package/src/utils/decode.ts +7 -0
- package/src/utils/dev-profile.ts +31 -0
- package/src/utils/error-log.ts +29 -0
- package/src/utils/fs-cache.ts +31 -0
- package/src/utils/fs.ts +119 -0
- package/src/utils/html.ts +46 -0
- package/src/utils/serialize.ts +378 -0
- package/src/utils/source.ts +35 -0
- package/src/utils/verbose.ts +39 -0
- package/tsconfig.json +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# pnext
|
|
4
|
+
|
|
5
|
+
**A fast little framework for server-first React apps, fully compatible with Next.js.**
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
## Measured against Next.js
|
|
10
|
+
|
|
11
|
+
The same fixture source runs under both frameworks; `bun bench` measures them side by side and rewrites [`reference/performance.md`](./reference/performance.md) with your machine's absolute numbers. The ranges below span the fixtures — hello-world, an SSR site, and a mid-size admin dashboard (30 routes, 18 client islands):
|
|
12
|
+
|
|
13
|
+
| | pnext vs Next.js |
|
|
14
|
+
|---|--:|
|
|
15
|
+
| Dev server ready | **2.5–3× faster** |
|
|
16
|
+
| First page, cold | **6.5–13× faster** |
|
|
17
|
+
| Warm request | **4–7.5× faster** |
|
|
18
|
+
| HMR save → visible | **1–2.5× faster** |
|
|
19
|
+
| Production build | **4.5–10× faster** |
|
|
20
|
+
| First-page client JS (gzip) | **6–65× less** |
|
|
21
|
+
|
|
22
|
+
Nothing is prebundled — the dev server compiles what a request needs and caches it content-addressed, so it's ready in ~100 ms at any app size.
|
|
23
|
+
|
|
24
|
+
Core pnext (no Next compat) is its own story, and it's smaller still:
|
|
25
|
+
|
|
26
|
+
- **Server-only pages ship 0 KB of JavaScript.**
|
|
27
|
+
- A server-rendered page with links ships **~1 KB gzip** of framework, total; the router + prefetch runtime alone is **348 bytes**.
|
|
28
|
+
- A fully hydrated route pays **~7.5 KB gzip** of framework — **12.5 KB** with React compat, **15 KB** with the full `next/*` surface. Next.js ships 130+ KB before your first component.
|
|
29
|
+
|
|
30
|
+
Compatibility is proven, not promised: pnext runs Next.js's own test suite — 4,400+ tracked assertions passing — so `next/link`, `next/navigation`, `next/headers`, metadata, middleware, and friends behave the way you already know.
|
|
31
|
+
|
|
32
|
+
## How
|
|
33
|
+
|
|
34
|
+
One pipeline, three fast tools: [Bun](https://bun.sh) as runtime, esbuild as the only bundler (dev and prod are the same artifacts — no dev/prod drift), and oxc for parsing, resolving, and transforms. Preact renders and hydrates; React APIs work through compat. The dev server compiles exactly what a request needs, when it needs it.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
bun add -d @wular/pnext
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "pnext dev --port 3000",
|
|
46
|
+
"build": "pnext build",
|
|
47
|
+
"build:vercel": "pnext build --adapter vercel",
|
|
48
|
+
"start": "pnext start --port 3000",
|
|
49
|
+
"analyze": "pnext analyze"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## App shape
|
|
55
|
+
|
|
56
|
+
pnext looks for `app/` or `src/app/`:
|
|
57
|
+
|
|
58
|
+
```txt
|
|
59
|
+
src/app/
|
|
60
|
+
globals.css
|
|
61
|
+
page.tsx
|
|
62
|
+
layout.tsx
|
|
63
|
+
users/
|
|
64
|
+
[id]/
|
|
65
|
+
page.tsx
|
|
66
|
+
api/
|
|
67
|
+
hello/
|
|
68
|
+
route.ts
|
|
69
|
+
public/
|
|
70
|
+
logo.svg
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`public/` is served from `/`. Global CSS imported from the root layout is compiled and linked in the head, with your PostCSS/Tailwind setup. CSS from pages and components becomes route CSS; `.module.css` is scoped. `layout.tsx` can export `metadata`, a default wrapper component, or both — a metadata-only root layout lets pnext create the document shell.
|
|
74
|
+
|
|
75
|
+
## Pages
|
|
76
|
+
|
|
77
|
+
Pages and layouts are Server Components by default:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
export const metadata = {
|
|
81
|
+
title: 'My app',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default async function Page() {
|
|
85
|
+
const post = await getPost();
|
|
86
|
+
return <article>{post.title}</article>;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Add a Client Component only where the browser matters:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
'use client';
|
|
94
|
+
|
|
95
|
+
import { useState } from 'preact/hooks';
|
|
96
|
+
|
|
97
|
+
export function Counter() {
|
|
98
|
+
const [count, setCount] = useState(0);
|
|
99
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Server Components render Client Components with serializable props; Client Components server-render and hydrate. Server-rendered children passed into a Client Component stay on the server and ship no code.
|
|
104
|
+
|
|
105
|
+
Dedupe repeated reads with server-only `cache()`:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { cache } from '@wular/pnext/cache';
|
|
109
|
+
|
|
110
|
+
export const getPost = cache(async (id: string) => {
|
|
111
|
+
return db.post.findUnique({ where: { id } });
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Routes
|
|
116
|
+
|
|
117
|
+
`route.ts` files are HTTP handlers:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import type { NextRequest } from '@wular/pnext/server';
|
|
121
|
+
|
|
122
|
+
export function GET(request: NextRequest) {
|
|
123
|
+
const name = request.nextUrl.searchParams.get('name');
|
|
124
|
+
return Response.json({ hello: name ?? 'world' });
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Static `GET` handlers and `[param]` pages with a `params()` export are written as static files at build time; everything else stays runtime. `pnext build --adapter vercel` emits `.vercel/output` directly.
|
|
129
|
+
|
|
130
|
+
## Types
|
|
131
|
+
|
|
132
|
+
`pnext dev`, `build`, and `typegen` generate route types in `.pnext/types`; import typed route props from `#gen/app/...`.
|
|
133
|
+
|
|
134
|
+
## Benchmarks
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
bun bench
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Runs pnext and Next.js side by side on the shared fixtures in [`bench/`](./bench/) — dev cold start, warm requests, HMR, production build, shipped bytes — and rewrites [`reference/performance.md`](./reference/performance.md) with your machine's numbers. Don't take our word for it.
|
|
141
|
+
|
|
142
|
+
## Reference
|
|
143
|
+
|
|
144
|
+
- [Overview](./reference/overview.md)
|
|
145
|
+
- [Routing](./reference/routing.md)
|
|
146
|
+
- [Metadata](./reference/metadata.md)
|
|
147
|
+
- [Rendering](./reference/rendering.md)
|
|
148
|
+
- [CSS](./reference/css.md)
|
|
149
|
+
- [Environment Variables](./reference/env.md)
|
|
150
|
+
- [Compatibility](./reference/compat.md)
|
|
151
|
+
- [Typegen](./reference/typegen.md)
|
|
152
|
+
- [Config](./reference/config.md)
|
|
153
|
+
- [Performance](./reference/performance.md)
|
package/bin/pnext
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
script=$0
|
|
4
|
+
|
|
5
|
+
# `dirname` is an external binary and `$(...)` forks a subshell, so spelling this
|
|
6
|
+
# the obvious way costs two process creations on every command. Parameter
|
|
7
|
+
# expansion plus a `cd` in *this* shell gets the same answer with no forks; the
|
|
8
|
+
# cwd is restored before exec so relative arguments still resolve.
|
|
9
|
+
resolve_dir() {
|
|
10
|
+
case $1 in
|
|
11
|
+
*/*) dirpart=${1%/*} ;;
|
|
12
|
+
*) dirpart=. ;;
|
|
13
|
+
esac
|
|
14
|
+
opwd=$PWD
|
|
15
|
+
CDPATH= cd -P "$dirpart" 2>/dev/null || return 1
|
|
16
|
+
dir=$PWD
|
|
17
|
+
CDPATH= cd "$opwd" 2>/dev/null || return 1
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
while [ -L "$script" ]; do
|
|
21
|
+
resolve_dir "$script" || break
|
|
22
|
+
target=$(readlink "$script")
|
|
23
|
+
case "$target" in
|
|
24
|
+
/*) script=$target ;;
|
|
25
|
+
*) script=$dir/$target ;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
resolve_dir "$script"
|
|
30
|
+
|
|
31
|
+
# Bun decides its JSX transform (jsx vs. the dev-only jsxDEV, which calls
|
|
32
|
+
# preact/jsx-dev-runtime with a different call signature) once per process,
|
|
33
|
+
# from NODE_ENV at startup — not per file. Setting it later from inside
|
|
34
|
+
# index.ts is too late: by the time that line runs, the entry file and
|
|
35
|
+
# everything reached by its static imports have already been transpiled
|
|
36
|
+
# with whatever NODE_ENV was inherited from the shell. So it must be
|
|
37
|
+
# exported here, before exec, not in TS.
|
|
38
|
+
if [ -z "$NODE_ENV" ]; then
|
|
39
|
+
case "$1" in
|
|
40
|
+
dev) export NODE_ENV=development ;;
|
|
41
|
+
*) export NODE_ENV=production ;;
|
|
42
|
+
esac
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Exec through a bun binary literally named for the command ("pnext-dev",
|
|
46
|
+
# "pnext-build", ...) so Activity Monitor and `ps` label every pnext process
|
|
47
|
+
# instead of showing "bun". The kernel takes the process name from the exec'd
|
|
48
|
+
# file's basename; argv0 tricks like `exec -a` never reach it.
|
|
49
|
+
#
|
|
50
|
+
# The cached names are hardlinks of a bun binary (see src/cli/named-bin.ts), so
|
|
51
|
+
# `-ef` — same device and inode — proves a candidate is *this* bun and never
|
|
52
|
+
# execs a stale one left by an earlier version. Resolving it here in sh instead
|
|
53
|
+
# of asking named-bin.ts saves a whole bun process per command; on a miss we run
|
|
54
|
+
# plain bun and the CLI creates the link for the next run.
|
|
55
|
+
case "$1" in
|
|
56
|
+
dev|build|start|analyze|typegen) named=pnext-$1 ;;
|
|
57
|
+
*) named=pnext ;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
bun_bin=$(command -v bun)
|
|
61
|
+
for candidate in "${XDG_CACHE_HOME:-$HOME/.cache}"/pnext/bin/bun-*/"$named"; do
|
|
62
|
+
if [ -x "$candidate" ] && [ "$candidate" -ef "$bun_bin" ]; then
|
|
63
|
+
exec "$candidate" --conditions=react-server "$dir/../src/cli/index.ts" "$@"
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
exec bun --conditions=react-server "$dir/../src/cli/index.ts" "$@"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { includeIgnoreFile } from '@eslint/compat';
|
|
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';
|
|
8
|
+
|
|
9
|
+
export default tseslint.config(
|
|
10
|
+
includeIgnoreFile(path.join(import.meta.dirname, '../../.gitignore')),
|
|
11
|
+
{ ignores: ['**/*.config.*', '**/*.d.ts', '**/.pnext/**', '**/dist/**'] },
|
|
12
|
+
{
|
|
13
|
+
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
|
|
14
|
+
plugins: {
|
|
15
|
+
import: importPlugin,
|
|
16
|
+
turbo: turboPlugin,
|
|
17
|
+
},
|
|
18
|
+
extends: [
|
|
19
|
+
eslint.configs.recommended,
|
|
20
|
+
...tseslint.configs.recommended,
|
|
21
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
22
|
+
...tseslint.configs.stylisticTypeChecked,
|
|
23
|
+
],
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
25
|
+
rules: {
|
|
26
|
+
// @ts-ignore
|
|
27
|
+
...turboPlugin.configs.recommended.rules,
|
|
28
|
+
'@typescript-eslint/no-unused-vars': [
|
|
29
|
+
'error',
|
|
30
|
+
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
31
|
+
],
|
|
32
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
33
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
34
|
+
'warn',
|
|
35
|
+
{ prefer: 'type-imports', fixStyle: 'inline-type-imports', disallowTypeAnnotations: false },
|
|
36
|
+
],
|
|
37
|
+
'prefer-const': 'off',
|
|
38
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
39
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
40
|
+
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
|
41
|
+
'@typescript-eslint/prefer-regexp-exec': 'off',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
linterOptions: { reportUnusedDisableDirectives: true },
|
|
46
|
+
languageOptions: { parserOptions: { projectService: true } },
|
|
47
|
+
},
|
|
48
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "Default",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"declaration": false,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"incremental": false,
|
|
8
|
+
"isolatedModules": true,
|
|
9
|
+
"lib": [
|
|
10
|
+
"ESNext"
|
|
11
|
+
],
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "Bundler",
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noUncheckedIndexedAccess": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"verbatimModuleSyntax": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"strict": true,
|
|
20
|
+
"strictNullChecks": true,
|
|
21
|
+
"target": "ES2021",
|
|
22
|
+
"checkJs": true,
|
|
23
|
+
"allowJs": true,
|
|
24
|
+
"noEmit": true
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wular/pnext",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"pnext": "bin/pnext"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"config",
|
|
11
|
+
"src",
|
|
12
|
+
"tsconfig.json",
|
|
13
|
+
"reference"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./src/index.ts",
|
|
20
|
+
"./internal": "./src/internal.ts",
|
|
21
|
+
"./cache": "./src/api/cache.ts",
|
|
22
|
+
"./dynamic": "./src/api/dynamic.tsx",
|
|
23
|
+
"./link": "./src/api/link.tsx",
|
|
24
|
+
"./navigation": "./src/api/navigation.ts",
|
|
25
|
+
"./navigation/client": "./src/api/client-navigation.ts",
|
|
26
|
+
"./server": "./src/api/server.ts"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"lint": "bun scripts/check-compat-boundary.ts && eslint . --max-warnings 0 && tsc --noEmit",
|
|
30
|
+
"bench": "bun bench/run.ts",
|
|
31
|
+
"clean": "rm -rf .turbo .pnext node_modules",
|
|
32
|
+
"prepublishOnly": "bun run lint",
|
|
33
|
+
"version-bump:patch": "bun scripts/bump.mjs patch",
|
|
34
|
+
"version-bump:minor": "bun scripts/bump.mjs minor",
|
|
35
|
+
"version-bump:major": "bun scripts/bump.mjs major"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"client-only": "^0.0.1",
|
|
39
|
+
"dotenv": "^16.0.3",
|
|
40
|
+
"esbuild": "^0.25.12",
|
|
41
|
+
"oxc-parser": "0.142.0",
|
|
42
|
+
"oxc-resolver": "^11.24.2",
|
|
43
|
+
"oxc-transform": "0.136.0",
|
|
44
|
+
"preact": "^10.29.2",
|
|
45
|
+
"preact-render-to-string": "^6.7.0",
|
|
46
|
+
"react-compiler-runtime": "^1.0.0",
|
|
47
|
+
"server-only": "^0.0.1",
|
|
48
|
+
"web-vitals": "^4.2.4"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/compat": "^1.4.0",
|
|
52
|
+
"@eslint/js": "^9.38.0",
|
|
53
|
+
"@types/bun": "^1.3.0",
|
|
54
|
+
"eslint": "^9.38.0",
|
|
55
|
+
"eslint-plugin-import": "^2.32.0",
|
|
56
|
+
"eslint-plugin-turbo": "^2.5.8",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"typescript-eslint": "^8.46.2"
|
|
59
|
+
},
|
|
60
|
+
"optionalDependencies": {
|
|
61
|
+
"@mdx-js/mdx": "^3.1.0",
|
|
62
|
+
"@opentelemetry/api": "^1.7.0",
|
|
63
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
64
|
+
"@typescript/native-preview": "^7.0.0-dev.20260707.2",
|
|
65
|
+
"next-font": "^2.0.2",
|
|
66
|
+
"sass": "^1.80.0",
|
|
67
|
+
"satori": "^0.12.0",
|
|
68
|
+
"sharp": "^0.34.0"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Compatibility
|
|
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, `proxy`/`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 rather than by hand-written parity claims.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
export default {
|
|
7
|
+
compat: {
|
|
8
|
+
react: true, // map react/react-dom onto Preact
|
|
9
|
+
next: true, // the next/* surface + next.config.js; implies react
|
|
10
|
+
reactCompiler: true, // React Compiler for React-style Client Components; implies react
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
```
|
|
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. `react`'s `cache()` maps to pnext's request cache on the server.
|
|
16
|
+
|
|
17
|
+
Importing `next/*` or `react` without the matching compat mode is a build error naming the flag to enable.
|
|
18
|
+
|
|
19
|
+
Everything below is a place pnext deliberately does not match Next. It is the whole list.
|
|
20
|
+
|
|
21
|
+
## Preact, not React
|
|
22
|
+
|
|
23
|
+
`react-dom/server`'s streaming renderers (`renderToReadableStream`, `renderToPipeableStream`) throw; the synchronous `renderToString`/`renderToStaticMarkup` work. Client components run on Preact's reconciler, so code reaching into React internals is out of scope.
|
|
24
|
+
|
|
25
|
+
Direct Preact imports and Preact Signals need no compat and produce smaller bundles than `preact/compat`.
|
|
26
|
+
|
|
27
|
+
## No Flight payload
|
|
28
|
+
|
|
29
|
+
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.
|
|
30
|
+
|
|
31
|
+
Server-rendered JSX crosses 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, like in Next. Elements inside `Map`/`Set` props are the one shape that throws.
|
|
32
|
+
|
|
33
|
+
## Pages Router is emulated
|
|
34
|
+
|
|
35
|
+
A `pages/` directory is materialized onto App Router routes, so `getStaticProps`/`getServerSideProps` pages and `pages/api` handlers run. `_app`, `_document`, and `_error` are ignored. `next/head` renders nothing — use the metadata exports. `next/router` maps onto the app router where the concepts line up and no-ops elsewhere.
|
|
36
|
+
|
|
37
|
+
## No webpack or Turbopack
|
|
38
|
+
|
|
39
|
+
esbuild is the only bundler, and a `webpack(config)` function in `next.config.js` is not executed (pnext warns once at config load when one is present). `turbopack.rules` loader chains, `turbopack.resolveAlias`, `transpilePackages`, `modularizeImports`, and `optimizePackageImports` are re-implemented on esbuild directly.
|
|
40
|
+
|
|
41
|
+
If `webpack()` references `@svgr/webpack` — the overwhelmingly common custom-loader use — pnext auto-detects it and compiles `.svg` imports to inline Preact components (root SVG attributes spread first, so `className`/`width`/`height`/etc. props override them), matching `@svgr/webpack`'s default output. Without that reference, `.svg` imports keep the normal static-asset URL behavior.
|
|
42
|
+
|
|
43
|
+
## Optional native dependencies
|
|
44
|
+
|
|
45
|
+
All three ship as `optionalDependencies`, so a normal install has them — same as Next. The graceful paths below only matter when the optional install fails.
|
|
46
|
+
|
|
47
|
+
- `next/image`'s `/_next/image` optimizer needs `sharp`. The component, `images` config validation, and static imports work without it.
|
|
48
|
+
- `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
|
+
- `next/font/google` resolves the catalog through `next-font`. If it cannot, the build fails rather than falling back to a hosted font.
|
|
50
|
+
|
|
51
|
+
## Smaller surfaces
|
|
52
|
+
|
|
53
|
+
- `userAgent()` uses an in-house parser covering mainstream browsers, engines, CPUs, and devices — not the full ua-parser-js database.
|
|
54
|
+
- Only these `next/dist/*` paths are shimmed; any other deep import fails with an error naming this list.
|
|
55
|
+
- `next/dist/client/components/app-router-headers`
|
|
56
|
+
- `next/dist/server/web/spec-extension/unstable-cache`
|
|
57
|
+
- `next/dist/server/web/spec-extension/unstable-no-store`
|
|
58
|
+
- `next/dist/server/web/spec-extension/revalidate`
|
|
59
|
+
- `next/dist/server/app-render/work-unit-async-storage.external` (server only)
|
|
60
|
+
|
|
61
|
+
## Cache state is per process
|
|
62
|
+
|
|
63
|
+
`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.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Config
|
|
2
|
+
|
|
3
|
+
pnext reads `pnext.config.ts` from the project root passed to the CLI. The file is optional.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import type { pnextConfig } from '@wular/pnext';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
outDir: '.pnext',
|
|
10
|
+
basePath: '',
|
|
11
|
+
productionBrowserSourceMaps: false,
|
|
12
|
+
compat: {
|
|
13
|
+
next: true,
|
|
14
|
+
},
|
|
15
|
+
} satisfies pnextConfig;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
With `compat.next`, `next.config.js` is loaded too, and it wins on the options both files can set (`basePath`, `assetPrefix`, `outDir`, `trailingSlash`, `skipTrailingSlashRedirect`, `productionBrowserSourceMaps`).
|
|
19
|
+
|
|
20
|
+
## Fields
|
|
21
|
+
|
|
22
|
+
### `outDir`
|
|
23
|
+
|
|
24
|
+
Default: `'.pnext'`
|
|
25
|
+
|
|
26
|
+
Build output directory for HTML, client assets, cache files, and `manifest.json`.
|
|
27
|
+
|
|
28
|
+
### `basePath`
|
|
29
|
+
|
|
30
|
+
Default: `''`
|
|
31
|
+
|
|
32
|
+
Path prefix for apps served below the domain root.
|
|
33
|
+
|
|
34
|
+
### `assetPrefix`
|
|
35
|
+
|
|
36
|
+
Default: `basePath`
|
|
37
|
+
|
|
38
|
+
URL prefix for emitted assets. Set it to serve `/assets/*` from a CDN.
|
|
39
|
+
|
|
40
|
+
### `trailingSlash`
|
|
41
|
+
|
|
42
|
+
Default: `false`
|
|
43
|
+
|
|
44
|
+
Canonicalize URLs to a trailing slash, redirecting the unslashed form.
|
|
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
|
|
117
|
+
|
|
118
|
+
pnext keeps the CLI root as the app root for `public/`, `.pnext/`, and `pnext.config.ts`.
|
|
119
|
+
|
|
120
|
+
For monorepos, pnext also infers a workspace root by walking upward to `package.json#workspaces` or `pnpm-workspace.yaml`. Set `workspaceRoot` only when that inference should be overridden.
|
package/reference/css.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# CSS
|
|
2
|
+
|
|
3
|
+
## Global CSS
|
|
4
|
+
|
|
5
|
+
Import global styles from the root layout. pnext compiles global CSS once and links it from every page as `/assets/global.css`.
|
|
6
|
+
|
|
7
|
+
Global CSS can use local workspace package imports, font files, image assets, and the app's PostCSS/Tailwind setup.
|
|
8
|
+
|
|
9
|
+
## PostCSS
|
|
10
|
+
|
|
11
|
+
When the app root has a `postcss.config.{cjs,js,mjs}`, pnext runs its plugins on every emitted stylesheet, in a worker thread. Tailwind v4 (`@tailwindcss/postcss`) stays warm there, so dev rebuilds are incremental; config-file edits need a dev-server restart.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import type { ComponentChildren } from 'preact';
|
|
15
|
+
import './globals.css';
|
|
16
|
+
|
|
17
|
+
export default function Layout({ children }: { children: ComponentChildren }) {
|
|
18
|
+
return (
|
|
19
|
+
<html>
|
|
20
|
+
<body>{children}</body>
|
|
21
|
+
</html>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Route CSS
|
|
27
|
+
|
|
28
|
+
Import plain CSS from pages, layouts, or components:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import './page.css';
|
|
32
|
+
|
|
33
|
+
export default function Page() {
|
|
34
|
+
return <h1 className="title">Hello</h1>;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
pnext emits route CSS only for routes that import CSS. A route with CSS imports gets a linked `/assets/<route>.css` chunk.
|
|
39
|
+
|
|
40
|
+
## CSS Modules
|
|
41
|
+
|
|
42
|
+
Use `.module.css` for scoped classes:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
.title {
|
|
46
|
+
color: rebeccapurple;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import styles from './page.module.css';
|
|
52
|
+
|
|
53
|
+
export default function Page() {
|
|
54
|
+
return <h1 className={styles.title}>Hello</h1>;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
CSS module class names are scoped in the emitted CSS and match the server-rendered HTML.
|