@tanstack/start-plugin-core 1.167.18 → 1.167.20

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 (184) hide show
  1. package/dist/esm/config-context.d.ts +26 -0
  2. package/dist/esm/config-context.js +81 -0
  3. package/dist/esm/config-context.js.map +1 -0
  4. package/dist/esm/constants.d.ts +6 -1
  5. package/dist/esm/constants.js +3 -2
  6. package/dist/esm/constants.js.map +1 -1
  7. package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js +1 -1
  8. package/dist/esm/import-protection-plugin/plugin.js +1 -1
  9. package/dist/esm/import-protection-plugin/virtualModules.js +1 -1
  10. package/dist/esm/index.d.ts +5 -3
  11. package/dist/esm/index.js +3 -4
  12. package/dist/esm/planning.d.ts +40 -0
  13. package/dist/esm/planning.js +107 -0
  14. package/dist/esm/planning.js.map +1 -0
  15. package/dist/esm/schema.d.ts +3093 -44
  16. package/dist/esm/schema.js +5 -5
  17. package/dist/esm/schema.js.map +1 -1
  18. package/dist/esm/serialization-adapters-module.d.ts +17 -0
  19. package/dist/esm/serialization-adapters-module.js +39 -0
  20. package/dist/esm/serialization-adapters-module.js.map +1 -0
  21. package/dist/esm/{start-compiler-plugin → start-compiler}/compiler.d.ts +2 -3
  22. package/dist/esm/{start-compiler-plugin → start-compiler}/compiler.js +17 -16
  23. package/dist/esm/start-compiler/compiler.js.map +1 -0
  24. package/dist/esm/start-compiler/config.d.ts +4 -0
  25. package/dist/esm/start-compiler/config.js +54 -0
  26. package/dist/esm/start-compiler/config.js.map +1 -0
  27. package/dist/esm/{start-compiler-plugin → start-compiler}/handleClientOnlyJSX.js +1 -1
  28. package/dist/esm/start-compiler/handleClientOnlyJSX.js.map +1 -0
  29. package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateIsomorphicFn.js +1 -1
  30. package/dist/esm/start-compiler/handleCreateIsomorphicFn.js.map +1 -0
  31. package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateMiddleware.js +1 -1
  32. package/dist/esm/start-compiler/handleCreateMiddleware.js.map +1 -0
  33. package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateServerFn.js +6 -17
  34. package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -0
  35. package/dist/esm/{start-compiler-plugin → start-compiler}/handleEnvOnly.js +1 -1
  36. package/dist/esm/start-compiler/handleEnvOnly.js.map +1 -0
  37. package/dist/esm/start-compiler/host.d.ts +20 -0
  38. package/dist/esm/start-compiler/host.js +38 -0
  39. package/dist/esm/start-compiler/host.js.map +1 -0
  40. package/dist/esm/start-compiler/load-module.d.ts +14 -0
  41. package/dist/esm/start-compiler/load-module.js +18 -0
  42. package/dist/esm/start-compiler/load-module.js.map +1 -0
  43. package/dist/esm/start-compiler/server-fn-resolver-module.d.ts +8 -0
  44. package/dist/esm/start-compiler/server-fn-resolver-module.js +77 -0
  45. package/dist/esm/start-compiler/server-fn-resolver-module.js.map +1 -0
  46. package/dist/esm/{start-compiler-plugin → start-compiler}/types.d.ts +4 -0
  47. package/dist/esm/{start-compiler-plugin → start-compiler}/utils.js +1 -1
  48. package/dist/esm/start-compiler/utils.js.map +1 -0
  49. package/dist/esm/start-manifest-plugin/manifestBuilder.d.ts +16 -16
  50. package/dist/esm/start-manifest-plugin/manifestBuilder.js +14 -45
  51. package/dist/esm/start-manifest-plugin/manifestBuilder.js.map +1 -1
  52. package/dist/esm/start-router-plugin/route-tree-footer.d.ts +6 -0
  53. package/dist/esm/start-router-plugin/route-tree-footer.js +44 -0
  54. package/dist/esm/start-router-plugin/route-tree-footer.js.map +1 -0
  55. package/dist/esm/types.d.ts +44 -10
  56. package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/dev-styles.js +1 -1
  57. package/dist/esm/vite/dev-server-plugin/dev-styles.js.map +1 -0
  58. package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/extract-html-scripts.js +1 -1
  59. package/dist/esm/vite/dev-server-plugin/extract-html-scripts.js.map +1 -0
  60. package/dist/esm/vite/dev-server-plugin/plugin.d.ts +7 -0
  61. package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/plugin.js +5 -6
  62. package/dist/esm/vite/dev-server-plugin/plugin.js.map +1 -0
  63. package/dist/esm/{load-env-plugin → vite/load-env-plugin}/plugin.js +1 -1
  64. package/dist/esm/vite/load-env-plugin/plugin.js.map +1 -0
  65. package/dist/esm/{output-directory.js → vite/output-directory.js} +2 -2
  66. package/dist/esm/vite/output-directory.js.map +1 -0
  67. package/dist/esm/vite/planning.d.ts +105 -0
  68. package/dist/esm/vite/planning.js +116 -0
  69. package/dist/esm/vite/planning.js.map +1 -0
  70. package/dist/esm/vite/plugin.d.ts +4 -0
  71. package/dist/esm/vite/plugin.js +169 -0
  72. package/dist/esm/vite/plugin.js.map +1 -0
  73. package/dist/esm/vite/plugins.d.ts +17 -0
  74. package/dist/esm/vite/plugins.js +50 -0
  75. package/dist/esm/vite/plugins.js.map +1 -0
  76. package/dist/esm/{post-server-build.d.ts → vite/post-server-build.d.ts} +1 -1
  77. package/dist/esm/{post-server-build.js → vite/post-server-build.js} +4 -4
  78. package/dist/esm/vite/post-server-build.js.map +1 -0
  79. package/dist/esm/{prerender.d.ts → vite/prerender.d.ts} +1 -1
  80. package/dist/esm/{prerender.js → vite/prerender.js} +5 -10
  81. package/dist/esm/vite/prerender.js.map +1 -0
  82. package/dist/esm/{preview-server-plugin → vite/preview-server-plugin}/plugin.js +4 -4
  83. package/dist/esm/vite/preview-server-plugin/plugin.js.map +1 -0
  84. package/dist/esm/vite/schema.d.ts +3373 -0
  85. package/dist/esm/vite/schema.js +12 -0
  86. package/dist/esm/vite/schema.js.map +1 -0
  87. package/dist/esm/vite/serialization-adapters-plugin.d.ts +5 -0
  88. package/dist/esm/vite/serialization-adapters-plugin.js +42 -0
  89. package/dist/esm/vite/serialization-adapters-plugin.js.map +1 -0
  90. package/dist/esm/vite/start-compiler-plugin/module-specifier.d.ts +3 -0
  91. package/dist/esm/vite/start-compiler-plugin/module-specifier.js +19 -0
  92. package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -0
  93. package/dist/esm/{start-compiler-plugin → vite/start-compiler-plugin}/plugin.d.ts +4 -3
  94. package/dist/esm/vite/start-compiler-plugin/plugin.js +202 -0
  95. package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -0
  96. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.d.ts +6 -0
  97. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js +81 -0
  98. package/dist/esm/vite/start-manifest-plugin/normalized-client-build.js.map +1 -0
  99. package/dist/esm/vite/start-manifest-plugin/plugin.d.ts +6 -0
  100. package/dist/esm/{start-manifest-plugin → vite/start-manifest-plugin}/plugin.js +14 -9
  101. package/dist/esm/vite/start-manifest-plugin/plugin.js.map +1 -0
  102. package/dist/esm/{start-router-plugin → vite/start-router-plugin}/plugin.d.ts +3 -2
  103. package/dist/esm/{start-router-plugin → vite/start-router-plugin}/plugin.js +14 -37
  104. package/dist/esm/vite/start-router-plugin/plugin.js.map +1 -0
  105. package/dist/esm/vite/types.d.ts +15 -0
  106. package/package.json +36 -25
  107. package/src/config-context.ts +138 -0
  108. package/src/constants.ts +7 -3
  109. package/src/index.ts +5 -5
  110. package/src/planning.ts +151 -0
  111. package/src/schema.ts +93 -93
  112. package/src/serialization-adapters-module.ts +82 -0
  113. package/src/{start-compiler-plugin → start-compiler}/compiler.ts +67 -61
  114. package/src/start-compiler/config.ts +73 -0
  115. package/src/{start-compiler-plugin → start-compiler}/handleCreateServerFn.ts +14 -41
  116. package/src/start-compiler/host.ts +80 -0
  117. package/src/start-compiler/load-module.ts +31 -0
  118. package/src/start-compiler/server-fn-resolver-module.ts +129 -0
  119. package/src/{start-compiler-plugin → start-compiler}/types.ts +5 -0
  120. package/src/start-manifest-plugin/manifestBuilder.ts +65 -107
  121. package/src/start-router-plugin/route-tree-footer.ts +99 -0
  122. package/src/types.ts +53 -10
  123. package/src/{dev-server-plugin → vite/dev-server-plugin}/plugin.ts +7 -6
  124. package/src/{output-directory.ts → vite/output-directory.ts} +2 -2
  125. package/src/vite/planning.ts +234 -0
  126. package/src/vite/plugin.ts +276 -0
  127. package/src/vite/plugins.ts +81 -0
  128. package/src/{post-server-build.ts → vite/post-server-build.ts} +4 -6
  129. package/src/{prerender.ts → vite/prerender.ts} +21 -46
  130. package/src/{preview-server-plugin → vite/preview-server-plugin}/plugin.ts +2 -2
  131. package/src/vite/schema.ts +30 -0
  132. package/src/vite/serialization-adapters-plugin.ts +69 -0
  133. package/src/vite/start-compiler-plugin/module-specifier.ts +31 -0
  134. package/src/vite/start-compiler-plugin/plugin.ts +345 -0
  135. package/src/vite/start-manifest-plugin/normalized-client-build.ts +131 -0
  136. package/src/{start-manifest-plugin → vite/start-manifest-plugin}/plugin.ts +21 -13
  137. package/src/{start-router-plugin → vite/start-router-plugin}/plugin.ts +14 -80
  138. package/src/vite/types.ts +18 -0
  139. package/LICENSE +0 -21
  140. package/dist/esm/dev-server-plugin/dev-styles.js.map +0 -1
  141. package/dist/esm/dev-server-plugin/extract-html-scripts.js.map +0 -1
  142. package/dist/esm/dev-server-plugin/plugin.d.ts +0 -6
  143. package/dist/esm/dev-server-plugin/plugin.js.map +0 -1
  144. package/dist/esm/load-env-plugin/plugin.js.map +0 -1
  145. package/dist/esm/output-directory.js.map +0 -1
  146. package/dist/esm/plugin.d.ts +0 -4
  147. package/dist/esm/plugin.js +0 -301
  148. package/dist/esm/plugin.js.map +0 -1
  149. package/dist/esm/post-server-build.js.map +0 -1
  150. package/dist/esm/prerender.js.map +0 -1
  151. package/dist/esm/preview-server-plugin/plugin.js.map +0 -1
  152. package/dist/esm/start-compiler-plugin/compiler.js.map +0 -1
  153. package/dist/esm/start-compiler-plugin/handleClientOnlyJSX.js.map +0 -1
  154. package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js.map +0 -1
  155. package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js.map +0 -1
  156. package/dist/esm/start-compiler-plugin/handleCreateServerFn.js.map +0 -1
  157. package/dist/esm/start-compiler-plugin/handleEnvOnly.js.map +0 -1
  158. package/dist/esm/start-compiler-plugin/plugin.js +0 -297
  159. package/dist/esm/start-compiler-plugin/plugin.js.map +0 -1
  160. package/dist/esm/start-compiler-plugin/utils.js.map +0 -1
  161. package/dist/esm/start-manifest-plugin/plugin.d.ts +0 -6
  162. package/dist/esm/start-manifest-plugin/plugin.js.map +0 -1
  163. package/dist/esm/start-router-plugin/plugin.js.map +0 -1
  164. package/src/plugin.ts +0 -471
  165. package/src/start-compiler-plugin/plugin.ts +0 -478
  166. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleClientOnlyJSX.d.ts +0 -0
  167. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateIsomorphicFn.d.ts +0 -0
  168. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateMiddleware.d.ts +0 -0
  169. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateServerFn.d.ts +0 -0
  170. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleEnvOnly.d.ts +0 -0
  171. /package/dist/esm/{start-compiler-plugin → start-compiler}/utils.d.ts +0 -0
  172. /package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/dev-styles.d.ts +0 -0
  173. /package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/extract-html-scripts.d.ts +0 -0
  174. /package/dist/esm/{load-env-plugin → vite/load-env-plugin}/plugin.d.ts +0 -0
  175. /package/dist/esm/{output-directory.d.ts → vite/output-directory.d.ts} +0 -0
  176. /package/dist/esm/{preview-server-plugin → vite/preview-server-plugin}/plugin.d.ts +0 -0
  177. /package/src/{start-compiler-plugin → start-compiler}/handleClientOnlyJSX.ts +0 -0
  178. /package/src/{start-compiler-plugin → start-compiler}/handleCreateIsomorphicFn.ts +0 -0
  179. /package/src/{start-compiler-plugin → start-compiler}/handleCreateMiddleware.ts +0 -0
  180. /package/src/{start-compiler-plugin → start-compiler}/handleEnvOnly.ts +0 -0
  181. /package/src/{start-compiler-plugin → start-compiler}/utils.ts +0 -0
  182. /package/src/{dev-server-plugin → vite/dev-server-plugin}/dev-styles.ts +0 -0
  183. /package/src/{dev-server-plugin → vite/dev-server-plugin}/extract-html-scripts.ts +0 -0
  184. /package/src/{load-env-plugin → vite/load-env-plugin}/plugin.ts +0 -0
@@ -1,478 +0,0 @@
1
- import assert from 'node:assert'
2
- import { VIRTUAL_MODULES } from '@tanstack/start-server-core'
3
- import { resolve as resolvePath } from 'pathe'
4
- import {
5
- SERVER_FN_LOOKUP,
6
- TRANSFORM_ID_REGEX,
7
- VITE_ENVIRONMENT_NAMES,
8
- } from '../constants'
9
- import {
10
- KindDetectionPatterns,
11
- LookupKindsPerEnv,
12
- StartCompiler,
13
- detectKindsInCode,
14
- } from './compiler'
15
- import { cleanId } from './utils'
16
- import type { CompileStartFrameworkOptions } from '../types'
17
- import type { LookupConfig, LookupKind } from './compiler'
18
- import type { GenerateFunctionIdFnOptional, ServerFn } from './types'
19
- import type { PluginOption } from 'vite'
20
-
21
- // Derive transform code filter from KindDetectionPatterns (single source of truth)
22
- function getTransformCodeFilterForEnv(env: 'client' | 'server'): Array<RegExp> {
23
- const validKinds = LookupKindsPerEnv[env]
24
- const patterns: Array<RegExp> = []
25
- for (const [kind, pattern] of Object.entries(KindDetectionPatterns) as Array<
26
- [LookupKind, RegExp]
27
- >) {
28
- if (validKinds.has(kind)) {
29
- patterns.push(pattern)
30
- }
31
- }
32
- return patterns
33
- }
34
-
35
- const getLookupConfigurationsForEnv = (
36
- env: 'client' | 'server',
37
- framework: CompileStartFrameworkOptions,
38
- ): Array<LookupConfig> => {
39
- // Common configs for all environments
40
- const commonConfigs: Array<LookupConfig> = [
41
- {
42
- libName: `@tanstack/${framework}-start`,
43
- rootExport: 'createServerFn',
44
- kind: 'Root',
45
- },
46
- {
47
- libName: `@tanstack/${framework}-start`,
48
- rootExport: 'createIsomorphicFn',
49
- kind: 'IsomorphicFn',
50
- },
51
- {
52
- libName: `@tanstack/${framework}-start`,
53
- rootExport: 'createServerOnlyFn',
54
- kind: 'ServerOnlyFn',
55
- },
56
- {
57
- libName: `@tanstack/${framework}-start`,
58
- rootExport: 'createClientOnlyFn',
59
- kind: 'ClientOnlyFn',
60
- },
61
- ]
62
-
63
- if (env === 'client') {
64
- return [
65
- {
66
- libName: `@tanstack/${framework}-start`,
67
- rootExport: 'createMiddleware',
68
- kind: 'Root',
69
- },
70
- {
71
- libName: `@tanstack/${framework}-start`,
72
- rootExport: 'createStart',
73
- kind: 'Root',
74
- },
75
- ...commonConfigs,
76
- ]
77
- } else {
78
- // Server-only: add ClientOnly JSX component lookup
79
- return [
80
- ...commonConfigs,
81
- {
82
- libName: `@tanstack/${framework}-router`,
83
- rootExport: 'ClientOnly',
84
- kind: 'ClientOnlyJSX',
85
- },
86
- ]
87
- }
88
- }
89
- // Re-export from shared constants for backwards compatibility
90
- export { SERVER_FN_LOOKUP }
91
-
92
- function resolveViteId(id: string) {
93
- return `\0${id}`
94
- }
95
-
96
- const validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`
97
-
98
- function parseIdQuery(id: string): {
99
- filename: string
100
- query: {
101
- [k: string]: string
102
- }
103
- } {
104
- if (!id.includes('?')) return { filename: id, query: {} }
105
- const [filename, rawQuery] = id.split(`?`, 2) as [string, string]
106
- const query = Object.fromEntries(new URLSearchParams(rawQuery))
107
- return { filename, query }
108
- }
109
-
110
- /**
111
- * Generates the manifest module code for server functions.
112
- * @param serverFnsById - Map of function IDs to their server function info
113
- * @param includeClientReferencedCheck - Whether to include isClientReferenced flag and runtime check.
114
- * This is needed when SSR is NOT the provider, so server-only-referenced functions in the manifest
115
- * can be blocked from client HTTP requests.
116
- */
117
- function generateManifestModule(
118
- serverFnsById: Record<string, ServerFn>,
119
- includeClientReferencedCheck: boolean,
120
- ): string {
121
- const manifestEntries = Object.entries(serverFnsById)
122
- .map(([id, fn]) => {
123
- const baseEntry = `'${id}': {
124
- functionName: '${fn.functionName}',
125
- importer: () => import(${JSON.stringify(fn.extractedFilename)})${
126
- includeClientReferencedCheck
127
- ? `,
128
- isClientReferenced: ${fn.isClientReferenced ?? true}`
129
- : ''
130
- }
131
- }`
132
- return baseEntry
133
- })
134
- .join(',')
135
-
136
- const getServerFnByIdParams = includeClientReferencedCheck ? 'id, opts' : 'id'
137
- const clientReferencedCheck = includeClientReferencedCheck
138
- ? `
139
- // If called from client, only allow client-referenced functions
140
- if (opts?.fromClient && !serverFnInfo.isClientReferenced) {
141
- throw new Error('Server function not accessible from client: ' + id)
142
- }
143
- `
144
- : ''
145
-
146
- return `
147
- const manifest = {${manifestEntries}}
148
-
149
- export async function getServerFnById(${getServerFnByIdParams}) {
150
- const serverFnInfo = manifest[id]
151
- if (!serverFnInfo) {
152
- throw new Error('Server function info not found for ' + id)
153
- }
154
- ${clientReferencedCheck}
155
- const fnModule = await serverFnInfo.importer()
156
-
157
- if (!fnModule) {
158
- console.info('serverFnInfo', serverFnInfo)
159
- throw new Error('Server function module not resolved for ' + id)
160
- }
161
-
162
- const action = fnModule[serverFnInfo.functionName]
163
-
164
- if (!action) {
165
- console.info('serverFnInfo', serverFnInfo)
166
- console.info('fnModule', fnModule)
167
-
168
- throw new Error(
169
- \`Server function module export not resolved for serverFn ID: \${id}\`,
170
- )
171
- }
172
- return action
173
- }
174
- `
175
- }
176
-
177
- export interface StartCompilerPluginOptions {
178
- framework: CompileStartFrameworkOptions
179
- environments: Array<{ name: string; type: 'client' | 'server' }>
180
- /**
181
- * Custom function ID generator (optional).
182
- */
183
- generateFunctionId?: GenerateFunctionIdFnOptional
184
- /**
185
- * The Vite environment name for the server function provider.
186
- */
187
- providerEnvName: string
188
- }
189
-
190
- export function startCompilerPlugin(
191
- opts: StartCompilerPluginOptions,
192
- ): PluginOption {
193
- const compilers: Record<string /* envName */, StartCompiler> = {}
194
-
195
- // Shared registry of server functions across all environments
196
- const serverFnsById: Record<string, ServerFn> = {}
197
-
198
- const onServerFnsById = (d: Record<string, ServerFn>) => {
199
- Object.assign(serverFnsById, d)
200
- }
201
-
202
- let root = process.cwd()
203
- let _command: 'build' | 'serve' = 'build'
204
-
205
- const resolvedResolverVirtualImportId = resolveViteId(
206
- VIRTUAL_MODULES.serverFnResolver,
207
- )
208
-
209
- // Determine which environments need the resolver (getServerFnById)
210
- // SSR environment always needs the resolver for server-side calls
211
- // Provider environment needs it for the actual implementation
212
- const ssrEnvName = VITE_ENVIRONMENT_NAMES.server
213
-
214
- // SSR is the provider when the provider environment is the default server environment
215
- const ssrIsProvider = opts.providerEnvName === ssrEnvName
216
-
217
- // Environments that need the resolver: SSR (for server calls) and provider (for implementation)
218
- const appliedResolverEnvironments = new Set(
219
- ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName],
220
- )
221
-
222
- function perEnvServerFnPlugin(environment: {
223
- name: string
224
- type: 'client' | 'server'
225
- }): PluginOption {
226
- // Derive transform code filter from KindDetectionPatterns (single source of truth)
227
- const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)
228
-
229
- return {
230
- name: `tanstack-start-core::server-fn:${environment.name}`,
231
- enforce: 'pre',
232
- applyToEnvironment(env) {
233
- return env.name === environment.name
234
- },
235
- configResolved(config) {
236
- root = config.root
237
- _command = config.command
238
- },
239
- transform: {
240
- filter: {
241
- id: {
242
- exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),
243
- include: TRANSFORM_ID_REGEX,
244
- },
245
- code: {
246
- include: transformCodeFilter,
247
- },
248
- },
249
- async handler(code, id) {
250
- let compiler = compilers[this.environment.name]
251
- if (!compiler) {
252
- // Default to 'dev' mode for unknown environments (conservative: no caching)
253
- const mode = this.environment.mode === 'build' ? 'build' : 'dev'
254
- compiler = new StartCompiler({
255
- env: environment.type,
256
- envName: environment.name,
257
- root,
258
- lookupKinds: LookupKindsPerEnv[environment.type],
259
- lookupConfigurations: getLookupConfigurationsForEnv(
260
- environment.type,
261
- opts.framework,
262
- ),
263
- mode,
264
- framework: opts.framework,
265
- providerEnvName: opts.providerEnvName,
266
- generateFunctionId: opts.generateFunctionId,
267
- onServerFnsById,
268
- getKnownServerFns: () => serverFnsById,
269
- loadModule: async (id: string) => {
270
- if (this.environment.mode === 'build') {
271
- const loaded = await this.load({ id })
272
- // Handle modules with no runtime code (e.g., type-only exports).
273
- // After TypeScript compilation, these become empty modules.
274
- // Create an empty module info instead of throwing.
275
- const code = loaded.code ?? ''
276
- compiler!.ingestModule({ code, id })
277
- } else if (this.environment.mode === 'dev') {
278
- /**
279
- * in dev, vite does not return code from `ctx.load()`
280
- * so instead, we need to take a different approach
281
- * we must force vite to load the module and run it through the vite plugin pipeline
282
- * we can do this by using the `fetchModule` method
283
- * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST
284
- */
285
- await this.environment.fetchModule(
286
- id + '?' + SERVER_FN_LOOKUP,
287
- )
288
- } else {
289
- throw new Error(
290
- `could not load module ${id}: unknown environment mode ${this.environment.mode}`,
291
- )
292
- }
293
- },
294
- resolveId: async (source: string, importer?: string) => {
295
- const r = await this.resolve(source, importer)
296
- if (r) {
297
- if (!r.external) {
298
- return cleanId(r.id)
299
- }
300
- }
301
- return null
302
- },
303
- })
304
- compilers[this.environment.name] = compiler
305
- }
306
-
307
- // Detect which kinds are present in this file before parsing
308
- const detectedKinds = detectKindsInCode(code, environment.type)
309
-
310
- const result = await compiler.compile({
311
- id,
312
- code,
313
- detectedKinds,
314
- })
315
- return result
316
- },
317
- },
318
-
319
- hotUpdate(ctx) {
320
- const compiler = compilers[this.environment.name]
321
-
322
- ctx.modules.forEach((m) => {
323
- if (m.id) {
324
- const deleted = compiler?.invalidateModule(m.id)
325
- if (deleted) {
326
- m.importers.forEach((importer) => {
327
- if (importer.id) {
328
- compiler?.invalidateModule(importer.id)
329
- }
330
- })
331
- }
332
- }
333
- })
334
- },
335
- }
336
- }
337
-
338
- return [
339
- ...opts.environments.map(perEnvServerFnPlugin),
340
- {
341
- name: 'tanstack-start-core:capture-server-fn-module-lookup',
342
- // we only need this plugin in dev mode
343
- apply: 'serve',
344
- applyToEnvironment(env) {
345
- return !!opts.environments.find((e) => e.name === env.name)
346
- },
347
- transform: {
348
- filter: {
349
- id: new RegExp(`${SERVER_FN_LOOKUP}$`),
350
- },
351
- handler(code, id) {
352
- const compiler = compilers[this.environment.name]
353
- compiler?.ingestModule({ code, id: cleanId(id) })
354
- },
355
- },
356
- },
357
- // Validate server function ID in dev mode
358
- {
359
- name: 'tanstack-start-core:validate-server-fn-id',
360
- apply: 'serve',
361
- load: {
362
- filter: {
363
- id: new RegExp(resolveViteId(validateServerFnIdVirtualModule)),
364
- },
365
- async handler(id) {
366
- const parsed = parseIdQuery(id)
367
- const fnId = parsed.query.id
368
- if (fnId && serverFnsById[fnId]) {
369
- return `export {}`
370
- }
371
-
372
- // ID not yet registered — the source file may not have been
373
- // transformed in this dev session yet (e.g. cold restart with
374
- // cached client). Try to decode the ID, discover the source
375
- // file, trigger its compilation, and re-check.
376
- if (fnId) {
377
- try {
378
- const decoded = JSON.parse(
379
- Buffer.from(fnId, 'base64url').toString('utf8'),
380
- )
381
- if (
382
- typeof decoded.file === 'string' &&
383
- typeof decoded.export === 'string'
384
- ) {
385
- // decoded.file looks like "/@id/src/foo.ts?tss-serverfn-split"
386
- // Strip the /@id/ prefix and ?tss-serverfn-split suffix to
387
- // get the original source file path that needs transforming.
388
- let sourceFile = decoded.file
389
- if (sourceFile.startsWith('/@id/')) {
390
- sourceFile = sourceFile.slice('/@id/'.length)
391
- }
392
- const qIdx = sourceFile.indexOf('?')
393
- if (qIdx !== -1) {
394
- sourceFile = sourceFile.slice(0, qIdx)
395
- }
396
-
397
- // Resolve to absolute path
398
- const absPath = resolvePath(root, sourceFile)
399
-
400
- // Trigger transform of the source file in this environment,
401
- // which will compile createServerFn calls and populate
402
- // serverFnsById as a side effect.
403
- // This plugin only runs in dev (apply: 'serve'), so mode
404
- // must be 'dev' — assert to narrow to DevEnvironment.
405
- assert(this.environment.mode === 'dev')
406
- await this.environment.fetchModule(absPath)
407
-
408
- // Re-check after lazy compilation
409
- if (serverFnsById[fnId]) {
410
- return `export {}`
411
- }
412
- }
413
- } catch {
414
- // Decoding or fetching failed — fall through to error
415
- }
416
- }
417
-
418
- this.error(`Invalid server function ID: ${fnId}`)
419
- },
420
- },
421
- },
422
- // Manifest plugin for server environments
423
- {
424
- name: 'tanstack-start-core:server-fn-resolver',
425
- enforce: 'pre',
426
- applyToEnvironment: (env) => {
427
- return appliedResolverEnvironments.has(env.name)
428
- },
429
- configResolved(config) {
430
- root = config.root
431
- _command = config.command
432
- },
433
- resolveId: {
434
- filter: { id: new RegExp(VIRTUAL_MODULES.serverFnResolver) },
435
- handler() {
436
- return resolvedResolverVirtualImportId
437
- },
438
- },
439
- load: {
440
- filter: { id: new RegExp(resolvedResolverVirtualImportId) },
441
- handler() {
442
- // When SSR is not the provider, SSR callers need to use HTTP to call server functions
443
- // since they can't directly import from the provider environment
444
- if (this.environment.name !== opts.providerEnvName) {
445
- // SSR caller: use HTTP-based getServerFnById
446
- // This re-exports from the start-server-core package which handles HTTP calls
447
- return `export { getServerFnById } from '@tanstack/start-server-core/server-fn-ssr-caller'`
448
- }
449
-
450
- if (this.environment.mode !== 'build') {
451
- const mod = `
452
- export async function getServerFnById(id) {
453
- const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + id
454
- await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)
455
- const decoded = Buffer.from(id, 'base64url').toString('utf8')
456
- const devServerFn = JSON.parse(decoded)
457
- const mod = await import(/* @vite-ignore */ devServerFn.file)
458
- return mod[devServerFn.export]
459
- }
460
- `
461
- return mod
462
- }
463
-
464
- // When SSR is the provider, server-only-referenced functions aren't in the manifest,
465
- // so no isClientReferenced check is needed.
466
- // When SSR is NOT the provider (custom provider env), server-only-referenced
467
- // functions ARE in the manifest and need the isClientReferenced check to
468
- // block direct client HTTP requests to server-only-referenced functions.
469
- const includeClientReferencedCheck = !ssrIsProvider
470
- return generateManifestModule(
471
- serverFnsById,
472
- includeClientReferencedCheck,
473
- )
474
- },
475
- },
476
- },
477
- ]
478
- }