@wular/pnext 0.0.4 → 0.0.6
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 +11 -11
- package/bin/pnext +1 -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 +1 -1
- package/reference/config.md +2 -2
- package/reference/css.md +13 -9
- package/reference/dev.md +1 -1
- package/reference/metadata.md +7 -7
- package/reference/navigation.md +35 -28
- package/reference/performance.md +70 -70
- package/reference/rendering.md +17 -17
- package/reference/routing.md +17 -17
- package/reference/typegen.md +12 -8
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +113 -109
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +49 -52
- 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 +71 -63
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +88 -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 +794 -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 +17 -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 +1988 -1992
- package/src/{api → client}/router/types.ts +93 -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 +69 -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 +2076 -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 +69 -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 +952 -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 +425 -404
- package/src/styles.d.ts +9 -0
- package/src/types.ts +320 -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/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/src/css/build.ts
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { writeFile } from 'node:fs/promises'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import type { Plugin } from 'esbuild'
|
|
5
|
-
import { build } from '../utils/esbuild'
|
|
6
|
-
import { ensureDir, readText } from '../utils/fs'
|
|
7
|
-
import { postcssConfigFile, runPostcss } from './postcss'
|
|
8
|
-
import { extraPageExtensions, getCssExtensions } from '../extensions'
|
|
9
|
-
import { resolveImport } from '../resolve/imports'
|
|
10
|
-
import { createVerboseLogger } from '../utils/verbose'
|
|
11
|
-
import type { ClientReference } from '../client/reference'
|
|
12
|
-
import type { ResolvedConfig } from '../config'
|
|
13
|
-
import type { RouteManifestEntry } from '../types'
|
|
14
|
-
|
|
15
|
-
import type { CssWorkerRequest, CssWorkerResponse } from './worker'
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { writeFile } from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import type { Plugin } from 'esbuild'
|
|
5
|
+
import { build } from '../utils/esbuild'
|
|
6
|
+
import { ensureDir, readText } from '../utils/fs'
|
|
7
|
+
import { postcssConfigFile, runPostcss } from './postcss'
|
|
8
|
+
import { extraPageExtensions, getCssExtensions } from '../extensions'
|
|
9
|
+
import { resolveImport } from '../resolve/imports'
|
|
10
|
+
import { createVerboseLogger } from '../utils/verbose'
|
|
11
|
+
import type { ClientReference } from '../client/reference'
|
|
12
|
+
import type { ResolvedConfig } from '../config'
|
|
13
|
+
import type { RouteManifestEntry } from '../types'
|
|
14
|
+
|
|
15
|
+
import type { CssWorkerRequest, CssWorkerResponse } from './worker'
|
|
16
16
|
|
|
17
17
|
interface Pending {
|
|
18
|
-
resolve: () => void
|
|
19
|
-
reject: (error: Error) => void
|
|
18
|
+
resolve: () => void
|
|
19
|
+
reject: (error: Error) => void
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// Bun's Worker carries node's ref/unref; the DOM lib typing does not.
|
|
23
23
|
// Bun's terminate() resolves once the thread is gone (lib.dom types it void).
|
|
24
|
-
type CssWorker = Worker & { ref(): void; unref(): void; terminate(): Promise<void> }
|
|
24
|
+
type CssWorker = Worker & { ref(): void; unref(): void; terminate(): Promise<void> }
|
|
25
25
|
|
|
26
|
-
let worker: CssWorker | undefined
|
|
27
|
-
let workerFailed = false
|
|
28
|
-
let nextId = 0
|
|
29
|
-
const pending = new Map<number, Pending>()
|
|
26
|
+
let worker: CssWorker | undefined
|
|
27
|
+
let workerFailed = false
|
|
28
|
+
let nextId = 0
|
|
29
|
+
const pending = new Map<number, Pending>()
|
|
30
30
|
|
|
31
31
|
function ensureWorker() {
|
|
32
|
-
if (worker || workerFailed) return worker
|
|
32
|
+
if (worker || workerFailed) return worker
|
|
33
33
|
try {
|
|
34
34
|
worker = new Worker(new URL('./worker.ts', import.meta.url).href, {
|
|
35
35
|
type: 'module',
|
|
36
|
-
}) as CssWorker
|
|
36
|
+
}) as CssWorker
|
|
37
37
|
} catch {
|
|
38
|
-
workerFailed = true
|
|
39
|
-
return undefined
|
|
38
|
+
workerFailed = true
|
|
39
|
+
return undefined
|
|
40
40
|
}
|
|
41
41
|
// Idle workers must not hold `pnext build` (or a test run) open; each in-flight
|
|
42
42
|
// request refs it again.
|
|
43
|
-
worker.unref()
|
|
43
|
+
worker.unref()
|
|
44
44
|
worker.onmessage = (event: MessageEvent<CssWorkerResponse>) => {
|
|
45
|
-
const { id, error } = event.data
|
|
46
|
-
const entry = pending.get(id)
|
|
47
|
-
if (!entry) return
|
|
48
|
-
pending.delete(id)
|
|
49
|
-
if (pending.size === 0) worker?.unref()
|
|
50
|
-
if (!error) return entry.resolve()
|
|
51
|
-
const failure = new Error(error.message)
|
|
52
|
-
failure.name = error.name
|
|
53
|
-
if (error.stack) failure.stack = error.stack
|
|
54
|
-
entry.reject(failure)
|
|
55
|
-
}
|
|
56
|
-
worker.onerror = () => failWorker(new Error('pnext CSS worker crashed'))
|
|
57
|
-
return worker
|
|
45
|
+
const { id, error } = event.data
|
|
46
|
+
const entry = pending.get(id)
|
|
47
|
+
if (!entry) return
|
|
48
|
+
pending.delete(id)
|
|
49
|
+
if (pending.size === 0) worker?.unref()
|
|
50
|
+
if (!error) return entry.resolve()
|
|
51
|
+
const failure = new Error(error.message)
|
|
52
|
+
failure.name = error.name
|
|
53
|
+
if (error.stack) failure.stack = error.stack
|
|
54
|
+
entry.reject(failure)
|
|
55
|
+
}
|
|
56
|
+
worker.onerror = () => failWorker(new Error('pnext CSS worker crashed'))
|
|
57
|
+
return worker
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// A dead worker takes its processor cache with it; drop it and let the next
|
|
61
61
|
// request fall back in-process rather than hanging every pending build.
|
|
62
62
|
function failWorker(error: Error) {
|
|
63
|
-
workerFailed = true
|
|
64
|
-
worker = undefined
|
|
65
|
-
for (const entry of pending.values()) entry.reject(error)
|
|
66
|
-
pending.clear()
|
|
63
|
+
workerFailed = true
|
|
64
|
+
worker = undefined
|
|
65
|
+
for (const entry of pending.values()) entry.reject(error)
|
|
66
|
+
pending.clear()
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function send(request: (id: number) => CssWorkerRequest) {
|
|
70
|
-
const active = ensureWorker()
|
|
71
|
-
if (!active) return undefined
|
|
72
|
-
const id = nextId
|
|
70
|
+
const active = ensureWorker()
|
|
71
|
+
if (!active) return undefined
|
|
72
|
+
const id = nextId++
|
|
73
73
|
return new Promise<void>((resolve, reject) => {
|
|
74
|
-
pending.set(id, { resolve, reject })
|
|
75
|
-
active.ref()
|
|
76
|
-
active.postMessage(request(id))
|
|
77
|
-
})
|
|
74
|
+
pending.set(id, { resolve, reject })
|
|
75
|
+
active.ref()
|
|
76
|
+
active.postMessage(request(id))
|
|
77
|
+
})
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/** Run the app's postcss pipeline over a built stylesheet, off the event loop. */
|
|
@@ -82,9 +82,9 @@ function send(request: (id: number) => CssWorkerRequest) {
|
|
|
82
82
|
// exit code to 1 on Linux after a fully successful build); one-shot commands
|
|
83
83
|
// terminate it explicitly before exiting.
|
|
84
84
|
export async function stopCssWorker(): Promise<void> {
|
|
85
|
-
const active = worker
|
|
86
|
-
worker = undefined
|
|
87
|
-
if (active) await Promise.resolve(active.terminate())
|
|
85
|
+
const active = worker
|
|
86
|
+
worker = undefined
|
|
87
|
+
if (active) await Promise.resolve(active.terminate())
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export async function runPostcssOffThread(
|
|
@@ -93,11 +93,11 @@ export async function runPostcssOffThread(
|
|
|
93
93
|
options: { dev?: boolean },
|
|
94
94
|
from?: string,
|
|
95
95
|
) {
|
|
96
|
-
const { root, outPath: outDir } = config
|
|
97
|
-
const dev = options.dev ?? false
|
|
98
|
-
const sent = send(id => ({ kind: 'process', id, root, dev, outDir, cssFile, from }))
|
|
99
|
-
if (sent) return sent
|
|
100
|
-
return runPostcss(root, cssFile, { dev, outDir }, from)
|
|
96
|
+
const { root, outPath: outDir } = config
|
|
97
|
+
const dev = options.dev ?? false
|
|
98
|
+
const sent = send(id => ({ kind: 'process', id, root, dev, outDir, cssFile, from }))
|
|
99
|
+
if (sent) return sent
|
|
100
|
+
return runPostcss(root, cssFile, { dev, outDir }, from)
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/**
|
|
@@ -116,28 +116,28 @@ export function warmCssWorker(
|
|
|
116
116
|
outDir: config.outPath,
|
|
117
117
|
}))?.catch(() => {
|
|
118
118
|
// A broken postcss config surfaces on the real build; warming stays quiet.
|
|
119
|
-
})
|
|
119
|
+
})
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
interface CssBuildOptions {
|
|
123
|
-
dev?: boolean
|
|
124
|
-
verbose?: boolean
|
|
123
|
+
dev?: boolean
|
|
124
|
+
verbose?: boolean
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
let cssRuntimeRegistered = false
|
|
127
|
+
let cssRuntimeRegistered = false
|
|
128
128
|
|
|
129
129
|
export function globalCssSource(config: ResolvedConfig) {
|
|
130
|
-
return globalCssSources(config)[0]
|
|
130
|
+
return globalCssSources(config)[0]
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
export function globalCssSources(config: Pick<ResolvedConfig, 'root' | 'appPath'>) {
|
|
134
|
-
return globalCssSourcesForPaths(config.root, config.appPath)
|
|
134
|
+
return globalCssSourcesForPaths(config.root, config.appPath)
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// The walk below reads and resolves the ROOT LAYOUT'S WHOLE IMPORT GRAPH, and every render asks it
|
|
138
138
|
// (via globalCssHref) whether the app has global CSS at all. Memoize per root+appPath; dev clears
|
|
139
139
|
// this on save (invalidateDevCaches), prod sources never change in-process.
|
|
140
|
-
const globalCssSourceCache = new Map<string, string[]>()
|
|
140
|
+
const globalCssSourceCache = new Map<string, string[]>()
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* Restart half of the walk above: the store persists the answer keyed by every
|
|
@@ -145,45 +145,45 @@ const globalCssSourceCache = new Map<string, string[]>();
|
|
|
145
145
|
* graph. `undefined` (prod, or the cache off) simply means always walk.
|
|
146
146
|
*/
|
|
147
147
|
export interface GlobalCssSourceStore {
|
|
148
|
-
load(key: string): string[] | undefined
|
|
149
|
-
save(key: string, sources: string[], visited: string[], missing: string[]): void
|
|
148
|
+
load(key: string): string[] | undefined
|
|
149
|
+
save(key: string, sources: string[], visited: string[], missing: string[]): void
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
let globalCssStore: GlobalCssSourceStore | undefined
|
|
152
|
+
let globalCssStore: GlobalCssSourceStore | undefined
|
|
153
153
|
|
|
154
154
|
export function setGlobalCssSourceStore(store: GlobalCssSourceStore | undefined) {
|
|
155
|
-
globalCssStore = store
|
|
155
|
+
globalCssStore = store
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
export function globalCssSourcesForPaths(root: string, appPath: string) {
|
|
159
|
-
const key = `${root}\0${appPath}
|
|
160
|
-
const cached = globalCssSourceCache.get(key)
|
|
161
|
-
if (cached) return cached
|
|
159
|
+
const key = `${root}\0${appPath}`
|
|
160
|
+
const cached = globalCssSourceCache.get(key)
|
|
161
|
+
if (cached) return cached
|
|
162
162
|
|
|
163
|
-
const stored = globalCssStore?.load(key)
|
|
163
|
+
const stored = globalCssStore?.load(key)
|
|
164
164
|
if (stored) {
|
|
165
|
-
globalCssSourceCache.set(key, stored)
|
|
166
|
-
return stored
|
|
165
|
+
globalCssSourceCache.set(key, stored)
|
|
166
|
+
return stored
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
const sources = new Set<string>()
|
|
170
|
-
const visited = new Set<string>()
|
|
171
|
-
const missing = new Set<string>()
|
|
172
|
-
collectGlobalCssSources(root, rootLayoutFile(appPath, missing), sources, visited, missing)
|
|
169
|
+
const sources = new Set<string>()
|
|
170
|
+
const visited = new Set<string>()
|
|
171
|
+
const missing = new Set<string>()
|
|
172
|
+
collectGlobalCssSources(root, rootLayoutFile(appPath, missing), sources, visited, missing)
|
|
173
173
|
|
|
174
|
-
const resolved = [...sources].map(file => path.resolve(file))
|
|
175
|
-
globalCssSourceCache.set(key, resolved)
|
|
174
|
+
const resolved = [...sources].map(file => path.resolve(file))
|
|
175
|
+
globalCssSourceCache.set(key, resolved)
|
|
176
176
|
// The answer depends on every file the walk READ (a new `import './x.css'`
|
|
177
177
|
// anywhere in the layout graph changes its importer's bytes) and on every
|
|
178
178
|
// path it found ABSENT (restoring one while the server was down would add an
|
|
179
179
|
// edge no importer's bytes record).
|
|
180
|
-
globalCssStore?.save(key, resolved, [...visited], [...missing])
|
|
181
|
-
return resolved
|
|
180
|
+
globalCssStore?.save(key, resolved, [...visited], [...missing])
|
|
181
|
+
return resolved
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/** Drop the memoized layout-graph walk (dev save invalidation). */
|
|
185
185
|
export function clearGlobalCssSourceCache() {
|
|
186
|
-
globalCssSourceCache.clear()
|
|
186
|
+
globalCssSourceCache.clear()
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
function collectGlobalCssSources(
|
|
@@ -193,49 +193,49 @@ function collectGlobalCssSources(
|
|
|
193
193
|
visited: Set<string>,
|
|
194
194
|
missing?: Set<string>,
|
|
195
195
|
) {
|
|
196
|
-
const resolvedFile = path.resolve(file)
|
|
197
|
-
if (visited.has(resolvedFile)) return
|
|
196
|
+
const resolvedFile = path.resolve(file)
|
|
197
|
+
if (visited.has(resolvedFile)) return
|
|
198
198
|
if (!existsSync(resolvedFile)) {
|
|
199
|
-
missing?.add(resolvedFile)
|
|
200
|
-
return
|
|
199
|
+
missing?.add(resolvedFile)
|
|
200
|
+
return
|
|
201
201
|
}
|
|
202
|
-
visited.add(resolvedFile)
|
|
202
|
+
visited.add(resolvedFile)
|
|
203
203
|
|
|
204
204
|
for (const specifier of moduleSpecifiers(readFileSync(resolvedFile, 'utf8'))) {
|
|
205
|
-
const resolved = resolveImport(root, resolvedFile, specifier)
|
|
206
|
-
if (!resolved) continue
|
|
205
|
+
const resolved = resolveImport(root, resolvedFile, specifier)
|
|
206
|
+
if (!resolved) continue
|
|
207
207
|
if (isCssFile(resolved)) {
|
|
208
|
-
sources.add(resolved)
|
|
208
|
+
sources.add(resolved)
|
|
209
209
|
} else {
|
|
210
|
-
collectGlobalCssSources(root, resolved, sources, visited, missing)
|
|
210
|
+
collectGlobalCssSources(root, resolved, sources, visited, missing)
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
function rootLayoutFile(appPath: string, missing?: Set<string>) {
|
|
216
216
|
for (const extension of ['tsx', 'ts', 'jsx', 'js', 'mjs', ...extraPageExtensions()]) {
|
|
217
|
-
const file = path.join(appPath, `layout.${extension}`)
|
|
218
|
-
if (existsSync(file)) return file
|
|
219
|
-
missing?.add(file)
|
|
217
|
+
const file = path.join(appPath, `layout.${extension}`)
|
|
218
|
+
if (existsSync(file)) return file
|
|
219
|
+
missing?.add(file)
|
|
220
220
|
}
|
|
221
|
-
return path.join(appPath, 'layout.tsx')
|
|
221
|
+
return path.join(appPath, 'layout.tsx')
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
export function globalCssHref(config: ResolvedConfig) {
|
|
225
225
|
return globalCssSources(config).length > 0
|
|
226
226
|
? withAssetPrefix(config, '/assets/global.css')
|
|
227
|
-
: undefined
|
|
227
|
+
: undefined
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
export function routeCssHref(
|
|
231
231
|
route: RouteManifestEntry,
|
|
232
232
|
config?: Pick<ResolvedConfig, 'assetPrefix'>,
|
|
233
233
|
): string | string[] | undefined {
|
|
234
|
-
if (route.cssImports.length === 0) return undefined
|
|
234
|
+
if (route.cssImports.length === 0) return undefined
|
|
235
235
|
if (route.cssAssets?.length) {
|
|
236
|
-
return route.cssAssets.map(asset => withAssetPrefix(config, `/assets/${asset}`))
|
|
236
|
+
return route.cssAssets.map(asset => withAssetPrefix(config, `/assets/${asset}`))
|
|
237
237
|
}
|
|
238
|
-
return withAssetPrefix(config, `/assets/${route.id}.css`)
|
|
238
|
+
return withAssetPrefix(config, `/assets/${route.id}.css`)
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
// Prepend the configured assetPrefix (a CDN origin or path) to an app-absolute
|
|
@@ -244,9 +244,9 @@ export function withAssetPrefix(
|
|
|
244
244
|
config: Pick<ResolvedConfig, 'assetPrefix'> | undefined,
|
|
245
245
|
href: string,
|
|
246
246
|
) {
|
|
247
|
-
const prefix = config?.assetPrefix
|
|
248
|
-
if (!prefix) return href
|
|
249
|
-
return `${prefix.replace(/\/$/, '')}${href}
|
|
247
|
+
const prefix = config?.assetPrefix
|
|
248
|
+
if (!prefix) return href
|
|
249
|
+
return `${prefix.replace(/\/$/, '')}${href}`
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/**
|
|
@@ -258,29 +258,29 @@ export function warmCssPipeline(
|
|
|
258
258
|
config: Pick<ResolvedConfig, 'root' | 'outPath'>,
|
|
259
259
|
options: CssBuildOptions = {},
|
|
260
260
|
) {
|
|
261
|
-
if (!hasPostcssConfig(config.root)) return
|
|
262
|
-
warmCssWorker(config, options)
|
|
261
|
+
if (!hasPostcssConfig(config.root)) return
|
|
262
|
+
warmCssWorker(config, options)
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
export async function buildGlobalCss(config: ResolvedConfig, options: CssBuildOptions = {}) {
|
|
266
|
-
const log = createVerboseLogger(options.verbose ?? false, 'css')
|
|
267
|
-
const sources = globalCssSources(config)
|
|
266
|
+
const log = createVerboseLogger(options.verbose ?? false, 'css')
|
|
267
|
+
const sources = globalCssSources(config)
|
|
268
268
|
if (sources.length === 0) {
|
|
269
|
-
log.log('global css: no side-effect css imports in root layout, skipping')
|
|
270
|
-
return undefined
|
|
269
|
+
log.log('global css: no side-effect css imports in root layout, skipping')
|
|
270
|
+
return undefined
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const outDir = options.dev
|
|
274
274
|
? path.join(config.outPath, 'cache', 'assets')
|
|
275
|
-
: path.join(config.outPath, 'public', 'assets')
|
|
276
|
-
const outfile = path.join(outDir, 'global.css')
|
|
277
|
-
await ensureDir(outDir)
|
|
275
|
+
: path.join(config.outPath, 'public', 'assets')
|
|
276
|
+
const outfile = path.join(outDir, 'global.css')
|
|
277
|
+
await ensureDir(outDir)
|
|
278
278
|
|
|
279
279
|
log.log(
|
|
280
280
|
`global css: ${sources.length} source${sources.length === 1 ? '' : 's'} — ${sources
|
|
281
281
|
.map(file => path.relative(config.root, file))
|
|
282
282
|
.join(', ')}`,
|
|
283
|
-
)
|
|
283
|
+
)
|
|
284
284
|
|
|
285
285
|
await log.step('global css: esbuild bundle', () =>
|
|
286
286
|
build({
|
|
@@ -310,60 +310,60 @@ export async function buildGlobalCss(config: ResolvedConfig, options: CssBuildOp
|
|
|
310
310
|
'.ico': 'file',
|
|
311
311
|
},
|
|
312
312
|
}),
|
|
313
|
-
)
|
|
313
|
+
)
|
|
314
314
|
if (hasPostcssConfig(config.root)) {
|
|
315
|
-
await rewriteTailwindConfigDirectives(outfile, sources)
|
|
315
|
+
await rewriteTailwindConfigDirectives(outfile, sources)
|
|
316
316
|
await log.step('global css: postcss', () =>
|
|
317
317
|
runPostcssOffThread(config, outfile, options, sources[0]),
|
|
318
|
-
)
|
|
318
|
+
)
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
log.log(`global css → ${path.relative(config.root, outfile)}`)
|
|
322
|
-
return outfile
|
|
321
|
+
log.log(`global css → ${path.relative(config.root, outfile)}`)
|
|
322
|
+
return outfile
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
function moduleSpecifiers(source: string) {
|
|
326
|
-
const specifiers: string[] = []
|
|
327
|
-
const pattern = /(?:import|export)\s+(?:[^'";]+?\s+from\s+)?['"]([^'"]+)['"]/g
|
|
328
|
-
let match: RegExpExecArray | null
|
|
326
|
+
const specifiers: string[] = []
|
|
327
|
+
const pattern = /(?:import|export)\s+(?:[^'";]+?\s+from\s+)?['"]([^'"]+)['"]/g
|
|
328
|
+
let match: RegExpExecArray | null
|
|
329
329
|
|
|
330
330
|
while ((match = pattern.exec(source))) {
|
|
331
|
-
if (match[1]) specifiers.push(match[1])
|
|
331
|
+
if (match[1]) specifiers.push(match[1])
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
return specifiers
|
|
334
|
+
return specifiers
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
function cssFileExtensions() {
|
|
338
|
-
return ['.css', ...getCssExtensions().extraCssExtensions()]
|
|
338
|
+
return ['.css', ...getCssExtensions().extraCssExtensions()]
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
export function isCssFile(file: string) {
|
|
342
|
-
return cssFileExtensions().some(extension => file.endsWith(extension))
|
|
342
|
+
return cssFileExtensions().some(extension => file.endsWith(extension))
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
function cssLoaderEntries() {
|
|
346
346
|
return Object.fromEntries(
|
|
347
|
-
getCssExtensions()
|
|
348
|
-
|
|
347
|
+
getCssExtensions()
|
|
348
|
+
.extraCssExtensions()
|
|
349
|
+
.map(extension => [extension, 'css'] as const),
|
|
350
|
+
)
|
|
349
351
|
}
|
|
350
352
|
|
|
351
353
|
// The compat CSS-chunk plan (Next `experimental.cssChunking`), computed once
|
|
352
354
|
// across all routes by prepareRouteCssChunks before the per-route build loop.
|
|
353
355
|
// Pure-core apps never populate it, so every route keeps its single chunk.
|
|
354
|
-
const routeCssPlan = new Map<string, string[][]>()
|
|
356
|
+
const routeCssPlan = new Map<string, string[][]>()
|
|
355
357
|
|
|
356
358
|
// Partition each route's ordered cssImports into chunk slices via the compat
|
|
357
359
|
// registry (Next's CSS chunking). Must run before buildRouteCss so the loop can
|
|
358
360
|
// emit one asset per slice; a no-op for pure-core apps (empty plan).
|
|
359
|
-
export function prepareRouteCssChunks(
|
|
360
|
-
|
|
361
|
-
) {
|
|
362
|
-
routeCssPlan.clear();
|
|
361
|
+
export function prepareRouteCssChunks(routes: Pick<RouteManifestEntry, 'id' | 'cssImports'>[]) {
|
|
362
|
+
routeCssPlan.clear()
|
|
363
363
|
const plan = getCssExtensions().planRouteCssChunks(
|
|
364
364
|
routes.map(route => ({ id: route.id, cssImports: route.cssImports })),
|
|
365
|
-
)
|
|
366
|
-
for (const [id, segments] of plan) routeCssPlan.set(id, segments)
|
|
365
|
+
)
|
|
366
|
+
for (const [id, segments] of plan) routeCssPlan.set(id, segments)
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
export async function buildRouteCss(
|
|
@@ -371,12 +371,12 @@ export async function buildRouteCss(
|
|
|
371
371
|
route: RouteManifestEntry,
|
|
372
372
|
options: CssBuildOptions = {},
|
|
373
373
|
) {
|
|
374
|
-
if (route.cssImports.length === 0) return undefined
|
|
375
|
-
const segments = routeCssPlan.get(route.id)
|
|
374
|
+
if (route.cssImports.length === 0) return undefined
|
|
375
|
+
const segments = routeCssPlan.get(route.id)
|
|
376
376
|
if (segments && segments.length > 1) {
|
|
377
|
-
const assetNames = segments.map((_, index) => `${route.id}-${index}.css`)
|
|
378
|
-
route.cssAssets = assetNames
|
|
379
|
-
const files: string[] = []
|
|
377
|
+
const assetNames = segments.map((_, index) => `${route.id}-${index}.css`)
|
|
378
|
+
route.cssAssets = assetNames
|
|
379
|
+
const files: string[] = []
|
|
380
380
|
for (const [index, segment] of segments.entries()) {
|
|
381
381
|
files.push(
|
|
382
382
|
await bundleCssChunk(
|
|
@@ -386,12 +386,18 @@ export async function buildRouteCss(
|
|
|
386
386
|
`route css ${route.route} #${index + 1}`,
|
|
387
387
|
options,
|
|
388
388
|
),
|
|
389
|
-
)
|
|
389
|
+
)
|
|
390
390
|
}
|
|
391
|
-
return files
|
|
391
|
+
return files
|
|
392
392
|
}
|
|
393
|
-
route.cssAssets = undefined
|
|
394
|
-
return bundleCssChunk(
|
|
393
|
+
route.cssAssets = undefined
|
|
394
|
+
return bundleCssChunk(
|
|
395
|
+
config,
|
|
396
|
+
route.cssImports,
|
|
397
|
+
`${route.id}.css`,
|
|
398
|
+
`route css ${route.route}`,
|
|
399
|
+
options,
|
|
400
|
+
)
|
|
395
401
|
}
|
|
396
402
|
|
|
397
403
|
// The synthetic document conventions are created at render time and never
|
|
@@ -400,7 +406,7 @@ export async function buildRouteCss(
|
|
|
400
406
|
// an unmatched URL rendering the root not-found ships `/assets/not-found.css`
|
|
401
407
|
// (its own CSS) alongside `/assets/global.css` (the root layout's CSS).
|
|
402
408
|
export async function buildNotFoundCss(config: ResolvedConfig, options: CssBuildOptions = {}) {
|
|
403
|
-
const { collectFileCss } = await import('../routing/routes')
|
|
409
|
+
const { collectFileCss } = await import('../routing/routes')
|
|
404
410
|
const targets: { id: string; files: string[]; includeGlobalCss?: boolean }[] = [
|
|
405
411
|
{
|
|
406
412
|
id: 'not-found',
|
|
@@ -418,18 +424,18 @@ export async function buildNotFoundCss(config: ResolvedConfig, options: CssBuild
|
|
|
418
424
|
id: 'global-error',
|
|
419
425
|
files: conventionCandidates(config.appPath, 'global-error'),
|
|
420
426
|
},
|
|
421
|
-
]
|
|
427
|
+
]
|
|
422
428
|
for (const target of targets) {
|
|
423
429
|
const cssImports = await collectFileCss(config.appPath, target.files, {
|
|
424
430
|
includeGlobalCss: target.includeGlobalCss ?? false,
|
|
425
|
-
})
|
|
426
|
-
if (cssImports.length === 0) continue
|
|
427
|
-
await bundleCssChunk(config, cssImports, `${target.id}.css`, `route css /${target.id}`, options)
|
|
431
|
+
})
|
|
432
|
+
if (cssImports.length === 0) continue
|
|
433
|
+
await bundleCssChunk(config, cssImports, `${target.id}.css`, `route css /${target.id}`, options)
|
|
428
434
|
}
|
|
429
435
|
}
|
|
430
436
|
|
|
431
437
|
function conventionCandidates(appPath: string, base: string) {
|
|
432
|
-
return ['tsx', 'ts', 'jsx', 'js'].map(ext => path.join(appPath, `${base}.${ext}`))
|
|
438
|
+
return ['tsx', 'ts', 'jsx', 'js'].map(ext => path.join(appPath, `${base}.${ext}`))
|
|
433
439
|
}
|
|
434
440
|
|
|
435
441
|
// CSS reachable only through a non-SSR dynamic island ships as its own chunk
|
|
@@ -440,14 +446,14 @@ export async function buildClientReferenceCss(
|
|
|
440
446
|
reference: ClientReference,
|
|
441
447
|
options: CssBuildOptions = {},
|
|
442
448
|
) {
|
|
443
|
-
if (!reference.cssImports || reference.cssImports.length === 0) return undefined
|
|
449
|
+
if (!reference.cssImports || reference.cssImports.length === 0) return undefined
|
|
444
450
|
return bundleCssChunk(
|
|
445
451
|
config,
|
|
446
452
|
reference.cssImports,
|
|
447
453
|
`${reference.id}.css`,
|
|
448
454
|
`island css ${reference.id}`,
|
|
449
455
|
options,
|
|
450
|
-
)
|
|
456
|
+
)
|
|
451
457
|
}
|
|
452
458
|
|
|
453
459
|
async function bundleCssChunk(
|
|
@@ -457,15 +463,15 @@ async function bundleCssChunk(
|
|
|
457
463
|
label: string,
|
|
458
464
|
options: CssBuildOptions,
|
|
459
465
|
) {
|
|
460
|
-
const log = createVerboseLogger(options.verbose ?? false, 'css')
|
|
466
|
+
const log = createVerboseLogger(options.verbose ?? false, 'css')
|
|
461
467
|
|
|
462
468
|
const outDir = options.dev
|
|
463
469
|
? path.join(config.outPath, 'cache', 'assets')
|
|
464
|
-
: path.join(config.outPath, 'public', 'assets')
|
|
465
|
-
const outfile = path.join(outDir, assetName)
|
|
466
|
-
await ensureDir(outDir)
|
|
470
|
+
: path.join(config.outPath, 'public', 'assets')
|
|
471
|
+
const outfile = path.join(outDir, assetName)
|
|
472
|
+
await ensureDir(outDir)
|
|
467
473
|
|
|
468
|
-
log.log(`${label}: ${cssImports.length} import${cssImports.length === 1 ? '' : 's'}`)
|
|
474
|
+
log.log(`${label}: ${cssImports.length} import${cssImports.length === 1 ? '' : 's'}`)
|
|
469
475
|
|
|
470
476
|
await build({
|
|
471
477
|
stdin: {
|
|
@@ -496,19 +502,19 @@ async function bundleCssChunk(
|
|
|
496
502
|
'.svg': 'file',
|
|
497
503
|
'.ico': 'file',
|
|
498
504
|
},
|
|
499
|
-
})
|
|
505
|
+
})
|
|
500
506
|
|
|
501
507
|
if (hasPostcssConfig(config.root)) {
|
|
502
|
-
await rewriteTailwindConfigDirectives(outfile, cssImports)
|
|
503
|
-
await log.step(`${label}: postcss`, () => runPostcssOffThread(config, outfile, options))
|
|
508
|
+
await rewriteTailwindConfigDirectives(outfile, cssImports)
|
|
509
|
+
await log.step(`${label}: postcss`, () => runPostcssOffThread(config, outfile, options))
|
|
504
510
|
}
|
|
505
511
|
|
|
506
|
-
return outfile
|
|
512
|
+
return outfile
|
|
507
513
|
}
|
|
508
514
|
|
|
509
515
|
export function registerCssRuntime() {
|
|
510
|
-
if (cssRuntimeRegistered) return
|
|
511
|
-
cssRuntimeRegistered = true
|
|
516
|
+
if (cssRuntimeRegistered) return
|
|
517
|
+
cssRuntimeRegistered = true
|
|
512
518
|
|
|
513
519
|
Bun.plugin({
|
|
514
520
|
name: 'pnext-css-runtime',
|
|
@@ -523,15 +529,15 @@ export function registerCssRuntime() {
|
|
|
523
529
|
contents: 'export default undefined;',
|
|
524
530
|
loader: 'js',
|
|
525
531
|
},
|
|
526
|
-
)
|
|
532
|
+
)
|
|
527
533
|
},
|
|
528
|
-
})
|
|
534
|
+
})
|
|
529
535
|
}
|
|
530
536
|
|
|
531
537
|
// Sass is unsupported (no compiler); its imports still must not break the
|
|
532
538
|
// bundle, so .scss/.sass load as empty modules with module class-name maps.
|
|
533
539
|
function isCssModuleFile(file: string) {
|
|
534
|
-
return /\.module\.(?:css|scss|sass)$/.test(file)
|
|
540
|
+
return /\.module\.(?:css|scss|sass)$/.test(file)
|
|
535
541
|
}
|
|
536
542
|
|
|
537
543
|
export function cssModuleClientPlugin(): Plugin {
|
|
@@ -543,9 +549,9 @@ export function cssModuleClientPlugin(): Plugin {
|
|
|
543
549
|
? `export default ${JSON.stringify(await cssModuleMapping(file))};`
|
|
544
550
|
: 'export default undefined;',
|
|
545
551
|
loader: 'js',
|
|
546
|
-
}))
|
|
552
|
+
}))
|
|
547
553
|
},
|
|
548
|
-
}
|
|
554
|
+
}
|
|
549
555
|
}
|
|
550
556
|
|
|
551
557
|
function cssModuleBuildPlugin(): Plugin {
|
|
@@ -555,43 +561,43 @@ function cssModuleBuildPlugin(): Plugin {
|
|
|
555
561
|
plugin.onLoad({ filter: /\.module\.css$/ }, async ({ path: file }) => ({
|
|
556
562
|
contents: transformCssModule(await readText(file), file),
|
|
557
563
|
loader: 'css',
|
|
558
|
-
}))
|
|
564
|
+
}))
|
|
559
565
|
},
|
|
560
|
-
}
|
|
566
|
+
}
|
|
561
567
|
}
|
|
562
568
|
|
|
563
569
|
async function cssModuleMapping(file: string) {
|
|
564
570
|
// Compat handles *.module.{scss,sass} (sass compiles + scopes); core keeps
|
|
565
571
|
// plain .module.css. Lazy read: the registry populates at compat bootstrap.
|
|
566
|
-
const compatMapping = getCssExtensions().resolveCssModule(file)
|
|
567
|
-
if (compatMapping) return compatMapping
|
|
568
|
-
const source = await readText(file)
|
|
569
|
-
const classNames = cssClassNames(source)
|
|
572
|
+
const compatMapping = getCssExtensions().resolveCssModule(file)
|
|
573
|
+
if (compatMapping) return compatMapping
|
|
574
|
+
const source = await readText(file)
|
|
575
|
+
const classNames = cssClassNames(source)
|
|
570
576
|
|
|
571
577
|
return Object.fromEntries(
|
|
572
578
|
[...classNames].map(className => [className, cssModuleClassName(file, className)]),
|
|
573
|
-
)
|
|
579
|
+
)
|
|
574
580
|
}
|
|
575
581
|
|
|
576
582
|
function cssClassNames(source: string) {
|
|
577
|
-
const classNames = new Set<string>()
|
|
578
|
-
const classPattern = /(^|[^\\])\.(-?[_a-zA-Z][\w-]*)/g
|
|
579
|
-
let match: RegExpExecArray | null
|
|
583
|
+
const classNames = new Set<string>()
|
|
584
|
+
const classPattern = /(^|[^\\])\.(-?[_a-zA-Z][\w-]*)/g
|
|
585
|
+
let match: RegExpExecArray | null
|
|
580
586
|
|
|
581
587
|
while ((match = classPattern.exec(source))) {
|
|
582
|
-
if (match[2]) classNames.add(match[2])
|
|
588
|
+
if (match[2]) classNames.add(match[2])
|
|
583
589
|
}
|
|
584
590
|
|
|
585
|
-
return classNames
|
|
591
|
+
return classNames
|
|
586
592
|
}
|
|
587
593
|
|
|
588
594
|
function transformCssModule(source: string, file: string) {
|
|
589
|
-
let css = source
|
|
595
|
+
let css = source
|
|
590
596
|
for (const className of cssClassNames(source)) {
|
|
591
|
-
css = rewriteClassSelector(css, cssModuleClassName(file, className), className)
|
|
597
|
+
css = rewriteClassSelector(css, cssModuleClassName(file, className), className)
|
|
592
598
|
}
|
|
593
|
-
css = scopeKeyframes(css, file)
|
|
594
|
-
return css
|
|
599
|
+
css = scopeKeyframes(css, file)
|
|
600
|
+
return css
|
|
595
601
|
}
|
|
596
602
|
|
|
597
603
|
// CSS-module `@keyframes` names are scoped like class names, so a local animation `example` from two
|
|
@@ -599,25 +605,22 @@ function transformCssModule(source: string, file: string) {
|
|
|
599
605
|
// reference to it are rewritten to the scoped name. `grid-area` names are NOT identifiers of this kind and
|
|
600
606
|
// are left untouched.
|
|
601
607
|
function scopeKeyframes(css: string, file: string) {
|
|
602
|
-
const names = keyframeNames(css)
|
|
603
|
-
if (names.size === 0) return css
|
|
608
|
+
const names = keyframeNames(css)
|
|
609
|
+
if (names.size === 0) return css
|
|
604
610
|
|
|
605
|
-
let out = css
|
|
611
|
+
let out = css
|
|
606
612
|
for (const name of names) {
|
|
607
|
-
const scoped = cssModuleClassName(file, name)
|
|
613
|
+
const scoped = cssModuleClassName(file, name)
|
|
608
614
|
// Rename the @keyframes / @-webkit-keyframes block name.
|
|
609
615
|
out = out.replace(
|
|
610
616
|
new RegExp(`(@(?:-webkit-)?keyframes\\s+)${escapeRegex(name)}(?![-_a-zA-Z0-9])`, 'g'),
|
|
611
617
|
`$1${scoped}`,
|
|
612
|
-
)
|
|
618
|
+
)
|
|
613
619
|
// Rename `animation-name: name`.
|
|
614
620
|
out = out.replace(
|
|
615
|
-
new RegExp(
|
|
616
|
-
`(animation-name\\s*:\\s*)${escapeRegex(name)}(?![-_a-zA-Z0-9])`,
|
|
617
|
-
'g',
|
|
618
|
-
),
|
|
621
|
+
new RegExp(`(animation-name\\s*:\\s*)${escapeRegex(name)}(?![-_a-zA-Z0-9])`, 'g'),
|
|
619
622
|
`$1${scoped}`,
|
|
620
|
-
)
|
|
623
|
+
)
|
|
621
624
|
// Rename the name inside an `animation:` shorthand (token-bounded).
|
|
622
625
|
out = out.replace(
|
|
623
626
|
new RegExp(
|
|
@@ -625,84 +628,84 @@ function scopeKeyframes(css: string, file: string) {
|
|
|
625
628
|
'g',
|
|
626
629
|
),
|
|
627
630
|
`$1${scoped}`,
|
|
628
|
-
)
|
|
631
|
+
)
|
|
629
632
|
}
|
|
630
|
-
return out
|
|
633
|
+
return out
|
|
631
634
|
}
|
|
632
635
|
|
|
633
636
|
function keyframeNames(css: string) {
|
|
634
|
-
const names = new Set<string>()
|
|
635
|
-
const pattern = /@(?:-webkit-)?keyframes\s+(-?[_a-zA-Z][\w-]*)/g
|
|
636
|
-
let match: RegExpExecArray | null
|
|
637
|
+
const names = new Set<string>()
|
|
638
|
+
const pattern = /@(?:-webkit-)?keyframes\s+(-?[_a-zA-Z][\w-]*)/g
|
|
639
|
+
let match: RegExpExecArray | null
|
|
637
640
|
while ((match = pattern.exec(css))) {
|
|
638
|
-
if (match[1]) names.add(match[1])
|
|
641
|
+
if (match[1]) names.add(match[1])
|
|
639
642
|
}
|
|
640
|
-
return names
|
|
643
|
+
return names
|
|
641
644
|
}
|
|
642
645
|
|
|
643
646
|
function cssModuleClassName(file: string, className: string) {
|
|
644
647
|
const base = path
|
|
645
648
|
.basename(file)
|
|
646
649
|
.replace(/\.module\.css$/, '')
|
|
647
|
-
.replace(/[^_a-zA-Z0-9]/g, '_')
|
|
648
|
-
const hash = pathHash(cssModuleScopePath(file))
|
|
649
|
-
return `${base}_${className}_${hash}
|
|
650
|
+
.replace(/[^_a-zA-Z0-9]/g, '_')
|
|
651
|
+
const hash = pathHash(cssModuleScopePath(file))
|
|
652
|
+
return `${base}_${className}_${hash}`
|
|
650
653
|
}
|
|
651
654
|
|
|
652
655
|
function cssModuleScopePath(file: string) {
|
|
653
|
-
const normalized = file.split(path.sep).join('/')
|
|
654
|
-
const appIndex = normalized.lastIndexOf('/app/')
|
|
655
|
-
if (appIndex !== -1) return normalized.slice(appIndex + 1)
|
|
656
|
-
return normalized.split('/').slice(-3).join('/')
|
|
656
|
+
const normalized = file.split(path.sep).join('/')
|
|
657
|
+
const appIndex = normalized.lastIndexOf('/app/')
|
|
658
|
+
if (appIndex !== -1) return normalized.slice(appIndex + 1)
|
|
659
|
+
return normalized.split('/').slice(-3).join('/')
|
|
657
660
|
}
|
|
658
661
|
|
|
659
662
|
function rewriteClassSelector(css: string, scopedClassName: string, originalClassName: string) {
|
|
660
663
|
const esbuildNamePattern = new RegExp(
|
|
661
664
|
`\\.${escapeRegex(originalClassName)}(?![-_a-zA-Z0-9])`,
|
|
662
665
|
'g',
|
|
663
|
-
)
|
|
664
|
-
return css.replace(esbuildNamePattern, `.${scopedClassName}`)
|
|
666
|
+
)
|
|
667
|
+
return css.replace(esbuildNamePattern, `.${scopedClassName}`)
|
|
665
668
|
}
|
|
666
669
|
|
|
667
670
|
function pathHash(file: string) {
|
|
668
|
-
let hash = 5381
|
|
669
|
-
for (const char of file) hash = ((hash << 5) + hash) ^ char.charCodeAt(0)
|
|
670
|
-
return (hash >>> 0).toString(36).slice(0, 5)
|
|
671
|
+
let hash = 5381
|
|
672
|
+
for (const char of file) hash = ((hash << 5) + hash) ^ char.charCodeAt(0)
|
|
673
|
+
return (hash >>> 0).toString(36).slice(0, 5)
|
|
671
674
|
}
|
|
672
675
|
|
|
673
676
|
function escapeRegex(value: string) {
|
|
674
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
677
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
675
678
|
}
|
|
676
679
|
|
|
677
680
|
function hasPostcssConfig(root: string) {
|
|
678
|
-
return postcssConfigFile(root) !== undefined
|
|
681
|
+
return postcssConfigFile(root) !== undefined
|
|
679
682
|
}
|
|
680
683
|
|
|
681
684
|
// Bundling moves the CSS away from the directory its `@config` paths were
|
|
682
685
|
// written against, and Tailwind resolves them against postcss's `from` (the
|
|
683
686
|
// original source, not the outfile). Absolute paths sidestep both bases.
|
|
684
687
|
export async function rewriteTailwindConfigDirectives(cssFile: string, sources: string[]) {
|
|
685
|
-
const candidateDirs = [path.dirname(cssFile), ...sources.map(file => path.dirname(file))]
|
|
686
|
-
let css = await readText(cssFile)
|
|
687
|
-
let changed = false
|
|
688
|
+
const candidateDirs = [path.dirname(cssFile), ...sources.map(file => path.dirname(file))]
|
|
689
|
+
let css = await readText(cssFile)
|
|
690
|
+
let changed = false
|
|
688
691
|
|
|
689
692
|
css = css.replace(
|
|
690
693
|
/@config\s+(['"])([^'"]+)\1\s*;/g,
|
|
691
694
|
(match, quote: string, specifier: string) => {
|
|
692
|
-
if (!isRelativeSpecifier(specifier)) return match
|
|
695
|
+
if (!isRelativeSpecifier(specifier)) return match
|
|
693
696
|
const resolved = candidateDirs
|
|
694
697
|
.map(dir => path.resolve(dir, specifier))
|
|
695
|
-
.find(file => existsSync(file))
|
|
696
|
-
if (!resolved) return match
|
|
698
|
+
.find(file => existsSync(file))
|
|
699
|
+
if (!resolved) return match
|
|
697
700
|
|
|
698
|
-
changed = true
|
|
699
|
-
return `@config ${quote}${resolved.split(path.sep).join('/')}${quote}
|
|
701
|
+
changed = true
|
|
702
|
+
return `@config ${quote}${resolved.split(path.sep).join('/')}${quote};`
|
|
700
703
|
},
|
|
701
|
-
)
|
|
704
|
+
)
|
|
702
705
|
|
|
703
|
-
if (changed) await writeFile(cssFile, css)
|
|
706
|
+
if (changed) await writeFile(cssFile, css)
|
|
704
707
|
}
|
|
705
708
|
|
|
706
709
|
function isRelativeSpecifier(specifier: string) {
|
|
707
|
-
return specifier.startsWith('./') || specifier.startsWith('../')
|
|
710
|
+
return specifier.startsWith('./') || specifier.startsWith('../')
|
|
708
711
|
}
|