@wular/pnext 0.0.4 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/README.md +22 -16
  2. package/bin/pnext +6 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +87 -22
  8. package/reference/config.md +40 -93
  9. package/reference/css.md +42 -33
  10. package/reference/dev.md +26 -33
  11. package/reference/env.md +18 -20
  12. package/reference/getting-started.md +132 -0
  13. package/reference/metadata.md +31 -46
  14. package/reference/navigation.md +65 -105
  15. package/reference/performance.md +21 -142
  16. package/reference/rendering.md +78 -75
  17. package/reference/routing.md +97 -107
  18. package/reference/typegen.md +27 -29
  19. package/src/api/cache.ts +36 -37
  20. package/src/api/client-cache.ts +2 -2
  21. package/src/api/client-navigation.ts +121 -114
  22. package/src/api/dynamic.tsx +58 -55
  23. package/src/api/link.tsx +52 -53
  24. package/src/api/navigation.ts +59 -58
  25. package/src/api/server.ts +152 -144
  26. package/src/api/suspense.ts +4 -4
  27. package/src/cli/adapters/vercel-warm.ts +126 -121
  28. package/src/cli/adapters/vercel.ts +437 -443
  29. package/src/cli/analyze.ts +333 -144
  30. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  31. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  32. package/src/cli/build.ts +976 -978
  33. package/src/cli/create.ts +72 -64
  34. package/src/cli/dev.ts +116 -116
  35. package/src/cli/index.ts +94 -85
  36. package/src/cli/migrate/package-json.ts +73 -71
  37. package/src/cli/migrate/report.ts +32 -33
  38. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  39. package/src/cli/migrate/scan.ts +46 -46
  40. package/src/cli/migrate/spinner.ts +9 -9
  41. package/src/cli/migrate/tsconfig.ts +35 -35
  42. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  43. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  44. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  45. package/src/cli/start.ts +65 -66
  46. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  47. package/src/client/build.ts +802 -768
  48. package/src/client/chunk-fold.ts +245 -240
  49. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  50. package/src/client/entry.ts +162 -147
  51. package/src/client/prebuilt.ts +231 -223
  52. package/src/client/profile.ts +29 -29
  53. package/src/client/react-compiler.ts +20 -15
  54. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  55. package/src/client/reference-stub.ts +51 -51
  56. package/src/client/reference.ts +19 -19
  57. package/src/{api → client}/router/events.ts +32 -17
  58. package/src/{api → client}/router/history.ts +16 -16
  59. package/src/{api → client}/router/hub.ts +52 -53
  60. package/src/{api/router.ts → client/router/index.ts} +61 -60
  61. package/src/{api → client}/router/policies.ts +24 -24
  62. package/src/{api → client}/router/runtime.ts +2022 -1995
  63. package/src/{api → client}/router/types.ts +98 -98
  64. package/src/compat/actions/client-plugin.ts +42 -43
  65. package/src/compat/actions/client-stub.ts +14 -14
  66. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  67. package/src/compat/actions/config.ts +63 -64
  68. package/src/compat/actions/detect.ts +68 -68
  69. package/src/compat/actions/discovery.ts +105 -105
  70. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  71. package/src/compat/actions/early-submit.ts +1 -1
  72. package/src/compat/actions/endpoint.ts +198 -198
  73. package/src/compat/actions/extensions.ts +811 -0
  74. package/src/compat/actions/flight.ts +23 -23
  75. package/src/compat/actions/form-state.ts +34 -34
  76. package/src/compat/actions/hoist.ts +382 -236
  77. package/src/compat/actions/ids.ts +7 -12
  78. package/src/compat/actions/index.ts +8 -8
  79. package/src/compat/actions/instances.ts +46 -46
  80. package/src/compat/actions/origin.ts +47 -48
  81. package/src/compat/actions/protocol.ts +22 -22
  82. package/src/compat/actions/registry.ts +19 -19
  83. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  84. package/src/compat/actions/rewrite.ts +125 -125
  85. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  86. package/src/compat/actions/serve.ts +132 -136
  87. package/src/compat/actions/server-tag.ts +4 -4
  88. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  89. package/src/compat/actions/unrecognized-error.ts +4 -4
  90. package/src/compat/{index.ts → aliases.ts} +112 -109
  91. package/src/compat/bundler/bun-externals.ts +18 -18
  92. package/src/compat/bundler/cjs-exports.ts +271 -223
  93. package/src/compat/bundler/config.ts +116 -111
  94. package/src/compat/bundler/externals.ts +12 -12
  95. package/src/compat/bundler/import-meta-url.ts +19 -19
  96. package/src/compat/bundler/modularize-imports.ts +36 -33
  97. package/src/compat/bundler/new-url-asset.ts +22 -24
  98. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  99. package/src/compat/bundler/polyfill.ts +28 -28
  100. package/src/compat/bundler/react-compiler.ts +35 -29
  101. package/src/compat/bundler/react-profiler.tsx +11 -11
  102. package/src/compat/bundler/relay-transform.ts +48 -47
  103. package/src/compat/bundler/require-context.ts +119 -113
  104. package/src/compat/bundler/resolve-extensions.ts +19 -19
  105. package/src/compat/bundler/source-cache.ts +25 -25
  106. package/src/compat/bundler/static-imports.ts +7 -7
  107. package/src/compat/bundler/symlink-imports.ts +46 -46
  108. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  109. package/src/compat/bundler/wasm.ts +58 -60
  110. package/src/compat/bundler/webpack-loaders.ts +254 -241
  111. package/src/compat/bundler/worker.ts +101 -104
  112. package/src/compat/cache/build-flags.ts +29 -29
  113. package/src/compat/cache/build-prerender-errors.ts +40 -44
  114. package/src/compat/cache/custom-handler.ts +60 -53
  115. package/src/compat/cache/fetch-patch.ts +240 -240
  116. package/src/compat/cache/handler.ts +27 -31
  117. package/src/compat/cache/modern-handler.ts +148 -126
  118. package/src/compat/cache/resume-data-cache.ts +47 -45
  119. package/src/compat/cache/revalidate.ts +233 -232
  120. package/src/compat/cache/runtime-error.ts +35 -35
  121. package/src/compat/cache/use-cache-transform.ts +442 -417
  122. package/src/compat/cache/use-cache.ts +650 -614
  123. package/src/compat/cache-control.ts +140 -142
  124. package/src/compat/client/base-path.ts +21 -20
  125. package/src/compat/client/css-order.ts +18 -18
  126. package/src/compat/client/errors/bare-boundary.ts +11 -11
  127. package/src/compat/client/errors/control-flow.ts +23 -23
  128. package/src/compat/client/errors/error-boundary.ts +61 -61
  129. package/src/compat/client/errors/global-error.ts +101 -91
  130. package/src/compat/client/errors/install.ts +71 -72
  131. package/src/compat/client/errors/lazy.ts +23 -23
  132. package/src/compat/client/errors/primitive-throw.ts +47 -45
  133. package/src/compat/client/errors/soft-refresh.ts +4 -4
  134. package/src/compat/client/link-status.ts +33 -33
  135. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  136. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  137. package/src/compat/client/navigation-scroll.ts +63 -63
  138. package/src/compat/client/optimistic-routing.ts +93 -88
  139. package/src/compat/client/prefetch-cache.ts +23 -24
  140. package/src/compat/client/route-announcer.ts +35 -35
  141. package/src/compat/client/segment-cache-policy.ts +20 -20
  142. package/src/compat/client/segment-cache.ts +309 -315
  143. package/src/compat/client/segment-prefetch.ts +127 -132
  144. package/src/compat/client/trailing-slash.ts +5 -4
  145. package/src/compat/css/chunking.ts +113 -116
  146. package/src/compat/css/inline-css.ts +21 -21
  147. package/src/compat/css/lightningcss.ts +37 -38
  148. package/src/compat/css/modules.ts +161 -175
  149. package/src/compat/css/nonce.ts +7 -7
  150. package/src/compat/css/sass-plugin.ts +18 -21
  151. package/src/compat/css/sass.ts +150 -152
  152. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  153. package/src/compat/css/styled-jsx.ts +21 -21
  154. package/src/compat/edge-runtime.ts +27 -27
  155. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  156. package/src/compat/export/client.ts +29 -31
  157. package/src/compat/export/{index.ts → emit.ts} +111 -110
  158. package/src/compat/export/standalone.ts +62 -54
  159. package/src/compat/image-optimizer/cache.ts +51 -49
  160. package/src/compat/image-optimizer/detect.ts +52 -52
  161. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  162. package/src/compat/image-optimizer/source.ts +77 -80
  163. package/src/compat/lifecycle/after-scope.ts +26 -26
  164. package/src/compat/lifecycle/after.ts +48 -45
  165. package/src/compat/lifecycle/error-funnel.ts +98 -102
  166. package/src/compat/lifecycle/error-serialize.ts +30 -26
  167. package/src/compat/lifecycle/error-ui.ts +67 -32
  168. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  169. package/src/compat/lifecycle/instrumentation.ts +85 -85
  170. package/src/compat/lifecycle/node-console.ts +11 -11
  171. package/src/compat/lifecycle/testmode.ts +160 -132
  172. package/src/compat/mdx/compile.ts +60 -57
  173. package/src/compat/mdx/plugin.ts +11 -11
  174. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  175. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  176. package/src/compat/metadata.ts +75 -81
  177. package/src/compat/next/cache.ts +68 -69
  178. package/src/compat/next/canonical-url.ts +9 -9
  179. package/src/compat/next/client-cache.ts +19 -19
  180. package/src/compat/next/client-navigation.ts +112 -116
  181. package/src/compat/next/client-only.ts +1 -1
  182. package/src/compat/next/client-script.tsx +99 -93
  183. package/src/compat/next/client-server.ts +10 -10
  184. package/src/compat/next/config-loader.ts +176 -173
  185. package/src/compat/next/config.ts +7 -7
  186. package/src/compat/next/constants.cjs +6 -6
  187. package/src/compat/next/constants.ts +6 -6
  188. package/src/compat/next/custom-server.ts +26 -24
  189. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  190. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  191. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  192. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  193. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  194. package/src/compat/next/dynamic.tsx +21 -18
  195. package/src/compat/next/error.tsx +52 -52
  196. package/src/compat/next/font/cache.ts +74 -74
  197. package/src/compat/next/font/google.ts +2 -2
  198. package/src/compat/next/font/index.ts +1 -1
  199. package/src/compat/next/font/local.ts +3 -3
  200. package/src/compat/next/font/runtime-client.ts +17 -15
  201. package/src/compat/next/font/runtime.ts +443 -408
  202. package/src/compat/next/font/shared.ts +120 -108
  203. package/src/compat/next/form.tsx +63 -63
  204. package/src/compat/next/head.tsx +2 -2
  205. package/src/compat/next/headers.ts +103 -95
  206. package/src/compat/next/image/client.tsx +220 -0
  207. package/src/compat/next/image/config.ts +56 -58
  208. package/src/compat/next/image/optimizer.ts +40 -36
  209. package/src/compat/next/image/patterns.ts +37 -40
  210. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  211. package/src/compat/next/image/shared.ts +65 -57
  212. package/src/compat/next/image/static-metadata.ts +98 -107
  213. package/src/compat/next/image/validate.ts +79 -88
  214. package/src/compat/next/image.tsx +19 -23
  215. package/src/compat/next/index.ts +1 -1
  216. package/src/compat/next/legacy-image.tsx +59 -60
  217. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  218. package/src/compat/next/link.tsx +158 -158
  219. package/src/compat/next/navigation.cjs +12 -3
  220. package/src/compat/next/navigation.ts +48 -50
  221. package/src/compat/next/offline.ts +27 -27
  222. package/src/compat/next/og.ts +121 -124
  223. package/src/compat/next/preferred-region.ts +13 -14
  224. package/src/compat/next/redirects.ts +58 -56
  225. package/src/compat/next/resource-hints.ts +73 -76
  226. package/src/compat/next/rewrites.ts +130 -133
  227. package/src/compat/next/root-params.ts +45 -45
  228. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  229. package/src/compat/next/router.cjs +4 -2
  230. package/src/compat/next/router.ts +58 -61
  231. package/src/compat/next/script.tsx +108 -108
  232. package/src/compat/next/server-only.ts +1 -1
  233. package/src/compat/next/server.ts +19 -19
  234. package/src/compat/next/svgr.ts +18 -17
  235. package/src/compat/next/telemetry.ts +24 -24
  236. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  237. package/src/compat/next/user-agent.ts +53 -49
  238. package/src/compat/next/web-vitals.ts +22 -24
  239. package/src/compat/otel/api.ts +41 -41
  240. package/src/compat/otel/client-trace-metadata.ts +25 -27
  241. package/src/compat/otel/fetch-span.ts +29 -29
  242. package/src/compat/otel/tracer.ts +331 -331
  243. package/src/compat/pages/api.ts +456 -0
  244. package/src/compat/pages/client-plugin.ts +36 -36
  245. package/src/compat/pages/router-state.ts +34 -34
  246. package/src/compat/pages/{index.ts → router.ts} +130 -135
  247. package/src/compat/ppr/io.ts +12 -12
  248. package/src/compat/ppr/missing-root-params.ts +34 -38
  249. package/src/compat/ppr/root-params-scan.ts +66 -66
  250. package/src/compat/ppr/root-params-transform.ts +24 -26
  251. package/src/compat/ppr/root-params.ts +30 -30
  252. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  253. package/src/compat/protocol.ts +71 -70
  254. package/src/compat/react/action-state.ts +47 -48
  255. package/src/compat/react/client-lite.ts +15 -15
  256. package/src/compat/react/client.ts +4 -4
  257. package/src/compat/react/compiler-runtime.ts +11 -11
  258. package/src/compat/react/dom-client.ts +44 -44
  259. package/src/compat/react/dom-react-server.ts +10 -16
  260. package/src/compat/react/dom-server.ts +10 -10
  261. package/src/compat/react/dom.ts +52 -52
  262. package/src/compat/react/hooks-extra.ts +34 -35
  263. package/src/compat/react/parity.ts +64 -61
  264. package/src/compat/react/preact.ts +81 -82
  265. package/src/compat/react/react-server.ts +28 -28
  266. package/src/compat/react/router-shim.ts +1 -1
  267. package/src/compat/react/server-component-use.ts +8 -8
  268. package/src/compat/react/server-inserted-html.ts +30 -31
  269. package/src/compat/react/server.ts +53 -55
  270. package/src/compat/react/use.ts +32 -32
  271. package/src/compat/react/view-transition.ts +20 -20
  272. package/src/compat/register/actions.ts +35 -824
  273. package/src/compat/register/boot.ts +41 -41
  274. package/src/compat/register/build-tier.ts +5 -5
  275. package/src/compat/register/build.ts +74 -70
  276. package/src/compat/register/bundler.ts +161 -156
  277. package/src/compat/register/cache.ts +20 -20
  278. package/src/compat/register/client-errors.ts +3 -3
  279. package/src/compat/register/config.ts +6 -6
  280. package/src/compat/register/css-extras.ts +30 -34
  281. package/src/compat/register/edge-runtime.ts +3 -3
  282. package/src/compat/register/errors.ts +10 -12
  283. package/src/compat/register/export.ts +16 -16
  284. package/src/compat/register/font.ts +11 -11
  285. package/src/compat/register/hooks.ts +2 -2
  286. package/src/compat/register/image.ts +40 -40
  287. package/src/compat/register/index.ts +59 -62
  288. package/src/compat/register/instrumentation-client.ts +10 -10
  289. package/src/compat/register/lifecycle.ts +25 -28
  290. package/src/compat/register/mdx.ts +10 -10
  291. package/src/compat/register/middleware.ts +226 -16
  292. package/src/compat/register/otel.ts +80 -88
  293. package/src/compat/register/pages-api.ts +10 -463
  294. package/src/compat/register/ppr.ts +16 -16
  295. package/src/compat/register/protocol.ts +17 -18
  296. package/src/compat/register/proxy.ts +49 -51
  297. package/src/compat/register/render.ts +79 -76
  298. package/src/compat/register/routing.ts +162 -159
  299. package/src/compat/register/segment.ts +24 -1897
  300. package/src/compat/register/static-image.ts +3 -3
  301. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  302. package/src/compat/register/typed-routes.ts +14 -14
  303. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  304. package/src/compat/register/validation.ts +18 -18
  305. package/src/compat/segment/loading-boundary.ts +43 -45
  306. package/src/compat/segment/page-slot.ts +69 -69
  307. package/src/compat/segment/serve.ts +1884 -0
  308. package/src/compat/segment/tree.ts +113 -112
  309. package/src/compat/segment/vary-key.ts +38 -38
  310. package/src/compat/segment/vary-params.ts +138 -142
  311. package/src/compat/static-params.ts +14 -12
  312. package/src/compat/tsconfig-defaults.ts +87 -91
  313. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  314. package/src/compat/typecheck/worker.ts +15 -12
  315. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  316. package/src/compat/typed-routes/manifest.ts +174 -170
  317. package/src/compat/typed-routes/typegen.ts +127 -110
  318. package/src/compat/validation/errors.ts +16 -19
  319. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  320. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  321. package/src/compat-bootstrap.ts +16 -16
  322. package/src/config.ts +86 -69
  323. package/src/css/build.ts +230 -227
  324. package/src/css/postcss.ts +79 -80
  325. package/src/css/worker.ts +14 -15
  326. package/src/dev/client-actions.ts +10 -10
  327. package/src/dev/client-chunk-store.ts +27 -27
  328. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  329. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  330. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  331. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  332. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  333. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  334. package/src/dev/server.ts +804 -820
  335. package/src/env.ts +46 -43
  336. package/src/extensions.ts +491 -478
  337. package/src/index.ts +8 -8
  338. package/src/internal.ts +20 -23
  339. package/src/{islands → render}/boundary-error.ts +3 -3
  340. package/src/render/hooks.ts +71 -71
  341. package/src/render/island-context.ts +14 -14
  342. package/src/render/metadata.ts +310 -310
  343. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  344. package/src/{ppr.ts → render/ppr.ts} +244 -245
  345. package/src/render/renderer.ts +2087 -2082
  346. package/src/render/resource-hints.ts +16 -17
  347. package/src/render/slots.tsx +224 -235
  348. package/src/{islands → render}/static-children.ts +9 -12
  349. package/src/{islands → render}/static-slots.ts +37 -37
  350. package/src/{cache/context.ts → request/cache.ts} +20 -20
  351. package/src/request/context.ts +107 -107
  352. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  353. package/src/resolve/engine.ts +90 -77
  354. package/src/resolve/imports.ts +475 -463
  355. package/src/resolve/scan-facts.ts +318 -296
  356. package/src/resolve/source-text.ts +37 -37
  357. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  358. package/src/routing/forwarded.ts +19 -19
  359. package/src/routing/handler.ts +84 -91
  360. package/src/routing/href.ts +87 -70
  361. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  362. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  363. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  364. package/src/routing/routes.ts +827 -815
  365. package/src/routing/slots.ts +164 -160
  366. package/src/runtime/loader.ts +954 -0
  367. package/src/{dev → runtime}/module-cache.ts +309 -287
  368. package/src/{dev → runtime}/module-generations.ts +9 -9
  369. package/src/{dev → runtime}/module-transform.ts +81 -72
  370. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  371. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  372. package/src/runtime/vendor.ts +428 -406
  373. package/src/styles.d.ts +9 -0
  374. package/src/types.ts +324 -335
  375. package/src/utils/ansi.ts +5 -5
  376. package/src/utils/{source.ts → code.ts} +15 -12
  377. package/src/utils/content-type.ts +3 -3
  378. package/src/utils/decode.ts +2 -2
  379. package/src/utils/dev-profile.ts +13 -13
  380. package/src/utils/error-log.ts +6 -6
  381. package/src/utils/esbuild.ts +18 -18
  382. package/src/utils/fs-cache.ts +13 -13
  383. package/src/utils/fs.ts +57 -49
  384. package/src/utils/html.ts +20 -24
  385. package/src/utils/native-require.ts +8 -8
  386. package/src/utils/serialize.ts +139 -146
  387. package/src/utils/verbose.ts +18 -18
  388. package/reference/overview.md +0 -35
  389. package/src/cli/analyze-print.ts +0 -181
  390. package/src/compat/middleware/manifest.ts +0 -210
  391. package/src/compat/next/image-client.tsx +0 -215
  392. package/src/compat/next/link-usage.ts +0 -29
  393. package/src/css/index.ts +0 -2
  394. package/src/render/index.ts +0 -1
  395. 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().extraCssExtensions().map(extension => [extension, 'css'] as const),
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
- routes: Pick<RouteManifestEntry, 'id' | 'cssImports'>[],
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(config, route.cssImports, `${route.id}.css`, `route css ${route.route}`, options);
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
  }