@servicetitan/startup 38.0.0 → 38.2.0

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 (429) hide show
  1. package/bin/js-yaml.js +2 -2
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/build.js +32 -10
  4. package/dist/cli/commands/build.js.map +1 -1
  5. package/dist/cli/commands/bundle-package.d.ts +6 -0
  6. package/dist/cli/commands/bundle-package.d.ts.map +1 -0
  7. package/dist/cli/commands/bundle-package.js +59 -0
  8. package/dist/cli/commands/bundle-package.js.map +1 -0
  9. package/dist/cli/commands/bundle-vite.js +13 -4
  10. package/dist/cli/commands/bundle-vite.js.map +1 -1
  11. package/dist/cli/commands/bundle-webpack.js +13 -4
  12. package/dist/cli/commands/bundle-webpack.js.map +1 -1
  13. package/dist/cli/commands/clean.js +13 -4
  14. package/dist/cli/commands/clean.js.map +1 -1
  15. package/dist/cli/commands/command.d.ts +13 -0
  16. package/dist/cli/commands/command.d.ts.map +1 -0
  17. package/dist/cli/commands/command.js +74 -0
  18. package/dist/cli/commands/command.js.map +1 -0
  19. package/dist/cli/commands/convert-eslint-config.js +14 -7
  20. package/dist/cli/commands/convert-eslint-config.js.map +1 -1
  21. package/dist/cli/commands/eslint.js +13 -4
  22. package/dist/cli/commands/eslint.js.map +1 -1
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/init.js +13 -5
  25. package/dist/cli/commands/init.js.map +1 -1
  26. package/dist/cli/commands/install.d.ts.map +1 -1
  27. package/dist/cli/commands/install.js +14 -21
  28. package/dist/cli/commands/install.js.map +1 -1
  29. package/dist/cli/commands/kendo-ui-license.js +13 -4
  30. package/dist/cli/commands/kendo-ui-license.js.map +1 -1
  31. package/dist/cli/commands/lint.js +13 -4
  32. package/dist/cli/commands/lint.js.map +1 -1
  33. package/dist/cli/commands/mfe-check.d.ts.map +1 -1
  34. package/dist/cli/commands/mfe-check.js +15 -7
  35. package/dist/cli/commands/mfe-check.js.map +1 -1
  36. package/dist/cli/commands/mfe-generate-metadata.js +13 -4
  37. package/dist/cli/commands/mfe-generate-metadata.js.map +1 -1
  38. package/dist/cli/commands/mfe-list.js +13 -4
  39. package/dist/cli/commands/mfe-list.js.map +1 -1
  40. package/dist/cli/commands/mfe-package-clean.js +13 -4
  41. package/dist/cli/commands/mfe-package-clean.js.map +1 -1
  42. package/dist/cli/commands/mfe-package-publish.js +13 -4
  43. package/dist/cli/commands/mfe-package-publish.js.map +1 -1
  44. package/dist/cli/commands/mfe-package-rollback.js +13 -4
  45. package/dist/cli/commands/mfe-package-rollback.js.map +1 -1
  46. package/dist/cli/commands/mfe-publish.js +13 -4
  47. package/dist/cli/commands/mfe-publish.js.map +1 -1
  48. package/dist/cli/commands/mfe-purge-cache.js +13 -4
  49. package/dist/cli/commands/mfe-purge-cache.js.map +1 -1
  50. package/dist/cli/commands/prepare-package.js +13 -4
  51. package/dist/cli/commands/prepare-package.js.map +1 -1
  52. package/dist/cli/commands/registry/build.d.ts +1 -1
  53. package/dist/cli/commands/registry/build.d.ts.map +1 -1
  54. package/dist/cli/commands/registry/build.js +3 -5
  55. package/dist/cli/commands/registry/build.js.map +1 -1
  56. package/dist/cli/commands/registry/bundle-package.d.ts +41 -0
  57. package/dist/cli/commands/registry/bundle-package.d.ts.map +1 -0
  58. package/dist/cli/commands/registry/bundle-package.js +54 -0
  59. package/dist/cli/commands/registry/bundle-package.js.map +1 -0
  60. package/dist/cli/commands/registry/command-registry.d.ts +42 -18
  61. package/dist/cli/commands/registry/command-registry.d.ts.map +1 -1
  62. package/dist/cli/commands/registry/command-registry.js +10 -19
  63. package/dist/cli/commands/registry/command-registry.js.map +1 -1
  64. package/dist/cli/commands/registry/install.d.ts +0 -16
  65. package/dist/cli/commands/registry/install.d.ts.map +1 -1
  66. package/dist/cli/commands/registry/install.js +1 -17
  67. package/dist/cli/commands/registry/install.js.map +1 -1
  68. package/dist/cli/commands/registry/start.d.ts +1 -1
  69. package/dist/cli/commands/registry/start.d.ts.map +1 -1
  70. package/dist/cli/commands/registry/start.js +3 -5
  71. package/dist/cli/commands/registry/start.js.map +1 -1
  72. package/dist/cli/commands/review/review.js +14 -7
  73. package/dist/cli/commands/review/review.js.map +1 -1
  74. package/dist/cli/commands/review/rules/no-deprecated-content-base.js +1 -3
  75. package/dist/cli/commands/review/rules/no-deprecated-content-base.js.map +1 -1
  76. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js +1 -3
  77. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js.map +1 -1
  78. package/dist/cli/commands/review/rules/no-typescript-entry-point.js +1 -3
  79. package/dist/cli/commands/review/rules/no-typescript-entry-point.js.map +1 -1
  80. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js +5 -12
  81. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js.map +1 -1
  82. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js +5 -12
  83. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js.map +1 -1
  84. package/dist/cli/commands/review/rules/require-explicit-side-effects.js +1 -3
  85. package/dist/cli/commands/review/rules/require-explicit-side-effects.js.map +1 -1
  86. package/dist/cli/commands/review/rules/require-one-collection-version.js +1 -3
  87. package/dist/cli/commands/review/rules/require-one-collection-version.js.map +1 -1
  88. package/dist/cli/commands/review/rules/require-servicetitan-scope.js +1 -3
  89. package/dist/cli/commands/review/rules/require-servicetitan-scope.js.map +1 -1
  90. package/dist/cli/commands/review/rules/require-tsconfig-references.js +1 -3
  91. package/dist/cli/commands/review/rules/require-tsconfig-references.js.map +1 -1
  92. package/dist/cli/commands/review/utils/compare-version.js +8 -19
  93. package/dist/cli/commands/review/utils/compare-version.js.map +1 -1
  94. package/dist/cli/commands/run-task.d.ts +1 -0
  95. package/dist/cli/commands/run-task.d.ts.map +1 -1
  96. package/dist/cli/commands/run-task.js +20 -6
  97. package/dist/cli/commands/run-task.js.map +1 -1
  98. package/dist/cli/commands/start.d.ts.map +1 -1
  99. package/dist/cli/commands/start.js +37 -14
  100. package/dist/cli/commands/start.js.map +1 -1
  101. package/dist/cli/commands/stylelint.js +13 -4
  102. package/dist/cli/commands/stylelint.js.map +1 -1
  103. package/dist/cli/commands/styles-check.js +13 -4
  104. package/dist/cli/commands/styles-check.js.map +1 -1
  105. package/dist/cli/commands/test/runners/jest.js +1 -3
  106. package/dist/cli/commands/test/runners/jest.js.map +1 -1
  107. package/dist/cli/commands/test/tests.js +13 -4
  108. package/dist/cli/commands/test/tests.js.map +1 -1
  109. package/dist/cli/commands/types.d.ts +1 -6
  110. package/dist/cli/commands/types.d.ts.map +1 -1
  111. package/dist/cli/commands/types.js +2 -20
  112. package/dist/cli/commands/types.js.map +1 -1
  113. package/dist/cli/commands/upload-sourcemaps.js +17 -13
  114. package/dist/cli/commands/upload-sourcemaps.js.map +1 -1
  115. package/dist/cli/index.js +1 -0
  116. package/dist/cli/index.js.map +1 -1
  117. package/dist/cli/tasks/cli-task.d.ts +3 -0
  118. package/dist/cli/tasks/cli-task.d.ts.map +1 -1
  119. package/dist/cli/tasks/cli-task.js +41 -9
  120. package/dist/cli/tasks/cli-task.js.map +1 -1
  121. package/dist/cli/tasks/swc-compile-package/get-swc-options.d.ts +9 -1
  122. package/dist/cli/tasks/swc-compile-package/get-swc-options.d.ts.map +1 -1
  123. package/dist/cli/tasks/swc-compile-package/get-swc-options.js +18 -2
  124. package/dist/cli/tasks/swc-compile-package/get-swc-options.js.map +1 -1
  125. package/dist/cli/tasks/swc-compile-package/swc-compile-package.d.ts +3 -1
  126. package/dist/cli/tasks/swc-compile-package/swc-compile-package.d.ts.map +1 -1
  127. package/dist/cli/tasks/swc-compile-package/swc-compile-package.js +17 -3
  128. package/dist/cli/tasks/swc-compile-package/swc-compile-package.js.map +1 -1
  129. package/dist/cli/tasks/task.d.ts +2 -1
  130. package/dist/cli/tasks/task.d.ts.map +1 -1
  131. package/dist/cli/tasks/task.js +6 -3
  132. package/dist/cli/tasks/task.js.map +1 -1
  133. package/dist/cli/tasks/tsc-compile/tsc-compile.js +1 -3
  134. package/dist/cli/tasks/tsc-compile/tsc-compile.js.map +1 -1
  135. package/dist/cli/utils/cli-git.d.ts +7 -0
  136. package/dist/cli/utils/cli-git.d.ts.map +1 -1
  137. package/dist/cli/utils/cli-git.js +30 -0
  138. package/dist/cli/utils/cli-git.js.map +1 -1
  139. package/dist/cli/utils/cli-npm.d.ts.map +1 -1
  140. package/dist/cli/utils/cli-npm.js +8 -1
  141. package/dist/cli/utils/cli-npm.js.map +1 -1
  142. package/dist/cli/utils/cli-os.d.ts +7 -1
  143. package/dist/cli/utils/cli-os.d.ts.map +1 -1
  144. package/dist/cli/utils/cli-os.js +42 -0
  145. package/dist/cli/utils/cli-os.js.map +1 -1
  146. package/dist/cli/utils/compile.d.ts.map +1 -1
  147. package/dist/cli/utils/compile.js +7 -4
  148. package/dist/cli/utils/compile.js.map +1 -1
  149. package/dist/cli/utils/copy-files.js +1 -0
  150. package/dist/cli/utils/copy-files.js.map +1 -1
  151. package/dist/cli/utils/index.d.ts +1 -1
  152. package/dist/cli/utils/index.d.ts.map +1 -1
  153. package/dist/cli/utils/index.js +1 -1
  154. package/dist/cli/utils/index.js.map +1 -1
  155. package/dist/cli/utils/process-tree.js +2 -6
  156. package/dist/cli/utils/process-tree.js.map +1 -1
  157. package/dist/cli/utils/resolve-bundler.d.ts.map +1 -1
  158. package/dist/cli/utils/resolve-bundler.js +2 -1
  159. package/dist/cli/utils/resolve-bundler.js.map +1 -1
  160. package/dist/cli/utils/ts-config.d.ts +1 -1
  161. package/dist/cli/utils/ts-config.d.ts.map +1 -1
  162. package/dist/cli/utils/ts-config.js +1 -3
  163. package/dist/cli/utils/ts-config.js.map +1 -1
  164. package/dist/cli/utils/with-exponential-backoff.d.ts +7 -0
  165. package/dist/cli/utils/with-exponential-backoff.d.ts.map +1 -0
  166. package/dist/cli/utils/with-exponential-backoff.js +28 -0
  167. package/dist/cli/utils/with-exponential-backoff.js.map +1 -0
  168. package/dist/core/constants.d.ts +2 -0
  169. package/dist/core/constants.d.ts.map +1 -1
  170. package/dist/core/constants.js +6 -1
  171. package/dist/core/constants.js.map +1 -1
  172. package/dist/postinstall.js +118 -0
  173. package/dist/scripts/generate-bin-wrappers.js +203 -0
  174. package/dist/storybook-config/swc.d.ts +6 -0
  175. package/dist/storybook-config/swc.d.ts.map +1 -1
  176. package/dist/storybook-config/webpack-final.d.ts.map +1 -1
  177. package/dist/storybook-config/webpack-final.js +2 -1
  178. package/dist/storybook-config/webpack-final.js.map +1 -1
  179. package/dist/telemetry/index.d.ts +3 -0
  180. package/dist/telemetry/index.d.ts.map +1 -0
  181. package/dist/telemetry/index.js +21 -0
  182. package/dist/telemetry/index.js.map +1 -0
  183. package/dist/telemetry/telemetry.d.ts +15 -0
  184. package/dist/telemetry/telemetry.d.ts.map +1 -0
  185. package/dist/telemetry/telemetry.js +176 -0
  186. package/dist/telemetry/telemetry.js.map +1 -0
  187. package/dist/utils/exit-when-parent-exits.d.ts +6 -0
  188. package/dist/utils/exit-when-parent-exits.d.ts.map +1 -0
  189. package/dist/utils/exit-when-parent-exits.js +37 -0
  190. package/dist/utils/exit-when-parent-exits.js.map +1 -0
  191. package/dist/utils/find-up.d.ts +1 -1
  192. package/dist/utils/find-up.d.ts.map +1 -1
  193. package/dist/utils/find-up.js +2 -2
  194. package/dist/utils/find-up.js.map +1 -1
  195. package/dist/utils/get-configuration.d.ts +6 -3
  196. package/dist/utils/get-configuration.d.ts.map +1 -1
  197. package/dist/utils/get-configuration.js +10 -2
  198. package/dist/utils/get-configuration.js.map +1 -1
  199. package/dist/utils/index.d.ts +1 -0
  200. package/dist/utils/index.d.ts.map +1 -1
  201. package/dist/utils/index.js +1 -0
  202. package/dist/utils/index.js.map +1 -1
  203. package/dist/utils/log.js +1 -3
  204. package/dist/utils/log.js.map +1 -1
  205. package/dist/vite/build-shared-dependencies.d.ts.map +1 -1
  206. package/dist/vite/build-shared-dependencies.js +2 -0
  207. package/dist/vite/build-shared-dependencies.js.map +1 -1
  208. package/dist/vite/config/base-config.d.ts.map +1 -1
  209. package/dist/vite/config/base-config.js +12 -1
  210. package/dist/vite/config/base-config.js.map +1 -1
  211. package/dist/vite/config/create-filtering-logger.d.ts.map +1 -1
  212. package/dist/vite/config/create-filtering-logger.js +6 -2
  213. package/dist/vite/config/create-filtering-logger.js.map +1 -1
  214. package/dist/vite/config/create-vite-config.js +7 -2
  215. package/dist/vite/config/create-vite-config.js.map +1 -1
  216. package/dist/vite/config/load-config-file.js +8 -19
  217. package/dist/vite/config/load-config-file.js.map +1 -1
  218. package/dist/vite/index.d.ts +2 -0
  219. package/dist/vite/index.d.ts.map +1 -1
  220. package/dist/vite/index.html +2 -2
  221. package/dist/vite/index.js +16 -0
  222. package/dist/vite/index.js.map +1 -1
  223. package/dist/vite/plugins/chain-source-maps-plugin.js +1 -1
  224. package/dist/vite/plugins/chain-source-maps-plugin.js.map +1 -1
  225. package/dist/vite/plugins/clean-plugin.js +1 -1
  226. package/dist/vite/plugins/clean-plugin.js.map +1 -1
  227. package/dist/vite/plugins/css-injector-plugin.js +1 -1
  228. package/dist/vite/plugins/css-injector-plugin.js.map +1 -1
  229. package/dist/vite/plugins/design-system-guard-plugin.d.ts.map +1 -1
  230. package/dist/vite/plugins/design-system-guard-plugin.js +10 -5
  231. package/dist/vite/plugins/design-system-guard-plugin.js.map +1 -1
  232. package/dist/vite/plugins/dev-server-routing-plugin.js +1 -1
  233. package/dist/vite/plugins/dev-server-routing-plugin.js.map +1 -1
  234. package/dist/vite/plugins/externals-plugin.d.ts.map +1 -1
  235. package/dist/vite/plugins/externals-plugin.js +11 -5
  236. package/dist/vite/plugins/externals-plugin.js.map +1 -1
  237. package/dist/vite/plugins/html-plugin.d.ts.map +1 -1
  238. package/dist/vite/plugins/html-plugin.js +5 -3
  239. package/dist/vite/plugins/html-plugin.js.map +1 -1
  240. package/dist/vite/plugins/ignore-modules-plugin.d.ts +2 -2
  241. package/dist/vite/plugins/ignore-modules-plugin.d.ts.map +1 -1
  242. package/dist/vite/plugins/ignore-modules-plugin.js +36 -24
  243. package/dist/vite/plugins/ignore-modules-plugin.js.map +1 -1
  244. package/dist/vite/plugins/index.d.ts +3 -0
  245. package/dist/vite/plugins/index.d.ts.map +1 -1
  246. package/dist/vite/plugins/index.js +3 -0
  247. package/dist/vite/plugins/index.js.map +1 -1
  248. package/dist/vite/plugins/less-tilde-plugin.d.ts +8 -0
  249. package/dist/vite/plugins/less-tilde-plugin.d.ts.map +1 -0
  250. package/dist/vite/plugins/less-tilde-plugin.js +53 -0
  251. package/dist/vite/plugins/less-tilde-plugin.js.map +1 -0
  252. package/dist/vite/plugins/magic-comments-plugin/magic-comments-plugin.js +1 -1
  253. package/dist/vite/plugins/magic-comments-plugin/magic-comments-plugin.js.map +1 -1
  254. package/dist/vite/plugins/metadata-plugin.js +1 -1
  255. package/dist/vite/plugins/metadata-plugin.js.map +1 -1
  256. package/dist/vite/plugins/moment-locales-plugin.d.ts +1 -1
  257. package/dist/vite/plugins/moment-locales-plugin.d.ts.map +1 -1
  258. package/dist/vite/plugins/moment-locales-plugin.js +30 -14
  259. package/dist/vite/plugins/moment-locales-plugin.js.map +1 -1
  260. package/dist/vite/plugins/react-refresh-plugin/index.d.ts +2 -0
  261. package/dist/vite/plugins/react-refresh-plugin/index.d.ts.map +1 -0
  262. package/dist/vite/plugins/react-refresh-plugin/index.js +20 -0
  263. package/dist/vite/plugins/react-refresh-plugin/index.js.map +1 -0
  264. package/dist/vite/plugins/react-refresh-plugin/react-refresh-plugin.d.ts +4 -0
  265. package/dist/vite/plugins/react-refresh-plugin/react-refresh-plugin.d.ts.map +1 -0
  266. package/dist/vite/plugins/react-refresh-plugin/react-refresh-plugin.js +143 -0
  267. package/dist/vite/plugins/react-refresh-plugin/react-refresh-plugin.js.map +1 -0
  268. package/dist/vite/plugins/react-refresh-plugin/refresh-runtime.js +113 -0
  269. package/dist/vite/plugins/shared-dependencies-plugin/shared-dependencies-plugin.d.ts.map +1 -1
  270. package/dist/vite/plugins/shared-dependencies-plugin/shared-dependencies-plugin.js +14 -11
  271. package/dist/vite/plugins/shared-dependencies-plugin/shared-dependencies-plugin.js.map +1 -1
  272. package/dist/vite/plugins/style-urls-plugin.js +1 -1
  273. package/dist/vite/plugins/style-urls-plugin.js.map +1 -1
  274. package/dist/vite/plugins/virtual-modules-plugin.d.ts.map +1 -1
  275. package/dist/vite/plugins/virtual-modules-plugin.js +9 -6
  276. package/dist/vite/plugins/virtual-modules-plugin.js.map +1 -1
  277. package/dist/vite/plugins/window-externals-plugin.d.ts +22 -0
  278. package/dist/vite/plugins/window-externals-plugin.d.ts.map +1 -0
  279. package/dist/vite/plugins/window-externals-plugin.js +74 -0
  280. package/dist/vite/plugins/window-externals-plugin.js.map +1 -0
  281. package/dist/webpack/bundle-webpack.d.ts.map +1 -1
  282. package/dist/webpack/bundle-webpack.js +6 -1
  283. package/dist/webpack/bundle-webpack.js.map +1 -1
  284. package/dist/webpack/configs/optimization-config.js +17 -12
  285. package/dist/webpack/configs/optimization-config.js.map +1 -1
  286. package/dist/webpack/configs/output-config.js +1 -1
  287. package/dist/webpack/configs/output-config.js.map +1 -1
  288. package/dist/webpack/configs/plugins/ignore-plugin/ignore-plugin.js +1 -3
  289. package/dist/webpack/configs/plugins/ignore-plugin/ignore-plugin.js.map +1 -1
  290. package/dist/webpack/loaders/expose-loader/__tests__/__mocks__/configuration.expose-loader.js +13 -0
  291. package/dist/webpack/loaders/expose-loader/__tests__/__mocks__/index.js +1 -0
  292. package/dist/webpack/utils/index.d.ts +1 -0
  293. package/dist/webpack/utils/index.d.ts.map +1 -1
  294. package/dist/webpack/utils/index.js +1 -0
  295. package/dist/webpack/utils/index.js.map +1 -1
  296. package/dist/webpack/utils/normalize-proxy-config.d.ts +6 -0
  297. package/dist/webpack/utils/normalize-proxy-config.d.ts.map +1 -0
  298. package/dist/webpack/utils/normalize-proxy-config.js +52 -0
  299. package/dist/webpack/utils/normalize-proxy-config.js.map +1 -0
  300. package/package.json +32 -26
  301. package/src/cli/commands/__tests__/build.test.ts +81 -20
  302. package/src/cli/commands/__tests__/bundle-package.test.ts +65 -0
  303. package/src/cli/commands/__tests__/command.test.ts +154 -0
  304. package/src/cli/commands/__tests__/init.test.ts +1 -1
  305. package/src/cli/commands/__tests__/install.test.ts +5 -72
  306. package/src/cli/commands/__tests__/mfe-check.test.ts +26 -5
  307. package/src/cli/commands/__tests__/run-task.test.ts +20 -1
  308. package/src/cli/commands/__tests__/start.test.ts +77 -16
  309. package/src/cli/commands/build.ts +15 -6
  310. package/src/cli/commands/bundle-package.ts +20 -0
  311. package/src/cli/commands/command.ts +64 -0
  312. package/src/cli/commands/init.ts +0 -1
  313. package/src/cli/commands/install.ts +5 -21
  314. package/src/cli/commands/mfe-check.ts +6 -10
  315. package/src/cli/commands/registry/build.ts +3 -2
  316. package/src/cli/commands/registry/bundle-package.ts +22 -0
  317. package/src/cli/commands/registry/command-registry.ts +2 -0
  318. package/src/cli/commands/registry/install.ts +1 -6
  319. package/src/cli/commands/registry/start.ts +3 -2
  320. package/src/cli/commands/run-task.ts +8 -2
  321. package/src/cli/commands/start.ts +17 -6
  322. package/src/cli/commands/types.ts +2 -6
  323. package/src/cli/index.ts +3 -0
  324. package/src/cli/tasks/__tests__/cli-task.test.ts +181 -69
  325. package/src/cli/tasks/__tests__/task.test.ts +40 -45
  326. package/src/cli/tasks/cli-task.ts +43 -2
  327. package/src/cli/tasks/swc-compile-package/__tests__/get-swc-options.test.ts +46 -4
  328. package/src/cli/tasks/swc-compile-package/__tests__/swc-compile-package.test.ts +25 -4
  329. package/src/cli/tasks/swc-compile-package/get-swc-options.ts +14 -1
  330. package/src/cli/tasks/swc-compile-package/swc-compile-package.ts +6 -2
  331. package/src/cli/tasks/task.ts +8 -2
  332. package/src/cli/tasks/tsc-compile/__tests__/tsc-compile.test.ts +8 -32
  333. package/src/cli/tasks/tsc-compile-package/__tests__/tsc-compile-package.test.ts +10 -19
  334. package/src/cli/utils/__tests__/cli-git.test.ts +54 -3
  335. package/src/cli/utils/__tests__/cli-npm.test.ts +33 -0
  336. package/src/cli/utils/__tests__/cli-os.test.ts +183 -4
  337. package/src/cli/utils/__tests__/compile.test.ts +37 -2
  338. package/src/cli/utils/__tests__/copy-files.test.ts +1 -1
  339. package/src/cli/utils/__tests__/with-exponential-backoff.test.ts +119 -0
  340. package/src/cli/utils/cli-git.ts +27 -1
  341. package/src/cli/utils/cli-npm.ts +19 -4
  342. package/src/cli/utils/cli-os.ts +44 -0
  343. package/src/cli/utils/compile.ts +8 -1
  344. package/src/cli/utils/copy-files.ts +1 -1
  345. package/src/cli/utils/index.ts +1 -1
  346. package/src/cli/utils/resolve-bundler.ts +2 -1
  347. package/src/cli/utils/ts-config.ts +1 -1
  348. package/src/cli/utils/with-exponential-backoff.ts +28 -0
  349. package/src/core/constants.ts +2 -0
  350. package/src/storybook-config/__tests__/vite-final.test.ts +6 -0
  351. package/src/storybook-config/__tests__/webpack-final.test.ts +26 -12
  352. package/src/storybook-config/webpack-final.ts +10 -4
  353. package/src/telemetry/__tests__/telemetry.test.ts +326 -0
  354. package/src/telemetry/index.ts +2 -0
  355. package/src/telemetry/telemetry.ts +134 -0
  356. package/src/utils/__tests__/exit-when-parent-exits.test.ts +87 -0
  357. package/src/utils/__tests__/find-up.test.ts +49 -0
  358. package/src/utils/__tests__/get-configuration.test.ts +62 -0
  359. package/src/utils/exit-when-parent-exits.ts +33 -0
  360. package/src/utils/find-up.ts +2 -2
  361. package/src/utils/get-configuration.ts +14 -5
  362. package/src/utils/index.ts +1 -0
  363. package/src/vite/__tests__/build-shared-dependencies.test.ts +39 -5
  364. package/src/vite/build-shared-dependencies.ts +2 -1
  365. package/src/vite/config/__tests__/base-config.test.ts +12 -4
  366. package/src/vite/config/__tests__/create-css-config.test.ts +2 -6
  367. package/src/vite/config/__tests__/create-filtering-logger.test.ts +3 -2
  368. package/src/vite/config/__tests__/create-vite-config.test.ts +6 -3
  369. package/src/vite/config/base-config.ts +13 -1
  370. package/src/vite/config/create-filtering-logger.ts +8 -2
  371. package/src/vite/config/create-vite-config.ts +6 -3
  372. package/src/vite/index.html +2 -2
  373. package/src/vite/index.ts +2 -0
  374. package/src/vite/plugins/__tests__/chain-source-maps-plugin.test.ts +1 -1
  375. package/src/vite/plugins/__tests__/clean-plugin.test.ts +1 -1
  376. package/src/vite/plugins/__tests__/css-injector-plugin.test.ts +1 -1
  377. package/src/vite/plugins/__tests__/design-system-guard-plugin.test.ts +15 -3
  378. package/src/vite/plugins/__tests__/dev-server-routing-plugin.test.ts +1 -1
  379. package/src/vite/plugins/__tests__/externals-plugin.test.ts +24 -3
  380. package/src/vite/plugins/__tests__/html-plugin.test.ts +10 -3
  381. package/src/vite/plugins/__tests__/html-template.test.ts +10 -2
  382. package/src/vite/plugins/__tests__/ignore-modules-plugin.test.ts +30 -6
  383. package/src/vite/plugins/__tests__/less-tilde-plugin.test.ts +91 -0
  384. package/src/vite/plugins/__tests__/metadata-plugin.test.ts +1 -1
  385. package/src/vite/plugins/__tests__/moment-locales-plugin.test.ts +35 -25
  386. package/src/vite/plugins/__tests__/style-urls-plugin.test.ts +1 -1
  387. package/src/vite/plugins/__tests__/virtual-modules-plugin.test.ts +20 -9
  388. package/src/vite/plugins/__tests__/window-externals-plugin.test.ts +128 -0
  389. package/src/vite/plugins/chain-source-maps-plugin.ts +1 -1
  390. package/src/vite/plugins/clean-plugin.ts +1 -1
  391. package/src/vite/plugins/css-injector-plugin.ts +1 -1
  392. package/src/vite/plugins/design-system-guard-plugin.ts +11 -8
  393. package/src/vite/plugins/dev-server-routing-plugin.ts +1 -1
  394. package/src/vite/plugins/externals-plugin.ts +15 -6
  395. package/src/vite/plugins/html-plugin.ts +4 -2
  396. package/src/vite/plugins/ignore-modules-plugin.ts +32 -23
  397. package/src/vite/plugins/index.ts +3 -0
  398. package/src/vite/plugins/less-tilde-plugin.ts +64 -0
  399. package/src/vite/plugins/magic-comments-plugin/magic-comments-plugin.ts +1 -1
  400. package/src/vite/plugins/metadata-plugin.ts +1 -1
  401. package/src/vite/plugins/moment-locales-plugin.ts +24 -14
  402. package/src/vite/plugins/react-refresh-plugin/README.md +165 -0
  403. package/src/vite/plugins/react-refresh-plugin/__tests__/react-refresh-plugin.test.ts +366 -0
  404. package/src/vite/plugins/react-refresh-plugin/__tests__/refresh-runtime.test.ts +193 -0
  405. package/src/vite/plugins/react-refresh-plugin/index.ts +1 -0
  406. package/src/vite/plugins/react-refresh-plugin/react-refresh-plugin.ts +144 -0
  407. package/src/vite/plugins/react-refresh-plugin/refresh-runtime.js +113 -0
  408. package/src/vite/plugins/shared-dependencies-plugin/__tests__/shared-dependencies-plugin.test.ts +21 -16
  409. package/src/vite/plugins/shared-dependencies-plugin/shared-dependencies-plugin.ts +13 -12
  410. package/src/vite/plugins/style-urls-plugin.ts +1 -1
  411. package/src/vite/plugins/virtual-modules-plugin.ts +8 -7
  412. package/src/vite/plugins/window-externals-plugin.ts +94 -0
  413. package/src/webpack/__tests__/bundle-webpack.test.ts +32 -0
  414. package/src/webpack/__tests__/create-webpack-config-shared-dependencies.test.ts +27 -1
  415. package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +17 -5
  416. package/src/webpack/__tests__/create-webpack-config.test.ts +10 -6
  417. package/src/webpack/bundle-webpack.ts +7 -1
  418. package/src/webpack/configs/optimization-config.ts +22 -11
  419. package/src/webpack/configs/output-config.ts +1 -1
  420. package/src/webpack/utils/__tests__/normalize-proxy-config.test.ts +121 -0
  421. package/src/webpack/utils/index.ts +1 -0
  422. package/src/webpack/utils/normalize-proxy-config.ts +59 -0
  423. package/tsconfig/types.d.ts +10 -0
  424. package/dist/cli/utils/get-bundle-command.d.ts +0 -3
  425. package/dist/cli/utils/get-bundle-command.d.ts.map +0 -1
  426. package/dist/cli/utils/get-bundle-command.js +0 -16
  427. package/dist/cli/utils/get-bundle-command.js.map +0 -1
  428. package/src/cli/utils/__tests__/get-bundle-command.test.ts +0 -23
  429. package/src/cli/utils/get-bundle-command.ts +0 -5
@@ -2,8 +2,11 @@ import type { Plugin } from 'vite';
2
2
  import { checkResource } from '../../core';
3
3
  import type { PackageContext } from '../../core/types';
4
4
 
5
- export const THROW_PREFIX = '\0IGNORE_THROW:';
6
- export const EMPTY_PREFIX = '\0IGNORE_EMPTY:';
5
+ const VIRTUAL_PREFIX = '\0ignore-modules:';
6
+ const VIRTUAL_ID_PATTERN = new RegExp(`^${VIRTUAL_PREFIX}`);
7
+
8
+ export const THROW_PREFIX = `${VIRTUAL_PREFIX}throw:`;
9
+ export const EMPTY_PREFIX = `${VIRTUAL_PREFIX}empty:`;
7
10
 
8
11
  /**
9
12
  * Handles optional peer dependencies that are not installed.
@@ -26,29 +29,35 @@ export function ignoreModulesPlugin(context: {
26
29
  const checker = checkResource(context);
27
30
 
28
31
  return {
29
- name: 'ignore-modules',
32
+ name: 'st:ignore-modules',
30
33
  enforce: 'pre',
31
- resolveId(source, importer) {
32
- if (!importer) {
33
- return;
34
- }
35
- const mode = checker({ resource: source, importer });
36
- if (mode === 'throw') {
37
- return `${THROW_PREFIX}${source}`;
38
- }
39
- if (mode === 'empty') {
40
- return `${EMPTY_PREFIX}${source}`;
41
- }
34
+ resolveId: {
35
+ filter: { id: /^[@a-z]/ }, // Only bare specifiers can be optional peers
36
+ handler(source, importer) {
37
+ if (!importer) {
38
+ return;
39
+ }
40
+ const mode = checker({ resource: source, importer });
41
+ if (mode === 'throw') {
42
+ return `${THROW_PREFIX}${source}`;
43
+ }
44
+ if (mode === 'empty') {
45
+ return `${EMPTY_PREFIX}${source}`;
46
+ }
47
+ },
42
48
  },
43
- load(id) {
44
- if (id.startsWith(THROW_PREFIX)) {
45
- const source = id.slice(THROW_PREFIX.length);
46
- const message = JSON.stringify(`Cannot find module '${source}'`);
47
- return `throw Object.assign(new Error(${message}), { code: 'MODULE_NOT_FOUND' });`;
48
- }
49
- if (id.startsWith(EMPTY_PREFIX)) {
50
- return 'export {};';
51
- }
49
+ load: {
50
+ filter: { id: VIRTUAL_ID_PATTERN },
51
+ handler(id) {
52
+ if (id.startsWith(THROW_PREFIX)) {
53
+ const source = id.slice(THROW_PREFIX.length);
54
+ const message = JSON.stringify(`Cannot find module '${source}'`);
55
+ return `throw Object.assign(new Error(${message}), { code: 'MODULE_NOT_FOUND' });`;
56
+ }
57
+ if (id.startsWith(EMPTY_PREFIX)) {
58
+ return 'export {};';
59
+ }
60
+ },
52
61
  },
53
62
  };
54
63
  }
@@ -8,9 +8,12 @@ export * from './externals-plugin';
8
8
  export * from './html-plugin';
9
9
  export * from './ignore-modules-plugin';
10
10
  export * from './istanbul-plugin';
11
+ export * from './less-tilde-plugin';
11
12
  export * from './magic-comments-plugin';
12
13
  export * from './metadata-plugin';
13
14
  export * from './moment-locales-plugin';
15
+ export * from './react-refresh-plugin';
14
16
  export * from './style-urls-plugin';
15
17
  export * from './svgr-plugin';
16
18
  export * from './virtual-modules-plugin';
19
+ export * from './window-externals-plugin';
@@ -0,0 +1,64 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { findUp } from '../../utils';
4
+
5
+ interface LessPluginManager {
6
+ addFileManager(manager: unknown): void;
7
+ }
8
+
9
+ /*
10
+ * Less plugin that resolves webpack-style `~pkg` imports (e.g. `~@servicetitan/tokens/...`) from
11
+ * node_modules. Vite's Less integration does not understand the `~` prefix, so without this every
12
+ * style importing a package with `~` fails to resolve. Mirrors the old less-loader behavior to
13
+ * ease webpack-to-Vite migration.
14
+ */
15
+ export function lessTildePlugin() {
16
+ return {
17
+ install(less: any, pluginManager: LessPluginManager) {
18
+ const TildeFileManager = createTildeFileManager(less);
19
+ pluginManager.addFileManager(new TildeFileManager());
20
+ },
21
+ };
22
+ }
23
+
24
+ /*
25
+ * A FileManager subclass bound to the Less instance Vite passes to the plugin. It claims `~`
26
+ * imports and rewrites them to a node_modules path before delegating to the base loader.
27
+ */
28
+ function createTildeFileManager(less: any) {
29
+ return class extends less.FileManager {
30
+ supports(filename: string) {
31
+ return filename.startsWith('~');
32
+ }
33
+
34
+ loadFile(
35
+ filename: string,
36
+ currentDirectory: string,
37
+ options: unknown,
38
+ environment: unknown
39
+ ) {
40
+ return super.loadFile(
41
+ resolveFromNodeModules(filename.slice(1), currentDirectory),
42
+ currentDirectory,
43
+ options,
44
+ environment
45
+ );
46
+ }
47
+ };
48
+ }
49
+
50
+ /*
51
+ * Resolve a bare `pkg/path` specifier against the nearest node_modules, walking up from the
52
+ * importing file's directory, so the import binds to the importer's dependencies (matching
53
+ * webpack, and covering both pnpm's symlinked store and npm's hoisted tree).
54
+ */
55
+ function resolveFromNodeModules(specifier: string, fromDirectory: string): string {
56
+ const withExtension = path.extname(specifier) ? specifier : `${specifier}.less`;
57
+
58
+ const resolved = findUp(directory => {
59
+ const candidate = path.join(directory, 'node_modules', withExtension);
60
+ return fs.existsSync(candidate) ? candidate : undefined;
61
+ }, fromDirectory);
62
+
63
+ return resolved ?? withExtension;
64
+ }
@@ -19,7 +19,7 @@ export function magicCommentsPlugin(context: ViteBuildContext): Plugin | undefin
19
19
  const moduleByName = new Map<string, string>();
20
20
 
21
21
  return {
22
- name: 'magic-comments',
22
+ name: 'st:magic-comments',
23
23
  apply: 'build',
24
24
  enforce: 'pre',
25
25
  config: () => ({
@@ -12,7 +12,7 @@ export function metadataPlugin(context: BuildContext): Plugin | undefined {
12
12
  let outDir = '';
13
13
 
14
14
  return {
15
- name: 'metadata',
15
+ name: 'st:metadata',
16
16
  configResolved(config) {
17
17
  outDir = config.build.outDir;
18
18
  },
@@ -1,7 +1,8 @@
1
1
  import type { Plugin } from 'vite';
2
2
  import { BuildContext, MOMENT_LOCALES } from '../../core';
3
3
 
4
- export const VIRTUAL_MOMENT = '\0VIRTUAL_MOMENT';
4
+ export const VIRTUAL_MOMENT = '\0moment-locales';
5
+ const VIRTUAL_ID_PATTERN = new RegExp(`^${VIRTUAL_MOMENT}`);
5
6
 
6
7
  const UMD_LOCALE = /^moment\/locale\/(.+)$/;
7
8
 
@@ -15,27 +16,36 @@ const UMD_LOCALE = /^moment\/locale\/(.+)$/;
15
16
  */
16
17
  export function momentLocalesPlugin(_context: BuildContext): Plugin {
17
18
  return {
18
- name: 'moment-locales',
19
+ name: 'st:moment-locales',
19
20
  enforce: 'pre',
20
- resolveId(source, importer, options) {
21
- if (source === 'moment') {
22
- return VIRTUAL_MOMENT;
23
- }
24
- // Redirect explicit UMD locale imports to the ESM build so they share that instance.
25
- const locale = UMD_LOCALE.exec(source)?.[1];
26
- if (locale) {
27
- return this.resolve(`moment/dist/locale/${locale}`, importer, options);
28
- }
21
+ resolveId: {
22
+ filter: { id: [/^moment$/, UMD_LOCALE] },
23
+ handler(source, importer, options) {
24
+ if (source === 'moment') {
25
+ return VIRTUAL_MOMENT;
26
+ }
27
+ // Redirect explicit UMD locale imports to the ESM build so they share that instance.
28
+ const locale = UMD_LOCALE.exec(source)?.[1];
29
+ if (locale) {
30
+ return this.resolve(`moment/dist/locale/${locale}`, importer, options);
31
+ }
32
+ },
29
33
  },
30
- load(id) {
31
- if (id === VIRTUAL_MOMENT) {
34
+ load: {
35
+ filter: { id: VIRTUAL_ID_PATTERN },
36
+ handler() {
32
37
  return [
33
38
  ...MOMENT_LOCALES.map(locale => `import 'moment/dist/locale/${locale}';`),
34
39
  `import moment from 'moment/dist/moment.js';`,
35
40
  `export * from 'moment/dist/moment.js';`,
36
41
  `export default moment;`,
42
+ /*
43
+ * moment attaches these to the function itself rather than declaring them as
44
+ * real ES named exports, so `export *` above doesn't forward them.
45
+ */
46
+ `export const isMoment = moment.isMoment;`,
37
47
  ].join('\n');
38
- }
48
+ },
39
49
  },
40
50
  };
41
51
  }
@@ -0,0 +1,165 @@
1
+ # React Fast Refresh Plugin
2
+
3
+ This plugin bridges Startup's Vite development build with Vite HMR and React Fast Refresh.
4
+
5
+ In Vite development mode, `swc` compiles TSX into `dist/` and injects React Fast Refresh markers into modules that contain statically identifiable React components. Vite serves those compiled files, but the markers are just global function calls until something provides the refresh runtime and tells Vite which modules can accept hot updates. This plugin provides that missing serve-time layer.
6
+
7
+ ## Responsibilities
8
+
9
+ The React Fast Refresh flow has four layers:
10
+
11
+ | Layer | Tool | Role |
12
+ | ------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | Compile | `swc` | Compiles TSX to JS in `dist/` and injects `$RefreshReg$` and `$RefreshSig$` markers. |
14
+ | Serve | Vite | Serves `dist/`, transforms modules, and sends HMR updates over WebSocket. |
15
+ | Bridge | `react-refresh-plugin` | Serves the refresh runtime, installs it into React's global hook, injects per-module locals, and validates refresh boundaries before update. |
16
+ | Render | React Fast Refresh runtime | Tracks component families and asks React to re-render with updated component functions. |
17
+
18
+ Plain CSS does not use React Fast Refresh. Vite handles plain CSS HMR natively by replacing the stylesheet in the DOM. CSS modules export class name bindings, so they behave more like JS modules and propagate through the importing React module.
19
+
20
+ ## What `swc` Provides
21
+
22
+ When `react.refresh` and `react.development` are enabled, `swc` emits markers like this:
23
+
24
+ ```js
25
+ var _s = $RefreshSig$();
26
+ export const App = () => {
27
+ _s();
28
+ return _jsx('div', { children: '...' });
29
+ };
30
+ _s(App, 'useState{[count, setCount]}');
31
+ $RefreshReg$(App, 'App');
32
+ ```
33
+
34
+ `$RefreshSig$` records the component's hook signature so React can decide whether state can be preserved. `$RefreshReg$` registers the component with a stable ID so the runtime can match the old and new component functions across edits.
35
+
36
+ `swc` can only register components it can statically identify. A direct function declaration or an arrow function assigned to a variable can be registered. A component returned from a higher-order function call, such as `provide({...})(() => ...)`, cannot. Those modules may get `$RefreshSig$` without `$RefreshReg$`, and this plugin lets those fall through to a full page reload because the runtime cannot track their component identity.
37
+
38
+ ## What The Plugin Does
39
+
40
+ The plugin runs with `enforce: 'pre'` so its refresh transforms run before Vite's normal transform pipeline. Its transform hook is also filtered to modules whose code contains `$RefreshReg$` or `$RefreshSig$`, so Vite can skip invoking it for unrelated modules.
41
+
42
+ The plugin does three things in development:
43
+
44
+ 1. It serves `react-refresh/runtime` as a virtual ESM module at `/@react-refresh`.
45
+ 2. It injects a preamble script into the HTML head before app code runs.
46
+ 3. It transforms served modules that contain refresh markers.
47
+
48
+ The virtual module wraps the official `react-refresh/runtime` package, stores it on `window.__ReactRefreshRuntime`, and appends local browser helpers from `refresh-runtime.js`. This global singleton matters in the monorepo because the host and MFE can be served by different Vite dev servers. Reusing one runtime ensures `performReactRefresh()` from an MFE update can reach the renderer captured when the host initialized React.
49
+
50
+ The preamble is a single side-effect import of the virtual module (`import "/@react-refresh"`). Importing the virtual module as a side effect is enough: the module's own initialization code calls `injectIntoGlobalHook(window)` the first time it loads (see `getRefreshRuntimeCode`), which patches `window.__REACT_DEVTOOLS_GLOBAL_HOOK__` so that React registers its renderer with the refresh runtime when React itself initializes. The preamble does not set `window.$RefreshReg$` or `window.$RefreshSig$`. Those are instead injected as per-module locals by the transform step (see below).
51
+
52
+ The preamble is injected with `injectTo: 'head-prepend'` as a module script. Shared dependency bundles are loaded with `defer`. Module scripts and defer scripts share the same execution queue and run in document order, so the preamble runs before React initializes. That timing ensures `injectIntoGlobalHook` patches the DevTools hook before React calls `hook.inject(renderer)`.
53
+
54
+ For each served module with `$RefreshReg$` or `$RefreshSig$`, the transform step applies these rules:
55
+
56
+ - Workspace package modules always receive a per-module prelude that defines local `$RefreshReg$` and `$RefreshSig$` variables. The local `$RefreshReg$` scopes registration IDs to the served module URL so host and MFE servers sharing one runtime cannot produce colliding refresh families. Modules with `$RefreshReg$` additionally receive an HMR postlude that records the current exports and self-accepts future updates.
57
+ - Accepted updates are validated before React Fast Refresh runs. If the module remains a safe refresh boundary, the helper queues `RefreshRuntime.performReactRefresh()`. If exports were added, removed, changed incompatibly, or exposed through getters, the helper calls `import.meta.hot.invalidate(...)` so Vite falls back to normal invalidation and full reload when needed.
58
+ - Workspace modules with only `$RefreshSig$` (HOC-wrapped components) receive the per-module prelude but not the postlude, so they are not self-accepted and Vite falls back to a full reload.
59
+ - Non-workspace library modules shadow `$RefreshReg$` and `$RefreshSig$` with no-ops.
60
+
61
+ The non-workspace library no-ops avoid duplicate registrations for third-party code that Startup does not own. Workspace package modules are allowed to register because their IDs are scoped to the served runtime URL, so the same local package can be loaded by multiple Vite servers without colliding.
62
+
63
+ The transform returns a normal source map for the code it changes. Vite decides whether to emit, inline, hide, or drop that map based on the application's source map config. This plugin does not require a specific source map mode, but it can only map back to the JavaScript it receives. Mapping all the way back to the original TSX source still depends on earlier compile steps, such as `swc`, providing their own maps for Vite to chain.
64
+
65
+ ## Key Decisions
66
+
67
+ ### Why `swc` Is Not Enough
68
+
69
+ `swc` only emits compile-time markers. It does not provide the browser runtime that implements `$RefreshReg$` and `$RefreshSig$`, and it does not tell Vite which JS modules can accept hot updates. Without this plugin, the compiled markers are just global calls with nothing reliable behind them.
70
+
71
+ The plugin supplies the serve-time pieces that `swc` does not own:
72
+
73
+ 1. Load the official React Fast Refresh runtime.
74
+ 2. Install the refresh globals before application modules execute.
75
+ 3. Mark modules with registered component families as candidate self-accepting HMR boundaries.
76
+ 4. Validate each accepted update against the previous module exports.
77
+ 5. Trigger `performReactRefresh()` for compatible boundaries, or invalidate incompatible ones so Vite can reload.
78
+
79
+ The refresh call is debounced from the HMR accept callback. This lets the accepted module finish evaluating and register its new component family before React Fast Refresh compares families and asks React to re-render.
80
+
81
+ ### Why Boundary Validation Is Required
82
+
83
+ Seeing `$RefreshReg$` in a module is not enough to prove every export can safely Fast Refresh. A module can register one component while exporting another value that React Fast Refresh cannot track, such as a component returned from a higher-order function call:
84
+
85
+ ```tsx
86
+ export const App = provide({...})(() => <div />);
87
+ ```
88
+
89
+ `swc` cannot register that `App` export as a component family. If the plugin blindly self-accepted the module, Vite would apply the update but React Fast Refresh would have no family to swap, leaving the browser stale. The runtime helper follows Vite React's boundary validation model instead: compatible component exports refresh, unchanged non-component exports are allowed, and incompatible export changes invalidate the module.
90
+
91
+ For an incompatible export, the browser console shows an invalidation message like:
92
+
93
+ ```text
94
+ [vite] invalidate /dist/app.js: Could not Fast Refresh ("App" export is incompatible).
95
+ ```
96
+
97
+ That full reload fallback is intentional. The contract is that edits either Fast Refresh or reload, but never silently no-op.
98
+
99
+ ### Why The Runtime Helpers Are A JavaScript Sidecar
100
+
101
+ The `/@react-refresh` virtual module must execute in the browser as ESM. The boundary helpers live in `refresh-runtime.js` and are copied to `dist/` as a normal JavaScript resource, then read into the virtual module at serve time.
102
+
103
+ Keeping the helpers in a source `.js` sidecar avoids compiling them through Startup's CommonJS package build, which would rewrite browser dynamic imports into `require(...)`. The helper's dynamic import intentionally stays as native browser ESM:
104
+
105
+ ```js
106
+ import(/* @vite-ignore */ module);
107
+ ```
108
+
109
+ ### Why The Runtime Is A Global Singleton
110
+
111
+ Startup can run a host and an MFE from separate Vite dev servers, such as the host on `localhost:8080` and the MFE on `localhost:8888`. The MFE is still rendered by React inside the host page, so refresh updates from the MFE need to reach the renderer and roots captured when the host initialized React.
112
+
113
+ If each Vite server imported its own refresh runtime instance, an MFE update could call `performReactRefresh()` on a runtime that did not capture the host renderer. The virtual module stores the runtime on `window.__ReactRefreshRuntime` so all dev servers in the same page share the same runtime instance.
114
+
115
+ ### Why Registration IDs Are Scoped To Runtime Module URLs
116
+
117
+ `swc` emits registration IDs from local component names, such as `"Routes"`. In a host/MFE page, different Vite servers can load different modules that contain components with the same local name. Because those servers intentionally share one runtime singleton, bare component names can collide and make React Fast Refresh treat unrelated host and MFE components as the same family.
118
+
119
+ Rather than rewriting each `$RefreshReg$(type, "Name")` call, the transform injects a per-module `$RefreshReg$` local that captures the module URL at definition time:
120
+
121
+ ```js
122
+ const __react_refresh_id__ = import.meta.url.replace(/[?#].*$/, '');
123
+ var $RefreshReg$ = (type, id) => RefreshRuntime.register(type, __react_refresh_id__ + ' ' + id);
124
+ ```
125
+
126
+ The query is stripped so the ID stays stable across Vite timestamp updates, but host and MFE servers still get different IDs for the same workspace file because their served URLs differ.
127
+
128
+ This matters for workspace libraries too. The host and MFE can both load `packages/web-components/dist/loader.js` into the same browser page. Scoping by runtime URL lets both servers register `Loader` without sharing one refresh family, while still allowing edits to `web-components` to update through React Fast Refresh instead of a full page reload.
129
+
130
+ ### Why Non-Workspace Library Markers Are No-Ops
131
+
132
+ Third-party libraries can be served through Vite as files outside the workspace packages directory. Startup does not compile or control their React Fast Refresh markers, so the plugin shadows `$RefreshReg$` and `$RefreshSig$` with no-ops for those modules. This keeps third-party code from registering duplicate or stale refresh families in the shared runtime.
133
+
134
+ Workspace modules receive real per-module locals instead of no-ops, so only third-party code is silenced.
135
+
136
+ ### Cross-Bundler Development (Webpack Host + Vite MFE)
137
+
138
+ React Fast Refresh requires `injectIntoGlobalHook(window)` to run before React initializes. In a Vite host this is guaranteed by the head-prepend preamble. In a webpack host there is no Vite preamble, so React loads from the shared webpack bundle before any Vite module runs. By the time the Vite MFE's first module imports `/@react-refresh` and calls `injectIntoGlobalHook`, React has already initialized without a hook, `hook.renderers` is empty, and `performReactRefresh()` silently no-ops — the browser accepts the HMR update but nothing visibly changes.
139
+
140
+ ## TSX Edit Flow
141
+
142
+ When a TSX file changes:
143
+
144
+ 1. `swc` recompiles the source file to `dist/` with fresh refresh markers.
145
+ 2. Vite detects the changed compiled module.
146
+ 3. If this plugin appended an HMR postlude, Vite treats the module as a candidate self-accepting boundary.
147
+ 4. The browser re-executes the module. The per-module `$RefreshReg$` local registers component families with URL-scoped stable IDs.
148
+ 5. The HMR postlude compares the previous and next module exports.
149
+ 6. For compatible boundaries, the runtime stores the update for each component family and queues `RefreshRuntime.performReactRefresh()`.
150
+ 7. React swaps `family.current` to the new function, compares hook signatures, and re-renders mounted roots.
151
+
152
+ If boundary validation fails, the postlude invalidates the module instead. Vite then propagates the update to importers and reloads the page if no valid parent boundary accepts it.
153
+
154
+ If the hook signature is compatible, React preserves state by reusing the existing fiber and hook slots. If hooks were added, removed, or reordered, React remounts that component so state slots do not get reused incorrectly.
155
+
156
+ ## CSS Edit Flow
157
+
158
+ Plain CSS imports take Vite's native CSS HMR path:
159
+
160
+ 1. The CSS source changes and Startup copies it to `dist/`.
161
+ 2. Vite detects the changed CSS file.
162
+ 3. Vite's CSS transform emits an update that calls its stylesheet replacement logic.
163
+ 4. The browser updates the stylesheet without involving React Fast Refresh.
164
+
165
+ CSS modules are different because they export a class-name mapping object. Updates to a CSS module propagate to the importing React module, and React Fast Refresh handles the re-render path for that importer.