@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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Phase decomposition for the client stage (read / transform / react-compiler /
|
|
2
|
+
// esbuild / write), off unless PNEXT_CLIENT_PROFILE is set. The bench needs the
|
|
3
|
+
// split to prove where the residual sits; a build must not pay for it.
|
|
4
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
5
|
+
const enabled = Boolean(process.env.PNEXT_CLIENT_PROFILE);
|
|
6
|
+
|
|
7
|
+
const totals = new Map<string, number>();
|
|
8
|
+
const spans = new Map<string, [number, number][]>();
|
|
9
|
+
|
|
10
|
+
/** Total wall covered by at least one span (overlaps counted once). */
|
|
11
|
+
function unionMs(intervals: [number, number][]) {
|
|
12
|
+
const sorted = [...intervals].sort((a, b) => a[0] - b[0]);
|
|
13
|
+
let total = 0;
|
|
14
|
+
let [openStart, openEnd] = sorted[0] ?? [0, 0];
|
|
15
|
+
for (const [start, end] of sorted.slice(1)) {
|
|
16
|
+
if (start > openEnd) {
|
|
17
|
+
total += openEnd - openStart;
|
|
18
|
+
[openStart, openEnd] = [start, end];
|
|
19
|
+
} else if (end > openEnd) {
|
|
20
|
+
openEnd = end;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return total + (openEnd - openStart);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const clientProfile = {
|
|
27
|
+
enabled,
|
|
28
|
+
/** Time `task` under `phase`. Returns the task's value untouched. */
|
|
29
|
+
time<T>(phase: string, task: () => T): T {
|
|
30
|
+
if (!enabled) return task();
|
|
31
|
+
const start = performance.now();
|
|
32
|
+
try {
|
|
33
|
+
return task();
|
|
34
|
+
} finally {
|
|
35
|
+
totals.set(phase, (totals.get(phase) ?? 0) + (performance.now() - start));
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Async phases overlap (esbuild runs onLoad concurrently), so summing each call's wall would count
|
|
40
|
+
* the same second many times. Record spans and report the union - the wall the phase occupies.
|
|
41
|
+
*/
|
|
42
|
+
async timeAsync<T>(phase: string, task: () => Promise<T>): Promise<T> {
|
|
43
|
+
if (!enabled) return task();
|
|
44
|
+
const start = performance.now();
|
|
45
|
+
try {
|
|
46
|
+
return await task();
|
|
47
|
+
} finally {
|
|
48
|
+
(spans.get(phase) ?? spans.set(phase, []).get(phase)!).push([start, performance.now()]);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
count(key: string, by = 1) {
|
|
52
|
+
if (!enabled) return;
|
|
53
|
+
totals.set(key, (totals.get(key) ?? 0) + by);
|
|
54
|
+
},
|
|
55
|
+
reset() {
|
|
56
|
+
totals.clear();
|
|
57
|
+
spans.clear();
|
|
58
|
+
},
|
|
59
|
+
snapshot(): Record<string, number> {
|
|
60
|
+
return {
|
|
61
|
+
...Object.fromEntries(totals),
|
|
62
|
+
...Object.fromEntries([...spans].map(([phase, list]) => [phase, unionMs(list)])),
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
/** Print the snapshot and clear it, so a second stage starts from zero. */
|
|
66
|
+
report(label: string) {
|
|
67
|
+
if (!enabled) return;
|
|
68
|
+
const snap = this.snapshot();
|
|
69
|
+
const line = Object.entries(snap)
|
|
70
|
+
.map(([phase, value]) => `${phase} ${value < 100 ? value.toFixed(1) : Math.round(value)}`)
|
|
71
|
+
.join(' · ');
|
|
72
|
+
console.log(`pnext client profile [${label}] ${line}`);
|
|
73
|
+
this.reset();
|
|
74
|
+
},
|
|
75
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { transform, transformSync, type TransformOptions, type TransformResult } from 'oxc-transform';
|
|
2
|
+
import type { getCompatModeExtensions } from '../extensions';
|
|
3
|
+
|
|
4
|
+
type ReactCompilerOptions = NonNullable<
|
|
5
|
+
ReturnType<ReturnType<typeof getCompatModeExtensions>['reactCompilerOptions']>
|
|
6
|
+
>;
|
|
7
|
+
|
|
8
|
+
// oxc-transform runs the React Compiler (Rust port) plus TypeScript stripping
|
|
9
|
+
// in a single pass, replacing the @babel/core round-trip. JSX is left intact
|
|
10
|
+
// (`jsx: 'preserve'`) so esbuild stays the single source of truth for the
|
|
11
|
+
// preact JSX transform downstream.
|
|
12
|
+
function compilerOptions(options: ReactCompilerOptions): TransformOptions {
|
|
13
|
+
return {
|
|
14
|
+
jsx: 'preserve',
|
|
15
|
+
sourcemap: false,
|
|
16
|
+
reactCompiler: {
|
|
17
|
+
panicThreshold: 'critical_errors',
|
|
18
|
+
target: options.target as '17' | '18' | '19',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The React Compiler pass. It has no esbuild plugin of its own: the client-source loader owns every
|
|
25
|
+
* first-party source file and calls this as the last step of that file's single rewrite pass, so
|
|
26
|
+
* the compiler applies exactly once regardless of plugin registration order. oxc strips TS types as
|
|
27
|
+
* part of the pass, so no separate type-import cleanup is needed.
|
|
28
|
+
*
|
|
29
|
+
* `transform`, not `transformSync`: the async binding runs on oxc's Rust threadpool, so esbuild's
|
|
30
|
+
* concurrent onLoad callbacks compile the whole route set in parallel instead of queueing on the
|
|
31
|
+
* JS thread.
|
|
32
|
+
*/
|
|
33
|
+
export async function transformReactCompiler(
|
|
34
|
+
source: string,
|
|
35
|
+
file: string,
|
|
36
|
+
options: ReactCompilerOptions,
|
|
37
|
+
) {
|
|
38
|
+
return reactCompilerResult(await transform(file, source, compilerOptions(options)), source, file);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Same pass, for the few callers that cannot await (kept in lock-step above). */
|
|
42
|
+
export function transformReactCompilerSync(
|
|
43
|
+
source: string,
|
|
44
|
+
file: string,
|
|
45
|
+
options: ReactCompilerOptions,
|
|
46
|
+
) {
|
|
47
|
+
return reactCompilerResult(transformSync(file, source, compilerOptions(options)), source, file);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function reactCompilerResult(result: TransformResult, source: string, file: string) {
|
|
51
|
+
// When the compiler cannot compile a function (rule-of-React violation, unsupported library, a
|
|
52
|
+
// construct the Rust port does not yet handle) it reports a diagnostic. If the whole file trips one,
|
|
53
|
+
// oxc emits no code at all - unlike Babel, which skips just that function - so fall back to the
|
|
54
|
+
// untransformed source and let esbuild strip types and handle JSX; the file ships un-memoized.
|
|
55
|
+
// `panicThreshold` does not change this: every value still yields empty output on a hard bailout.
|
|
56
|
+
if (!result.code) {
|
|
57
|
+
// Only genuine transform failures (not React Compiler bailouts) are worth
|
|
58
|
+
// surfacing; esbuild re-parses the fallback source and would flag the rest.
|
|
59
|
+
const failures = result.errors.filter(error => !error.message.startsWith('[ReactCompiler]'));
|
|
60
|
+
if (failures.length > 0) {
|
|
61
|
+
console.error(
|
|
62
|
+
`React Compiler (oxc) failed for ${file}:\n${failures.map(error => error.message).join('\n')}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return source;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result.code;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function stripPureTypeImports(source: string) {
|
|
72
|
+
return source
|
|
73
|
+
.replace(/^\s*import\s+type\s+[\s\S]*?\s+from\s+['"][^'"]+['"]\s*;?\s*$/gm, '')
|
|
74
|
+
.replace(
|
|
75
|
+
/^\s*import\s+\{([^}]*)\}\s+from\s+(['"][^'"]+['"])\s*;?\s*$/gm,
|
|
76
|
+
(_match, clause: string, specifier: string) => {
|
|
77
|
+
const valueSpecifiers = clause
|
|
78
|
+
.split(',')
|
|
79
|
+
.map(item => item.trim())
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.filter(item => !item.startsWith('type '));
|
|
82
|
+
|
|
83
|
+
return valueSpecifiers.length > 0
|
|
84
|
+
? `import { ${valueSpecifiers.join(', ')} } from ${specifier};`
|
|
85
|
+
: '';
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** JSX always; a plain .ts/.js only when it looks like it holds a component. */
|
|
91
|
+
export function shouldReactCompile(source: string, file: string) {
|
|
92
|
+
if (/\.[cm]?[jt]sx$/.test(file)) return true;
|
|
93
|
+
return /\b(?:use[A-Z][\w$]*|createElement|memo|forwardRef)\b/.test(source);
|
|
94
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stub a server-graph module gets in place of a `'use client'` file: a component object tagged
|
|
3
|
+
* with the reference the renderer matches islands by. Shared by the two places that cross a client
|
|
4
|
+
* boundary from the server graph - the dev module pass and the vendor bundler (a package's own
|
|
5
|
+
* `'use client'` files, reached mid-bundle).
|
|
6
|
+
*/
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { clientReferenceId } from './reference';
|
|
9
|
+
import { pathToFileHref } from '../config';
|
|
10
|
+
import type { ResolvedConfig } from '../config';
|
|
11
|
+
import { resolveImport } from '../resolve/imports';
|
|
12
|
+
import { moduleExportNames, moduleExportStars } from '../resolve/scan-facts';
|
|
13
|
+
import { readText } from '../utils/fs';
|
|
14
|
+
|
|
15
|
+
export const clientReferenceRuntimeFile = path.resolve(import.meta.dirname, 'reference.ts');
|
|
16
|
+
|
|
17
|
+
export interface ClientReferenceModuleOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Inline `Symbol.for('pnext.clientReference')` instead of importing the
|
|
20
|
+
* runtime module. A stub esbuild BUNDLES (the vendor pass) has no way to
|
|
21
|
+
* reach pnext's own source tree, and the symbol is registry-global, so an
|
|
22
|
+
* inlined lookup is the same symbol the renderer tests for.
|
|
23
|
+
*/
|
|
24
|
+
inlineSymbol?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function clientReferenceModuleSource(
|
|
28
|
+
sourceFile: string,
|
|
29
|
+
exportNames: string[],
|
|
30
|
+
options: ClientReferenceModuleOptions = {},
|
|
31
|
+
) {
|
|
32
|
+
const reference = (exportName: string) =>
|
|
33
|
+
`createReference({ id: ${JSON.stringify(`c-${clientReferenceId(sourceFile, exportName)}`)}, file: ${JSON.stringify(sourceFile)}, exportName: ${JSON.stringify(exportName)} })`;
|
|
34
|
+
const defaultExport = exportNames.includes('default')
|
|
35
|
+
? `export default ${reference('default')};`
|
|
36
|
+
: '';
|
|
37
|
+
const namedExports = exportNames
|
|
38
|
+
.filter(name => name !== 'default')
|
|
39
|
+
.map(name => `export const ${name} = ${reference(name)};`);
|
|
40
|
+
const symbol = options.inlineSymbol
|
|
41
|
+
? `const clientReferenceSymbol = Symbol.for('pnext.clientReference');`
|
|
42
|
+
: `import { clientReferenceSymbol } from ${JSON.stringify(pathToFileHref(clientReferenceRuntimeFile))};`;
|
|
43
|
+
|
|
44
|
+
return `${symbol}
|
|
45
|
+
|
|
46
|
+
function createReference(reference) {
|
|
47
|
+
function ClientReference({ children }) {
|
|
48
|
+
return children ?? null;
|
|
49
|
+
}
|
|
50
|
+
ClientReference[clientReferenceSymbol] = reference;
|
|
51
|
+
return ClientReference;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
${defaultExport}
|
|
55
|
+
${namedExports.join('\n')}
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The names a stub must republish. `export *` is followed because the star's
|
|
61
|
+
* targets live in other files, and a name the stub omits is a hard link error
|
|
62
|
+
* at the importer.
|
|
63
|
+
*/
|
|
64
|
+
export async function clientReferenceExportNames(
|
|
65
|
+
config: ResolvedConfig,
|
|
66
|
+
file: string,
|
|
67
|
+
source?: string,
|
|
68
|
+
visited = new Set<string>(),
|
|
69
|
+
): Promise<string[]> {
|
|
70
|
+
const key = path.resolve(file);
|
|
71
|
+
if (visited.has(key)) return [];
|
|
72
|
+
visited.add(key);
|
|
73
|
+
const text = source ?? (await readText(file));
|
|
74
|
+
const names = new Set(moduleExportNames(text, file));
|
|
75
|
+
// A CommonJS-style client module (`exports.X = ...`) has no ESM exports for
|
|
76
|
+
// the transpiler scan; recover the statically visible names so its reference
|
|
77
|
+
// shim exposes them (mirrors the client bundle's CJS-name recovery).
|
|
78
|
+
if (names.size === 0) {
|
|
79
|
+
for (const match of text.matchAll(/\bexports\.([A-Za-z_$][\w$]*)\s*=/g)) {
|
|
80
|
+
if (match[1] !== '__esModule') names.add(match[1]!);
|
|
81
|
+
}
|
|
82
|
+
if (/\bmodule\.exports\s*=/.test(text)) names.add('default');
|
|
83
|
+
}
|
|
84
|
+
// `export * from './x'` re-exports every named export of the target, whose
|
|
85
|
+
// names live in that module — union them recursively (default stays
|
|
86
|
+
// excluded, per ES module star semantics). `export * as ns from` exports
|
|
87
|
+
// only `ns`, which the own-module scan already lists.
|
|
88
|
+
for (const specifier of moduleExportStars(text, file)) {
|
|
89
|
+
const resolved = resolveImport(config.root, file, specifier);
|
|
90
|
+
if (!resolved || !isInside(config.workspaceRoot, resolved)) continue;
|
|
91
|
+
for (const name of await clientReferenceExportNames(config, resolved, undefined, visited)) {
|
|
92
|
+
if (name !== 'default') names.add(name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return [...names];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Comments and preceding directives do not end the directive prologue. Hand-scanned rather than
|
|
100
|
+
* matched by a regex on purpose: the prologue grammar (a lazy repeat over an alternation whose
|
|
101
|
+
* branches both end in `*?`) is catastrophically ambiguous, so on a file with no directive but a
|
|
102
|
+
* few leading comments a backtracking engine tries every way of splitting the prefix. This scan is
|
|
103
|
+
* linear and allocation-free.
|
|
104
|
+
*/
|
|
105
|
+
export function hasUseClientDirective(source: string) {
|
|
106
|
+
const isSpace = (index: number) => {
|
|
107
|
+
const code = source.charCodeAt(index);
|
|
108
|
+
return code === 32 || (code >= 9 && code <= 13) || (code > 127 && /\s/.test(source[index]!));
|
|
109
|
+
};
|
|
110
|
+
let i = 0;
|
|
111
|
+
for (;;) {
|
|
112
|
+
while (i < source.length && isSpace(i)) i += 1;
|
|
113
|
+
if (source.startsWith('//', i)) {
|
|
114
|
+
const newline = source.indexOf('\n', i);
|
|
115
|
+
if (newline === -1) return false;
|
|
116
|
+
i = newline + 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (source.startsWith('/*', i)) {
|
|
120
|
+
const end = source.indexOf('*/', i + 2);
|
|
121
|
+
if (end === -1) return false;
|
|
122
|
+
i = end + 2;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// Anything that is not a string literal ends the prologue.
|
|
126
|
+
const quote = source[i];
|
|
127
|
+
if (quote !== '"' && quote !== "'") return false;
|
|
128
|
+
let end = i + 1;
|
|
129
|
+
while (end < source.length) {
|
|
130
|
+
const char = source[end]!;
|
|
131
|
+
if (char === quote || char === '\n' || char === '\\') break;
|
|
132
|
+
end += 1;
|
|
133
|
+
}
|
|
134
|
+
if (source[end] !== quote) return false;
|
|
135
|
+
if (source.slice(i + 1, end) === 'use client') return true;
|
|
136
|
+
i = end + 1;
|
|
137
|
+
while (i < source.length && isSpace(i)) i += 1;
|
|
138
|
+
if (source[i] === ';') i += 1;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isInside(root: string, file: string) {
|
|
143
|
+
const relative = path.relative(root, file);
|
|
144
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
145
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export interface ClientReference {
|
|
4
|
+
id: string;
|
|
5
|
+
file: string;
|
|
6
|
+
exportName: string;
|
|
7
|
+
dynamic?: ClientDynamicReference;
|
|
8
|
+
cssImports?: string[];
|
|
9
|
+
/**
|
|
10
|
+
* A `'use client'` module imported only for its side effects (a bare
|
|
11
|
+
* `import './client-only'` with no bindings). It is never rendered as a
|
|
12
|
+
* component, but webpack eagerly initializes every client reference module in
|
|
13
|
+
* a route's bundle once any of them renders, so pnext bundles it into the
|
|
14
|
+
* client entry (a bare side-effect import) to run its top-level code. It has
|
|
15
|
+
* no SSR component, so it is excluded from every server-side marking pass.
|
|
16
|
+
*/
|
|
17
|
+
sideEffect?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ClientDynamicReference {
|
|
21
|
+
load?: 'render' | 'visible';
|
|
22
|
+
rootMargin?: string;
|
|
23
|
+
ssr?: boolean;
|
|
24
|
+
threshold?: number | number[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const clientReferenceSymbol = Symbol.for('pnext.clientReference');
|
|
28
|
+
|
|
29
|
+
export type ClientComponent = ((props: Record<string, unknown>) => unknown) & {
|
|
30
|
+
[clientReferenceSymbol]?: ClientReference;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function clientReferenceId(file: string, exportName: string) {
|
|
34
|
+
return createHash('sha256')
|
|
35
|
+
.update(file)
|
|
36
|
+
.update('\0')
|
|
37
|
+
.update(exportName)
|
|
38
|
+
.digest('hex')
|
|
39
|
+
.slice(0, 10);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function ssrClientReference(reference: Pick<ClientReference, 'dynamic' | 'sideEffect'>) {
|
|
43
|
+
if (reference.sideEffect) return false;
|
|
44
|
+
if (reference.dynamic?.ssr === false) return false;
|
|
45
|
+
if (reference.dynamic?.load === 'visible' && reference.dynamic.ssr !== true) return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|