@tanstack/start-plugin-core 1.167.34 → 1.168.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 (197) hide show
  1. package/dist/esm/import-protection/adapterUtils.d.ts +27 -0
  2. package/dist/esm/import-protection/adapterUtils.js +31 -0
  3. package/dist/esm/import-protection/adapterUtils.js.map +1 -0
  4. package/dist/esm/import-protection/analysis.d.ts +36 -0
  5. package/dist/esm/import-protection/analysis.js +407 -0
  6. package/dist/esm/import-protection/analysis.js.map +1 -0
  7. package/dist/esm/{import-protection-plugin → import-protection}/ast.js +1 -1
  8. package/dist/esm/import-protection/ast.js.map +1 -0
  9. package/dist/esm/import-protection/constants.d.ts +11 -0
  10. package/dist/esm/{import-protection-plugin → import-protection}/constants.js +7 -2
  11. package/dist/esm/import-protection/constants.js.map +1 -0
  12. package/dist/esm/{import-protection-plugin → import-protection}/defaults.js +1 -1
  13. package/dist/esm/import-protection/defaults.js.map +1 -0
  14. package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.js +1 -1
  15. package/dist/esm/import-protection/extensionlessAbsoluteIdResolver.js.map +1 -0
  16. package/dist/esm/{import-protection-plugin → import-protection}/matchers.js +1 -1
  17. package/dist/esm/import-protection/matchers.js.map +1 -0
  18. package/dist/esm/{import-protection-plugin/rewriteDeniedImports.d.ts → import-protection/rewrite.d.ts} +0 -4
  19. package/dist/esm/import-protection/rewrite.js +121 -0
  20. package/dist/esm/import-protection/rewrite.js.map +1 -0
  21. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.d.ts +32 -3
  22. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.js +65 -10
  23. package/dist/esm/import-protection/sourceLocation.js.map +1 -0
  24. package/dist/esm/{import-protection-plugin → import-protection}/trace.d.ts +0 -1
  25. package/dist/esm/{import-protection-plugin → import-protection}/trace.js +1 -1
  26. package/dist/esm/import-protection/trace.js.map +1 -0
  27. package/dist/esm/{import-protection-plugin → import-protection}/utils.d.ts +18 -1
  28. package/dist/esm/{import-protection-plugin → import-protection}/utils.js +12 -19
  29. package/dist/esm/import-protection/utils.js.map +1 -0
  30. package/dist/esm/import-protection/virtualModules.d.ts +25 -0
  31. package/dist/esm/{import-protection-plugin → import-protection}/virtualModules.js +5 -117
  32. package/dist/esm/import-protection/virtualModules.js.map +1 -0
  33. package/dist/esm/index.d.ts +4 -0
  34. package/dist/esm/index.js +3 -1
  35. package/dist/esm/post-build.d.ts +9 -0
  36. package/dist/esm/post-build.js +37 -0
  37. package/dist/esm/post-build.js.map +1 -0
  38. package/dist/esm/prerender.d.ts +11 -0
  39. package/dist/esm/prerender.js +159 -0
  40. package/dist/esm/prerender.js.map +1 -0
  41. package/dist/esm/rsbuild/dev-server.d.ts +21 -0
  42. package/dist/esm/rsbuild/dev-server.js +76 -0
  43. package/dist/esm/rsbuild/dev-server.js.map +1 -0
  44. package/dist/esm/rsbuild/import-protection.d.ts +10 -0
  45. package/dist/esm/rsbuild/import-protection.js +775 -0
  46. package/dist/esm/rsbuild/import-protection.js.map +1 -0
  47. package/dist/esm/rsbuild/normalized-client-build.d.ts +18 -0
  48. package/dist/esm/rsbuild/normalized-client-build.js +207 -0
  49. package/dist/esm/rsbuild/normalized-client-build.js.map +1 -0
  50. package/dist/esm/rsbuild/planning.d.ts +52 -0
  51. package/dist/esm/rsbuild/planning.js +108 -0
  52. package/dist/esm/rsbuild/planning.js.map +1 -0
  53. package/dist/esm/rsbuild/plugin.d.ts +4 -0
  54. package/dist/esm/rsbuild/plugin.js +344 -0
  55. package/dist/esm/rsbuild/plugin.js.map +1 -0
  56. package/dist/esm/rsbuild/post-build.d.ts +6 -0
  57. package/dist/esm/rsbuild/post-build.js +57 -0
  58. package/dist/esm/rsbuild/post-build.js.map +1 -0
  59. package/dist/esm/rsbuild/schema.d.ts +3372 -0
  60. package/dist/esm/rsbuild/schema.js +12 -0
  61. package/dist/esm/rsbuild/schema.js.map +1 -0
  62. package/dist/esm/rsbuild/start-compiler-host.d.ts +20 -0
  63. package/dist/esm/rsbuild/start-compiler-host.js +150 -0
  64. package/dist/esm/rsbuild/start-compiler-host.js.map +1 -0
  65. package/dist/esm/rsbuild/start-router-plugin.d.ts +18 -0
  66. package/dist/esm/rsbuild/start-router-plugin.js +63 -0
  67. package/dist/esm/rsbuild/start-router-plugin.js.map +1 -0
  68. package/dist/esm/rsbuild/swc-rsc.d.ts +14 -0
  69. package/dist/esm/rsbuild/swc-rsc.js +93 -0
  70. package/dist/esm/rsbuild/swc-rsc.js.map +1 -0
  71. package/dist/esm/rsbuild/types.d.ts +17 -0
  72. package/dist/esm/rsbuild/types.js +0 -0
  73. package/dist/esm/rsbuild/virtual-modules.d.ts +53 -0
  74. package/dist/esm/rsbuild/virtual-modules.js +287 -0
  75. package/dist/esm/rsbuild/virtual-modules.js.map +1 -0
  76. package/dist/esm/schema.d.ts +43 -43
  77. package/dist/esm/schema.js +1 -1
  78. package/dist/esm/start-compiler/compiler.d.ts +1 -1
  79. package/dist/esm/start-compiler/compiler.js +80 -9
  80. package/dist/esm/start-compiler/compiler.js.map +1 -1
  81. package/dist/esm/start-compiler/handleCreateServerFn.js +9 -0
  82. package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -1
  83. package/dist/esm/start-compiler/host.js +5 -1
  84. package/dist/esm/start-compiler/host.js.map +1 -1
  85. package/dist/esm/start-compiler/types.d.ts +1 -0
  86. package/dist/esm/start-manifest-plugin/manifestBuilder.d.ts +3 -6
  87. package/dist/esm/start-manifest-plugin/manifestBuilder.js +34 -81
  88. package/dist/esm/start-manifest-plugin/manifestBuilder.js.map +1 -1
  89. package/dist/esm/utils.d.ts +1 -0
  90. package/dist/esm/utils.js +4 -1
  91. package/dist/esm/utils.js.map +1 -1
  92. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.js +41 -92
  93. package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -0
  94. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/types.d.ts +5 -5
  95. package/dist/esm/vite/import-protection-plugin/virtualModules.d.ts +8 -0
  96. package/dist/esm/vite/import-protection-plugin/virtualModules.js +49 -0
  97. package/dist/esm/vite/import-protection-plugin/virtualModules.js.map +1 -0
  98. package/dist/esm/vite/plugin.js +4 -12
  99. package/dist/esm/vite/plugin.js.map +1 -1
  100. package/dist/esm/vite/plugins.d.ts +1 -5
  101. package/dist/esm/vite/plugins.js +2 -17
  102. package/dist/esm/vite/plugins.js.map +1 -1
  103. package/dist/esm/vite/post-server-build.js +14 -32
  104. package/dist/esm/vite/post-server-build.js.map +1 -1
  105. package/dist/esm/vite/prerender.d.ts +2 -2
  106. package/dist/esm/vite/prerender.js +17 -147
  107. package/dist/esm/vite/prerender.js.map +1 -1
  108. package/dist/esm/vite/schema.d.ts +23 -23
  109. package/dist/esm/vite/start-compiler-plugin/hot-update.d.ts +2 -0
  110. package/dist/esm/vite/start-compiler-plugin/hot-update.js +16 -0
  111. package/dist/esm/vite/start-compiler-plugin/hot-update.js.map +1 -0
  112. package/dist/esm/vite/start-compiler-plugin/module-specifier.js +9 -4
  113. package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -1
  114. package/dist/esm/vite/start-compiler-plugin/plugin.js +86 -13
  115. package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
  116. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js +2 -2
  117. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js.map +1 -1
  118. package/dist/esm/vite/start-manifest-plugin/plugin.d.ts +1 -2
  119. package/dist/esm/vite/start-manifest-plugin/plugin.js +48 -14
  120. package/dist/esm/vite/start-manifest-plugin/plugin.js.map +1 -1
  121. package/package.json +17 -4
  122. package/src/import-protection/INTERNALS.md +266 -0
  123. package/src/import-protection/adapterUtils.ts +94 -0
  124. package/src/import-protection/analysis.ts +853 -0
  125. package/src/{import-protection-plugin → import-protection}/constants.ts +7 -0
  126. package/src/import-protection/rewrite.ts +229 -0
  127. package/src/{import-protection-plugin → import-protection}/sourceLocation.ts +125 -9
  128. package/src/{import-protection-plugin → import-protection}/trace.ts +0 -1
  129. package/src/{import-protection-plugin → import-protection}/utils.ts +35 -20
  130. package/src/{import-protection-plugin → import-protection}/virtualModules.ts +30 -177
  131. package/src/index.ts +5 -0
  132. package/src/post-build.ts +64 -0
  133. package/src/prerender.ts +292 -0
  134. package/src/rsbuild/INTERNALS-import-protection.md +169 -0
  135. package/src/rsbuild/dev-server.ts +129 -0
  136. package/src/rsbuild/import-protection.ts +1600 -0
  137. package/src/rsbuild/normalized-client-build.ts +346 -0
  138. package/src/rsbuild/planning.ts +234 -0
  139. package/src/rsbuild/plugin.ts +754 -0
  140. package/src/rsbuild/post-build.ts +96 -0
  141. package/src/rsbuild/schema.ts +31 -0
  142. package/src/rsbuild/start-compiler-host.ts +250 -0
  143. package/src/rsbuild/start-router-plugin.ts +86 -0
  144. package/src/rsbuild/swc-rsc.ts +166 -0
  145. package/src/rsbuild/types.ts +20 -0
  146. package/src/rsbuild/virtual-modules.ts +565 -0
  147. package/src/start-compiler/compiler.ts +153 -19
  148. package/src/start-compiler/handleCreateServerFn.ts +18 -0
  149. package/src/start-compiler/types.ts +1 -0
  150. package/src/start-manifest-plugin/manifestBuilder.ts +53 -116
  151. package/src/utils.ts +4 -0
  152. package/src/vite/import-protection-plugin/INTERNALS.md +187 -0
  153. package/src/{import-protection-plugin → vite/import-protection-plugin}/plugin.ts +73 -158
  154. package/src/{import-protection-plugin → vite/import-protection-plugin}/types.ts +5 -5
  155. package/src/vite/import-protection-plugin/virtualModules.ts +122 -0
  156. package/src/vite/plugin.ts +1 -18
  157. package/src/vite/plugins.ts +2 -33
  158. package/src/vite/post-server-build.ts +14 -57
  159. package/src/vite/prerender.ts +19 -260
  160. package/src/vite/start-compiler-plugin/hot-update.ts +24 -0
  161. package/src/vite/start-compiler-plugin/module-specifier.ts +15 -5
  162. package/src/vite/start-compiler-plugin/plugin.ts +193 -18
  163. package/src/vite/start-manifest-plugin/normalized-client-build.ts +15 -16
  164. package/src/vite/start-manifest-plugin/plugin.ts +121 -38
  165. package/dist/esm/import-protection-plugin/ast.js.map +0 -1
  166. package/dist/esm/import-protection-plugin/constants.d.ts +0 -6
  167. package/dist/esm/import-protection-plugin/constants.js.map +0 -1
  168. package/dist/esm/import-protection-plugin/defaults.js.map +0 -1
  169. package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js.map +0 -1
  170. package/dist/esm/import-protection-plugin/matchers.js.map +0 -1
  171. package/dist/esm/import-protection-plugin/plugin.js.map +0 -1
  172. package/dist/esm/import-protection-plugin/postCompileUsage.d.ts +0 -13
  173. package/dist/esm/import-protection-plugin/postCompileUsage.js +0 -63
  174. package/dist/esm/import-protection-plugin/postCompileUsage.js.map +0 -1
  175. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js +0 -205
  176. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js.map +0 -1
  177. package/dist/esm/import-protection-plugin/sourceLocation.js.map +0 -1
  178. package/dist/esm/import-protection-plugin/trace.js.map +0 -1
  179. package/dist/esm/import-protection-plugin/utils.js.map +0 -1
  180. package/dist/esm/import-protection-plugin/virtualModules.d.ts +0 -78
  181. package/dist/esm/import-protection-plugin/virtualModules.js.map +0 -1
  182. package/dist/esm/start-compiler/load-module.d.ts +0 -14
  183. package/dist/esm/start-compiler/load-module.js +0 -18
  184. package/dist/esm/start-compiler/load-module.js.map +0 -1
  185. package/src/import-protection-plugin/INTERNALS.md +0 -700
  186. package/src/import-protection-plugin/postCompileUsage.ts +0 -100
  187. package/src/import-protection-plugin/rewriteDeniedImports.ts +0 -379
  188. package/src/start-compiler/load-module.ts +0 -31
  189. /package/dist/esm/{import-protection-plugin → import-protection}/ast.d.ts +0 -0
  190. /package/dist/esm/{import-protection-plugin → import-protection}/defaults.d.ts +0 -0
  191. /package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.d.ts +0 -0
  192. /package/dist/esm/{import-protection-plugin → import-protection}/matchers.d.ts +0 -0
  193. /package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.d.ts +0 -0
  194. /package/src/{import-protection-plugin → import-protection}/ast.ts +0 -0
  195. /package/src/{import-protection-plugin → import-protection}/defaults.ts +0 -0
  196. /package/src/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.ts +0 -0
  197. /package/src/{import-protection-plugin → import-protection}/matchers.ts +0 -0
@@ -0,0 +1,122 @@
1
+ import { resolveViteId } from '../../utils'
2
+ import {
3
+ MARKER_PREFIX,
4
+ MOCK_BUILD_PREFIX,
5
+ MOCK_EDGE_PREFIX,
6
+ MOCK_MODULE_ID,
7
+ MOCK_RUNTIME_PREFIX,
8
+ RUNTIME_SUGGESTION_TEXT,
9
+ generateDevSelfDenialModule,
10
+ generateSelfContainedMockModule,
11
+ loadMarkerModule,
12
+ loadMockEdgeModule,
13
+ loadMockRuntimeModule,
14
+ loadSilentMockModule,
15
+ makeMockEdgeModuleId,
16
+ mockRuntimeModuleIdFromViolation,
17
+ } from '../../import-protection/virtualModules'
18
+ import { VITE_BROWSER_VIRTUAL_PREFIX } from '../../import-protection/constants'
19
+
20
+ const RESOLVED_MOCK_MODULE_ID = resolveViteId(MOCK_MODULE_ID)
21
+ const RESOLVED_MOCK_BUILD_PREFIX = resolveViteId(MOCK_BUILD_PREFIX)
22
+ const RESOLVED_MOCK_EDGE_PREFIX = resolveViteId(MOCK_EDGE_PREFIX)
23
+ const RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX)
24
+ const RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX)
25
+ const RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`)
26
+ const RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`)
27
+
28
+ export function resolvedMarkerVirtualModuleId(
29
+ kind: 'server' | 'client',
30
+ ): string {
31
+ return kind === 'server'
32
+ ? RESOLVED_MARKER_SERVER_ONLY
33
+ : RESOLVED_MARKER_CLIENT_ONLY
34
+ }
35
+
36
+ export function getResolvedVirtualModuleMatchers(): ReadonlyArray<string> {
37
+ return RESOLVED_VIRTUAL_MODULE_MATCHERS
38
+ }
39
+
40
+ const RESOLVED_VIRTUAL_MODULE_MATCHERS = [
41
+ RESOLVED_MOCK_MODULE_ID,
42
+ RESOLVED_MOCK_BUILD_PREFIX,
43
+ RESOLVED_MOCK_EDGE_PREFIX,
44
+ RESOLVED_MOCK_RUNTIME_PREFIX,
45
+ RESOLVED_MARKER_PREFIX,
46
+ ] as const
47
+
48
+ const RESOLVE_PREFIX_PAIRS = [
49
+ [MOCK_EDGE_PREFIX, RESOLVED_MOCK_EDGE_PREFIX],
50
+ [MOCK_RUNTIME_PREFIX, RESOLVED_MOCK_RUNTIME_PREFIX],
51
+ [MOCK_BUILD_PREFIX, RESOLVED_MOCK_BUILD_PREFIX],
52
+ [MARKER_PREFIX, RESOLVED_MARKER_PREFIX],
53
+ ] as const
54
+
55
+ export function resolveInternalVirtualModuleId(
56
+ source: string,
57
+ ): string | undefined {
58
+ if (source.startsWith(VITE_BROWSER_VIRTUAL_PREFIX)) {
59
+ return resolveInternalVirtualModuleId(
60
+ `\0${source.slice(VITE_BROWSER_VIRTUAL_PREFIX.length)}`,
61
+ )
62
+ }
63
+
64
+ if (source === MOCK_MODULE_ID || source === RESOLVED_MOCK_MODULE_ID) {
65
+ return RESOLVED_MOCK_MODULE_ID
66
+ }
67
+
68
+ for (const [unresolvedPrefix, resolvedPrefix] of RESOLVE_PREFIX_PAIRS) {
69
+ if (source.startsWith(unresolvedPrefix)) {
70
+ return resolveViteId(source)
71
+ }
72
+
73
+ if (source.startsWith(resolvedPrefix)) {
74
+ return source
75
+ }
76
+ }
77
+
78
+ return undefined
79
+ }
80
+
81
+ export function loadResolvedVirtualModule(
82
+ id: string,
83
+ ): { code: string } | undefined {
84
+ if (id === RESOLVED_MOCK_MODULE_ID) {
85
+ return loadSilentMockModule()
86
+ }
87
+
88
+ if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {
89
+ return loadSilentMockModule()
90
+ }
91
+
92
+ if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {
93
+ return loadMockEdgeModule(id.slice(RESOLVED_MOCK_EDGE_PREFIX.length))
94
+ }
95
+
96
+ if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {
97
+ return loadMockRuntimeModule(id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length))
98
+ }
99
+
100
+ if (id.startsWith(RESOLVED_MARKER_PREFIX)) {
101
+ return loadMarkerModule()
102
+ }
103
+
104
+ return undefined
105
+ }
106
+
107
+ export {
108
+ MARKER_PREFIX,
109
+ MOCK_BUILD_PREFIX,
110
+ MOCK_EDGE_PREFIX,
111
+ MOCK_MODULE_ID,
112
+ MOCK_RUNTIME_PREFIX,
113
+ RUNTIME_SUGGESTION_TEXT,
114
+ generateDevSelfDenialModule,
115
+ generateSelfContainedMockModule,
116
+ loadMarkerModule,
117
+ loadMockEdgeModule,
118
+ loadMockRuntimeModule,
119
+ loadSilentMockModule,
120
+ makeMockEdgeModuleId,
121
+ mockRuntimeModuleIdFromViolation,
122
+ }
@@ -5,12 +5,12 @@ import {
5
5
  createStartConfigContext,
6
6
  } from '../config-context'
7
7
  import { START_ENVIRONMENT_NAMES } from '../constants'
8
- import { importProtectionPlugin } from '../import-protection-plugin/plugin'
9
8
  import {
10
9
  createServerFnBasePath,
11
10
  normalizePublicBase,
12
11
  shouldRewriteDevBasepath,
13
12
  } from '../planning'
13
+ import { importProtectionPlugin } from './import-protection-plugin/plugin'
14
14
  import { startCompilerPlugin } from './start-compiler-plugin/plugin'
15
15
  import { loadEnvPlugin } from './load-env-plugin/plugin'
16
16
  import {
@@ -22,7 +22,6 @@ import {
22
22
  import { devServerPlugin } from './dev-server-plugin/plugin'
23
23
  import { previewServerPlugin } from './preview-server-plugin/plugin'
24
24
  import {
25
- createCaptureClientBuildPlugin,
26
25
  createDevBaseRewritePlugin,
27
26
  createPostBuildPlugin,
28
27
  createVirtualClientEntryPlugin,
@@ -36,12 +35,10 @@ import {
36
35
  } from './output-directory'
37
36
  import { postServerBuild } from './post-server-build'
38
37
  import { serializationAdaptersPlugin } from './serialization-adapters-plugin'
39
- import type { NormalizedClientBuild } from '../types'
40
38
  import type {
41
39
  TanStackStartVitePluginCoreOptions,
42
40
  ViteRscForwardSsrResolverStrategy,
43
41
  } from './types'
44
- import type { StartEnvironmentName } from '../constants'
45
42
  import type { TanStackStartViteInputConfig } from './schema'
46
43
  import type { PluginOption } from 'vite'
47
44
 
@@ -64,16 +61,6 @@ export function tanStackStartVite(
64
61
  // we install a URL rewrite middleware instead of erroring.
65
62
  let needsDevBaseRewrite = false
66
63
 
67
- const capturedClientBuild: Partial<
68
- Record<StartEnvironmentName, NormalizedClientBuild>
69
- > = {}
70
-
71
- function getClientBuild(
72
- envName: StartEnvironmentName,
73
- ): NormalizedClientBuild | undefined {
74
- return capturedClientBuild[envName]
75
- }
76
-
77
64
  const environments: Array<{
78
65
  name: string
79
66
  type: 'client' | 'server'
@@ -242,7 +229,6 @@ export function tanStackStartVite(
242
229
  getClientEntry: () => configContext.resolveEntries().entryPaths.client,
243
230
  }),
244
231
  startManifestPlugin({
245
- getClientBuild: () => getClientBuild(START_ENVIRONMENT_NAMES.client),
246
232
  getConfig,
247
233
  }),
248
234
  // When the vite base and router basepath are misaligned (e.g. base: '/_ui/', basepath: '/'),
@@ -266,9 +252,6 @@ export function tanStackStartVite(
266
252
  serializationAdaptersPlugin({
267
253
  adapters: corePluginOpts.serializationAdapters,
268
254
  }),
269
- createCaptureClientBuildPlugin({
270
- capturedClientBuild,
271
- }),
272
255
  ]
273
256
  }
274
257
 
@@ -1,13 +1,7 @@
1
1
  import { normalizePath } from 'vite'
2
- import { ENTRY_POINTS, START_ENVIRONMENT_NAMES } from '../constants'
2
+ import { ENTRY_POINTS } from '../constants'
3
3
  import { createVirtualModule } from './createVirtualModule'
4
- import { normalizeViteClientBuild } from './start-manifest-plugin/normalized-client-build'
5
- import type {
6
- GetConfigFn,
7
- NormalizedClientBuild,
8
- ResolvedStartConfig,
9
- } from '../types'
10
- import type { StartEnvironmentName } from '../constants'
4
+ import type { GetConfigFn, ResolvedStartConfig } from '../types'
11
5
  import type { PluginOption, ViteBuilder } from 'vite'
12
6
 
13
7
  export function createVirtualClientEntryPlugin(opts: {
@@ -69,28 +63,3 @@ export function createDevBaseRewritePlugin(opts: {
69
63
  },
70
64
  }
71
65
  }
72
-
73
- export function createCaptureClientBuildPlugin(opts: {
74
- capturedClientBuild: Partial<
75
- Record<StartEnvironmentName, NormalizedClientBuild>
76
- >
77
- }): PluginOption {
78
- return {
79
- name: 'tanstack-start:core:capture-bundle',
80
- applyToEnvironment(environment) {
81
- return environment.name === START_ENVIRONMENT_NAMES.client
82
- },
83
- enforce: 'post',
84
- generateBundle(_options, bundle) {
85
- const environment = this.environment.name as StartEnvironmentName
86
-
87
- if (environment !== START_ENVIRONMENT_NAMES.client) {
88
- throw new Error(
89
- `Unexpected environment for client build capture: ${environment}`,
90
- )
91
- }
92
-
93
- opts.capturedClientBuild[environment] = normalizeViteClientBuild(bundle)
94
- },
95
- }
96
- }
@@ -1,7 +1,6 @@
1
- import { HEADERS } from '@tanstack/start-server-core'
2
- import { buildSitemap } from '../build-sitemap'
3
- import { prerender } from './prerender'
1
+ import { postBuild } from '../post-build'
4
2
  import { getClientOutputDirectory } from './output-directory'
3
+ import { prerenderWithVite } from './prerender'
5
4
  import type { TanStackStartOutputConfig } from '../schema'
6
5
  import type { ViteBuilder } from 'vite'
7
6
 
@@ -12,60 +11,18 @@ export async function postServerBuild({
12
11
  builder: ViteBuilder
13
12
  startConfig: TanStackStartOutputConfig
14
13
  }) {
15
- // If the user has not set a prerender option, we need to set it to true
16
- // if the pages array is not empty and has sub options requiring for prerendering
17
- // If the user has explicitly set prerender.enabled, this should be respected
18
- if (startConfig.prerender?.enabled !== false) {
19
- startConfig.prerender = {
20
- ...startConfig.prerender,
21
- enabled:
22
- startConfig.prerender?.enabled ??
23
- startConfig.pages.some((d) =>
24
- typeof d === 'string' ? false : !!d.prerender?.enabled,
25
- ),
26
- }
27
- }
28
-
29
- // Setup the options for prerendering the SPA shell (i.e `src/routes/__root.tsx`)
30
- if (startConfig.spa?.enabled) {
31
- startConfig.prerender = {
32
- ...startConfig.prerender,
33
- enabled: true,
34
- }
35
-
36
- const maskUrl = new URL(startConfig.spa.maskPath, 'http://localhost')
37
- if (maskUrl.origin !== 'http://localhost') {
38
- throw new Error('spa.maskPath must be a path (no protocol/host)')
39
- }
40
-
41
- startConfig.pages.push({
42
- path: maskUrl.toString().replace('http://localhost', ''),
43
- prerender: {
44
- ...startConfig.spa.prerender,
45
- headers: {
46
- ...startConfig.spa.prerender.headers,
47
- [HEADERS.TSS_SHELL]: 'true',
48
- },
14
+ await postBuild({
15
+ startConfig,
16
+ adapter: {
17
+ getClientOutputDirectory() {
18
+ return getClientOutputDirectory(builder.config)
49
19
  },
50
- sitemap: {
51
- exclude: true,
20
+ prerender(startConfig) {
21
+ return prerenderWithVite({
22
+ startConfig,
23
+ builder,
24
+ })
52
25
  },
53
- })
54
- }
55
-
56
- // Run the prerendering process
57
- if (startConfig.prerender.enabled) {
58
- await prerender({
59
- startConfig,
60
- builder,
61
- })
62
- }
63
-
64
- // Run the sitemap build process
65
- if (startConfig.sitemap?.enabled) {
66
- buildSitemap({
67
- startConfig,
68
- publicDir: getClientOutputDirectory(builder.config),
69
- })
70
- }
26
+ },
27
+ })
71
28
  }
@@ -1,50 +1,16 @@
1
- import { promises as fsp } from 'node:fs'
2
- import os from 'node:os'
3
- import path from 'pathe'
4
- import { joinURL, withBase, withTrailingSlash, withoutBase } from 'ufo'
5
1
  import { VITE_ENVIRONMENT_NAMES } from '../constants'
6
- import { createLogger } from '../utils'
7
- import { Queue } from '../queue'
2
+ import { prerender } from '../prerender'
3
+ import type { PrerenderHandler } from '../prerender'
4
+ import type { TanStackStartOutputConfig } from '../schema'
8
5
  import type { PreviewServer, ResolvedConfig, ViteBuilder } from 'vite'
9
- import type { Page, TanStackStartOutputConfig } from '../schema'
10
6
 
11
- export async function prerender({
7
+ export async function prerenderWithVite({
12
8
  startConfig,
13
9
  builder,
14
10
  }: {
15
11
  startConfig: TanStackStartOutputConfig
16
12
  builder: ViteBuilder
17
13
  }) {
18
- const logger = createLogger('prerender')
19
- logger.info('Prerendering pages...')
20
-
21
- if (startConfig.prerender?.enabled) {
22
- let pages = startConfig.pages.length ? startConfig.pages : [{ path: '/' }]
23
-
24
- if (startConfig.prerender.autoStaticPathsDiscovery ?? true) {
25
- const pagesMap = new Map(pages.map((item) => [item.path, item]))
26
- const discoveredPages = globalThis.TSS_PRERENDABLE_PATHS || []
27
-
28
- for (const page of discoveredPages) {
29
- if (!pagesMap.has(page.path)) {
30
- pagesMap.set(page.path, page)
31
- }
32
- }
33
-
34
- pages = Array.from(pagesMap.values())
35
- }
36
-
37
- startConfig.pages = pages
38
- }
39
-
40
- const routerBasePath = joinURL('/', startConfig.router.basepath ?? '')
41
- const routerBaseUrl = new URL(routerBasePath, 'http://localhost')
42
-
43
- startConfig.pages = validateAndNormalizePrerenderPages(
44
- startConfig.pages,
45
- routerBaseUrl,
46
- )
47
-
48
14
  const serverEnv = builder.environments[VITE_ENVIRONMENT_NAMES.server]
49
15
 
50
16
  if (!serverEnv) {
@@ -68,203 +34,23 @@ export async function prerender({
68
34
  const previewServer = await startPreviewServer(serverEnv.config)
69
35
  const baseUrl = getResolvedUrl(previewServer)
70
36
 
71
- const isRedirectResponse = (res: Response) => {
72
- return res.status >= 300 && res.status < 400 && res.headers.get('location')
73
- }
74
-
75
- async function localFetch(
76
- path: string,
77
- options?: RequestInit,
78
- maxRedirects: number = 5,
79
- ): Promise<Response> {
80
- const url = new URL(path, baseUrl)
81
- const request = new Request(url, options)
82
- const response = await fetch(request)
83
-
84
- if (isRedirectResponse(response) && maxRedirects > 0) {
85
- const location = response.headers.get('location')!
86
- if (location.startsWith('http://localhost') || location.startsWith('/')) {
87
- const newUrl = location.replace('http://localhost', '')
88
- return localFetch(newUrl, options, maxRedirects - 1)
89
- }
90
-
91
- logger.warn(`Skipping redirect to external location: ${location}`)
92
- }
93
-
94
- return response
95
- }
96
-
97
- try {
98
- const pages = await prerenderPages({ outputDir })
99
-
100
- logger.info(`Prerendered ${pages.length} pages:`)
101
- pages.forEach((page) => {
102
- logger.info(`- ${page}`)
103
- })
104
- } catch (error) {
105
- logger.error(error)
106
- } finally {
107
- await previewServer.close()
37
+ const handler: PrerenderHandler = {
38
+ getClientOutputDirectory() {
39
+ return outputDir
40
+ },
41
+ request(path, options) {
42
+ const url = new URL(path, baseUrl)
43
+ return fetch(new Request(url, options))
44
+ },
45
+ close() {
46
+ return previewServer.close()
47
+ },
108
48
  }
109
49
 
110
- function extractLinks(html: string): Array<string> {
111
- const linkRegex = /<a[^>]+href=["']([^"']+)["'][^>]*>/g
112
- const links: Array<string> = []
113
- let match: RegExpExecArray | null
114
-
115
- while ((match = linkRegex.exec(html)) !== null) {
116
- const href = match[1]
117
- if (href && (href.startsWith('/') || href.startsWith('./'))) {
118
- links.push(href)
119
- }
120
- }
121
-
122
- return links
123
- }
124
-
125
- async function prerenderPages({ outputDir }: { outputDir: string }) {
126
- const seen = new Set<string>()
127
- const prerendered = new Set<string>()
128
- const retriesByPath = new Map<string, number>()
129
- const concurrency = startConfig.prerender?.concurrency ?? os.cpus().length
130
- logger.info(`Concurrency: ${concurrency}`)
131
- const queue = new Queue({ concurrency })
132
- const routerBasePath = joinURL('/', startConfig.router.basepath ?? '')
133
-
134
- const routerBaseUrl = new URL(routerBasePath, 'http://localhost')
135
- startConfig.pages = validateAndNormalizePrerenderPages(
136
- startConfig.pages,
137
- routerBaseUrl,
138
- )
139
-
140
- startConfig.pages.forEach((page) => addCrawlPageTask(page))
141
-
142
- if (queue.isSettled()) {
143
- logger.info('No pages matched prerender filter; skipping.')
144
- return Array.from(prerendered)
145
- }
146
-
147
- await queue.start()
148
-
149
- return Array.from(prerendered)
150
-
151
- function addCrawlPageTask(page: Page) {
152
- if (seen.has(page.path)) return
153
-
154
- seen.add(page.path)
155
-
156
- if (page.fromCrawl) {
157
- startConfig.pages.push(page)
158
- }
159
-
160
- if (!(page.prerender?.enabled ?? true)) return
161
-
162
- if (
163
- startConfig.prerender?.filter &&
164
- !startConfig.prerender.filter(page)
165
- ) {
166
- return
167
- }
168
-
169
- const prerenderOptions = {
170
- ...startConfig.prerender,
171
- ...page.prerender,
172
- }
173
-
174
- queue.add(async () => {
175
- logger.info(`Crawling: ${page.path}`)
176
- const retries = retriesByPath.get(page.path) || 0
177
- try {
178
- const res = await localFetch(
179
- withTrailingSlash(withBase(page.path, routerBasePath)),
180
- {
181
- headers: {
182
- ...(prerenderOptions.headers ?? {}),
183
- },
184
- },
185
- prerenderOptions.maxRedirects,
186
- )
187
-
188
- if (!res.ok) {
189
- if (isRedirectResponse(res)) {
190
- logger.warn(`Max redirects reached for ${page.path}`)
191
- }
192
- throw new Error(`Failed to fetch ${page.path}: ${res.statusText}`, {
193
- cause: res,
194
- })
195
- }
196
-
197
- const cleanPagePath = (
198
- prerenderOptions.outputPath || page.path
199
- ).split(/[?#]/)[0]!
200
-
201
- const contentType = res.headers.get('content-type') || ''
202
- const isImplicitHTML =
203
- !cleanPagePath.endsWith('.html') && contentType.includes('html')
204
-
205
- const routeWithIndex = cleanPagePath.endsWith('/')
206
- ? cleanPagePath + 'index'
207
- : cleanPagePath
208
-
209
- const isSpaShell =
210
- startConfig.spa?.prerender.outputPath === cleanPagePath
211
-
212
- let htmlPath: string
213
- if (isSpaShell) {
214
- htmlPath = cleanPagePath + '.html'
215
- } else if (
216
- cleanPagePath.endsWith('/') ||
217
- (prerenderOptions.autoSubfolderIndex ?? true)
218
- ) {
219
- htmlPath = joinURL(cleanPagePath, 'index.html')
220
- } else {
221
- htmlPath = cleanPagePath + '.html'
222
- }
223
-
224
- const filename = withoutBase(
225
- isImplicitHTML ? htmlPath : routeWithIndex,
226
- routerBasePath,
227
- )
228
-
229
- const html = await res.text()
230
-
231
- const filepath = path.join(outputDir, filename)
232
-
233
- await fsp.mkdir(path.dirname(filepath), {
234
- recursive: true,
235
- })
236
-
237
- await fsp.writeFile(filepath, html)
238
-
239
- prerendered.add(page.path)
240
-
241
- const newPage = await prerenderOptions.onSuccess?.({ page, html })
242
-
243
- if (newPage) {
244
- Object.assign(page, newPage)
245
- }
246
-
247
- if (prerenderOptions.crawlLinks ?? true) {
248
- const links = extractLinks(html)
249
- for (const link of links) {
250
- addCrawlPageTask({ path: link, fromCrawl: true })
251
- }
252
- }
253
- } catch (error) {
254
- if (retries < (prerenderOptions.retryCount ?? 0)) {
255
- logger.warn(`Encountered error, retrying: ${page.path} in 500ms`)
256
- await new Promise((resolve) =>
257
- setTimeout(resolve, prerenderOptions.retryDelay),
258
- )
259
- retriesByPath.set(page.path, retries + 1)
260
- addCrawlPageTask(page)
261
- } else if (prerenderOptions.failOnError ?? true) {
262
- throw error
263
- }
264
- }
265
- })
266
- }
267
- }
50
+ return prerender({
51
+ startConfig,
52
+ handler,
53
+ })
268
54
  }
269
55
 
270
56
  async function startPreviewServer(
@@ -299,30 +85,3 @@ function getResolvedUrl(previewServer: PreviewServer): URL {
299
85
 
300
86
  return new URL(baseUrl)
301
87
  }
302
-
303
- function validateAndNormalizePrerenderPages(
304
- pages: Array<Page>,
305
- routerBaseUrl: URL,
306
- ): Array<Page> {
307
- return pages.map((page) => {
308
- let url: URL
309
- try {
310
- url = new URL(page.path, routerBaseUrl)
311
- } catch (err) {
312
- throw new Error(`prerender page path must be relative: ${page.path}`, {
313
- cause: err,
314
- })
315
- }
316
-
317
- if (url.origin !== 'http://localhost') {
318
- throw new Error(`prerender page path must be relative: ${page.path}`)
319
- }
320
-
321
- const decodedPathname = decodeURIComponent(url.pathname)
322
-
323
- return {
324
- ...page,
325
- path: decodedPathname + url.search + url.hash,
326
- }
327
- })
328
- }
@@ -0,0 +1,24 @@
1
+ import type { EnvironmentModuleNode } from 'vite'
2
+
3
+ export function mergeHotUpdateModules(
4
+ currentModules: Array<EnvironmentModuleNode>,
5
+ additionalModules: Array<EnvironmentModuleNode>,
6
+ ): Array<EnvironmentModuleNode> | undefined {
7
+ if (additionalModules.length === 0) {
8
+ return undefined
9
+ }
10
+
11
+ const mergedModules = currentModules.slice()
12
+ const seenModules = new Set(currentModules)
13
+
14
+ for (const mod of additionalModules) {
15
+ if (seenModules.has(mod)) {
16
+ continue
17
+ }
18
+
19
+ seenModules.add(mod)
20
+ mergedModules.push(mod)
21
+ }
22
+
23
+ return mergedModules
24
+ }
@@ -3,16 +3,21 @@ import type { DevServerFnModuleSpecifierEncoder } from '../../start-compiler/typ
3
3
  export function createViteDevServerFnModuleSpecifierEncoder(
4
4
  root: string,
5
5
  ): DevServerFnModuleSpecifierEncoder {
6
- const rootWithTrailingSlash = root.endsWith('/') ? root : `${root}/`
6
+ const normalizedRoot = root.replace(/\\/g, '/')
7
+ const rootWithTrailingSlash = normalizedRoot.endsWith('/')
8
+ ? normalizedRoot
9
+ : `${normalizedRoot}/`
7
10
 
8
11
  return ({ extractedFilename }) => {
9
- let file = extractedFilename
12
+ const normalizedFile = extractedFilename.replace(/\\/g, '/')
10
13
 
11
- if (file.startsWith(rootWithTrailingSlash)) {
12
- file = file.slice(rootWithTrailingSlash.length)
14
+ if (normalizedFile.startsWith(rootWithTrailingSlash)) {
15
+ return `/${normalizedFile.slice(rootWithTrailingSlash.length)}`
13
16
  }
14
17
 
15
- return `/@id/${file}`
18
+ return normalizedFile.startsWith('/')
19
+ ? `/@fs${normalizedFile}`
20
+ : `/@fs/${normalizedFile}`
16
21
  }
17
22
  }
18
23
 
@@ -23,6 +28,11 @@ export function decodeViteDevServerModuleSpecifier(
23
28
 
24
29
  if (sourceFile.startsWith('/@id/')) {
25
30
  sourceFile = sourceFile.slice('/@id/'.length)
31
+ } else if (sourceFile.startsWith('/@fs/')) {
32
+ sourceFile = sourceFile.slice('/@fs'.length)
33
+ sourceFile = sourceFile.replace(/^\/([A-Za-z]:\/)/, '$1')
34
+ } else if (sourceFile.startsWith('/')) {
35
+ sourceFile = sourceFile.slice(1)
26
36
  }
27
37
 
28
38
  const queryIndex = sourceFile.indexOf('?')