one 1.25.12 → 1.25.15

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 (308) hide show
  1. package/dist/cjs/cli/build.cjs +37 -186
  2. package/dist/cjs/cli/build.native.js +270 -423
  3. package/dist/cjs/cli/build.native.js.map +1 -1
  4. package/dist/cjs/cli/buildPage.cjs +7 -7
  5. package/dist/cjs/cli/buildPage.native.js +7 -7
  6. package/dist/cjs/cli/buildPage.native.js.map +1 -1
  7. package/dist/cjs/cli/buildPageWorker.cjs +1 -1
  8. package/dist/cjs/cli/buildPageWorker.native.js +1 -1
  9. package/dist/cjs/cli/buildPageWorker.native.js.map +1 -1
  10. package/dist/cjs/cli/serverRouteModules.cjs +47 -0
  11. package/dist/cjs/cli/serverRouteModules.native.js +52 -0
  12. package/dist/cjs/cli/serverRouteModules.native.js.map +1 -0
  13. package/dist/cjs/cli/workerPool.native.js.map +1 -1
  14. package/dist/cjs/createApp.cjs +3 -0
  15. package/dist/cjs/createDevHandleRequest.cjs +151 -0
  16. package/dist/cjs/createDevHandleRequest.native.js +194 -0
  17. package/dist/cjs/createDevHandleRequest.native.js.map +1 -0
  18. package/dist/cjs/createHandleRequest.cjs +1 -123
  19. package/dist/cjs/createHandleRequest.native.js +1 -163
  20. package/dist/cjs/createHandleRequest.native.js.map +1 -1
  21. package/dist/cjs/createHandleRequest.test.cjs +25 -25
  22. package/dist/cjs/createHandleRequest.test.native.js +25 -25
  23. package/dist/cjs/createHandleRequest.test.native.js.map +1 -1
  24. package/dist/cjs/headless-server.native.js.map +1 -1
  25. package/dist/cjs/headless.cjs +4 -0
  26. package/dist/cjs/headless.native.js +4 -0
  27. package/dist/cjs/headless.native.js.map +1 -1
  28. package/dist/cjs/layouts/Drawer.cjs +0 -2
  29. package/dist/cjs/layouts/Drawer.native.js.map +1 -1
  30. package/dist/cjs/layouts/Tabs.cjs +0 -2
  31. package/dist/cjs/layouts/Tabs.native.js.map +1 -1
  32. package/dist/cjs/router/diagnoseRouteLoadFailure.native.js.map +1 -1
  33. package/dist/cjs/router/useViteRoutes.cjs +9 -1
  34. package/dist/cjs/router/useViteRoutes.native.js +9 -1
  35. package/dist/cjs/router/useViteRoutes.native.js.map +1 -1
  36. package/dist/cjs/router/web/WebStackView.cjs +0 -2
  37. package/dist/cjs/router/web/WebStackView.native.js +0 -2
  38. package/dist/cjs/router/web/WebStackView.native.js.map +1 -1
  39. package/dist/cjs/serve-worker.cjs +3 -2
  40. package/dist/cjs/serve-worker.native.js +3 -2
  41. package/dist/cjs/serve-worker.native.js.map +1 -1
  42. package/dist/cjs/server/oneServe.cjs +23 -4
  43. package/dist/cjs/server/oneServe.native.js +25 -6
  44. package/dist/cjs/server/oneServe.native.js.map +1 -1
  45. package/dist/cjs/server/routeExportsFromEntry.cjs +47 -0
  46. package/dist/cjs/server/routeExportsFromEntry.native.js +52 -0
  47. package/dist/cjs/server/routeExportsFromEntry.native.js.map +1 -0
  48. package/dist/cjs/server/workerHandler.cjs +30 -12
  49. package/dist/cjs/server/workerHandler.native.js +32 -13
  50. package/dist/cjs/server/workerHandler.native.js.map +1 -1
  51. package/dist/cjs/server/workerHandler.test.cjs +43 -10
  52. package/dist/cjs/server/workerHandler.test.native.js +46 -10
  53. package/dist/cjs/server/workerHandler.test.native.js.map +1 -1
  54. package/dist/cjs/views/ScrollBehavior.native.js.map +1 -1
  55. package/dist/cjs/vite/cloudflareWranglerConfig.cjs +247 -0
  56. package/dist/cjs/vite/cloudflareWranglerConfig.native.js +392 -0
  57. package/dist/cjs/vite/cloudflareWranglerConfig.native.js.map +1 -0
  58. package/dist/cjs/vite/cloudflareWranglerConfig.test.cjs +116 -0
  59. package/dist/cjs/vite/cloudflareWranglerConfig.test.native.js +120 -0
  60. package/dist/cjs/vite/cloudflareWranglerConfig.test.native.js.map +1 -0
  61. package/dist/cjs/vite/one.cjs +4 -2
  62. package/dist/cjs/vite/one.native.js +8 -6
  63. package/dist/cjs/vite/one.native.js.map +1 -1
  64. package/dist/cjs/vite/plugins/SSRCSSPlugin.cjs +10 -1
  65. package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js +52 -3
  66. package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
  67. package/dist/cjs/vite/plugins/environmentGuardPlugin.cjs +1 -1
  68. package/dist/cjs/vite/plugins/environmentGuardPlugin.native.js +1 -1
  69. package/dist/cjs/vite/plugins/environmentGuardPlugin.native.js.map +1 -1
  70. package/dist/cjs/vite/plugins/environmentGuardPlugin.test.cjs +4 -0
  71. package/dist/cjs/vite/plugins/environmentGuardPlugin.test.native.js +4 -0
  72. package/dist/cjs/vite/plugins/environmentGuardPlugin.test.native.js.map +1 -1
  73. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.cjs +14 -5
  74. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js +15 -5
  75. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
  76. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.test.cjs +47 -0
  77. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.test.native.js +47 -0
  78. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.test.native.js.map +1 -1
  79. package/dist/cjs/vite/plugins/virtualEntryPlugin.cjs +9 -7
  80. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js +11 -7
  81. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  82. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.cjs +12 -0
  83. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js +12 -0
  84. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
  85. package/dist/cjs/vite/plugins/workerdDevPlugin.cjs +364 -0
  86. package/dist/cjs/vite/plugins/workerdDevPlugin.native.js +461 -0
  87. package/dist/cjs/vite/plugins/workerdDevPlugin.native.js.map +1 -0
  88. package/dist/cjs/vite/plugins/workerdDevPlugin.test.cjs +42 -0
  89. package/dist/cjs/vite/plugins/workerdDevPlugin.test.native.js +45 -0
  90. package/dist/cjs/vite/plugins/workerdDevPlugin.test.native.js.map +1 -0
  91. package/dist/cjs/vite/replaceLoader.cjs +6 -3
  92. package/dist/cjs/vite/replaceLoader.native.js +8 -3
  93. package/dist/cjs/vite/replaceLoader.native.js.map +1 -1
  94. package/dist/esm/cli/build.mjs +31 -180
  95. package/dist/esm/cli/build.mjs.map +1 -1
  96. package/dist/esm/cli/build.native.js +264 -417
  97. package/dist/esm/cli/build.native.js.map +1 -1
  98. package/dist/esm/cli/buildPage.mjs +7 -7
  99. package/dist/esm/cli/buildPage.mjs.map +1 -1
  100. package/dist/esm/cli/buildPage.native.js +7 -7
  101. package/dist/esm/cli/buildPage.native.js.map +1 -1
  102. package/dist/esm/cli/buildPageWorker.mjs +1 -1
  103. package/dist/esm/cli/buildPageWorker.mjs.map +1 -1
  104. package/dist/esm/cli/buildPageWorker.native.js +1 -1
  105. package/dist/esm/cli/buildPageWorker.native.js.map +1 -1
  106. package/dist/esm/cli/serverRouteModules.mjs +22 -0
  107. package/dist/esm/cli/serverRouteModules.mjs.map +1 -0
  108. package/dist/esm/cli/serverRouteModules.native.js +24 -0
  109. package/dist/esm/cli/serverRouteModules.native.js.map +1 -0
  110. package/dist/esm/cli/workerPool.mjs.map +1 -1
  111. package/dist/esm/cli/workerPool.native.js.map +1 -1
  112. package/dist/esm/createApp.mjs +4 -1
  113. package/dist/esm/createApp.mjs.map +1 -1
  114. package/dist/esm/createDevHandleRequest.mjs +126 -0
  115. package/dist/esm/createDevHandleRequest.mjs.map +1 -0
  116. package/dist/esm/createDevHandleRequest.native.js +166 -0
  117. package/dist/esm/createDevHandleRequest.native.js.map +1 -0
  118. package/dist/esm/createHandleRequest.mjs +1 -123
  119. package/dist/esm/createHandleRequest.mjs.map +1 -1
  120. package/dist/esm/createHandleRequest.native.js +1 -163
  121. package/dist/esm/createHandleRequest.native.js.map +1 -1
  122. package/dist/esm/createHandleRequest.test.mjs +1 -1
  123. package/dist/esm/createHandleRequest.test.native.js +1 -1
  124. package/dist/esm/headless-server.mjs.map +1 -1
  125. package/dist/esm/headless-server.native.js.map +1 -1
  126. package/dist/esm/headless.mjs +4 -0
  127. package/dist/esm/headless.mjs.map +1 -1
  128. package/dist/esm/headless.native.js +4 -0
  129. package/dist/esm/headless.native.js.map +1 -1
  130. package/dist/esm/layouts/Drawer.mjs +0 -2
  131. package/dist/esm/layouts/Drawer.mjs.map +1 -1
  132. package/dist/esm/layouts/Drawer.native.js.map +1 -1
  133. package/dist/esm/layouts/Tabs.mjs +0 -2
  134. package/dist/esm/layouts/Tabs.mjs.map +1 -1
  135. package/dist/esm/layouts/Tabs.native.js.map +1 -1
  136. package/dist/esm/router/diagnoseRouteLoadFailure.mjs.map +1 -1
  137. package/dist/esm/router/diagnoseRouteLoadFailure.native.js.map +1 -1
  138. package/dist/esm/router/useViteRoutes.mjs +9 -1
  139. package/dist/esm/router/useViteRoutes.mjs.map +1 -1
  140. package/dist/esm/router/useViteRoutes.native.js +9 -1
  141. package/dist/esm/router/useViteRoutes.native.js.map +1 -1
  142. package/dist/esm/router/web/WebStackView.mjs +0 -2
  143. package/dist/esm/router/web/WebStackView.mjs.map +1 -1
  144. package/dist/esm/router/web/WebStackView.native.js +0 -2
  145. package/dist/esm/router/web/WebStackView.native.js.map +1 -1
  146. package/dist/esm/serve-worker.mjs +3 -2
  147. package/dist/esm/serve-worker.mjs.map +1 -1
  148. package/dist/esm/serve-worker.native.js +3 -2
  149. package/dist/esm/serve-worker.native.js.map +1 -1
  150. package/dist/esm/server/oneServe.mjs +23 -4
  151. package/dist/esm/server/oneServe.mjs.map +1 -1
  152. package/dist/esm/server/oneServe.native.js +25 -6
  153. package/dist/esm/server/oneServe.native.js.map +1 -1
  154. package/dist/esm/server/routeExportsFromEntry.mjs +21 -0
  155. package/dist/esm/server/routeExportsFromEntry.mjs.map +1 -0
  156. package/dist/esm/server/routeExportsFromEntry.native.js +23 -0
  157. package/dist/esm/server/routeExportsFromEntry.native.js.map +1 -0
  158. package/dist/esm/server/workerHandler.mjs +30 -12
  159. package/dist/esm/server/workerHandler.mjs.map +1 -1
  160. package/dist/esm/server/workerHandler.native.js +32 -13
  161. package/dist/esm/server/workerHandler.native.js.map +1 -1
  162. package/dist/esm/server/workerHandler.test.mjs +43 -10
  163. package/dist/esm/server/workerHandler.test.mjs.map +1 -1
  164. package/dist/esm/server/workerHandler.test.native.js +46 -10
  165. package/dist/esm/server/workerHandler.test.native.js.map +1 -1
  166. package/dist/esm/views/ScrollBehavior.mjs.map +1 -1
  167. package/dist/esm/views/ScrollBehavior.native.js.map +1 -1
  168. package/dist/esm/vite/cloudflareWranglerConfig.mjs +202 -0
  169. package/dist/esm/vite/cloudflareWranglerConfig.mjs.map +1 -0
  170. package/dist/esm/vite/cloudflareWranglerConfig.native.js +344 -0
  171. package/dist/esm/vite/cloudflareWranglerConfig.native.js.map +1 -0
  172. package/dist/esm/vite/cloudflareWranglerConfig.test.mjs +117 -0
  173. package/dist/esm/vite/cloudflareWranglerConfig.test.mjs.map +1 -0
  174. package/dist/esm/vite/cloudflareWranglerConfig.test.native.js +118 -0
  175. package/dist/esm/vite/cloudflareWranglerConfig.test.native.js.map +1 -0
  176. package/dist/esm/vite/one.mjs +4 -2
  177. package/dist/esm/vite/one.mjs.map +1 -1
  178. package/dist/esm/vite/one.native.js +8 -6
  179. package/dist/esm/vite/one.native.js.map +1 -1
  180. package/dist/esm/vite/plugins/SSRCSSPlugin.mjs +10 -1
  181. package/dist/esm/vite/plugins/SSRCSSPlugin.mjs.map +1 -1
  182. package/dist/esm/vite/plugins/SSRCSSPlugin.native.js +52 -3
  183. package/dist/esm/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
  184. package/dist/esm/vite/plugins/environmentGuardPlugin.mjs +1 -1
  185. package/dist/esm/vite/plugins/environmentGuardPlugin.mjs.map +1 -1
  186. package/dist/esm/vite/plugins/environmentGuardPlugin.native.js +1 -1
  187. package/dist/esm/vite/plugins/environmentGuardPlugin.native.js.map +1 -1
  188. package/dist/esm/vite/plugins/environmentGuardPlugin.test.mjs +4 -0
  189. package/dist/esm/vite/plugins/environmentGuardPlugin.test.mjs.map +1 -1
  190. package/dist/esm/vite/plugins/environmentGuardPlugin.test.native.js +4 -0
  191. package/dist/esm/vite/plugins/environmentGuardPlugin.test.native.js.map +1 -1
  192. package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs +13 -4
  193. package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs.map +1 -1
  194. package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js +14 -4
  195. package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
  196. package/dist/esm/vite/plugins/fileSystemRouterPlugin.test.mjs +47 -0
  197. package/dist/esm/vite/plugins/fileSystemRouterPlugin.test.mjs.map +1 -1
  198. package/dist/esm/vite/plugins/fileSystemRouterPlugin.test.native.js +47 -0
  199. package/dist/esm/vite/plugins/fileSystemRouterPlugin.test.native.js.map +1 -1
  200. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs +9 -7
  201. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs.map +1 -1
  202. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js +11 -7
  203. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  204. package/dist/esm/vite/plugins/virtualEntryPlugin.test.mjs +12 -0
  205. package/dist/esm/vite/plugins/virtualEntryPlugin.test.mjs.map +1 -1
  206. package/dist/esm/vite/plugins/virtualEntryPlugin.test.native.js +12 -0
  207. package/dist/esm/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
  208. package/dist/esm/vite/plugins/workerdDevPlugin.mjs +336 -0
  209. package/dist/esm/vite/plugins/workerdDevPlugin.mjs.map +1 -0
  210. package/dist/esm/vite/plugins/workerdDevPlugin.native.js +430 -0
  211. package/dist/esm/vite/plugins/workerdDevPlugin.native.js.map +1 -0
  212. package/dist/esm/vite/plugins/workerdDevPlugin.test.mjs +43 -0
  213. package/dist/esm/vite/plugins/workerdDevPlugin.test.mjs.map +1 -0
  214. package/dist/esm/vite/plugins/workerdDevPlugin.test.native.js +43 -0
  215. package/dist/esm/vite/plugins/workerdDevPlugin.test.native.js.map +1 -0
  216. package/dist/esm/vite/replaceLoader.mjs +6 -3
  217. package/dist/esm/vite/replaceLoader.mjs.map +1 -1
  218. package/dist/esm/vite/replaceLoader.native.js +8 -3
  219. package/dist/esm/vite/replaceLoader.native.js.map +1 -1
  220. package/package.json +9 -9
  221. package/src/cli/build.ts +48 -224
  222. package/src/cli/buildPage.ts +9 -7
  223. package/src/cli/buildPageWorker.ts +1 -0
  224. package/src/cli/serverRouteModules.ts +33 -0
  225. package/src/cli/workerPool.ts +1 -0
  226. package/src/createApp.tsx +5 -1
  227. package/src/createDevHandleRequest.ts +186 -0
  228. package/src/createHandleRequest.test.ts +1 -1
  229. package/src/createHandleRequest.ts +2 -172
  230. package/src/headless-server.ts +0 -1
  231. package/src/headless.tsx +5 -0
  232. package/src/layouts/Drawer.web.tsx +0 -3
  233. package/src/layouts/Tabs.web.tsx +0 -2
  234. package/src/router/diagnoseRouteLoadFailure.ts +3 -1
  235. package/src/router/useViteRoutes.tsx +9 -1
  236. package/src/router/web/WebStackView.tsx +0 -3
  237. package/src/serve-worker.ts +6 -1
  238. package/src/server/oneServe.ts +40 -16
  239. package/src/server/routeExportsFromEntry.ts +59 -0
  240. package/src/server/workerHandler.test.ts +37 -9
  241. package/src/server/workerHandler.ts +39 -13
  242. package/src/views/ScrollBehavior.tsx +5 -1
  243. package/src/vite/cloudflareWranglerConfig.test.ts +101 -0
  244. package/src/vite/cloudflareWranglerConfig.ts +252 -0
  245. package/src/vite/one.ts +14 -1
  246. package/src/vite/plugins/SSRCSSPlugin.ts +17 -2
  247. package/src/vite/plugins/environmentGuardPlugin.test.ts +5 -0
  248. package/src/vite/plugins/environmentGuardPlugin.ts +2 -2
  249. package/src/vite/plugins/fileSystemRouterPlugin.test.ts +44 -0
  250. package/src/vite/plugins/fileSystemRouterPlugin.tsx +20 -8
  251. package/src/vite/plugins/virtualEntryPlugin.test.ts +13 -0
  252. package/src/vite/plugins/virtualEntryPlugin.ts +13 -9
  253. package/src/vite/plugins/workerdDevPlugin.test.ts +44 -0
  254. package/src/vite/plugins/workerdDevPlugin.ts +398 -0
  255. package/src/vite/replaceLoader.ts +10 -2
  256. package/types/cli/build.d.ts.map +1 -1
  257. package/types/cli/buildPage.d.ts +1 -1
  258. package/types/cli/buildPage.d.ts.map +1 -1
  259. package/types/cli/serverRouteModules.d.ts +2 -0
  260. package/types/cli/serverRouteModules.d.ts.map +1 -0
  261. package/types/cli/workerPool.d.ts +1 -0
  262. package/types/cli/workerPool.d.ts.map +1 -1
  263. package/types/createApp.d.ts.map +1 -1
  264. package/types/createDevHandleRequest.d.ts +10 -0
  265. package/types/createDevHandleRequest.d.ts.map +1 -0
  266. package/types/createHandleRequest.d.ts +2 -9
  267. package/types/createHandleRequest.d.ts.map +1 -1
  268. package/types/headless-server.d.ts +0 -1
  269. package/types/headless-server.d.ts.map +1 -1
  270. package/types/headless.d.ts.map +1 -1
  271. package/types/layouts/Drawer.web.d.ts.map +1 -1
  272. package/types/layouts/Tabs.web.d.ts.map +1 -1
  273. package/types/router/diagnoseRouteLoadFailure.d.ts.map +1 -1
  274. package/types/router/useViteRoutes.d.ts.map +1 -1
  275. package/types/router/web/WebStackView.d.ts.map +1 -1
  276. package/types/serve-worker.d.ts +3 -1
  277. package/types/serve-worker.d.ts.map +1 -1
  278. package/types/server/oneServe.d.ts +1 -1
  279. package/types/server/oneServe.d.ts.map +1 -1
  280. package/types/server/routeExportsFromEntry.d.ts +29 -0
  281. package/types/server/routeExportsFromEntry.d.ts.map +1 -0
  282. package/types/server/workerHandler.d.ts +2 -1
  283. package/types/server/workerHandler.d.ts.map +1 -1
  284. package/types/views/ScrollBehavior.d.ts.map +1 -1
  285. package/types/vite/cloudflareWranglerConfig.d.ts +21 -0
  286. package/types/vite/cloudflareWranglerConfig.d.ts.map +1 -0
  287. package/types/vite/cloudflareWranglerConfig.test.d.ts +2 -0
  288. package/types/vite/cloudflareWranglerConfig.test.d.ts.map +1 -0
  289. package/types/vite/one.d.ts.map +1 -1
  290. package/types/vite/plugins/SSRCSSPlugin.d.ts.map +1 -1
  291. package/types/vite/plugins/fileSystemRouterPlugin.d.ts.map +1 -1
  292. package/types/vite/plugins/virtualEntryPlugin.d.ts.map +1 -1
  293. package/types/vite/plugins/workerdDevPlugin.d.ts +15 -0
  294. package/types/vite/plugins/workerdDevPlugin.d.ts.map +1 -0
  295. package/types/vite/plugins/workerdDevPlugin.test.d.ts +2 -0
  296. package/types/vite/plugins/workerdDevPlugin.test.d.ts.map +1 -0
  297. package/types/vite/replaceLoader.d.ts +2 -1
  298. package/types/vite/replaceLoader.d.ts.map +1 -1
  299. package/dist/cjs/headless/devHeadlessNote.cjs +0 -34
  300. package/dist/cjs/headless/devHeadlessNote.native.js +0 -37
  301. package/dist/cjs/headless/devHeadlessNote.native.js.map +0 -1
  302. package/dist/esm/headless/devHeadlessNote.mjs +0 -9
  303. package/dist/esm/headless/devHeadlessNote.mjs.map +0 -1
  304. package/dist/esm/headless/devHeadlessNote.native.js +0 -9
  305. package/dist/esm/headless/devHeadlessNote.native.js.map +0 -1
  306. package/src/headless/devHeadlessNote.ts +0 -13
  307. package/types/headless/devHeadlessNote.d.ts +0 -2
  308. package/types/headless/devHeadlessNote.d.ts.map +0 -1
@@ -15,21 +15,23 @@ import {
15
15
  } from '../createHandleRequest'
16
16
  import type { RenderAppProps } from '../types'
17
17
  import { getPathFromLoaderPath } from '../utils/cleanUrl'
18
+ import { getRouterRootFromOneOptions } from '../utils/getRouterRootFromOneOptions'
18
19
  import { isResponse } from '../utils/isResponse'
19
20
  import { resolveResponse } from '../vite/resolveResponse'
20
21
  import type { One } from '../vite/types'
21
22
  import type { RouteInfoCompiled } from './createRoutesManifest'
23
+ import { getRouteExportsFromEntry } from './routeExportsFromEntry'
22
24
  import { setSSRLoaderData } from './ssrLoaderData'
23
25
  import { getFetchStaticHtml } from './staticHtmlFetcher'
24
26
 
25
27
  export type LazyRoutes = {
28
+ pages?: Record<string, () => Promise<any>>
26
29
  serverEntry: () => Promise<{
27
30
  default: {
28
31
  render: (props: any) => any
29
32
  renderStream?: (props: any) => Promise<ReadableStream>
30
33
  }
31
34
  }>
32
- pages: Record<string, () => Promise<any>>
33
35
  api: Record<string, () => Promise<any>>
34
36
  middlewares: Record<string, () => Promise<any>>
35
37
  }
@@ -38,10 +40,15 @@ type WorkerHandlerOptions = {
38
40
  oneOptions: One.PluginOptions
39
41
  buildInfo: One.BuildInfo
40
42
  lazyRoutes: LazyRoutes
43
+ // when true, skip the module/loader caches so vite hmr of a route file is
44
+ // visible on the next request. production omits this.
45
+ disableModuleCache?: boolean
41
46
  }
42
47
 
43
48
  export function createWorkerHandler(options: WorkerHandlerOptions) {
44
49
  const { oneOptions } = options
50
+ const disableModuleCache = !!options.disableModuleCache
51
+ const routerRoot = getRouterRootFromOneOptions(oneOptions)
45
52
 
46
53
  // mutable state for route swapping
47
54
  let currentLazyRoutes = options.lazyRoutes
@@ -91,13 +98,21 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
91
98
  let renderStream: ((props: RenderAppProps) => Promise<ReadableStream>) | null = null
92
99
  let renderLoading: Promise<void> | null = null
93
100
  let renderGeneration = 0
101
+ let entryLoading: Promise<any> | null = null
102
+
103
+ // route modules are resolved through the built server entry, see
104
+ // routeExportsFromEntry
105
+ function loadServerEntry(): Promise<any> {
106
+ if (!entryLoading) entryLoading = currentLazyRoutes.serverEntry()
107
+ return entryLoading
108
+ }
94
109
 
95
110
  function ensureRenderLoaded(): void | Promise<void> {
96
111
  if (render) return
97
112
  if (renderLoading) return renderLoading
98
113
  const gen = ++renderGeneration
99
114
  renderLoading = (async () => {
100
- const entry = await currentLazyRoutes.serverEntry()
115
+ const entry = await loadServerEntry()
101
116
  // if updateRoutes was called while we were loading, discard stale entry
102
117
  if (gen !== renderGeneration) return
103
118
  render = entry.default.render as any
@@ -137,25 +152,35 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
137
152
  lazyKey: string | undefined
138
153
  ): Function | null | Promise<Function | null> {
139
154
  const cacheKey = lazyKey || ''
140
- const cached = loaderCache.get(cacheKey)
141
- if (cached !== undefined) return cached
155
+ if (!disableModuleCache) {
156
+ const cached = loaderCache.get(cacheKey)
157
+ if (cached !== undefined) return cached
158
+ }
142
159
 
143
160
  return (async () => {
144
161
  let routeExported: any
145
- if (moduleImportCache.has(cacheKey)) {
162
+ if (!disableModuleCache && moduleImportCache.has(cacheKey)) {
146
163
  routeExported = moduleImportCache.get(cacheKey)
147
- } else if (lazyKey && currentLazyRoutes.pages[lazyKey]) {
148
- routeExported = await currentLazyRoutes.pages[lazyKey]()
149
- moduleImportCache.set(cacheKey, routeExported)
164
+ } else if (currentLazyRoutes.pages?.[cacheKey]) {
165
+ routeExported = await currentLazyRoutes.pages[cacheKey]()
166
+ if (!disableModuleCache) moduleImportCache.set(cacheKey, routeExported)
150
167
  } else {
151
- console.warn(`[one/worker] no lazy route for ${cacheKey}`)
152
- loaderCache.set(cacheKey, null)
153
- return null
168
+ routeExported = lazyKey
169
+ ? await getRouteExportsFromEntry(await loadServerEntry(), routerRoot, lazyKey)
170
+ : null
171
+ if (!routeExported) {
172
+ console.warn(`[one/worker] no lazy route for ${cacheKey}`)
173
+ if (!disableModuleCache) loaderCache.set(cacheKey, null)
174
+ return null
175
+ }
176
+ if (!disableModuleCache) moduleImportCache.set(cacheKey, routeExported)
154
177
  }
155
178
 
156
179
  const loader = routeExported?.loader || null
157
- loaderCache.set(cacheKey, loader)
158
- loaderCacheFnMap.set(cacheKey, routeExported?.loaderCache ?? null)
180
+ if (!disableModuleCache) {
181
+ loaderCache.set(cacheKey, loader)
182
+ loaderCacheFnMap.set(cacheKey, routeExported?.loaderCache ?? null)
183
+ }
159
184
  return loader
160
185
  })()
161
186
  }
@@ -789,6 +814,7 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
789
814
  render = null
790
815
  renderStream = null
791
816
  renderLoading = null
817
+ entryLoading = null
792
818
  }
793
819
 
794
820
  return { handleRequest, updateRoutes }
@@ -1,6 +1,10 @@
1
1
  import { useEffect } from 'react'
2
2
  import { setLastAction } from '../router/lastAction'
3
- import { routeInfo, subscribeToLoadingState, subscribeToRootState } from '../router/router'
3
+ import {
4
+ routeInfo,
5
+ subscribeToLoadingState,
6
+ subscribeToRootState,
7
+ } from '../router/router'
4
8
 
5
9
  const KEY = 'one-sr'
6
10
  const GROUP_KEY = 'one-sr-groups'
@@ -0,0 +1,101 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+ import { afterEach, describe, expect, it } from 'vitest'
5
+ import {
6
+ createCloudflareWranglerConfig,
7
+ isExperimentalWorkerDevEnabled,
8
+ loadUserWranglerConfigSync,
9
+ shouldEnableWorkerdDev,
10
+ } from './cloudflareWranglerConfig'
11
+
12
+ describe('createCloudflareWranglerConfig', () => {
13
+ it('synthesizes a worker config when no user wrangler file exists', () => {
14
+ const config = createCloudflareWranglerConfig('my-app')
15
+ expect(config.name).toBe('my-app')
16
+ expect(config.main).toBe('worker.js')
17
+ expect(config.compatibility_flags).toEqual(['nodejs_compat'])
18
+ expect(config.find_additional_modules).toBe(true)
19
+ expect(config.assets).toEqual({
20
+ directory: 'client',
21
+ binding: 'ASSETS',
22
+ run_worker_first: true,
23
+ })
24
+ })
25
+
26
+ it('merges user wrangler.jsonc the same way the cloudflare build does', () => {
27
+ const config = createCloudflareWranglerConfig('generated-name', {
28
+ name: 'test-cloudflare-user-config',
29
+ compatibility_date: '2025-01-01',
30
+ compatibility_flags: ['nodejs_als'],
31
+ vars: { CUSTOM_VALUE: 'from-root-config' },
32
+ assets: { html_handling: 'auto-trailing-slash' },
33
+ rules: [{ type: 'ESModule', globs: ['./extra/**/*.js'], fallthrough: true }],
34
+ })
35
+
36
+ expect(config.name).toBe('test-cloudflare-user-config')
37
+ expect(config.main).toBe('worker.js')
38
+ expect(config.compatibility_date).toBe('2025-01-01')
39
+ expect(config.compatibility_flags).toEqual(['nodejs_compat', 'nodejs_als'])
40
+ expect(config.vars).toEqual({ CUSTOM_VALUE: 'from-root-config' })
41
+ expect(config.assets).toEqual({
42
+ html_handling: 'auto-trailing-slash',
43
+ directory: 'client',
44
+ binding: 'ASSETS',
45
+ run_worker_first: true,
46
+ })
47
+ expect(config.rules).toEqual([
48
+ { type: 'ESModule', globs: ['./server/**/*.js'], fallthrough: true },
49
+ { type: 'ESModule', globs: ['./api/**/*.js'], fallthrough: true },
50
+ { type: 'ESModule', globs: ['./middlewares/**/*.js'], fallthrough: true },
51
+ { type: 'ESModule', globs: ['./assets/**/*.js'], fallthrough: true },
52
+ { type: 'ESModule', globs: ['./extra/**/*.js'], fallthrough: true },
53
+ ])
54
+ })
55
+ })
56
+
57
+ describe('shouldEnableWorkerdDev', () => {
58
+ const previous = process.env.ONE_EXPERIMENTAL_WORKER_DEV
59
+
60
+ afterEach(() => {
61
+ if (previous === undefined) delete process.env.ONE_EXPERIMENTAL_WORKER_DEV
62
+ else process.env.ONE_EXPERIMENTAL_WORKER_DEV = previous
63
+ })
64
+
65
+ it('is off when the flag is unset', () => {
66
+ delete process.env.ONE_EXPERIMENTAL_WORKER_DEV
67
+ expect(isExperimentalWorkerDevEnabled()).toBe(false)
68
+ expect(shouldEnableWorkerdDev('cloudflare', '/tmp')).toBe(false)
69
+ })
70
+
71
+ it('is off when the flag is on but the app has no cloudflare target or wrangler file', () => {
72
+ process.env.ONE_EXPERIMENTAL_WORKER_DEV = '1'
73
+ const root = mkdtempSync(join(tmpdir(), 'one-workerd-flag-'))
74
+ try {
75
+ expect(shouldEnableWorkerdDev(undefined, root)).toBe(false)
76
+ expect(shouldEnableWorkerdDev('node', root)).toBe(false)
77
+ } finally {
78
+ rmSync(root, { recursive: true, force: true })
79
+ }
80
+ })
81
+
82
+ it('is on when the flag is set and deploy is cloudflare', () => {
83
+ process.env.ONE_EXPERIMENTAL_WORKER_DEV = '1'
84
+ expect(shouldEnableWorkerdDev('cloudflare', '/tmp-does-not-exist')).toBe(true)
85
+ expect(shouldEnableWorkerdDev({ target: 'cloudflare' }, '/tmp-does-not-exist')).toBe(
86
+ true
87
+ )
88
+ })
89
+
90
+ it('is on when the flag is set and wrangler.jsonc exists', () => {
91
+ process.env.ONE_EXPERIMENTAL_WORKER_DEV = '1'
92
+ const root = mkdtempSync(join(tmpdir(), 'one-workerd-wrangler-'))
93
+ try {
94
+ writeFileSync(join(root, 'wrangler.jsonc'), '{ "name": "from-file" }\n')
95
+ expect(shouldEnableWorkerdDev(undefined, root)).toBe(true)
96
+ expect(loadUserWranglerConfigSync(root)?.config.name).toBe('from-file')
97
+ } finally {
98
+ rmSync(root, { recursive: true, force: true })
99
+ }
100
+ })
101
+ })
@@ -0,0 +1,252 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import { join, relative } from 'node:path'
3
+ import FSExtra from 'fs-extra'
4
+
5
+ export type JsonPrimitive = string | number | boolean | null
6
+ export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue }
7
+
8
+ export const GENERATED_CLOUDFLARE_WRANGLER_RULES: JsonValue[] = [
9
+ { type: 'ESModule', globs: ['./server/**/*.js'], fallthrough: true },
10
+ { type: 'ESModule', globs: ['./api/**/*.js'], fallthrough: true },
11
+ { type: 'ESModule', globs: ['./middlewares/**/*.js'], fallthrough: true },
12
+ { type: 'ESModule', globs: ['./assets/**/*.js'], fallthrough: true },
13
+ ]
14
+
15
+ export function isPlainObject(value: unknown): value is Record<string, JsonValue> {
16
+ return !!value && typeof value === 'object' && !Array.isArray(value)
17
+ }
18
+
19
+ function mergeJsonObjects(
20
+ base: Record<string, JsonValue>,
21
+ overrides: Record<string, JsonValue>
22
+ ): Record<string, JsonValue> {
23
+ const merged: Record<string, JsonValue> = { ...base }
24
+
25
+ for (const [key, value] of Object.entries(overrides)) {
26
+ const baseValue = merged[key]
27
+ if (isPlainObject(baseValue) && isPlainObject(value)) {
28
+ merged[key] = mergeJsonObjects(baseValue, value)
29
+ } else {
30
+ merged[key] = value
31
+ }
32
+ }
33
+
34
+ return merged
35
+ }
36
+
37
+ function dedupeJsonValues<T extends JsonValue>(values: T[]): T[] {
38
+ const seen = new Set<string>()
39
+ return values.filter((value) => {
40
+ const key = JSON.stringify(value)
41
+ if (seen.has(key)) return false
42
+ seen.add(key)
43
+ return true
44
+ })
45
+ }
46
+
47
+ function mergeCloudflareCompatibilityFlags(flags: unknown): string[] {
48
+ const userFlags = Array.isArray(flags)
49
+ ? flags.filter((flag): flag is string => typeof flag === 'string')
50
+ : []
51
+
52
+ return dedupeJsonValues<string>(['nodejs_compat', ...userFlags])
53
+ }
54
+
55
+ function mergeCloudflareRules(rules: unknown): JsonValue[] {
56
+ const userRules = Array.isArray(rules)
57
+ ? rules.filter((rule): rule is JsonValue => isPlainObject(rule))
58
+ : []
59
+
60
+ return dedupeJsonValues<JsonValue>([
61
+ ...GENERATED_CLOUDFLARE_WRANGLER_RULES,
62
+ ...userRules,
63
+ ])
64
+ }
65
+
66
+ // minimal JSONC parser: strips line/block comments (string-aware) and trailing
67
+ // commas, then runs JSON.parse. sufficient for small hand-written config files.
68
+ function parseJsonc(text: string): unknown {
69
+ let out = ''
70
+ let i = 0
71
+ let inString = false
72
+ let quote = ''
73
+ while (i < text.length) {
74
+ const ch = text[i]
75
+ const next = text[i + 1]
76
+ if (inString) {
77
+ if (ch === '\\') {
78
+ out += ch + (next ?? '')
79
+ i += 2
80
+ continue
81
+ }
82
+ if (ch === quote) inString = false
83
+ out += ch
84
+ i++
85
+ continue
86
+ }
87
+ if (ch === '"' || ch === "'") {
88
+ inString = true
89
+ quote = ch
90
+ out += ch
91
+ i++
92
+ continue
93
+ }
94
+ if (ch === '/' && next === '/') {
95
+ while (i < text.length && text[i] !== '\n') i++
96
+ continue
97
+ }
98
+ if (ch === '/' && next === '*') {
99
+ i += 2
100
+ while (i < text.length - 1 && !(text[i] === '*' && text[i + 1] === '/')) i++
101
+ i += 2
102
+ continue
103
+ }
104
+ out += ch
105
+ i++
106
+ }
107
+ return JSON.parse(out.replace(/,(\s*[}\]])/g, '$1'))
108
+ }
109
+
110
+ const WRANGLER_FILE_NAMES = ['wrangler.jsonc', 'wrangler.json'] as const
111
+
112
+ function wranglerCandidateRoots(root: string): string[] {
113
+ return [...new Set([root, process.cwd()])]
114
+ }
115
+
116
+ export function hasUserWranglerConfig(root: string): boolean {
117
+ for (const candidateRoot of wranglerCandidateRoots(root)) {
118
+ for (const fileName of WRANGLER_FILE_NAMES) {
119
+ if (existsSync(join(candidateRoot, fileName))) return true
120
+ }
121
+ }
122
+ return false
123
+ }
124
+
125
+ function parseUserWranglerFile(configPath: string): {
126
+ path: string
127
+ config: Record<string, JsonValue>
128
+ } {
129
+ const contents = readFileSync(configPath, 'utf-8')
130
+ let parsed: unknown
131
+ try {
132
+ parsed = parseJsonc(contents)
133
+ } catch (err) {
134
+ throw new Error(
135
+ `Failed to parse ${relative(process.cwd(), configPath)}: ${(err as Error).message}`
136
+ )
137
+ }
138
+
139
+ if (!isPlainObject(parsed)) {
140
+ throw new Error(
141
+ `Expected ${relative(process.cwd(), configPath)} to contain a top-level JSON object`
142
+ )
143
+ }
144
+
145
+ return {
146
+ path: configPath,
147
+ config: parsed,
148
+ }
149
+ }
150
+
151
+ export function loadUserWranglerConfigSync(
152
+ root: string
153
+ ): { path: string; config: Record<string, JsonValue> } | null {
154
+ for (const candidateRoot of wranglerCandidateRoots(root)) {
155
+ for (const fileName of WRANGLER_FILE_NAMES) {
156
+ const configPath = join(candidateRoot, fileName)
157
+ if (!existsSync(configPath)) continue
158
+ return parseUserWranglerFile(configPath)
159
+ }
160
+ }
161
+ return null
162
+ }
163
+
164
+ export async function loadUserWranglerConfig(
165
+ root: string
166
+ ): Promise<{ path: string; config: Record<string, JsonValue> } | null> {
167
+ const candidateRoots = wranglerCandidateRoots(root)
168
+
169
+ for (const candidateRoot of candidateRoots) {
170
+ for (const fileName of WRANGLER_FILE_NAMES) {
171
+ const configPath = join(candidateRoot, fileName)
172
+ if (!(await FSExtra.pathExists(configPath))) {
173
+ continue
174
+ }
175
+ return parseUserWranglerFile(configPath)
176
+ }
177
+ }
178
+
179
+ return null
180
+ }
181
+
182
+ export function createCloudflareWranglerConfig(
183
+ projectName: string,
184
+ userConfig?: Record<string, JsonValue>
185
+ ): Record<string, JsonValue> {
186
+ const generatedConfig: Record<string, JsonValue> = {
187
+ name: projectName,
188
+ main: 'worker.js',
189
+ compatibility_date: '2024-12-05',
190
+ compatibility_flags: ['nodejs_compat'],
191
+ find_additional_modules: true,
192
+ rules: GENERATED_CLOUDFLARE_WRANGLER_RULES,
193
+ assets: {
194
+ directory: 'client',
195
+ binding: 'ASSETS',
196
+ run_worker_first: true,
197
+ },
198
+ }
199
+
200
+ const mergedConfig = userConfig
201
+ ? mergeJsonObjects(generatedConfig, userConfig)
202
+ : generatedConfig
203
+
204
+ mergedConfig.main = 'worker.js'
205
+ mergedConfig.find_additional_modules = true
206
+ mergedConfig.compatibility_flags = mergeCloudflareCompatibilityFlags(
207
+ mergedConfig.compatibility_flags
208
+ )
209
+ mergedConfig.rules = mergeCloudflareRules(mergedConfig.rules)
210
+ mergedConfig.assets = {
211
+ ...(isPlainObject(mergedConfig.assets) ? mergedConfig.assets : {}),
212
+ directory: 'client',
213
+ binding: 'ASSETS',
214
+ run_worker_first: true,
215
+ }
216
+
217
+ return mergedConfig
218
+ }
219
+
220
+ export function getCloudflareProjectNameSync(root: string): string {
221
+ try {
222
+ const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf-8'))
223
+ if (pkg.name) {
224
+ return String(pkg.name).replace(/^@[^/]+\//, '')
225
+ }
226
+ } catch {}
227
+ return 'one-app'
228
+ }
229
+
230
+ export async function getCloudflareProjectName(root: string): Promise<string> {
231
+ try {
232
+ const pkg = JSON.parse(await FSExtra.readFile(join(root, 'package.json'), 'utf-8'))
233
+ if (pkg.name) {
234
+ return pkg.name.replace(/^@[^/]+\//, '')
235
+ }
236
+ } catch {}
237
+ return 'one-app'
238
+ }
239
+
240
+ export function isExperimentalWorkerDevEnabled(): boolean {
241
+ return process.env.ONE_EXPERIMENTAL_WORKER_DEV === '1'
242
+ }
243
+
244
+ export function shouldEnableWorkerdDev(deploy: unknown, root: string): boolean {
245
+ if (!isExperimentalWorkerDevEnabled()) return false
246
+ const target =
247
+ typeof deploy === 'string'
248
+ ? deploy
249
+ : (deploy as { target?: string } | undefined)?.target
250
+ if (target === 'cloudflare') return true
251
+ return hasUserWranglerConfig(root)
252
+ }
package/src/vite/one.ts CHANGED
@@ -34,6 +34,10 @@ import { SSRCSSPlugin } from './plugins/SSRCSSPlugin'
34
34
  import { virtualEntryId } from './plugins/virtualEntryConstants'
35
35
  import { createVirtualEntry } from './plugins/virtualEntryPlugin'
36
36
  import { environmentGuardPlugin } from './plugins/environmentGuardPlugin'
37
+ import {
38
+ createWorkerdDevPlugins,
39
+ shouldEnableWorkerdDev,
40
+ } from './plugins/workerdDevPlugin'
37
41
  import type { One } from './types'
38
42
 
39
43
  type MetroOptions = MetroPluginOptions
@@ -553,7 +557,11 @@ export function one(options: One.PluginOptions = {}): PluginOption {
553
557
  resolveId: {
554
558
  filter: { id: RN_DEEP_IMPORT_RE },
555
559
  handler(source) {
556
- if (this.environment?.name === 'client' || this.environment?.name === 'ssr') {
560
+ if (
561
+ this.environment?.name === 'client' ||
562
+ this.environment?.name === 'ssr' ||
563
+ this.environment?.name === 'worker'
564
+ ) {
557
565
  return '\0rn-empty-module'
558
566
  }
559
567
  },
@@ -867,7 +875,12 @@ export function one(options: One.PluginOptions = {}): PluginOption {
867
875
  return inspector ? sourceInspectorPlugin({ editor }) : []
868
876
  })()
869
877
 
878
+ const workerdDevPlugins = shouldEnableWorkerdDev(options.web?.deploy, root)
879
+ ? createWorkerdDevPlugins(options, root, routeIndex)
880
+ : []
881
+
870
882
  return [
883
+ ...workerdDevPlugins,
871
884
  ...vxrnPlugins,
872
885
  ...devAndProdPlugins,
873
886
  ...inspectorPlugins,
@@ -1,4 +1,4 @@
1
- import type { Plugin, ViteDevServer } from 'vite'
1
+ import type { ModuleNode, Plugin, ViteDevServer } from 'vite'
2
2
  import { VIRTUAL_SSR_CSS_ENTRY, VIRTUAL_SSR_CSS_HREF } from '../../constants'
3
3
 
4
4
  // thanks to hi-ogawa https://github.com/hi-ogawa/vite-plugins/tree/main/packages/ssr-css
@@ -152,6 +152,21 @@ async function collectStyleUrls(
152
152
  ): Promise<string[]> {
153
153
  const visited = new Set<string>()
154
154
 
155
+ // every module in importedModules already carries the id vite resolved when
156
+ // it entered the graph, so walk them directly. resolveUrl runs the whole
157
+ // plugin container and was awaited once per import EDGE rather than once per
158
+ // module, which on a large app is the entire cost of serving this stylesheet.
159
+ // the walk is an explicit stack so a deep import chain cannot overflow.
160
+ function walk(root: ModuleNode) {
161
+ const stack = [root]
162
+ while (stack.length) {
163
+ const mod = stack.pop()!
164
+ if (!mod.id || mod.url.includes('.server.') || visited.has(mod.id)) continue
165
+ visited.add(mod.id)
166
+ for (const childMod of mod.importedModules) stack.push(childMod)
167
+ }
168
+ }
169
+
155
170
  async function traverse(url: string) {
156
171
  if (url.includes('.server.')) return
157
172
  const [, id] = await server.moduleGraph.resolveUrl(url)
@@ -163,7 +178,7 @@ async function collectStyleUrls(
163
178
  if (!mod) {
164
179
  return
165
180
  }
166
- await Promise.all([...mod.importedModules].map((childMod) => traverse(childMod.url)))
181
+ for (const childMod of mod.importedModules) walk(childMod)
167
182
  }
168
183
 
169
184
  // ensure vite's import analysis is ready _only_ for top entries to not go too aggresive
@@ -135,6 +135,11 @@ describe('environmentGuardPlugin', () => {
135
135
  expect(result).toBe('export {}')
136
136
  })
137
137
 
138
+ it('web-only: allowed in worker', () => {
139
+ const result = loadEnvironmentGuard('\0one-env-guard:web-only:worker:server')
140
+ expect(result).toBe('export {}')
141
+ })
142
+
138
143
  it('web-only: forbidden in ios', () => {
139
144
  const result = loadEnvironmentGuard('\0one-env-guard:web-only:ios:unknown')
140
145
  expect(result).toContain('throw new Error')
@@ -35,11 +35,11 @@ const GUARD_SPECIFIERS = [
35
35
  const GUARD_SPECIFIERS_RE = new RegExp(`^(?:${GUARD_SPECIFIERS.join('|')})$`)
36
36
 
37
37
  type GuardSpecifier = (typeof GUARD_SPECIFIERS)[number]
38
- type ViteEnvironment = 'client' | 'ssr' | 'ios' | 'android'
38
+ type ViteEnvironment = 'client' | 'ssr' | 'ios' | 'android' | 'worker'
39
39
 
40
40
  const ALLOWED_BY_NAME: Partial<Record<GuardSpecifier, readonly ViteEnvironment[]>> = {
41
41
  'native-only': ['ios', 'android'],
42
- 'web-only': ['client', 'ssr'],
42
+ 'web-only': ['client', 'ssr', 'worker'],
43
43
  }
44
44
 
45
45
  const ALLOWED_BY_CONSUMER: Partial<Record<GuardSpecifier, 'server' | 'client'>> = {
@@ -124,6 +124,50 @@ describe('createFileSystemRouterPlugin', () => {
124
124
  )
125
125
  })
126
126
 
127
+ it('does not install the node request middleware when a worker environment exists', async () => {
128
+ process.env.IS_VXRN_CLI = '1'
129
+ tempRoot = mkdtempSync(path.join(tmpdir(), 'one-router-worker-'))
130
+ const appDir = path.join(tempRoot, 'app')
131
+ writeFileSync(path.join(tempRoot, 'package.json'), '{}\n')
132
+ mkdirSync(appDir)
133
+ writeFileSync(
134
+ path.join(appDir, 'index.tsx'),
135
+ 'export default function Index() { return null }\n'
136
+ )
137
+
138
+ ;(globalThis as any).__vxrnPluginConfig__ = {
139
+ web: {
140
+ defaultRenderMode: 'ssg',
141
+ },
142
+ }
143
+
144
+ const { createRouteIndex } = await import('../../utils/routeIndex')
145
+ const { createFileSystemRouterPlugin } = await import('./fileSystemRouterPlugin')
146
+ const plugin = createFileSystemRouterPlugin(
147
+ {
148
+ router: { root: appDir },
149
+ },
150
+ createRouteIndex({ routerRoot: appDir })
151
+ )
152
+
153
+ const use = vi.fn()
154
+ const server = {
155
+ environments: {
156
+ ssr: {},
157
+ worker: { moduleGraph: { getModuleById: vi.fn() } },
158
+ },
159
+ middlewares: { use },
160
+ watcher: {
161
+ addListener: vi.fn(),
162
+ on: vi.fn(),
163
+ },
164
+ }
165
+
166
+ const installMiddlewares = (plugin as any).configureServer(server)
167
+ installMiddlewares()
168
+ expect(use).not.toHaveBeenCalled()
169
+ })
170
+
127
171
  it('caches dev ssg html until the module runner is invalidated', async () => {
128
172
  process.env.VITE_ENVIRONMENT = 'ssr'
129
173
  tempRoot = mkdtempSync(path.join(tmpdir(), 'one-router-ssg-cache-'))