@tanstack/start-plugin-core 1.167.18 → 1.167.19

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 (183) 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 +12 -1
  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/dist/esm/dev-server-plugin/dev-styles.js.map +0 -1
  140. package/dist/esm/dev-server-plugin/extract-html-scripts.js.map +0 -1
  141. package/dist/esm/dev-server-plugin/plugin.d.ts +0 -6
  142. package/dist/esm/dev-server-plugin/plugin.js.map +0 -1
  143. package/dist/esm/load-env-plugin/plugin.js.map +0 -1
  144. package/dist/esm/output-directory.js.map +0 -1
  145. package/dist/esm/plugin.d.ts +0 -4
  146. package/dist/esm/plugin.js +0 -301
  147. package/dist/esm/plugin.js.map +0 -1
  148. package/dist/esm/post-server-build.js.map +0 -1
  149. package/dist/esm/prerender.js.map +0 -1
  150. package/dist/esm/preview-server-plugin/plugin.js.map +0 -1
  151. package/dist/esm/start-compiler-plugin/compiler.js.map +0 -1
  152. package/dist/esm/start-compiler-plugin/handleClientOnlyJSX.js.map +0 -1
  153. package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js.map +0 -1
  154. package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js.map +0 -1
  155. package/dist/esm/start-compiler-plugin/handleCreateServerFn.js.map +0 -1
  156. package/dist/esm/start-compiler-plugin/handleEnvOnly.js.map +0 -1
  157. package/dist/esm/start-compiler-plugin/plugin.js +0 -297
  158. package/dist/esm/start-compiler-plugin/plugin.js.map +0 -1
  159. package/dist/esm/start-compiler-plugin/utils.js.map +0 -1
  160. package/dist/esm/start-manifest-plugin/plugin.d.ts +0 -6
  161. package/dist/esm/start-manifest-plugin/plugin.js.map +0 -1
  162. package/dist/esm/start-router-plugin/plugin.js.map +0 -1
  163. package/src/plugin.ts +0 -471
  164. package/src/start-compiler-plugin/plugin.ts +0 -478
  165. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleClientOnlyJSX.d.ts +0 -0
  166. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateIsomorphicFn.d.ts +0 -0
  167. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateMiddleware.d.ts +0 -0
  168. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleCreateServerFn.d.ts +0 -0
  169. /package/dist/esm/{start-compiler-plugin → start-compiler}/handleEnvOnly.d.ts +0 -0
  170. /package/dist/esm/{start-compiler-plugin → start-compiler}/utils.d.ts +0 -0
  171. /package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/dev-styles.d.ts +0 -0
  172. /package/dist/esm/{dev-server-plugin → vite/dev-server-plugin}/extract-html-scripts.d.ts +0 -0
  173. /package/dist/esm/{load-env-plugin → vite/load-env-plugin}/plugin.d.ts +0 -0
  174. /package/dist/esm/{output-directory.d.ts → vite/output-directory.d.ts} +0 -0
  175. /package/dist/esm/{preview-server-plugin → vite/preview-server-plugin}/plugin.d.ts +0 -0
  176. /package/src/{start-compiler-plugin → start-compiler}/handleClientOnlyJSX.ts +0 -0
  177. /package/src/{start-compiler-plugin → start-compiler}/handleCreateIsomorphicFn.ts +0 -0
  178. /package/src/{start-compiler-plugin → start-compiler}/handleCreateMiddleware.ts +0 -0
  179. /package/src/{start-compiler-plugin → start-compiler}/handleEnvOnly.ts +0 -0
  180. /package/src/{start-compiler-plugin → start-compiler}/utils.ts +0 -0
  181. /package/src/{dev-server-plugin → vite/dev-server-plugin}/dev-styles.ts +0 -0
  182. /package/src/{dev-server-plugin → vite/dev-server-plugin}/extract-html-scripts.ts +0 -0
  183. /package/src/{load-env-plugin → vite/load-env-plugin}/plugin.ts +0 -0
@@ -15,6 +15,7 @@ import { handleEnvOnlyFn } from './handleEnvOnly'
15
15
  import { handleClientOnlyJSX } from './handleClientOnlyJSX'
16
16
  import type {
17
17
  CompilationContext,
18
+ DevServerFnModuleSpecifierEncoder,
18
19
  MethodChainPaths,
19
20
  RewriteCandidate,
20
21
  ServerFn,
@@ -311,9 +312,6 @@ export class StartCompiler {
311
312
  private entryIdToFunctionId = new Map<string, string>()
312
313
  private functionIds = new Set<string>()
313
314
 
314
- // Cached root path with trailing slash for dev mode function ID generation
315
- private _rootWithTrailingSlash: string | undefined
316
-
317
315
  constructor(
318
316
  private options: {
319
317
  env: 'client' | 'server'
@@ -353,6 +351,7 @@ export class StartCompiler {
353
351
  * Used by server callers to look up canonical extracted filenames.
354
352
  */
355
353
  getKnownServerFns?: () => Record<string, ServerFn>
354
+ devServerFnModuleSpecifierEncoder?: DevServerFnModuleSpecifierEncoder
356
355
  },
357
356
  ) {
358
357
  this.validLookupKinds = options.lookupKinds
@@ -369,12 +368,20 @@ export class StartCompiler {
369
368
  extractedFilename: string
370
369
  }): string {
371
370
  if (this.mode === 'dev') {
372
- // In dev, encode the file path and export name for direct lookup
373
- let file = opts.extractedFilename
374
- if (opts.extractedFilename.startsWith(this.rootWithTrailingSlash)) {
375
- file = opts.extractedFilename.slice(this.rootWithTrailingSlash.length)
371
+ // In dev, encode the file path and export name for direct lookup.
372
+ // Each bundler adapter supplies its own strategy for encoding
373
+ // module specifiers that work with its dev server runtime.
374
+ const encodeModuleSpecifier =
375
+ this.options.devServerFnModuleSpecifierEncoder
376
+ if (!encodeModuleSpecifier) {
377
+ throw new Error(
378
+ 'devServerFnModuleSpecifierEncoder is required in dev mode.',
379
+ )
376
380
  }
377
- file = `/@id/${file}`
381
+ const file = encodeModuleSpecifier({
382
+ extractedFilename: opts.extractedFilename,
383
+ root: this.options.root,
384
+ })
378
385
 
379
386
  const serverFn = {
380
387
  file,
@@ -415,15 +422,6 @@ export class StartCompiler {
415
422
  return this.options.mode ?? 'dev'
416
423
  }
417
424
 
418
- private get rootWithTrailingSlash(): string {
419
- if (this._rootWithTrailingSlash === undefined) {
420
- this._rootWithTrailingSlash = this.options.root.endsWith('/')
421
- ? this.options.root
422
- : `${this.options.root}/`
423
- }
424
- return this._rootWithTrailingSlash
425
- }
426
-
427
425
  private async resolveIdCached(id: string, importer?: string) {
428
426
  if (this.mode === 'dev') {
429
427
  return this.options.resolveId(id, importer)
@@ -460,54 +458,62 @@ export class StartCompiler {
460
458
  ]),
461
459
  )
462
460
 
463
- await Promise.all(
464
- this.options.lookupConfigurations.map(async (config) => {
465
- // Populate the fast lookup map for direct imports (by package name)
466
- // This allows O(1) recognition of imports from known packages.
467
- let libExports = this.knownRootImports.get(config.libName)
468
- if (!libExports) {
469
- libExports = new Map()
470
- this.knownRootImports.set(config.libName, libExports)
471
- }
472
- libExports.set(config.rootExport, config.kind)
473
-
474
- // For JSX lookups (e.g., ClientOnlyJSX), we only need the knownRootImports
475
- // fast path to verify imports. Skip module resolution which may fail if
476
- // the package isn't a direct dependency (e.g., @tanstack/react-router from
477
- // within start-plugin-core).
478
- if (config.kind !== 'Root') {
479
- const setup = LookupSetup[config.kind]
480
- if (setup.type === 'jsx') {
481
- return
482
- }
483
- }
461
+ // Register start-client-core exports for internal package usage (e.g., react-start-rsc).
462
+ // These don't need module resolution - only the knownRootImports fast path.
463
+ this.knownRootImports.set(
464
+ '@tanstack/start-client-core',
465
+ new Map<string, Kind>([
466
+ ['createIsomorphicFn', 'IsomorphicFn'],
467
+ ['createServerOnlyFn', 'ServerOnlyFn'],
468
+ ['createClientOnlyFn', 'ClientOnlyFn'],
469
+ ]),
470
+ )
484
471
 
485
- const libId = await this.resolveIdCached(config.libName)
486
- if (!libId) {
487
- throw new Error(`could not resolve "${config.libName}"`)
488
- }
489
- let rootModule = this.moduleCache.get(libId)
490
- if (!rootModule) {
491
- // insert root binding
492
- rootModule = {
493
- bindings: new Map(),
494
- exports: new Map(),
495
- id: libId,
496
- reExportAllSources: [],
497
- }
498
- this.moduleCache.set(libId, rootModule)
472
+ for (const config of this.options.lookupConfigurations) {
473
+ // Populate the fast lookup map for direct imports (by package name)
474
+ // This allows O(1) recognition of imports from known packages.
475
+ let libExports = this.knownRootImports.get(config.libName)
476
+ if (!libExports) {
477
+ libExports = new Map()
478
+ this.knownRootImports.set(config.libName, libExports)
479
+ }
480
+ libExports.set(config.rootExport, config.kind)
481
+
482
+ // For JSX lookups (e.g., ClientOnlyJSX), we only need the knownRootImports
483
+ // fast path to verify imports. Skip synthetic root module setup.
484
+ if (config.kind !== 'Root') {
485
+ const setup = LookupSetup[config.kind]
486
+ if (setup.type === 'jsx') {
487
+ continue
499
488
  }
489
+ }
500
490
 
501
- rootModule.exports.set(config.rootExport, config.rootExport)
502
- rootModule.exports.set('*', config.rootExport)
503
- rootModule.bindings.set(config.rootExport, {
504
- type: 'var',
505
- init: null, // Not needed since resolvedKind is set
506
- resolvedKind: config.kind satisfies Kind,
507
- })
491
+ // Root lookup metadata is synthetic package-level state, not a real
492
+ // resolved module. Keep the ID stable across bundlers and export-map
493
+ // behavior by always keying it to the package specifier itself.
494
+ const libId = config.libName
495
+
496
+ let rootModule = this.moduleCache.get(libId)
497
+ if (!rootModule) {
498
+ // insert root binding
499
+ rootModule = {
500
+ bindings: new Map(),
501
+ exports: new Map(),
502
+ id: libId,
503
+ reExportAllSources: [],
504
+ }
508
505
  this.moduleCache.set(libId, rootModule)
509
- }),
510
- )
506
+ }
507
+
508
+ rootModule.exports.set(config.rootExport, config.rootExport)
509
+ rootModule.exports.set('*', config.rootExport)
510
+ rootModule.bindings.set(config.rootExport, {
511
+ type: 'var',
512
+ init: null, // Not needed since resolvedKind is set
513
+ resolvedKind: config.kind satisfies Kind,
514
+ })
515
+ this.moduleCache.set(libId, rootModule)
516
+ }
511
517
 
512
518
  this.initialized = true
513
519
  }
@@ -0,0 +1,73 @@
1
+ import { KindDetectionPatterns, LookupKindsPerEnv } from './compiler'
2
+ import type { LookupConfig, LookupKind } from './compiler'
3
+ import type { CompileStartFrameworkOptions } from '../types'
4
+
5
+ export function getTransformCodeFilterForEnv(
6
+ env: 'client' | 'server',
7
+ ): Array<RegExp> {
8
+ const validKinds = LookupKindsPerEnv[env]
9
+ const patterns: Array<RegExp> = []
10
+
11
+ for (const [kind, pattern] of Object.entries(KindDetectionPatterns) as Array<
12
+ [LookupKind, RegExp]
13
+ >) {
14
+ if (validKinds.has(kind)) {
15
+ patterns.push(pattern)
16
+ }
17
+ }
18
+
19
+ return patterns
20
+ }
21
+
22
+ export function getLookupConfigurationsForEnv(
23
+ env: 'client' | 'server',
24
+ framework: CompileStartFrameworkOptions,
25
+ ): Array<LookupConfig> {
26
+ const commonConfigs: Array<LookupConfig> = [
27
+ {
28
+ libName: `@tanstack/${framework}-start`,
29
+ rootExport: 'createServerFn',
30
+ kind: 'Root',
31
+ },
32
+ {
33
+ libName: `@tanstack/${framework}-start`,
34
+ rootExport: 'createIsomorphicFn',
35
+ kind: 'IsomorphicFn',
36
+ },
37
+ {
38
+ libName: `@tanstack/${framework}-start`,
39
+ rootExport: 'createServerOnlyFn',
40
+ kind: 'ServerOnlyFn',
41
+ },
42
+ {
43
+ libName: `@tanstack/${framework}-start`,
44
+ rootExport: 'createClientOnlyFn',
45
+ kind: 'ClientOnlyFn',
46
+ },
47
+ ]
48
+
49
+ if (env === 'client') {
50
+ return [
51
+ {
52
+ libName: `@tanstack/${framework}-start`,
53
+ rootExport: 'createMiddleware',
54
+ kind: 'Root',
55
+ },
56
+ {
57
+ libName: `@tanstack/${framework}-start`,
58
+ rootExport: 'createStart',
59
+ kind: 'Root',
60
+ },
61
+ ...commonConfigs,
62
+ ]
63
+ }
64
+
65
+ return [
66
+ ...commonConfigs,
67
+ {
68
+ libName: `@tanstack/${framework}-router`,
69
+ rootExport: 'ClientOnly',
70
+ kind: 'ClientOnlyJSX',
71
+ },
72
+ ]
73
+ }
@@ -1,7 +1,6 @@
1
1
  import * as t from '@babel/types'
2
2
  import babel from '@babel/core'
3
3
  import path from 'pathe'
4
- import { VITE_ENVIRONMENT_NAMES } from '../constants'
5
4
  import { cleanId, codeFrameError, stripMethodCall } from './utils'
6
5
  import type { CompilationContext, RewriteCandidate, ServerFn } from './types'
7
6
  import type { CompileStartFrameworkOptions } from '../types'
@@ -22,16 +21,11 @@ const clientRpcTemplate = babel.template.expression(
22
21
  `createClientRpc(%%functionId%%)`,
23
22
  )
24
23
 
25
- // Template for SSR caller files (manifest lookup): createSsrRpc(functionId)
24
+ // Template for SSR caller files: createSsrRpc(functionId)
26
25
  const ssrRpcManifestTemplate = babel.template.expression(
27
26
  `createSsrRpc(%%functionId%%)`,
28
27
  )
29
28
 
30
- // Template for SSR caller files (with importer): createSsrRpc(functionId, () => import(...).then(m => m['name']))
31
- const ssrRpcImporterTemplate = babel.template.expression(
32
- `createSsrRpc(%%functionId%%, () => import(%%extractedFilename%%).then(m => m[%%functionName%%]))`,
33
- )
34
-
35
29
  // ============================================================================
36
30
  // Runtime code cache (cached per framework to avoid repeated AST generation)
37
31
  // ============================================================================
@@ -75,8 +69,6 @@ function getCachedRuntimeCode(
75
69
  interface EnvConfig {
76
70
  /** Whether this environment is a client environment */
77
71
  isClientEnvironment: boolean
78
- /** Whether SSR is the provider environment */
79
- ssrIsProvider: boolean
80
72
  /** The runtime code type to use for imports */
81
73
  runtimeCodeType: RuntimeCodeType
82
74
  }
@@ -88,15 +80,11 @@ function getEnvConfig(
88
80
  context: CompilationContext,
89
81
  isProviderFile: boolean,
90
82
  ): EnvConfig {
91
- const { providerEnvName, env } = context
92
-
93
- // SSR is the provider when the provider environment is the default server environment
94
- const ssrIsProvider = providerEnvName === VITE_ENVIRONMENT_NAMES.server
83
+ const { env } = context
95
84
 
96
85
  if (isProviderFile) {
97
86
  return {
98
87
  isClientEnvironment: false,
99
- ssrIsProvider,
100
88
  runtimeCodeType: 'provider',
101
89
  }
102
90
  }
@@ -104,7 +92,6 @@ function getEnvConfig(
104
92
  if (env === 'client') {
105
93
  return {
106
94
  isClientEnvironment: true,
107
- ssrIsProvider,
108
95
  runtimeCodeType: 'client',
109
96
  }
110
97
  }
@@ -112,7 +99,6 @@ function getEnvConfig(
112
99
  // Server caller (SSR)
113
100
  return {
114
101
  isClientEnvironment: false,
115
- ssrIsProvider,
116
102
  runtimeCodeType: 'ssr',
117
103
  }
118
104
  }
@@ -154,9 +140,6 @@ function generateProviderRpcStub(
154
140
  */
155
141
  function generateCallerRpcStub(
156
142
  functionId: string,
157
- functionName: string,
158
- extractedFilename: string,
159
- isClientReferenced: boolean,
160
143
  envConfig: EnvConfig,
161
144
  ): t.Expression {
162
145
  const functionIdLiteral = t.stringLiteral(functionId)
@@ -167,20 +150,8 @@ function generateCallerRpcStub(
167
150
  })
168
151
  }
169
152
 
170
- // SSR caller
171
- // When the function is client-referenced, it's in the manifest - use manifest lookup
172
- // When SSR is NOT the provider, always use manifest lookup (no import() for different env)
173
- // Otherwise, use the importer for functions only referenced on the server when SSR is the provider
174
- if (isClientReferenced || !envConfig.ssrIsProvider) {
175
- return ssrRpcManifestTemplate({
176
- functionId: functionIdLiteral,
177
- })
178
- }
179
-
180
- return ssrRpcImporterTemplate({
153
+ return ssrRpcManifestTemplate({
181
154
  functionId: functionIdLiteral,
182
- extractedFilename: t.stringLiteral(extractedFilename),
183
- functionName: t.stringLiteral(functionName),
184
155
  })
185
156
  }
186
157
 
@@ -262,7 +233,15 @@ export function handleCreateServerFn(
262
233
 
263
234
  // Check if this function was already discovered by the client build
264
235
  const knownFn = knownFns[functionId]
265
- const isClientReferenced = envConfig.isClientEnvironment || !!knownFn
236
+ // A server function is client-referenced when:
237
+ // 1. We're in the client (browser) environment, OR
238
+ // 2. It was already discovered by another environment (knownFn), OR
239
+ // 3. We're in an SSR caller environment — any server function reachable from
240
+ // SSR module graph is callable via client navigation HTTP requests
241
+ const isClientReferenced =
242
+ envConfig.isClientEnvironment ||
243
+ !!knownFn ||
244
+ envConfig.runtimeCodeType === 'ssr'
266
245
 
267
246
  // Use canonical extracted filename from known functions if available
268
247
  const canonicalExtractedFilename =
@@ -395,7 +374,7 @@ export function handleCreateServerFn(
395
374
  // Expected output format:
396
375
  // const myFn = createServerFn().handler(createClientRpc("id"))
397
376
  // or
398
- // const myFn = createServerFn().handler(createSsrRpc("id", () => import(...)))
377
+ // const myFn = createServerFn().handler(createSsrRpc("id"))
399
378
 
400
379
  // If the handler function is an identifier, we need to remove the bound function
401
380
  // from the file since it won't be needed
@@ -408,13 +387,7 @@ export function handleCreateServerFn(
408
387
 
409
388
  // Generate the RPC stub using pre-compiled templates
410
389
  // Note: Caller files only pass functionId, not the full serverFnMeta
411
- const rpcStub = generateCallerRpcStub(
412
- functionId,
413
- functionName,
414
- canonicalExtractedFilename,
415
- isClientReferenced,
416
- envConfig,
417
- )
390
+ const rpcStub = generateCallerRpcStub(functionId, envConfig)
418
391
 
419
392
  // Replace ONLY the handler argument with the RPC stub
420
393
  // Keep the createServerFn().handler() wrapper intact for client middleware
@@ -0,0 +1,80 @@
1
+ import { LookupKindsPerEnv, StartCompiler } from './compiler'
2
+ import { getLookupConfigurationsForEnv } from './config'
3
+ import type { CompileStartFrameworkOptions } from '../types'
4
+ import type {
5
+ DevServerFnModuleSpecifierEncoder,
6
+ GenerateFunctionIdFnOptional,
7
+ ServerFn,
8
+ } from './types'
9
+
10
+ export interface CreateStartCompilerOptions {
11
+ env: 'client' | 'server'
12
+ envName: string
13
+ root: string
14
+ framework: CompileStartFrameworkOptions
15
+ providerEnvName: string
16
+ mode: 'dev' | 'build'
17
+ generateFunctionId?: GenerateFunctionIdFnOptional
18
+ onServerFnsById?: (d: Record<string, ServerFn>) => void
19
+ getKnownServerFns?: () => Record<string, ServerFn>
20
+ encodeModuleSpecifierInDev?: DevServerFnModuleSpecifierEncoder
21
+ loadModule: (id: string) => Promise<void>
22
+ resolveId: (id: string, importer?: string) => Promise<string | null>
23
+ }
24
+
25
+ export function createStartCompiler(
26
+ options: CreateStartCompilerOptions,
27
+ ): StartCompiler {
28
+ return new StartCompiler({
29
+ env: options.env,
30
+ envName: options.envName,
31
+ root: options.root,
32
+ lookupKinds: LookupKindsPerEnv[options.env],
33
+ lookupConfigurations: getLookupConfigurationsForEnv(
34
+ options.env,
35
+ options.framework,
36
+ ),
37
+ mode: options.mode,
38
+ framework: options.framework,
39
+ providerEnvName: options.providerEnvName,
40
+ generateFunctionId: options.generateFunctionId,
41
+ onServerFnsById: options.onServerFnsById,
42
+ getKnownServerFns: options.getKnownServerFns,
43
+ devServerFnModuleSpecifierEncoder: options.encodeModuleSpecifierInDev,
44
+ loadModule: options.loadModule,
45
+ resolveId: options.resolveId,
46
+ })
47
+ }
48
+
49
+ export function mergeServerFnsById(
50
+ current: Record<string, ServerFn>,
51
+ next: Record<string, ServerFn>,
52
+ ): void {
53
+ for (const [id, fn] of Object.entries(next)) {
54
+ const existing = current[id]
55
+
56
+ if (existing) {
57
+ current[id] = {
58
+ ...fn,
59
+ isClientReferenced:
60
+ existing.isClientReferenced || fn.isClientReferenced,
61
+ }
62
+ continue
63
+ }
64
+
65
+ current[id] = fn
66
+ }
67
+ }
68
+
69
+ export function matchesCodeFilters(
70
+ code: string,
71
+ filters: ReadonlyArray<RegExp>,
72
+ ): boolean {
73
+ for (const pattern of filters) {
74
+ if (pattern.test(code)) {
75
+ return true
76
+ }
77
+ }
78
+
79
+ return false
80
+ }
@@ -0,0 +1,31 @@
1
+ import { SERVER_FN_LOOKUP } from '../constants'
2
+ import type { StartCompiler } from './compiler'
3
+
4
+ interface ViteCompilerModuleLoaderOptions {
5
+ compiler: StartCompiler
6
+ mode: string
7
+ fetchModule?: (id: string) => Promise<unknown>
8
+ loadModule: (opts: { id: string }) => Promise<{ code?: string | null }>
9
+ id: string
10
+ }
11
+
12
+ export async function loadModuleForViteCompiler(
13
+ opts: ViteCompilerModuleLoaderOptions,
14
+ ): Promise<void> {
15
+ if (opts.mode === 'build') {
16
+ const loaded = await opts.loadModule({ id: opts.id })
17
+ const code = loaded.code ?? ''
18
+
19
+ opts.compiler.ingestModule({ code, id: opts.id })
20
+
21
+ return
22
+ }
23
+
24
+ if (opts.mode !== 'dev' || !opts.fetchModule) {
25
+ throw new Error(
26
+ `could not load module ${opts.id}: unknown environment mode ${opts.mode}`,
27
+ )
28
+ }
29
+
30
+ await opts.fetchModule(`${opts.id}?${SERVER_FN_LOOKUP}`)
31
+ }
@@ -0,0 +1,129 @@
1
+ import type { ServerFn } from './types'
2
+
3
+ interface ResolverManifestEntry {
4
+ id: string
5
+ functionName: string
6
+ extractedFilename: string
7
+ isClientReferenced: boolean
8
+ }
9
+
10
+ interface GenerateServerFnResolverModuleOptions {
11
+ serverFnsById: Record<string, ServerFn>
12
+ includeClientReferencedCheck: boolean
13
+ useStaticImports?: boolean
14
+ }
15
+
16
+ function getResolverManifestEntries(
17
+ serverFnsById: Record<string, ServerFn>,
18
+ ): Array<ResolverManifestEntry> {
19
+ return Object.entries(serverFnsById).map(([id, fn]) => ({
20
+ id,
21
+ functionName: fn.functionName,
22
+ extractedFilename: fn.extractedFilename,
23
+ isClientReferenced: fn.isClientReferenced ?? true,
24
+ }))
25
+ }
26
+
27
+ function getClientReferencedCheck(
28
+ includeClientReferencedCheck: boolean,
29
+ ): string {
30
+ if (!includeClientReferencedCheck) {
31
+ return ''
32
+ }
33
+
34
+ return `
35
+ if (access.origin === 'client' && !serverFnInfo.isClientReferenced) {
36
+ throw new Error('Server function not accessible from client: ' + id)
37
+ }
38
+ `
39
+ }
40
+
41
+ function getResolverBody(): string {
42
+ return `
43
+ export async function getServerFnById(id, access) {
44
+ const serverFnInfo = manifest[id]
45
+ if (!serverFnInfo) {
46
+ throw new Error('Server function info not found for ' + id)
47
+ }
48
+ __CLIENT_REFERENCED_CHECK__
49
+ const fnModule = serverFnInfo.module ?? (await serverFnInfo.importer())
50
+ if (!fnModule) {
51
+ throw new Error('Server function module not resolved for ' + id)
52
+ }
53
+ const action = fnModule[serverFnInfo.functionName]
54
+ if (!action) {
55
+ throw new Error('Server function module export not resolved for serverFn ID: ' + id)
56
+ }
57
+ return action
58
+ }
59
+ `
60
+ }
61
+
62
+ function getResolverManifestModuleAccess(opts: {
63
+ useStaticImports?: boolean
64
+ extractedFilename: string
65
+ moduleRef: string
66
+ }): string {
67
+ if (opts.useStaticImports) {
68
+ return `module: ${opts.moduleRef}`
69
+ }
70
+
71
+ return `importer: () => import(${JSON.stringify(opts.extractedFilename)})`
72
+ }
73
+
74
+ function getResolverManifestEntry(opts: {
75
+ entry: ResolverManifestEntry
76
+ moduleAccess: string
77
+ includeClientReferencedCheck: boolean
78
+ }): string {
79
+ const clientReferenced = opts.includeClientReferencedCheck
80
+ ? `,\n isClientReferenced: ${opts.entry.isClientReferenced}`
81
+ : ''
82
+
83
+ return `'${opts.entry.id}': {
84
+ functionName: '${opts.entry.functionName}',
85
+ ${opts.moduleAccess}${clientReferenced}
86
+ }`
87
+ }
88
+
89
+ export function generateServerFnResolverModule(
90
+ opts: GenerateServerFnResolverModuleOptions,
91
+ ): string {
92
+ const manifestEntries = getResolverManifestEntries(opts.serverFnsById)
93
+ const staticImports: Array<string> = []
94
+
95
+ const manifest = manifestEntries
96
+ .map((entry, index) => {
97
+ const moduleRef = `serverFnModule${index}`
98
+
99
+ if (opts.useStaticImports) {
100
+ staticImports.push(
101
+ `import * as ${moduleRef} from ${JSON.stringify(entry.extractedFilename)}`,
102
+ )
103
+ }
104
+
105
+ return getResolverManifestEntry({
106
+ entry,
107
+ moduleAccess: getResolverManifestModuleAccess({
108
+ useStaticImports: opts.useStaticImports,
109
+ extractedFilename: entry.extractedFilename,
110
+ moduleRef,
111
+ }),
112
+ includeClientReferencedCheck: opts.includeClientReferencedCheck,
113
+ })
114
+ })
115
+ .join(',\n ')
116
+
117
+ const body = getResolverBody().replace(
118
+ '__CLIENT_REFERENCED_CHECK__',
119
+ getClientReferencedCheck(opts.includeClientReferencedCheck),
120
+ )
121
+
122
+ return `
123
+ ${staticImports.join('\n')}
124
+ const manifest = {
125
+ ${manifest}
126
+ }
127
+ ${body}
128
+ `
129
+ }
@@ -112,6 +112,11 @@ export type GenerateFunctionIdFnOptional = (
112
112
  * Function type for generating replacement code for server functions.
113
113
  * Used internally by handleCreateServerFn.
114
114
  */
115
+ export type DevServerFnModuleSpecifierEncoder = (opts: {
116
+ extractedFilename: string
117
+ root: string
118
+ }) => string
119
+
115
120
  export type ReplacerFn = (opts: {
116
121
  /** Placeholder for the original function expression */
117
122
  fn: string