@wular/pnext 0.0.3 → 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.
Files changed (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -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 +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1961
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1887
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +152 -143
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +442 -186
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +833 -848
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
package/src/cli/create.ts CHANGED
@@ -1,43 +1,45 @@
1
- import { existsSync } from 'node:fs';
2
- import { mkdir, readdir } from 'node:fs/promises';
3
- import path from 'node:path';
4
- import { bold, cyan, dim, green } from '../utils/ansi';
1
+ import { existsSync } from 'node:fs'
2
+ import { mkdir, readdir } from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import { bold, cyan, dim, green } from '../utils/ansi'
5
+ import { pnextVersionRange } from '../utils/fs'
6
+ import { formatDuration } from '../utils/verbose'
5
7
 
6
8
  export interface CreateAppOptions {
7
- install: boolean;
9
+ install: boolean
8
10
  }
9
11
 
10
12
  export async function createApp(dir: string | undefined, options: CreateAppOptions) {
11
13
  if (!dir) {
12
- console.log('Usage: pnext create <directory> [--no-install]');
13
- throw new Error('pnext create requires a directory argument');
14
+ console.log('Usage: pnext create <directory> [--no-install]')
15
+ throw new Error('pnext create requires a directory argument')
14
16
  }
15
17
 
16
- const target = path.resolve(dir);
18
+ const target = path.resolve(dir)
17
19
  if (existsSync(target)) {
18
20
  if ((await readdir(target)).length > 0) {
19
- throw new Error(`Directory already exists and is not empty: ${target}`);
21
+ throw new Error(`Directory already exists and is not empty: ${target}`)
20
22
  }
21
23
  } else {
22
- await mkdir(target, { recursive: true });
24
+ await mkdir(target, { recursive: true })
23
25
  }
24
26
 
25
- const name = sanitizePackageName(path.basename(target));
26
- console.log(`${cyan('▲')} ${bold('pnext create')} ${dim(`— scaffolding ${name}`)}\n`);
27
+ const name = sanitizePackageName(path.basename(target))
28
+ console.log(`${cyan('▲')} ${bold('pnext create')} ${dim(`— scaffolding ${name}`)}\n`)
27
29
 
28
- const files = scaffoldFiles(name);
30
+ const files = scaffoldFiles(name)
29
31
  await Promise.all(
30
32
  Object.entries(files).map(([file, source]) => Bun.write(path.join(target, file), source)),
31
- );
32
- for (const file of Object.keys(files)) console.log(` ${green('+')} ${dim(file)}`);
33
+ )
34
+ for (const file of Object.keys(files)) console.log(` ${green('+')} ${dim(file)}`)
33
35
 
34
- let installed = false;
36
+ let installed = false
35
37
  if (options.install) {
36
- console.log('');
37
- installed = await install(target, dir);
38
+ console.log('')
39
+ installed = await install(target, dir)
38
40
  }
39
41
 
40
- printNextSteps(dir, installed);
42
+ printNextSteps(dir, installed)
41
43
  }
42
44
 
43
45
  // npm package name rules: lowercase, url-safe, no leading dot/underscore.
@@ -46,71 +48,68 @@ function sanitizePackageName(raw: string) {
46
48
  .trim()
47
49
  .toLowerCase()
48
50
  .replace(/[^a-z0-9._-]+/g, '-')
49
- .replace(/^[-._]+|[-._]+$/g, '');
50
- return name || 'pnext-app';
51
+ .replace(/^[-._]+|[-._]+$/g, '')
52
+ return name || 'pnext-app'
51
53
  }
52
54
 
53
55
  async function install(target: string, dir: string) {
54
- const stop = spinner('Installing dependencies...');
55
- const start = Bun.nanoseconds();
56
- const proc = Bun.spawn(['bun', 'install'], { cwd: target, stdout: 'pipe', stderr: 'pipe' });
56
+ const stop = spinner('Installing dependencies...')
57
+ const start = Bun.nanoseconds()
58
+ const proc = Bun.spawn(['bun', 'install'], { cwd: target, stdout: 'pipe', stderr: 'pipe' })
57
59
  // Drain both pipes: an unread pipe can fill and stall the child.
58
60
  const [stderr, , code] = await Promise.all([
59
61
  new Response(proc.stderr).text(),
60
62
  new Response(proc.stdout).text(),
61
63
  proc.exited,
62
- ]);
63
- stop();
64
+ ])
65
+ stop()
64
66
 
65
67
  if (code === 0) {
66
- const durationMs = (Bun.nanoseconds() - start) / 1e6;
67
- console.log(`${green('✓')} ${bold('Installed dependencies')} ${dim(`in ${formatDuration(durationMs)}`)}`);
68
- return true;
68
+ const durationMs = (Bun.nanoseconds() - start) / 1e6
69
+ console.log(
70
+ `${green('✓')} ${bold('Installed dependencies')} ${dim(`in ${formatDuration(durationMs)}`)}`,
71
+ )
72
+ return true
69
73
  }
70
- console.log(`${dim('Install failed. Run it manually:')}`);
71
- console.log(` ${cyan('cd')} ${dir}`);
72
- console.log(` ${cyan('bun install')}`);
73
- if (stderr.trim()) console.log(dim(stderr.trim()));
74
- return false;
74
+ console.log(`${dim('Install failed. Run it manually:')}`)
75
+ console.log(` ${cyan('cd')} ${dir}`)
76
+ console.log(` ${cyan('bun install')}`)
77
+ if (stderr.trim()) console.log(dim(stderr.trim()))
78
+ return false
75
79
  }
76
80
 
77
81
  /** Braille spinner, TTY-only; a plain line prints once and stays put otherwise. */
78
82
  function spinner(label: string) {
79
83
  if (!process.stdout.isTTY) {
80
- console.log(label);
81
- return () => undefined;
84
+ console.log(label)
85
+ return () => undefined
82
86
  }
83
- const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
84
- let frame = 0;
85
- process.stdout.write(`${cyan(frames[0]!)} ${label}`);
87
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
88
+ let frame = 0
89
+ process.stdout.write(`${cyan(frames[0]!)} ${label}`)
86
90
  const timer = setInterval(() => {
87
- frame = (frame + 1) % frames.length;
88
- process.stdout.write(`\r${cyan(frames[frame]!)} ${label}`);
89
- }, 80);
91
+ frame = (frame + 1) % frames.length
92
+ process.stdout.write(`\r${cyan(frames[frame]!)} ${label}`)
93
+ }, 80)
90
94
  return () => {
91
- clearInterval(timer);
92
- process.stdout.write('\r\x1b[K');
93
- };
94
- }
95
-
96
- function formatDuration(durationMs: number) {
97
- const totalSeconds = Math.max(0, durationMs) / 1000;
98
- return `${totalSeconds.toFixed(totalSeconds < 10 ? 2 : 1)}s`;
95
+ clearInterval(timer)
96
+ process.stdout.write('\r\x1b[K')
97
+ }
99
98
  }
100
99
 
101
100
  function printNextSteps(dir: string, installed: boolean) {
102
- const commands = installed ? [`cd ${dir}`, 'bun dev'] : [`cd ${dir}`, 'bun install', 'bun dev'];
103
- const title = 'Next steps';
104
- const width = Math.max(title.length, ...commands.map(c => c.length)) + 2;
101
+ const commands = installed ? [`cd ${dir}`, 'bun dev'] : [`cd ${dir}`, 'bun install', 'bun dev']
102
+ const title = 'Next steps'
103
+ const width = Math.max(title.length, ...commands.map(c => c.length)) + 2
105
104
  const row = (text: string, colorFn: (s: string) => string = s => s) =>
106
- `${dim('│')} ${colorFn(text.padEnd(width))} ${dim('│')}`;
105
+ `${dim('│')} ${colorFn(text.padEnd(width))} ${dim('│')}`
107
106
 
108
- console.log('');
109
- console.log(dim(`┌${'─'.repeat(width + 2)}┐`));
110
- console.log(row(title, bold));
111
- console.log(row(''));
112
- for (const cmd of commands) console.log(row(cmd, cyan));
113
- console.log(dim(`└${'─'.repeat(width + 2)}┘`));
107
+ console.log('')
108
+ console.log(dim(`┌${'─'.repeat(width + 2)}┐`))
109
+ console.log(row(title, bold))
110
+ console.log(row(''))
111
+ for (const cmd of commands) console.log(row(cmd, cyan))
112
+ console.log(dim(`└${'─'.repeat(width + 2)}┘`))
114
113
  }
115
114
 
116
115
  function scaffoldFiles(name: string): Record<string, string> {
@@ -119,9 +118,18 @@ function scaffoldFiles(name: string): Record<string, string> {
119
118
  {
120
119
  name,
121
120
  private: true,
122
- scripts: { dev: 'pnext dev', build: 'pnext build', start: 'pnext start', analyze: 'pnext analyze' },
121
+ scripts: {
122
+ dev: 'pnext dev',
123
+ build: 'pnext build',
124
+ start: 'pnext start',
125
+ analyze: 'pnext analyze',
126
+ },
123
127
  dependencies: { preact: '^10' },
124
- devDependencies: { '@wular/pnext': '^0.0.1', typescript: '^5', '@types/bun': '^1' },
128
+ devDependencies: {
129
+ '@wular/pnext': pnextVersionRange(),
130
+ typescript: '^5',
131
+ '@types/bun': '^1',
132
+ },
125
133
  },
126
134
  null,
127
135
  2,
@@ -142,5 +150,5 @@ function scaffoldFiles(name: string): Record<string, string> {
142
150
  'app/globals.css': `body {\n margin: 0;\n font-family: system-ui, sans-serif;\n}\n`,
143
151
  '.gitignore': `node_modules\n.pnext\n`,
144
152
  'README.md': `# ${name}\n\nA pnext app.\n\n\`\`\`\nbun install\nbun dev\n\`\`\`\n\nDocs: node_modules/@wular/pnext/reference/overview.md\n`,
145
- };
153
+ }
146
154
  }
package/src/cli/dev.ts CHANGED
@@ -1,28 +1,28 @@
1
- import { dim } from '../utils/ansi';
2
- import { moduleGenerationStats } from '../dev/module-generations';
3
- import { markBoot, printBootTrace } from './boot-trace';
4
- import { browserHost, ensurePortFree, openBrowser, printServerReady } from './serve-ui';
1
+ import { dim } from '../utils/ansi'
2
+ import { moduleGenerationStats } from '../runtime/module-generations'
3
+ import { markBoot, printBootTrace } from './boot/trace'
4
+ import { browserHost, ensurePortFree, openBrowser, printServerReady } from './serve/ui'
5
5
 
6
- export const devProcessTitle = 'pnext-dev';
7
- export const devRestartEnv = 'PNEXT_DEV_RESTART';
6
+ export const devProcessTitle = 'pnext-dev'
7
+ export const devRestartEnv = 'PNEXT_DEV_RESTART'
8
8
 
9
- const defaultMaxDevRssMb = 2048;
10
- const defaultMaxEsbuildRssMb = 1024;
9
+ const defaultMaxDevRssMb = 2048
10
+ const defaultMaxEsbuildRssMb = 1024
11
11
  // A leaf edit supersedes a couple of generations, so this caps stale mass at roughly 300 MB -
12
12
  // about one recycle per 75 leaf edits, and one per ~30 on wide-shared-module edits that rename
13
13
  // most of a route graph.
14
- const defaultMaxStaleModules = 150;
14
+ const defaultMaxStaleModules = 150
15
15
  /** How long a recycle waits for in-flight responses before replacing the image. */
16
- const drainTimeoutMs = 5_000;
16
+ const drainTimeoutMs = 5_000
17
17
 
18
18
  export function nameDevProcess() {
19
- process.title = devProcessTitle;
19
+ process.title = devProcessTitle
20
20
  }
21
21
 
22
22
  export interface DevOptions {
23
- root?: string;
24
- port?: number;
25
- hostname?: string;
23
+ root?: string
24
+ port?: number
25
+ hostname?: string
26
26
  }
27
27
 
28
28
  /**
@@ -31,49 +31,49 @@ export interface DevOptions {
31
31
  * place, which frees the module graph without paying a second process spawn on every boot.
32
32
  */
33
33
  export async function dev(options: DevOptions = {}) {
34
- nameDevProcess();
34
+ nameDevProcess()
35
35
  // Loaded lazily so config resolution and the server graph start in parallel.
36
36
  const [{ loadConfig }, { startDevServer }] = await Promise.all([
37
37
  import('../config'),
38
38
  import('../dev/server'),
39
- ]);
40
- markBoot('dev:imports');
41
- const config = await loadConfig(options.root, { dev: true });
42
- markBoot('dev:config');
43
- const port = options.port ?? 3000;
44
- const hostname = options.hostname ?? 'localhost';
39
+ ])
40
+ markBoot('dev:imports')
41
+ const config = await loadConfig(options.root, { dev: true })
42
+ markBoot('dev:config')
43
+ const port = options.port ?? 3000
44
+ const hostname = options.hostname ?? 'localhost'
45
45
  // A memory-triggered restart can briefly race the previous listener's
46
46
  // shutdown, so give the port a moment to free before failing.
47
- await ensurePortFree(port, hostname, { attempts: 10 });
48
- markBoot('dev:port');
49
- const start = Date.now();
47
+ await ensurePortFree(port, hostname, { attempts: 10 })
48
+ markBoot('dev:port')
49
+ const start = Date.now()
50
50
  // Bisect switch, same role `PNEXT_DEV_RESTART_CACHE=0` plays for the restart
51
51
  // caches: turns the boot warm-up off so a measurement can price it.
52
52
  // eslint-disable-next-line turbo/no-undeclared-env-vars
53
- const warm = process.env.PNEXT_DEV_WARM !== '0';
54
- const server = await startDevServer({ config, port, hostname, warm });
55
- markBoot('dev:server');
56
- const elapsedMs = Date.now() - start;
57
- const url = `http://${browserHost(hostname)}:${server.port ?? port}`;
58
- printServerReady({ mode: 'dev', hostname, port: server.port ?? port, elapsedMs });
59
- printBootTrace();
53
+ const warm = process.env.PNEXT_DEV_WARM !== '0'
54
+ const server = await startDevServer({ config, port, hostname, warm })
55
+ markBoot('dev:server')
56
+ const elapsedMs = Date.now() - start
57
+ const url = `http://${browserHost(hostname)}:${server.port ?? port}`
58
+ printServerReady({ mode: 'dev', hostname, port: server.port ?? port, elapsedMs })
59
+ printBootTrace()
60
60
  // Boot compiles nothing (config loads natively), so the first compile would pay esbuild's service
61
61
  // spawn. Warm it here, after the banner - readiness must not wait on it. PNEXT_DEV_ESBUILD_WARM=0 opts out.
62
62
  // eslint-disable-next-line turbo/no-undeclared-env-vars
63
63
  if (process.env.PNEXT_DEV_ESBUILD_WARM !== '0') {
64
- void import('../utils/esbuild').then(module => module.warmEsbuildService());
64
+ void import('../utils/esbuild').then(module => module.warmEsbuildService())
65
65
  }
66
- registerShutdown(server);
67
- watchServerMemory(server);
68
- watchStaleModules(server);
69
- watchEsbuildMemory();
66
+ registerShutdown(server)
67
+ watchServerMemory(server)
68
+ watchStaleModules(server)
69
+ watchEsbuildMemory()
70
70
  // Hold the browser until the entry route has compiled, so it opens onto an
71
71
  // already-built page instead of a multi-second cold compile.
72
- if (server.warmup) console.log(dim('Warming up and opening the browser...'));
73
- await server.warmup;
72
+ if (server.warmup) console.log(dim('Warming up and opening the browser...'))
73
+ await server.warmup
74
74
  // A memory-triggered restart should refresh silently, not open another tab.
75
- if (process.env[devRestartEnv] !== '1') openBrowser(url);
76
- return server;
75
+ if (process.env[devRestartEnv] !== '1') openBrowser(url)
76
+ return server
77
77
  }
78
78
 
79
79
  // Every dev reload imports changed modules under fresh URLs, and the ES module
@@ -82,22 +82,22 @@ export async function dev(options: DevOptions = {}) {
82
82
  // preserved on disk) for getting the memory back.
83
83
  function watchServerMemory(server: DevServerHandle) {
84
84
  // eslint-disable-next-line turbo/no-undeclared-env-vars
85
- const limitMb = Number(process.env.PNEXT_DEV_MAX_RSS_MB || defaultMaxDevRssMb);
86
- if (!Number.isFinite(limitMb) || limitMb <= 0) return;
87
- const limitBytes = limitMb * 1024 * 1024;
85
+ const limitMb = Number(process.env.PNEXT_DEV_MAX_RSS_MB || defaultMaxDevRssMb)
86
+ if (!Number.isFinite(limitMb) || limitMb <= 0) return
87
+ const limitBytes = limitMb * 1024 * 1024
88
88
  const timer = setInterval(() => {
89
- const rss = process.memoryUsage.rss();
90
- if (rss < limitBytes) return;
91
- clearInterval(timer);
92
- const usedMb = Math.round(rss / (1024 * 1024));
89
+ const rss = process.memoryUsage.rss()
90
+ if (rss < limitBytes) return
91
+ clearInterval(timer)
92
+ const usedMb = Math.round(rss / (1024 * 1024))
93
93
  console.log(
94
94
  dim(
95
95
  `Dev server reached ${usedMb}MB of memory (limit ${limitMb}MB, set PNEXT_DEV_MAX_RSS_MB to change); restarting to release stale modules...`,
96
96
  ),
97
- );
98
- void restartDevProcess(server);
99
- }, 15_000);
100
- timer.unref();
97
+ )
98
+ void restartDevProcess(server)
99
+ }, 15_000)
100
+ timer.unref()
101
101
  }
102
102
 
103
103
  // The esbuild Go service self-drains its heap when idle, so two consecutive readings above the
@@ -105,35 +105,35 @@ function watchServerMemory(server: DevServerHandle) {
105
105
  // builds, never incremental contexts. A stop that races an in-flight build fails that one build;
106
106
  // dev asset caches drop failed builds, so the next request retries.
107
107
  function watchEsbuildMemory() {
108
- if (process.platform === 'win32') return;
108
+ if (process.platform === 'win32') return
109
109
  // eslint-disable-next-line turbo/no-undeclared-env-vars
110
- const limitMb = Number(process.env.PNEXT_DEV_MAX_ESBUILD_RSS_MB || defaultMaxEsbuildRssMb);
111
- if (!Number.isFinite(limitMb) || limitMb <= 0) return;
112
- let highTicks = 0;
110
+ const limitMb = Number(process.env.PNEXT_DEV_MAX_ESBUILD_RSS_MB || defaultMaxEsbuildRssMb)
111
+ if (!Number.isFinite(limitMb) || limitMb <= 0) return
112
+ let highTicks = 0
113
113
  const timer = setInterval(() => {
114
- const rssMb = esbuildServiceRssMb();
115
- highTicks = rssMb > limitMb ? highTicks + 1 : 0;
116
- if (highTicks < 2) return;
117
- highTicks = 0;
114
+ const rssMb = esbuildServiceRssMb()
115
+ highTicks = rssMb > limitMb ? highTicks + 1 : 0
116
+ if (highTicks < 2) return
117
+ highTicks = 0
118
118
  console.log(
119
119
  dim(
120
120
  `esbuild reached ${Math.round(rssMb)}MB of memory (limit ${limitMb}MB, set PNEXT_DEV_MAX_ESBUILD_RSS_MB to change); restarting it to release the heap...`,
121
121
  ),
122
- );
122
+ )
123
123
  void (async () => {
124
124
  try {
125
- const esbuild = await import('esbuild');
126
- await esbuild.stop();
125
+ const esbuild = await import('esbuild')
126
+ await esbuild.stop()
127
127
  } catch {
128
128
  // ignore: the service may already be gone
129
129
  }
130
130
  // stop() can strand in-flight build promises unsettled; fail their
131
131
  // waiters so requests retry against the respawned service.
132
- const { failInFlightClientBuilds } = await import('../dev/server');
133
- failInFlightClientBuilds('esbuild service restarted by the memory watchdog');
134
- })();
135
- }, 15_000);
136
- timer.unref();
132
+ const { failInFlightClientBuilds } = await import('../dev/server')
133
+ failInFlightClientBuilds('esbuild service restarted by the memory watchdog')
134
+ })()
135
+ }, 15_000)
136
+ timer.unref()
137
137
  }
138
138
 
139
139
  /**
@@ -146,48 +146,48 @@ function watchEsbuildMemory() {
146
146
  */
147
147
  function watchStaleModules(server: DevServerHandle) {
148
148
  // eslint-disable-next-line turbo/no-undeclared-env-vars
149
- const limit = Number(process.env.PNEXT_DEV_MAX_STALE_MODULES || defaultMaxStaleModules);
150
- if (!Number.isFinite(limit) || limit <= 0) return;
149
+ const limit = Number(process.env.PNEXT_DEV_MAX_STALE_MODULES || defaultMaxStaleModules)
150
+ if (!Number.isFinite(limit) || limit <= 0) return
151
151
  const timer = setInterval(() => {
152
- const { stale } = moduleGenerationStats();
153
- if (stale < limit) return;
154
- clearInterval(timer);
152
+ const { stale } = moduleGenerationStats()
153
+ if (stale < limit) return
154
+ clearInterval(timer)
155
155
  console.log(
156
156
  dim(
157
157
  `Dev server is holding ${stale} superseded module generations (limit ${limit}, set PNEXT_DEV_MAX_STALE_MODULES to change); restarting to release them...`,
158
158
  ),
159
- );
160
- void restartDevProcess(server);
161
- }, 15_000);
162
- timer.unref();
159
+ )
160
+ void restartDevProcess(server)
161
+ }, 15_000)
162
+ timer.unref()
163
163
  }
164
164
 
165
165
  // Our esbuild service children: [pid, RSS in MB] per process.
166
166
  function esbuildServices(): [number, number][] {
167
- const found: [number, number][] = [];
167
+ const found: [number, number][] = []
168
168
  try {
169
- const stdout = Bun.spawnSync(['ps', '-ax', '-o', 'pid=,ppid=,rss=,ucomm=']).stdout.toString();
169
+ const stdout = Bun.spawnSync(['ps', '-ax', '-o', 'pid=,ppid=,rss=,ucomm=']).stdout.toString()
170
170
  for (const line of stdout.split('\n')) {
171
- const [pid, ppid, rss, ...name] = line.trim().split(/\s+/);
171
+ const [pid, ppid, rss, ...name] = line.trim().split(/\s+/)
172
172
  if (Number(ppid) === process.pid && name.join(' ').includes('esbuild')) {
173
- found.push([Number(pid), Number(rss) / 1024]);
173
+ found.push([Number(pid), Number(rss) / 1024])
174
174
  }
175
175
  }
176
176
  } catch {
177
177
  // ignore: no ps available means no monitoring, not a broken dev server
178
178
  }
179
- return found;
179
+ return found
180
180
  }
181
181
 
182
182
  // RSS of our esbuild service, in MB (0 when not running).
183
183
  function esbuildServiceRssMb() {
184
- return esbuildServices().reduce((total, [, rssMb]) => total + rssMb, 0);
184
+ return esbuildServices().reduce((total, [, rssMb]) => total + rssMb, 0)
185
185
  }
186
186
 
187
187
  interface DevServerHandle {
188
- stop(closeActiveConnections?: boolean): unknown;
188
+ stop(closeActiveConnections?: boolean): unknown
189
189
  /** Resolves once nothing is being served (or the timeout elapses). */
190
- drain?(timeoutMs: number): Promise<boolean>;
190
+ drain?(timeoutMs: number): Promise<boolean>
191
191
  }
192
192
 
193
193
  /**
@@ -201,9 +201,9 @@ async function restartDevProcess(server: DevServerHandle): Promise<void> {
201
201
  try {
202
202
  // Stop accepting, then let what is already being served finish: an exec
203
203
  // mid-response would leave the browser with a truncated page and no error.
204
- server.stop(false);
205
- await server.drain?.(drainTimeoutMs);
206
- server.stop(true);
204
+ server.stop(false)
205
+ await server.drain?.(drainTimeoutMs)
206
+ server.stop(true)
207
207
  } catch {
208
208
  // ignore: we are being replaced regardless
209
209
  }
@@ -211,72 +211,72 @@ async function restartDevProcess(server: DevServerHandle): Promise<void> {
211
211
  // image that owned it — with exactly the heap this restart is reclaiming.
212
212
  for (const [pid] of esbuildServices()) {
213
213
  try {
214
- process.kill(pid, 'SIGTERM');
214
+ process.kill(pid, 'SIGTERM')
215
215
  } catch {
216
216
  // ignore: already gone
217
217
  }
218
218
  }
219
- const argv = [process.execPath, '--conditions=react-server', ...process.argv.slice(1)];
220
- const env = { ...process.env, [devRestartEnv]: '1' };
219
+ const argv = [process.execPath, '--conditions=react-server', ...process.argv.slice(1)]
220
+ const env = { ...process.env, [devRestartEnv]: '1' }
221
221
  try {
222
- await execSelf(argv, env);
222
+ await execSelf(argv, env)
223
223
  } catch {
224
224
  // ignore: fall through to the spawn path
225
225
  }
226
226
  // Only reached when exec is unavailable or failed.
227
- Bun.spawn(argv, { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', env });
228
- process.exit(0);
227
+ Bun.spawn(argv, { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', env })
228
+ process.exit(0)
229
229
  }
230
230
 
231
231
  // execve(2) via libc. argv/envp are NUL-terminated C string arrays, and the
232
232
  // pointer array must stay reachable until the call returns (it never does on
233
233
  // success).
234
234
  async function execSelf(argv: string[], env: Record<string, string | undefined>): Promise<void> {
235
- if (process.platform === 'win32') return;
236
- const { dlopen, FFIType, ptr, suffix } = await import('bun:ffi');
237
- const libc = process.platform === 'darwin' ? '/usr/lib/libSystem.B.dylib' : `libc.${suffix}.6`;
235
+ if (process.platform === 'win32') return
236
+ const { dlopen, FFIType, ptr, suffix } = await import('bun:ffi')
237
+ const libc = process.platform === 'darwin' ? '/usr/lib/libSystem.B.dylib' : `libc.${suffix}.6`
238
238
  const { symbols } = dlopen(libc, {
239
239
  execve: {
240
240
  args: [FFIType.cstring, FFIType.ptr, FFIType.ptr],
241
241
  returns: FFIType.i32,
242
242
  },
243
- });
244
- const encoder = new TextEncoder();
245
- const cString = (value: string) => encoder.encode(`${value}\0`);
243
+ })
244
+ const encoder = new TextEncoder()
245
+ const cString = (value: string) => encoder.encode(`${value}\0`)
246
246
  const cArray = (values: string[]) => {
247
- const cells = values.map(cString);
248
- const array = new BigInt64Array(cells.length + 1);
247
+ const cells = values.map(cString)
248
+ const array = new BigInt64Array(cells.length + 1)
249
249
  cells.forEach((cell, index) => {
250
- array[index] = BigInt(ptr(cell));
251
- });
252
- return { array, cells };
253
- };
254
- const args = cArray(argv);
250
+ array[index] = BigInt(ptr(cell))
251
+ })
252
+ return { array, cells }
253
+ }
254
+ const args = cArray(argv)
255
255
  const envp = cArray(
256
256
  Object.entries(env)
257
257
  .filter(([, value]) => value !== undefined)
258
258
  .map(([key, value]) => `${key}=${value}`),
259
- );
260
- symbols.execve(cString(argv[0]!), ptr(args.array), ptr(envp.array));
259
+ )
260
+ symbols.execve(cString(argv[0]!), ptr(args.array), ptr(envp.array))
261
261
  // execve only returns on failure; keep the buffers alive until then.
262
- void [args.cells, envp.cells];
262
+ void [args.cells, envp.cells]
263
263
  }
264
264
 
265
265
  // Stop the server and run process `exit` handlers on a terminating signal,
266
266
  // so killing the dev server never leaves orphaned subprocesses behind.
267
267
  function registerShutdown(server: DevServerHandle) {
268
- let closing = false;
268
+ let closing = false
269
269
  const shutdown = () => {
270
- if (closing) return;
271
- closing = true;
270
+ if (closing) return
271
+ closing = true
272
272
  try {
273
- server.stop(true);
273
+ server.stop(true)
274
274
  } catch {
275
275
  // ignore: process is exiting regardless
276
276
  }
277
- process.exit(0);
278
- };
277
+ process.exit(0)
278
+ }
279
279
  for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'] as const) {
280
- process.once(signal, shutdown);
280
+ process.once(signal, shutdown)
281
281
  }
282
282
  }