@tanstack/start-plugin-core 1.142.0 → 1.142.1

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.
@@ -53,9 +53,10 @@ export declare class ServerFnCompiler {
53
53
  id: string;
54
54
  }): ModuleInfo;
55
55
  invalidateModule(id: string): boolean;
56
- compile({ code, id }: {
56
+ compile({ code, id, isProviderFile, }: {
57
57
  code: string;
58
58
  id: string;
59
+ isProviderFile: boolean;
59
60
  }): Promise<import('@tanstack/router-utils').GeneratorResult | null>;
60
61
  private collectCandidates;
61
62
  private resolveIdentifierKind;
@@ -131,7 +131,11 @@ class ServerFnCompiler {
131
131
  invalidateModule(id) {
132
132
  return this.moduleCache.delete(id);
133
133
  }
134
- async compile({ code, id }) {
134
+ async compile({
135
+ code,
136
+ id,
137
+ isProviderFile
138
+ }) {
135
139
  if (!this.initialized) {
136
140
  await this.init(id);
137
141
  }
@@ -171,7 +175,8 @@ class ServerFnCompiler {
171
175
  handleCreateServerFn(p.nodePath, {
172
176
  env: this.options.env,
173
177
  code,
174
- directive: this.options.directive
178
+ directive: this.options.directive,
179
+ isProviderFile
175
180
  });
176
181
  } else {
177
182
  handleCreateMiddleware(p.nodePath, { env: this.options.env });
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.js","sources":["../../../src/create-server-fn-plugin/compiler.ts"],"sourcesContent":["/* eslint-disable import/no-commonjs */\nimport * as t from '@babel/types'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport babel from '@babel/core'\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { handleCreateServerFn } from './handleCreateServerFn'\nimport { handleCreateMiddleware } from './handleCreateMiddleware'\n\ntype Binding =\n | {\n type: 'import'\n source: string\n importedName: string\n resolvedKind?: Kind\n }\n | {\n type: 'var'\n init: t.Expression | null\n resolvedKind?: Kind\n }\n\ntype ExportEntry =\n | { tag: 'Normal'; name: string }\n | { tag: 'Default'; name: string }\n | { tag: 'Namespace'; name: string; targetId: string } // for `export * as ns from './x'`\n\ntype Kind = 'None' | `Root` | `Builder` | LookupKind\n\nexport type LookupKind = 'ServerFn' | 'Middleware'\n\nconst LookupSetup: Record<\n LookupKind,\n { candidateCallIdentifier: Set<string> }\n> = {\n ServerFn: { candidateCallIdentifier: new Set(['handler']) },\n Middleware: {\n candidateCallIdentifier: new Set(['server', 'client', 'createMiddlewares']),\n },\n}\n\nexport type LookupConfig = {\n libName: string\n rootExport: string\n}\ninterface ModuleInfo {\n id: string\n code: string\n ast: ReturnType<typeof parseAst>\n bindings: Map<string, Binding>\n exports: Map<string, ExportEntry>\n}\n\nexport class ServerFnCompiler {\n private moduleCache = new Map<string, ModuleInfo>()\n private initialized = false\n private validLookupKinds: Set<LookupKind>\n constructor(\n private options: {\n env: 'client' | 'server'\n directive: string\n lookupConfigurations: Array<LookupConfig>\n lookupKinds: Set<LookupKind>\n loadModule: (id: string) => Promise<void>\n resolveId: (id: string, importer?: string) => Promise<string | null>\n },\n ) {\n this.validLookupKinds = options.lookupKinds\n }\n\n private async init(id: string) {\n await Promise.all(\n this.options.lookupConfigurations.map(async (config) => {\n const libId = await this.options.resolveId(config.libName, id)\n if (!libId) {\n throw new Error(`could not resolve \"${config.libName}\"`)\n }\n let rootModule = this.moduleCache.get(libId)\n if (!rootModule) {\n // insert root binding\n rootModule = {\n ast: null as any,\n bindings: new Map(),\n exports: new Map(),\n code: '',\n id: libId,\n }\n this.moduleCache.set(libId, rootModule)\n }\n\n rootModule.exports.set(config.rootExport, {\n tag: 'Normal',\n name: config.rootExport,\n })\n rootModule.exports.set('*', {\n tag: 'Namespace',\n name: config.rootExport,\n targetId: libId,\n })\n rootModule.bindings.set(config.rootExport, {\n type: 'var',\n init: t.identifier(config.rootExport),\n resolvedKind: `Root` satisfies Kind,\n })\n this.moduleCache.set(libId, rootModule)\n }),\n )\n\n this.initialized = true\n }\n\n public ingestModule({ code, id }: { code: string; id: string }) {\n const ast = parseAst({ code })\n\n const bindings = new Map<string, Binding>()\n const exports = new Map<string, ExportEntry>()\n\n // we are only interested in top-level bindings, hence we don't traverse the AST\n // instead we only iterate over the program body\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node)) {\n const source = node.source.value\n for (const s of node.specifiers) {\n if (t.isImportSpecifier(s)) {\n const importedName = t.isIdentifier(s.imported)\n ? s.imported.name\n : s.imported.value\n bindings.set(s.local.name, { type: 'import', source, importedName })\n } else if (t.isImportDefaultSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: 'default',\n })\n } else if (t.isImportNamespaceSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: '*',\n })\n }\n }\n } else if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n if (t.isIdentifier(decl.id)) {\n bindings.set(decl.id.name, {\n type: 'var',\n init: decl.init ?? null,\n })\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n // export const foo = ...\n if (node.declaration) {\n if (t.isVariableDeclaration(node.declaration)) {\n for (const d of node.declaration.declarations) {\n if (t.isIdentifier(d.id)) {\n exports.set(d.id.name, { tag: 'Normal', name: d.id.name })\n bindings.set(d.id.name, { type: 'var', init: d.init ?? null })\n }\n }\n }\n }\n for (const sp of node.specifiers) {\n if (t.isExportNamespaceSpecifier(sp)) {\n exports.set(sp.exported.name, {\n tag: 'Namespace',\n name: sp.exported.name,\n targetId: node.source?.value || '',\n })\n }\n // export { local as exported }\n else if (t.isExportSpecifier(sp)) {\n const local = sp.local.name\n const exported = t.isIdentifier(sp.exported)\n ? sp.exported.name\n : sp.exported.value\n exports.set(exported, { tag: 'Normal', name: local })\n }\n }\n } else if (t.isExportDefaultDeclaration(node)) {\n const d = node.declaration\n if (t.isIdentifier(d)) {\n exports.set('default', { tag: 'Default', name: d.name })\n } else {\n const synth = '__default_export__'\n bindings.set(synth, { type: 'var', init: d as t.Expression })\n exports.set('default', { tag: 'Default', name: synth })\n }\n }\n }\n\n const info: ModuleInfo = { code, id, ast, bindings, exports }\n this.moduleCache.set(id, info)\n return info\n }\n\n public invalidateModule(id: string) {\n return this.moduleCache.delete(id)\n }\n\n public async compile({ code, id }: { code: string; id: string }) {\n if (!this.initialized) {\n await this.init(id)\n }\n const { bindings, ast } = this.ingestModule({ code, id })\n const candidates = this.collectCandidates(bindings)\n if (candidates.length === 0) {\n // this hook will only be invoked if there is `.handler(` | `.server(` | `.client(` in the code,\n // so not discovering a handler candidate is rather unlikely, but maybe possible?\n return null\n }\n\n // let's find out which of the candidates are actually server functions\n const toRewrite: Array<{\n callExpression: t.CallExpression\n kind: LookupKind\n }> = []\n for (const handler of candidates) {\n const kind = await this.resolveExprKind(handler, id)\n if (this.validLookupKinds.has(kind as LookupKind)) {\n toRewrite.push({ callExpression: handler, kind: kind as LookupKind })\n }\n }\n if (toRewrite.length === 0) {\n return null\n }\n\n const pathsToRewrite: Array<{\n nodePath: babel.NodePath<t.CallExpression>\n kind: LookupKind\n }> = []\n babel.traverse(ast, {\n CallExpression(path) {\n const found = toRewrite.findIndex((h) => path.node === h.callExpression)\n if (found !== -1) {\n pathsToRewrite.push({ nodePath: path, kind: toRewrite[found]!.kind })\n // delete from toRewrite\n toRewrite.splice(found, 1)\n }\n },\n })\n\n if (toRewrite.length > 0) {\n throw new Error(\n `Internal error: could not find all paths to rewrite. please file an issue`,\n )\n }\n\n const refIdents = findReferencedIdentifiers(ast)\n\n pathsToRewrite.map((p) => {\n if (p.kind === 'ServerFn') {\n handleCreateServerFn(p.nodePath, {\n env: this.options.env,\n code,\n directive: this.options.directive,\n })\n } else {\n handleCreateMiddleware(p.nodePath, { env: this.options.env })\n }\n })\n\n deadCodeElimination(ast, refIdents)\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n }\n\n // collects all candidate CallExpressions at top-level\n private collectCandidates(bindings: Map<string, Binding>) {\n const candidates: Array<t.CallExpression> = []\n\n for (const binding of bindings.values()) {\n if (binding.type === 'var') {\n const handler = isCandidateCallExpression(\n binding.init,\n this.validLookupKinds,\n )\n if (handler) {\n candidates.push(handler)\n }\n }\n }\n return candidates\n }\n\n private async resolveIdentifierKind(\n ident: string,\n id: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n const info = await this.getModuleInfo(id)\n\n const binding = info.bindings.get(ident)\n if (!binding) {\n return 'None'\n }\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n\n // TODO improve cycle detection? should we throw here instead of returning 'None'?\n // prevent cycles\n const vKey = `${id}:${ident}`\n if (visited.has(vKey)) {\n return 'None'\n }\n visited.add(vKey)\n\n const resolvedKind = await this.resolveBindingKind(binding, id, visited)\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveBindingKind(\n binding: Binding,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n if (binding.type === 'import') {\n const target = await this.options.resolveId(binding.source, fileId)\n if (!target) {\n return 'None'\n }\n\n const importedModule = await this.getModuleInfo(target)\n\n const moduleExport = importedModule.exports.get(binding.importedName)\n if (!moduleExport) {\n return 'None'\n }\n const importedBinding = importedModule.bindings.get(moduleExport.name)\n if (!importedBinding) {\n return 'None'\n }\n if (importedBinding.resolvedKind) {\n return importedBinding.resolvedKind\n }\n\n const resolvedKind = await this.resolveBindingKind(\n importedBinding,\n importedModule.id,\n visited,\n )\n importedBinding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n const resolvedKind = await this.resolveExprKind(\n binding.init,\n fileId,\n visited,\n )\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveExprKind(\n expr: t.Expression | null,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (!expr) {\n return 'None'\n }\n\n let result: Kind = 'None'\n\n if (t.isCallExpression(expr)) {\n if (!t.isExpression(expr.callee)) {\n return 'None'\n }\n const calleeKind = await this.resolveCalleeKind(\n expr.callee,\n fileId,\n visited,\n )\n if (calleeKind !== 'None') {\n if (calleeKind === `Root` || calleeKind === `Builder`) {\n return `Builder`\n }\n for (const kind of this.validLookupKinds) {\n if (calleeKind === kind) {\n return kind\n }\n }\n }\n } else if (t.isMemberExpression(expr) && t.isIdentifier(expr.property)) {\n result = await this.resolveCalleeKind(expr.object, fileId, visited)\n }\n\n if (result === 'None' && t.isIdentifier(expr)) {\n result = await this.resolveIdentifierKind(expr.name, fileId, visited)\n }\n\n if (result === 'None' && t.isTSAsExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n if (result === 'None' && t.isTSNonNullExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n if (result === 'None' && t.isParenthesizedExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n\n return result\n }\n\n private async resolveCalleeKind(\n callee: t.Expression,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (t.isIdentifier(callee)) {\n return this.resolveIdentifierKind(callee.name, fileId, visited)\n }\n\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {\n const prop = callee.property.name\n\n if (\n this.validLookupKinds.has('ServerFn') &&\n LookupSetup['ServerFn'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder') {\n return 'ServerFn'\n }\n return 'None'\n } else if (\n this.validLookupKinds.has('Middleware') &&\n LookupSetup['Middleware'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder' || base === 'Middleware') {\n return 'Middleware'\n }\n return 'None'\n }\n // Check if the object is a namespace import\n if (t.isIdentifier(callee.object)) {\n const info = await this.getModuleInfo(fileId)\n const binding = info.bindings.get(callee.object.name)\n if (\n binding &&\n binding.type === 'import' &&\n binding.importedName === '*'\n ) {\n // resolve the property from the target module\n const targetModuleId = await this.options.resolveId(\n binding.source,\n fileId,\n )\n if (targetModuleId) {\n const targetModule = await this.getModuleInfo(targetModuleId)\n const exportEntry = targetModule.exports.get(callee.property.name)\n if (exportEntry) {\n const exportedBinding = targetModule.bindings.get(\n exportEntry.name,\n )\n if (exportedBinding) {\n return await this.resolveBindingKind(\n exportedBinding,\n targetModule.id,\n visited,\n )\n }\n }\n } else {\n return 'None'\n }\n }\n }\n return this.resolveExprKind(callee.object, fileId, visited)\n }\n\n // handle nested expressions\n return this.resolveExprKind(callee, fileId, visited)\n }\n\n private async getModuleInfo(id: string) {\n let cached = this.moduleCache.get(id)\n if (cached) {\n return cached\n }\n\n await this.options.loadModule(id)\n\n cached = this.moduleCache.get(id)\n if (!cached) {\n throw new Error(`could not load module info for ${id}`)\n }\n return cached\n }\n}\n\nfunction isCandidateCallExpression(\n node: t.Node | null | undefined,\n lookupKinds: Set<LookupKind>,\n): undefined | t.CallExpression {\n if (!t.isCallExpression(node)) return undefined\n\n const callee = node.callee\n if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {\n return undefined\n }\n for (const kind of lookupKinds) {\n if (LookupSetup[kind].candidateCallIdentifier.has(callee.property.name)) {\n return node\n }\n }\n\n return undefined\n}\n"],"names":["babel","resolvedKind"],"mappings":"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"}
1
+ {"version":3,"file":"compiler.js","sources":["../../../src/create-server-fn-plugin/compiler.ts"],"sourcesContent":["/* eslint-disable import/no-commonjs */\nimport * as t from '@babel/types'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport babel from '@babel/core'\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { handleCreateServerFn } from './handleCreateServerFn'\nimport { handleCreateMiddleware } from './handleCreateMiddleware'\n\ntype Binding =\n | {\n type: 'import'\n source: string\n importedName: string\n resolvedKind?: Kind\n }\n | {\n type: 'var'\n init: t.Expression | null\n resolvedKind?: Kind\n }\n\ntype ExportEntry =\n | { tag: 'Normal'; name: string }\n | { tag: 'Default'; name: string }\n | { tag: 'Namespace'; name: string; targetId: string } // for `export * as ns from './x'`\n\ntype Kind = 'None' | `Root` | `Builder` | LookupKind\n\nexport type LookupKind = 'ServerFn' | 'Middleware'\n\nconst LookupSetup: Record<\n LookupKind,\n { candidateCallIdentifier: Set<string> }\n> = {\n ServerFn: { candidateCallIdentifier: new Set(['handler']) },\n Middleware: {\n candidateCallIdentifier: new Set(['server', 'client', 'createMiddlewares']),\n },\n}\n\nexport type LookupConfig = {\n libName: string\n rootExport: string\n}\ninterface ModuleInfo {\n id: string\n code: string\n ast: ReturnType<typeof parseAst>\n bindings: Map<string, Binding>\n exports: Map<string, ExportEntry>\n}\n\nexport class ServerFnCompiler {\n private moduleCache = new Map<string, ModuleInfo>()\n private initialized = false\n private validLookupKinds: Set<LookupKind>\n constructor(\n private options: {\n env: 'client' | 'server'\n directive: string\n lookupConfigurations: Array<LookupConfig>\n lookupKinds: Set<LookupKind>\n loadModule: (id: string) => Promise<void>\n resolveId: (id: string, importer?: string) => Promise<string | null>\n },\n ) {\n this.validLookupKinds = options.lookupKinds\n }\n\n private async init(id: string) {\n await Promise.all(\n this.options.lookupConfigurations.map(async (config) => {\n const libId = await this.options.resolveId(config.libName, id)\n if (!libId) {\n throw new Error(`could not resolve \"${config.libName}\"`)\n }\n let rootModule = this.moduleCache.get(libId)\n if (!rootModule) {\n // insert root binding\n rootModule = {\n ast: null as any,\n bindings: new Map(),\n exports: new Map(),\n code: '',\n id: libId,\n }\n this.moduleCache.set(libId, rootModule)\n }\n\n rootModule.exports.set(config.rootExport, {\n tag: 'Normal',\n name: config.rootExport,\n })\n rootModule.exports.set('*', {\n tag: 'Namespace',\n name: config.rootExport,\n targetId: libId,\n })\n rootModule.bindings.set(config.rootExport, {\n type: 'var',\n init: t.identifier(config.rootExport),\n resolvedKind: `Root` satisfies Kind,\n })\n this.moduleCache.set(libId, rootModule)\n }),\n )\n\n this.initialized = true\n }\n\n public ingestModule({ code, id }: { code: string; id: string }) {\n const ast = parseAst({ code })\n\n const bindings = new Map<string, Binding>()\n const exports = new Map<string, ExportEntry>()\n\n // we are only interested in top-level bindings, hence we don't traverse the AST\n // instead we only iterate over the program body\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node)) {\n const source = node.source.value\n for (const s of node.specifiers) {\n if (t.isImportSpecifier(s)) {\n const importedName = t.isIdentifier(s.imported)\n ? s.imported.name\n : s.imported.value\n bindings.set(s.local.name, { type: 'import', source, importedName })\n } else if (t.isImportDefaultSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: 'default',\n })\n } else if (t.isImportNamespaceSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: '*',\n })\n }\n }\n } else if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n if (t.isIdentifier(decl.id)) {\n bindings.set(decl.id.name, {\n type: 'var',\n init: decl.init ?? null,\n })\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n // export const foo = ...\n if (node.declaration) {\n if (t.isVariableDeclaration(node.declaration)) {\n for (const d of node.declaration.declarations) {\n if (t.isIdentifier(d.id)) {\n exports.set(d.id.name, { tag: 'Normal', name: d.id.name })\n bindings.set(d.id.name, { type: 'var', init: d.init ?? null })\n }\n }\n }\n }\n for (const sp of node.specifiers) {\n if (t.isExportNamespaceSpecifier(sp)) {\n exports.set(sp.exported.name, {\n tag: 'Namespace',\n name: sp.exported.name,\n targetId: node.source?.value || '',\n })\n }\n // export { local as exported }\n else if (t.isExportSpecifier(sp)) {\n const local = sp.local.name\n const exported = t.isIdentifier(sp.exported)\n ? sp.exported.name\n : sp.exported.value\n exports.set(exported, { tag: 'Normal', name: local })\n }\n }\n } else if (t.isExportDefaultDeclaration(node)) {\n const d = node.declaration\n if (t.isIdentifier(d)) {\n exports.set('default', { tag: 'Default', name: d.name })\n } else {\n const synth = '__default_export__'\n bindings.set(synth, { type: 'var', init: d as t.Expression })\n exports.set('default', { tag: 'Default', name: synth })\n }\n }\n }\n\n const info: ModuleInfo = { code, id, ast, bindings, exports }\n this.moduleCache.set(id, info)\n return info\n }\n\n public invalidateModule(id: string) {\n return this.moduleCache.delete(id)\n }\n\n public async compile({\n code,\n id,\n isProviderFile,\n }: {\n code: string\n id: string\n isProviderFile: boolean\n }) {\n if (!this.initialized) {\n await this.init(id)\n }\n const { bindings, ast } = this.ingestModule({ code, id })\n const candidates = this.collectCandidates(bindings)\n if (candidates.length === 0) {\n // this hook will only be invoked if there is `.handler(` | `.server(` | `.client(` in the code,\n // so not discovering a handler candidate is rather unlikely, but maybe possible?\n return null\n }\n\n // let's find out which of the candidates are actually server functions\n const toRewrite: Array<{\n callExpression: t.CallExpression\n kind: LookupKind\n }> = []\n for (const handler of candidates) {\n const kind = await this.resolveExprKind(handler, id)\n if (this.validLookupKinds.has(kind as LookupKind)) {\n toRewrite.push({ callExpression: handler, kind: kind as LookupKind })\n }\n }\n if (toRewrite.length === 0) {\n return null\n }\n\n const pathsToRewrite: Array<{\n nodePath: babel.NodePath<t.CallExpression>\n kind: LookupKind\n }> = []\n babel.traverse(ast, {\n CallExpression(path) {\n const found = toRewrite.findIndex((h) => path.node === h.callExpression)\n if (found !== -1) {\n pathsToRewrite.push({ nodePath: path, kind: toRewrite[found]!.kind })\n // delete from toRewrite\n toRewrite.splice(found, 1)\n }\n },\n })\n\n if (toRewrite.length > 0) {\n throw new Error(\n `Internal error: could not find all paths to rewrite. please file an issue`,\n )\n }\n\n const refIdents = findReferencedIdentifiers(ast)\n\n pathsToRewrite.map((p) => {\n if (p.kind === 'ServerFn') {\n handleCreateServerFn(p.nodePath, {\n env: this.options.env,\n code,\n directive: this.options.directive,\n isProviderFile,\n })\n } else {\n handleCreateMiddleware(p.nodePath, { env: this.options.env })\n }\n })\n\n deadCodeElimination(ast, refIdents)\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n }\n\n // collects all candidate CallExpressions at top-level\n private collectCandidates(bindings: Map<string, Binding>) {\n const candidates: Array<t.CallExpression> = []\n\n for (const binding of bindings.values()) {\n if (binding.type === 'var') {\n const handler = isCandidateCallExpression(\n binding.init,\n this.validLookupKinds,\n )\n if (handler) {\n candidates.push(handler)\n }\n }\n }\n return candidates\n }\n\n private async resolveIdentifierKind(\n ident: string,\n id: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n const info = await this.getModuleInfo(id)\n\n const binding = info.bindings.get(ident)\n if (!binding) {\n return 'None'\n }\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n\n // TODO improve cycle detection? should we throw here instead of returning 'None'?\n // prevent cycles\n const vKey = `${id}:${ident}`\n if (visited.has(vKey)) {\n return 'None'\n }\n visited.add(vKey)\n\n const resolvedKind = await this.resolveBindingKind(binding, id, visited)\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveBindingKind(\n binding: Binding,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n if (binding.type === 'import') {\n const target = await this.options.resolveId(binding.source, fileId)\n if (!target) {\n return 'None'\n }\n\n const importedModule = await this.getModuleInfo(target)\n\n const moduleExport = importedModule.exports.get(binding.importedName)\n if (!moduleExport) {\n return 'None'\n }\n const importedBinding = importedModule.bindings.get(moduleExport.name)\n if (!importedBinding) {\n return 'None'\n }\n if (importedBinding.resolvedKind) {\n return importedBinding.resolvedKind\n }\n\n const resolvedKind = await this.resolveBindingKind(\n importedBinding,\n importedModule.id,\n visited,\n )\n importedBinding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n const resolvedKind = await this.resolveExprKind(\n binding.init,\n fileId,\n visited,\n )\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveExprKind(\n expr: t.Expression | null,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (!expr) {\n return 'None'\n }\n\n let result: Kind = 'None'\n\n if (t.isCallExpression(expr)) {\n if (!t.isExpression(expr.callee)) {\n return 'None'\n }\n const calleeKind = await this.resolveCalleeKind(\n expr.callee,\n fileId,\n visited,\n )\n if (calleeKind !== 'None') {\n if (calleeKind === `Root` || calleeKind === `Builder`) {\n return `Builder`\n }\n for (const kind of this.validLookupKinds) {\n if (calleeKind === kind) {\n return kind\n }\n }\n }\n } else if (t.isMemberExpression(expr) && t.isIdentifier(expr.property)) {\n result = await this.resolveCalleeKind(expr.object, fileId, visited)\n }\n\n if (result === 'None' && t.isIdentifier(expr)) {\n result = await this.resolveIdentifierKind(expr.name, fileId, visited)\n }\n\n if (result === 'None' && t.isTSAsExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n if (result === 'None' && t.isTSNonNullExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n if (result === 'None' && t.isParenthesizedExpression(expr)) {\n result = await this.resolveExprKind(expr.expression, fileId, visited)\n }\n\n return result\n }\n\n private async resolveCalleeKind(\n callee: t.Expression,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (t.isIdentifier(callee)) {\n return this.resolveIdentifierKind(callee.name, fileId, visited)\n }\n\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {\n const prop = callee.property.name\n\n if (\n this.validLookupKinds.has('ServerFn') &&\n LookupSetup['ServerFn'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder') {\n return 'ServerFn'\n }\n return 'None'\n } else if (\n this.validLookupKinds.has('Middleware') &&\n LookupSetup['Middleware'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder' || base === 'Middleware') {\n return 'Middleware'\n }\n return 'None'\n }\n // Check if the object is a namespace import\n if (t.isIdentifier(callee.object)) {\n const info = await this.getModuleInfo(fileId)\n const binding = info.bindings.get(callee.object.name)\n if (\n binding &&\n binding.type === 'import' &&\n binding.importedName === '*'\n ) {\n // resolve the property from the target module\n const targetModuleId = await this.options.resolveId(\n binding.source,\n fileId,\n )\n if (targetModuleId) {\n const targetModule = await this.getModuleInfo(targetModuleId)\n const exportEntry = targetModule.exports.get(callee.property.name)\n if (exportEntry) {\n const exportedBinding = targetModule.bindings.get(\n exportEntry.name,\n )\n if (exportedBinding) {\n return await this.resolveBindingKind(\n exportedBinding,\n targetModule.id,\n visited,\n )\n }\n }\n } else {\n return 'None'\n }\n }\n }\n return this.resolveExprKind(callee.object, fileId, visited)\n }\n\n // handle nested expressions\n return this.resolveExprKind(callee, fileId, visited)\n }\n\n private async getModuleInfo(id: string) {\n let cached = this.moduleCache.get(id)\n if (cached) {\n return cached\n }\n\n await this.options.loadModule(id)\n\n cached = this.moduleCache.get(id)\n if (!cached) {\n throw new Error(`could not load module info for ${id}`)\n }\n return cached\n }\n}\n\nfunction isCandidateCallExpression(\n node: t.Node | null | undefined,\n lookupKinds: Set<LookupKind>,\n): undefined | t.CallExpression {\n if (!t.isCallExpression(node)) return undefined\n\n const callee = node.callee\n if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {\n return undefined\n }\n for (const kind of lookupKinds) {\n if (LookupSetup[kind].candidateCallIdentifier.has(callee.property.name)) {\n return node\n }\n }\n\n return undefined\n}\n"],"names":["babel","resolvedKind"],"mappings":"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"}
@@ -4,4 +4,9 @@ export declare function handleCreateServerFn(path: babel.NodePath<t.CallExpressi
4
4
  env: 'client' | 'server';
5
5
  code: string;
6
6
  directive: string;
7
+ /**
8
+ * Whether this file is a provider file (extracted server function file).
9
+ * Only provider files should have the handler implementation as a second argument.
10
+ */
11
+ isProviderFile: boolean;
7
12
  }): void;
@@ -75,7 +75,7 @@ function handleCreateServerFn(path, opts) {
75
75
  )
76
76
  )
77
77
  );
78
- if (opts.env === "server") {
78
+ if (opts.env === "server" && opts.isProviderFile) {
79
79
  callExpressionPaths.handler.node.arguments.push(handlerFn);
80
80
  }
81
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"handleCreateServerFn.js","sources":["../../../src/create-server-fn-plugin/handleCreateServerFn.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport {\n codeFrameError,\n getRootCallExpression,\n} from '../start-compiler-plugin/utils'\nimport type * as babel from '@babel/core'\n\nexport function handleCreateServerFn(\n path: babel.NodePath<t.CallExpression>,\n opts: {\n env: 'client' | 'server'\n code: string\n directive: string\n },\n) {\n // Traverse the member expression and find the call expressions for\n // the validator, handler, and middleware methods. Check to make sure they\n // are children of the createServerFn call expression.\n\n const validMethods = ['middleware', 'inputValidator', 'handler'] as const\n type ValidMethods = (typeof validMethods)[number]\n const callExpressionPaths: Record<\n ValidMethods,\n babel.NodePath<t.CallExpression> | null\n > = {\n middleware: null,\n inputValidator: null,\n handler: null,\n }\n\n const rootCallExpression = getRootCallExpression(path)\n\n // if (debug)\n // console.info(\n // 'Handling createServerFn call expression:',\n // rootCallExpression.toString(),\n // )\n\n // Check if the call is assigned to a variable\n if (!rootCallExpression.parentPath.isVariableDeclarator()) {\n throw new Error('createServerFn must be assigned to a variable!')\n }\n\n // Get the identifier name of the variable\n const variableDeclarator = rootCallExpression.parentPath.node\n const existingVariableName = (variableDeclarator.id as t.Identifier).name\n\n rootCallExpression.traverse({\n MemberExpression(memberExpressionPath) {\n if (t.isIdentifier(memberExpressionPath.node.property)) {\n const name = memberExpressionPath.node.property.name as ValidMethods\n\n if (\n validMethods.includes(name) &&\n memberExpressionPath.parentPath.isCallExpression()\n ) {\n callExpressionPaths[name] = memberExpressionPath.parentPath\n }\n }\n },\n })\n\n if (callExpressionPaths.inputValidator) {\n const innerInputExpression =\n callExpressionPaths.inputValidator.node.arguments[0]\n\n if (!innerInputExpression) {\n throw new Error(\n 'createServerFn().inputValidator() must be called with a validator!',\n )\n }\n\n // If we're on the client, remove the validator call expression\n if (opts.env === 'client') {\n if (\n t.isMemberExpression(callExpressionPaths.inputValidator.node.callee)\n ) {\n callExpressionPaths.inputValidator.replaceWith(\n callExpressionPaths.inputValidator.node.callee.object,\n )\n }\n }\n }\n\n // First, we need to move the handler function to a nested function call\n // that is applied to the arguments passed to the server function.\n\n const handlerFnPath = callExpressionPaths.handler?.get(\n 'arguments.0',\n ) as babel.NodePath<any>\n\n if (!callExpressionPaths.handler || !handlerFnPath.node) {\n throw codeFrameError(\n opts.code,\n path.node.callee.loc!,\n `createServerFn must be called with a \"handler\" property!`,\n )\n }\n\n const handlerFn = handlerFnPath.node\n\n // So, the way we do this is we give the handler function a way\n // to access the serverFn ctx on the server via function scope.\n // The 'use server' extracted function will be called with the\n // payload from the client, then use the scoped serverFn ctx\n // to execute the handler function.\n // This way, we can do things like data and middleware validation\n // in the __execute function without having to AST transform the\n // handler function too much itself.\n\n // .handler((optsOut, ctx) => {\n // return ((optsIn) => {\n // 'use server'\n // ctx.__execute(handlerFn, optsIn)\n // })(optsOut)\n // })\n\n // If the handler function is an identifier and we're on the client, we need to\n // remove the bound function from the file.\n // If we're on the server, you can leave it, since it will get referenced\n // as a second argument.\n\n if (t.isIdentifier(handlerFn)) {\n if (opts.env === 'client') {\n // Find the binding for the handler function\n const binding = handlerFnPath.scope.getBinding(handlerFn.name)\n // Remove it\n if (binding) {\n binding.path.remove()\n }\n }\n // If the env is server, just leave it alone\n }\n\n handlerFnPath.replaceWith(\n t.arrowFunctionExpression(\n [t.identifier('opts'), t.identifier('signal')],\n t.blockStatement(\n // Everything in here is server-only, since the client\n // will strip out anything in the 'use server' directive.\n [\n t.returnStatement(\n t.callExpression(\n t.identifier(`${existingVariableName}.__executeServer`),\n [t.identifier('opts'), t.identifier('signal')],\n ),\n ),\n ],\n [t.directive(t.directiveLiteral(opts.directive))],\n ),\n ),\n )\n\n if (opts.env === 'server') {\n callExpressionPaths.handler.node.arguments.push(handlerFn)\n }\n}\n"],"names":[],"mappings":";;AAOO,SAAS,qBACd,MACA,MAKA;AAKA,QAAM,eAAe,CAAC,cAAc,kBAAkB,SAAS;AAE/D,QAAM,sBAGF;AAAA,IACF,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,SAAS;AAAA,EAAA;AAGX,QAAM,qBAAqB,sBAAsB,IAAI;AASrD,MAAI,CAAC,mBAAmB,WAAW,wBAAwB;AACzD,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAGA,QAAM,qBAAqB,mBAAmB,WAAW;AACzD,QAAM,uBAAwB,mBAAmB,GAAoB;AAErE,qBAAmB,SAAS;AAAA,IAC1B,iBAAiB,sBAAsB;AACrC,UAAI,EAAE,aAAa,qBAAqB,KAAK,QAAQ,GAAG;AACtD,cAAM,OAAO,qBAAqB,KAAK,SAAS;AAEhD,YACE,aAAa,SAAS,IAAI,KAC1B,qBAAqB,WAAW,oBAChC;AACA,8BAAoB,IAAI,IAAI,qBAAqB;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EAAA,CACD;AAED,MAAI,oBAAoB,gBAAgB;AACtC,UAAM,uBACJ,oBAAoB,eAAe,KAAK,UAAU,CAAC;AAErD,QAAI,CAAC,sBAAsB;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAGA,QAAI,KAAK,QAAQ,UAAU;AACzB,UACE,EAAE,mBAAmB,oBAAoB,eAAe,KAAK,MAAM,GACnE;AACA,4BAAoB,eAAe;AAAA,UACjC,oBAAoB,eAAe,KAAK,OAAO;AAAA,QAAA;AAAA,MAEnD;AAAA,IACF;AAAA,EACF;AAKA,QAAM,gBAAgB,oBAAoB,SAAS;AAAA,IACjD;AAAA,EAAA;AAGF,MAAI,CAAC,oBAAoB,WAAW,CAAC,cAAc,MAAM;AACvD,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,KAAK,OAAO;AAAA,MACjB;AAAA,IAAA;AAAA,EAEJ;AAEA,QAAM,YAAY,cAAc;AAuBhC,MAAI,EAAE,aAAa,SAAS,GAAG;AAC7B,QAAI,KAAK,QAAQ,UAAU;AAEzB,YAAM,UAAU,cAAc,MAAM,WAAW,UAAU,IAAI;AAE7D,UAAI,SAAS;AACX,gBAAQ,KAAK,OAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEF;AAEA,gBAAc;AAAA,IACZ,EAAE;AAAA,MACA,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,MAC7C,EAAE;AAAA;AAAA;AAAA,QAGA;AAAA,UACE,EAAE;AAAA,YACA,EAAE;AAAA,cACA,EAAE,WAAW,GAAG,oBAAoB,kBAAkB;AAAA,cACtD,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,YAAA;AAAA,UAC/C;AAAA,QACF;AAAA,QAEF,CAAC,EAAE,UAAU,EAAE,iBAAiB,KAAK,SAAS,CAAC,CAAC;AAAA,MAAA;AAAA,IAClD;AAAA,EACF;AAGF,MAAI,KAAK,QAAQ,UAAU;AACzB,wBAAoB,QAAQ,KAAK,UAAU,KAAK,SAAS;AAAA,EAC3D;AACF;"}
1
+ {"version":3,"file":"handleCreateServerFn.js","sources":["../../../src/create-server-fn-plugin/handleCreateServerFn.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport {\n codeFrameError,\n getRootCallExpression,\n} from '../start-compiler-plugin/utils'\nimport type * as babel from '@babel/core'\n\nexport function handleCreateServerFn(\n path: babel.NodePath<t.CallExpression>,\n opts: {\n env: 'client' | 'server'\n code: string\n directive: string\n /**\n * Whether this file is a provider file (extracted server function file).\n * Only provider files should have the handler implementation as a second argument.\n */\n isProviderFile: boolean\n },\n) {\n // Traverse the member expression and find the call expressions for\n // the validator, handler, and middleware methods. Check to make sure they\n // are children of the createServerFn call expression.\n\n const validMethods = ['middleware', 'inputValidator', 'handler'] as const\n type ValidMethods = (typeof validMethods)[number]\n const callExpressionPaths: Record<\n ValidMethods,\n babel.NodePath<t.CallExpression> | null\n > = {\n middleware: null,\n inputValidator: null,\n handler: null,\n }\n\n const rootCallExpression = getRootCallExpression(path)\n\n // if (debug)\n // console.info(\n // 'Handling createServerFn call expression:',\n // rootCallExpression.toString(),\n // )\n\n // Check if the call is assigned to a variable\n if (!rootCallExpression.parentPath.isVariableDeclarator()) {\n throw new Error('createServerFn must be assigned to a variable!')\n }\n\n // Get the identifier name of the variable\n const variableDeclarator = rootCallExpression.parentPath.node\n const existingVariableName = (variableDeclarator.id as t.Identifier).name\n\n rootCallExpression.traverse({\n MemberExpression(memberExpressionPath) {\n if (t.isIdentifier(memberExpressionPath.node.property)) {\n const name = memberExpressionPath.node.property.name as ValidMethods\n\n if (\n validMethods.includes(name) &&\n memberExpressionPath.parentPath.isCallExpression()\n ) {\n callExpressionPaths[name] = memberExpressionPath.parentPath\n }\n }\n },\n })\n\n if (callExpressionPaths.inputValidator) {\n const innerInputExpression =\n callExpressionPaths.inputValidator.node.arguments[0]\n\n if (!innerInputExpression) {\n throw new Error(\n 'createServerFn().inputValidator() must be called with a validator!',\n )\n }\n\n // If we're on the client, remove the validator call expression\n if (opts.env === 'client') {\n if (\n t.isMemberExpression(callExpressionPaths.inputValidator.node.callee)\n ) {\n callExpressionPaths.inputValidator.replaceWith(\n callExpressionPaths.inputValidator.node.callee.object,\n )\n }\n }\n }\n\n // First, we need to move the handler function to a nested function call\n // that is applied to the arguments passed to the server function.\n\n const handlerFnPath = callExpressionPaths.handler?.get(\n 'arguments.0',\n ) as babel.NodePath<any>\n\n if (!callExpressionPaths.handler || !handlerFnPath.node) {\n throw codeFrameError(\n opts.code,\n path.node.callee.loc!,\n `createServerFn must be called with a \"handler\" property!`,\n )\n }\n\n const handlerFn = handlerFnPath.node\n\n // So, the way we do this is we give the handler function a way\n // to access the serverFn ctx on the server via function scope.\n // The 'use server' extracted function will be called with the\n // payload from the client, then use the scoped serverFn ctx\n // to execute the handler function.\n // This way, we can do things like data and middleware validation\n // in the __execute function without having to AST transform the\n // handler function too much itself.\n\n // .handler((optsOut, ctx) => {\n // return ((optsIn) => {\n // 'use server'\n // ctx.__execute(handlerFn, optsIn)\n // })(optsOut)\n // })\n\n // If the handler function is an identifier and we're on the client, we need to\n // remove the bound function from the file.\n // If we're on the server, you can leave it, since it will get referenced\n // as a second argument.\n\n if (t.isIdentifier(handlerFn)) {\n if (opts.env === 'client') {\n // Find the binding for the handler function\n const binding = handlerFnPath.scope.getBinding(handlerFn.name)\n // Remove it\n if (binding) {\n binding.path.remove()\n }\n }\n // If the env is server, just leave it alone\n }\n\n handlerFnPath.replaceWith(\n t.arrowFunctionExpression(\n [t.identifier('opts'), t.identifier('signal')],\n t.blockStatement(\n // Everything in here is server-only, since the client\n // will strip out anything in the 'use server' directive.\n [\n t.returnStatement(\n t.callExpression(\n t.identifier(`${existingVariableName}.__executeServer`),\n [t.identifier('opts'), t.identifier('signal')],\n ),\n ),\n ],\n [t.directive(t.directiveLiteral(opts.directive))],\n ),\n ),\n )\n\n // Add the serverFn as a second argument on the server side,\n // but ONLY for provider files (extracted server function files).\n // Caller files must NOT have the second argument because the implementation is already available in the extracted chunk\n // and including it would duplicate code\n if (opts.env === 'server' && opts.isProviderFile) {\n callExpressionPaths.handler.node.arguments.push(handlerFn)\n }\n}\n"],"names":[],"mappings":";;AAOO,SAAS,qBACd,MACA,MAUA;AAKA,QAAM,eAAe,CAAC,cAAc,kBAAkB,SAAS;AAE/D,QAAM,sBAGF;AAAA,IACF,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,SAAS;AAAA,EAAA;AAGX,QAAM,qBAAqB,sBAAsB,IAAI;AASrD,MAAI,CAAC,mBAAmB,WAAW,wBAAwB;AACzD,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAGA,QAAM,qBAAqB,mBAAmB,WAAW;AACzD,QAAM,uBAAwB,mBAAmB,GAAoB;AAErE,qBAAmB,SAAS;AAAA,IAC1B,iBAAiB,sBAAsB;AACrC,UAAI,EAAE,aAAa,qBAAqB,KAAK,QAAQ,GAAG;AACtD,cAAM,OAAO,qBAAqB,KAAK,SAAS;AAEhD,YACE,aAAa,SAAS,IAAI,KAC1B,qBAAqB,WAAW,oBAChC;AACA,8BAAoB,IAAI,IAAI,qBAAqB;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EAAA,CACD;AAED,MAAI,oBAAoB,gBAAgB;AACtC,UAAM,uBACJ,oBAAoB,eAAe,KAAK,UAAU,CAAC;AAErD,QAAI,CAAC,sBAAsB;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAGA,QAAI,KAAK,QAAQ,UAAU;AACzB,UACE,EAAE,mBAAmB,oBAAoB,eAAe,KAAK,MAAM,GACnE;AACA,4BAAoB,eAAe;AAAA,UACjC,oBAAoB,eAAe,KAAK,OAAO;AAAA,QAAA;AAAA,MAEnD;AAAA,IACF;AAAA,EACF;AAKA,QAAM,gBAAgB,oBAAoB,SAAS;AAAA,IACjD;AAAA,EAAA;AAGF,MAAI,CAAC,oBAAoB,WAAW,CAAC,cAAc,MAAM;AACvD,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,KAAK,OAAO;AAAA,MACjB;AAAA,IAAA;AAAA,EAEJ;AAEA,QAAM,YAAY,cAAc;AAuBhC,MAAI,EAAE,aAAa,SAAS,GAAG;AAC7B,QAAI,KAAK,QAAQ,UAAU;AAEzB,YAAM,UAAU,cAAc,MAAM,WAAW,UAAU,IAAI;AAE7D,UAAI,SAAS;AACX,gBAAQ,KAAK,OAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEF;AAEA,gBAAc;AAAA,IACZ,EAAE;AAAA,MACA,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,MAC7C,EAAE;AAAA;AAAA;AAAA,QAGA;AAAA,UACE,EAAE;AAAA,YACA,EAAE;AAAA,cACA,EAAE,WAAW,GAAG,oBAAoB,kBAAkB;AAAA,cACtD,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,YAAA;AAAA,UAC/C;AAAA,QACF;AAAA,QAEF,CAAC,EAAE,UAAU,EAAE,iBAAiB,KAAK,SAAS,CAAC,CAAC;AAAA,MAAA;AAAA,IAClD;AAAA,EACF;AAOF,MAAI,KAAK,QAAQ,YAAY,KAAK,gBAAgB;AAChD,wBAAoB,QAAQ,KAAK,UAAU,KAAK,SAAS;AAAA,EAC3D;AACF;"}
@@ -29,8 +29,12 @@ const getLookupConfigurationsForEnv = (env, framework) => {
29
29
  }
30
30
  };
31
31
  const SERVER_FN_LOOKUP = "server-fn-module-lookup";
32
+ function buildDirectiveSplitParam(directive) {
33
+ return `tsr-directive-${directive.replace(/[^a-zA-Z0-9]/g, "-")}`;
34
+ }
32
35
  function createServerFnPlugin(opts) {
33
36
  const compilers = {};
37
+ const directiveSplitParam = buildDirectiveSplitParam(opts.directive);
34
38
  function perEnvServerFnPlugin(environment) {
35
39
  const transformCodeFilter = environment.type === "client" ? [/\.\s*handler\(/, /\.\s*createMiddleware\(\)/] : [/\.\s*handler\(/];
36
40
  return {
@@ -89,8 +93,9 @@ function createServerFnPlugin(opts) {
89
93
  });
90
94
  compilers[this.environment.name] = compiler;
91
95
  }
96
+ const isProviderFile = id.includes(directiveSplitParam);
92
97
  id = cleanId(id);
93
- const result = await compiler.compile({ id, code });
98
+ const result = await compiler.compile({ id, code, isProviderFile });
94
99
  return result;
95
100
  }
96
101
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../../src/create-server-fn-plugin/plugin.ts"],"sourcesContent":["import { TRANSFORM_ID_REGEX } from '../constants'\nimport { ServerFnCompiler } from './compiler'\nimport type { LookupConfig, LookupKind } from './compiler'\nimport type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'\nimport type { PluginOption } from 'vite'\n\nfunction cleanId(id: string): string {\n return id.split('?')[0]!\n}\n\nconst LookupKindsPerEnv: Record<'client' | 'server', Set<LookupKind>> = {\n client: new Set(['Middleware', 'ServerFn'] as const),\n server: new Set(['ServerFn'] as const),\n}\n\nconst getLookupConfigurationsForEnv = (\n env: 'client' | 'server',\n framework: CompileStartFrameworkOptions,\n): Array<LookupConfig> => {\n const createServerFnConfig: LookupConfig = {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerFn',\n }\n if (env === 'client') {\n return [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createMiddleware',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createStart',\n },\n\n createServerFnConfig,\n ]\n } else {\n return [createServerFnConfig]\n }\n}\nconst SERVER_FN_LOOKUP = 'server-fn-module-lookup'\nexport function createServerFnPlugin(opts: {\n framework: CompileStartFrameworkOptions\n directive: string\n environments: Array<{ name: string; type: 'client' | 'server' }>\n}): PluginOption {\n const compilers: Record<string /* envName */, ServerFnCompiler> = {}\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // in server environments, we don't transform middleware calls\n const transformCodeFilter =\n environment.type === 'client'\n ? [/\\.\\s*handler\\(/, /\\.\\s*createMiddleware\\(\\)/]\n : [/\\.\\s*handler\\(/]\n\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers[this.environment.name]\n if (!compiler) {\n compiler = new ServerFnCompiler({\n env: environment.type,\n directive: opts.directive,\n lookupKinds: LookupKindsPerEnv[environment.type],\n lookupConfigurations: getLookupConfigurationsForEnv(\n environment.type,\n opts.framework,\n ),\n loadModule: async (id: string) => {\n if (this.environment.mode === 'build') {\n const loaded = await this.load({ id })\n if (!loaded.code) {\n throw new Error(`could not load module ${id}`)\n }\n compiler!.ingestModule({ code: loaded.code, id })\n } else if (this.environment.mode === 'dev') {\n /**\n * in dev, vite does not return code from `ctx.load()`\n * so instead, we need to take a different approach\n * we must force vite to load the module and run it through the vite plugin pipeline\n * we can do this by using the `fetchModule` method\n * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST\n */\n await this.environment.fetchModule(\n id + '?' + SERVER_FN_LOOKUP,\n )\n } else {\n throw new Error(\n `could not load module ${id}: unknown environment mode ${this.environment.mode}`,\n )\n }\n },\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n return null\n },\n })\n compilers[this.environment.name] = compiler\n }\n\n id = cleanId(id)\n const result = await compiler.compile({ id, code })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers[this.environment.name]\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers[this.environment.name]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n ]\n}\n"],"names":["id"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../../src/create-server-fn-plugin/plugin.ts"],"sourcesContent":["import { TRANSFORM_ID_REGEX } from '../constants'\nimport { ServerFnCompiler } from './compiler'\nimport type { LookupConfig, LookupKind } from './compiler'\nimport type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'\nimport type { PluginOption } from 'vite'\n\nfunction cleanId(id: string): string {\n return id.split('?')[0]!\n}\n\nconst LookupKindsPerEnv: Record<'client' | 'server', Set<LookupKind>> = {\n client: new Set(['Middleware', 'ServerFn'] as const),\n server: new Set(['ServerFn'] as const),\n}\n\nconst getLookupConfigurationsForEnv = (\n env: 'client' | 'server',\n framework: CompileStartFrameworkOptions,\n): Array<LookupConfig> => {\n const createServerFnConfig: LookupConfig = {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerFn',\n }\n if (env === 'client') {\n return [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createMiddleware',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createStart',\n },\n\n createServerFnConfig,\n ]\n } else {\n return [createServerFnConfig]\n }\n}\nconst SERVER_FN_LOOKUP = 'server-fn-module-lookup'\n\nfunction buildDirectiveSplitParam(directive: string) {\n return `tsr-directive-${directive.replace(/[^a-zA-Z0-9]/g, '-')}`\n}\n\nexport function createServerFnPlugin(opts: {\n framework: CompileStartFrameworkOptions\n directive: string\n environments: Array<{ name: string; type: 'client' | 'server' }>\n}): PluginOption {\n const compilers: Record<string /* envName */, ServerFnCompiler> = {}\n const directiveSplitParam = buildDirectiveSplitParam(opts.directive)\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // in server environments, we don't transform middleware calls\n const transformCodeFilter =\n environment.type === 'client'\n ? [/\\.\\s*handler\\(/, /\\.\\s*createMiddleware\\(\\)/]\n : [/\\.\\s*handler\\(/]\n\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers[this.environment.name]\n if (!compiler) {\n compiler = new ServerFnCompiler({\n env: environment.type,\n directive: opts.directive,\n lookupKinds: LookupKindsPerEnv[environment.type],\n lookupConfigurations: getLookupConfigurationsForEnv(\n environment.type,\n opts.framework,\n ),\n loadModule: async (id: string) => {\n if (this.environment.mode === 'build') {\n const loaded = await this.load({ id })\n if (!loaded.code) {\n throw new Error(`could not load module ${id}`)\n }\n compiler!.ingestModule({ code: loaded.code, id })\n } else if (this.environment.mode === 'dev') {\n /**\n * in dev, vite does not return code from `ctx.load()`\n * so instead, we need to take a different approach\n * we must force vite to load the module and run it through the vite plugin pipeline\n * we can do this by using the `fetchModule` method\n * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST\n */\n await this.environment.fetchModule(\n id + '?' + SERVER_FN_LOOKUP,\n )\n } else {\n throw new Error(\n `could not load module ${id}: unknown environment mode ${this.environment.mode}`,\n )\n }\n },\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n return null\n },\n })\n compilers[this.environment.name] = compiler\n }\n\n const isProviderFile = id.includes(directiveSplitParam)\n\n id = cleanId(id)\n const result = await compiler.compile({ id, code, isProviderFile })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers[this.environment.name]\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers[this.environment.name]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n ]\n}\n"],"names":["id"],"mappings":";;AAMA,SAAS,QAAQ,IAAoB;AACnC,SAAO,GAAG,MAAM,GAAG,EAAE,CAAC;AACxB;AAEA,MAAM,oBAAkE;AAAA,EACtE,QAAQ,oBAAI,IAAI,CAAC,cAAc,UAAU,CAAU;AAAA,EACnD,QAAQ,oBAAI,IAAI,CAAC,UAAU,CAAU;AACvC;AAEA,MAAM,gCAAgC,CACpC,KACA,cACwB;AACxB,QAAM,uBAAqC;AAAA,IACzC,SAAS,aAAa,SAAS;AAAA,IAC/B,YAAY;AAAA,EAAA;AAEd,MAAI,QAAQ,UAAU;AACpB,WAAO;AAAA,MACL;AAAA,QACE,SAAS,aAAa,SAAS;AAAA,QAC/B,YAAY;AAAA,MAAA;AAAA,MAEd;AAAA,QACE,SAAS,aAAa,SAAS;AAAA,QAC/B,YAAY;AAAA,MAAA;AAAA,MAGd;AAAA,IAAA;AAAA,EAEJ,OAAO;AACL,WAAO,CAAC,oBAAoB;AAAA,EAC9B;AACF;AACA,MAAM,mBAAmB;AAEzB,SAAS,yBAAyB,WAAmB;AACnD,SAAO,iBAAiB,UAAU,QAAQ,iBAAiB,GAAG,CAAC;AACjE;AAEO,SAAS,qBAAqB,MAIpB;AACf,QAAM,YAA4D,CAAA;AAClE,QAAM,sBAAsB,yBAAyB,KAAK,SAAS;AAEnE,WAAS,qBAAqB,aAGb;AAEf,UAAM,sBACJ,YAAY,SAAS,WACjB,CAAC,kBAAkB,2BAA2B,IAC9C,CAAC,gBAAgB;AAEvB,WAAO;AAAA,MACL,MAAM,kCAAkC,YAAY,IAAI;AAAA,MACxD,SAAS;AAAA,MACT,mBAAmB,KAAK;AACtB,eAAO,IAAI,SAAS,YAAY;AAAA,MAClC;AAAA,MACA,WAAW;AAAA,QACT,QAAQ;AAAA,UACN,IAAI;AAAA,YACF,SAAS,IAAI,OAAO,GAAG,gBAAgB,GAAG;AAAA,YAC1C,SAAS;AAAA,UAAA;AAAA,UAEX,MAAM;AAAA,YACJ,SAAS;AAAA,UAAA;AAAA,QACX;AAAA,QAEF,MAAM,QAAQ,MAAM,IAAI;AACtB,cAAI,WAAW,UAAU,KAAK,YAAY,IAAI;AAC9C,cAAI,CAAC,UAAU;AACb,uBAAW,IAAI,iBAAiB;AAAA,cAC9B,KAAK,YAAY;AAAA,cACjB,WAAW,KAAK;AAAA,cAChB,aAAa,kBAAkB,YAAY,IAAI;AAAA,cAC/C,sBAAsB;AAAA,gBACpB,YAAY;AAAA,gBACZ,KAAK;AAAA,cAAA;AAAA,cAEP,YAAY,OAAOA,QAAe;AAChC,oBAAI,KAAK,YAAY,SAAS,SAAS;AACrC,wBAAM,SAAS,MAAM,KAAK,KAAK,EAAE,IAAAA,KAAI;AACrC,sBAAI,CAAC,OAAO,MAAM;AAChB,0BAAM,IAAI,MAAM,yBAAyBA,GAAE,EAAE;AAAA,kBAC/C;AACA,2BAAU,aAAa,EAAE,MAAM,OAAO,MAAM,IAAAA,KAAI;AAAA,gBAClD,WAAW,KAAK,YAAY,SAAS,OAAO;AAQ1C,wBAAM,KAAK,YAAY;AAAA,oBACrBA,MAAK,MAAM;AAAA,kBAAA;AAAA,gBAEf,OAAO;AACL,wBAAM,IAAI;AAAA,oBACR,yBAAyBA,GAAE,8BAA8B,KAAK,YAAY,IAAI;AAAA,kBAAA;AAAA,gBAElF;AAAA,cACF;AAAA,cACA,WAAW,OAAO,QAAgB,aAAsB;AACtD,sBAAM,IAAI,MAAM,KAAK,QAAQ,QAAQ,QAAQ;AAC7C,oBAAI,GAAG;AACL,sBAAI,CAAC,EAAE,UAAU;AACf,2BAAO,QAAQ,EAAE,EAAE;AAAA,kBACrB;AAAA,gBACF;AACA,uBAAO;AAAA,cACT;AAAA,YAAA,CACD;AACD,sBAAU,KAAK,YAAY,IAAI,IAAI;AAAA,UACrC;AAEA,gBAAM,iBAAiB,GAAG,SAAS,mBAAmB;AAEtD,eAAK,QAAQ,EAAE;AACf,gBAAM,SAAS,MAAM,SAAS,QAAQ,EAAE,IAAI,MAAM,gBAAgB;AAClE,iBAAO;AAAA,QACT;AAAA,MAAA;AAAA,MAGF,UAAU,KAAK;AACb,cAAM,WAAW,UAAU,KAAK,YAAY,IAAI;AAEhD,YAAI,QAAQ,QAAQ,CAAC,MAAM;AACzB,cAAI,EAAE,IAAI;AACR,kBAAM,UAAU,UAAU,iBAAiB,EAAE,EAAE;AAC/C,gBAAI,SAAS;AACX,gBAAE,UAAU,QAAQ,CAAC,aAAa;AAChC,oBAAI,SAAS,IAAI;AACf,4BAAU,iBAAiB,SAAS,EAAE;AAAA,gBACxC;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AAAA,IACL,GAAG,KAAK,aAAa,IAAI,oBAAoB;AAAA,IAC7C;AAAA,MACE,MAAM;AAAA;AAAA,MAEN,OAAO;AAAA,MACP,mBAAmB,KAAK;AACtB,eAAO,CAAC,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,IAAI;AAAA,MAC5D;AAAA,MACA,WAAW;AAAA,QACT,QAAQ;AAAA,UACN,IAAI,IAAI,OAAO,GAAG,gBAAgB,GAAG;AAAA,QAAA;AAAA,QAEvC,QAAQ,MAAM,IAAI;AAChB,gBAAM,WAAW,UAAU,KAAK,YAAY,IAAI;AAChD,oBAAU,aAAa,EAAE,MAAM,IAAI,QAAQ,EAAE,GAAG;AAAA,QAClD;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ;"}
@@ -22,9 +22,11 @@ export interface ResolvedStartConfig {
22
22
  routerFilePath: string;
23
23
  srcDirectory: string;
24
24
  viteAppBase: string;
25
+ serverFnProviderEnv: string;
25
26
  }
26
27
  export type GetConfigFn = () => {
27
28
  startConfig: TanStackStartOutputConfig;
28
29
  resolvedStartConfig: ResolvedStartConfig;
30
+ corePluginOpts: TanStackStartVitePluginCoreOptions;
29
31
  };
30
32
  export declare function TanStackStartVitePluginCore(corePluginOpts: TanStackStartVitePluginCoreOptions, startPluginOpts: TanStackStartInputConfig): Array<PluginOption>;
@@ -26,12 +26,15 @@ function isFullUrl(str) {
26
26
  }
27
27
  }
28
28
  function TanStackStartVitePluginCore(corePluginOpts, startPluginOpts) {
29
+ const serverFnProviderEnv = corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server;
30
+ const ssrIsProvider = serverFnProviderEnv === VITE_ENVIRONMENT_NAMES.server;
29
31
  const resolvedStartConfig = {
30
32
  root: "",
31
33
  startFilePath: void 0,
32
34
  routerFilePath: "",
33
35
  srcDirectory: "",
34
- viteAppBase: ""
36
+ viteAppBase: "",
37
+ serverFnProviderEnv
35
38
  };
36
39
  const directive = corePluginOpts.serverFn?.directive ?? "use server";
37
40
  let startConfig;
@@ -46,7 +49,7 @@ function TanStackStartVitePluginCore(corePluginOpts, startPluginOpts) {
46
49
  resolvedStartConfig.root
47
50
  );
48
51
  }
49
- return { startConfig, resolvedStartConfig };
52
+ return { startConfig, resolvedStartConfig, corePluginOpts };
50
53
  };
51
54
  const capturedBundle = {};
52
55
  function getBundle(envName) {
@@ -256,6 +259,17 @@ function TanStackStartVitePluginCore(corePluginOpts, startPluginOpts) {
256
259
  if (!server.isBuilt) {
257
260
  await builder.build(server);
258
261
  }
262
+ if (!ssrIsProvider) {
263
+ const providerEnv = builder.environments[serverFnProviderEnv];
264
+ if (!providerEnv) {
265
+ throw new Error(
266
+ `Provider environment "${serverFnProviderEnv}" not found`
267
+ );
268
+ }
269
+ if (!providerEnv.isBuilt) {
270
+ await builder.build(providerEnv);
271
+ }
272
+ }
259
273
  }
260
274
  }
261
275
  };
@@ -293,14 +307,18 @@ function TanStackStartVitePluginCore(corePluginOpts, startPluginOpts) {
293
307
  envConsumer: "server",
294
308
  getRuntimeCode: () => `import { createSsrRpc } from '@tanstack/${corePluginOpts.framework}-start/ssr-rpc'`,
295
309
  envName: VITE_ENVIRONMENT_NAMES.server,
296
- replacer: (d) => `createSsrRpc('${d.functionId}')`,
297
- getServerFnById: corePluginOpts.serverFn?.ssr?.getServerFnById
310
+ replacer: (d) => (
311
+ // When the function is client-referenced, it's in the manifest - use manifest lookup
312
+ // When SSR is NOT the provider, always use manifest lookup (no import() for different env)
313
+ // Otherwise, use the importer for functions only referenced on the server when SSR is the provider
314
+ d.isClientReferenced || !ssrIsProvider ? `createSsrRpc('${d.functionId}')` : `createSsrRpc('${d.functionId}', () => import(${JSON.stringify(d.extractedFilename)}).then(m => m['${d.functionName}']))`
315
+ )
298
316
  }
299
317
  ],
300
318
  provider: {
301
319
  getRuntimeCode: () => `import { createServerRpc } from '@tanstack/${corePluginOpts.framework}-start/server-rpc'`,
302
320
  replacer: (d) => `createServerRpc('${d.functionId}', ${d.fn})`,
303
- envName: corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server
321
+ envName: serverFnProviderEnv
304
322
  }
305
323
  }),
306
324
  loadEnvPlugin(),
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { joinPaths } from '@tanstack/router-core'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { TanStackServerFnPlugin } from '@tanstack/server-functions-plugin'\nimport * as vite from 'vite'\nimport { crawlFrameworkPkgs } from 'vitefu'\nimport { join } from 'pathe'\nimport { escapePath } from 'tinyglobby'\nimport { startManifestPlugin } from './start-manifest-plugin/plugin'\nimport { startCompilerPlugin } from './start-compiler-plugin/plugin'\nimport { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from './constants'\nimport { tanStackStartRouter } from './start-router-plugin/plugin'\nimport { loadEnvPlugin } from './load-env-plugin/plugin'\nimport { devServerPlugin } from './dev-server-plugin/plugin'\nimport { previewServerPlugin } from './preview-server-plugin/plugin'\nimport { parseStartConfig } from './schema'\nimport { resolveEntry } from './resolve-entries'\nimport {\n getClientOutputDirectory,\n getServerOutputDirectory,\n} from './output-directory'\nimport { postServerBuild } from './post-server-build'\nimport { createServerFnPlugin } from './create-server-fn-plugin/plugin'\nimport type { ViteEnvironmentNames } from './constants'\nimport type {\n TanStackStartInputConfig,\n TanStackStartOutputConfig,\n} from './schema'\nimport type { PluginOption } from 'vite'\nimport type { CompileStartFrameworkOptions } from './start-compiler-plugin/compilers'\n\nexport interface TanStackStartVitePluginCoreOptions {\n framework: CompileStartFrameworkOptions\n defaultEntryPaths: {\n client: string\n server: string\n start: string\n }\n serverFn?: {\n directive?: string\n ssr?: {\n getServerFnById?: string\n }\n providerEnv?: string\n }\n}\n\nexport interface ResolvedStartConfig {\n root: string\n startFilePath: string | undefined\n routerFilePath: string\n srcDirectory: string\n viteAppBase: string\n}\n\nexport type GetConfigFn = () => {\n startConfig: TanStackStartOutputConfig\n resolvedStartConfig: ResolvedStartConfig\n}\n\nfunction isFullUrl(str: string): boolean {\n try {\n new URL(str)\n return true\n } catch {\n return false\n }\n}\n\nexport function TanStackStartVitePluginCore(\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n startPluginOpts: TanStackStartInputConfig,\n): Array<PluginOption> {\n const resolvedStartConfig: ResolvedStartConfig = {\n root: '',\n startFilePath: undefined,\n routerFilePath: '',\n srcDirectory: '',\n viteAppBase: '',\n }\n\n const directive = corePluginOpts.serverFn?.directive ?? 'use server'\n\n let startConfig: TanStackStartOutputConfig | null\n const getConfig: GetConfigFn = () => {\n if (!resolvedStartConfig.root) {\n throw new Error(`Cannot get config before root is resolved`)\n }\n if (!startConfig) {\n startConfig = parseStartConfig(\n startPluginOpts,\n corePluginOpts,\n resolvedStartConfig.root,\n )\n }\n return { startConfig, resolvedStartConfig }\n }\n\n const capturedBundle: Partial<\n Record<ViteEnvironmentNames, vite.Rollup.OutputBundle>\n > = {}\n\n function getBundle(envName: ViteEnvironmentNames): vite.Rollup.OutputBundle {\n const bundle = capturedBundle[envName]\n if (!bundle) {\n throw new Error(`No bundle captured for environment: ${envName}`)\n }\n return bundle\n }\n\n const environments: Array<{ name: string; type: 'client' | 'server' }> = [\n { name: VITE_ENVIRONMENT_NAMES.client, type: 'client' },\n { name: VITE_ENVIRONMENT_NAMES.server, type: 'server' },\n ]\n if (\n corePluginOpts.serverFn?.providerEnv &&\n !environments.find((e) => e.name === corePluginOpts.serverFn?.providerEnv)\n ) {\n environments.push({\n name: corePluginOpts.serverFn.providerEnv,\n type: 'server',\n })\n }\n return [\n {\n name: 'tanstack-start-core:config',\n enforce: 'pre',\n async config(viteConfig, { command }) {\n resolvedStartConfig.viteAppBase = viteConfig.base ?? '/'\n if (!isFullUrl(resolvedStartConfig.viteAppBase)) {\n resolvedStartConfig.viteAppBase = joinPaths([\n '/',\n viteConfig.base,\n '/',\n ])\n }\n const root = viteConfig.root || process.cwd()\n resolvedStartConfig.root = root\n\n const { startConfig } = getConfig()\n if (startConfig.router.basepath === undefined) {\n if (!isFullUrl(resolvedStartConfig.viteAppBase)) {\n startConfig.router.basepath =\n resolvedStartConfig.viteAppBase.replace(/^\\/|\\/$/g, '')\n } else {\n startConfig.router.basepath = '/'\n }\n } else {\n if (command === 'serve' && !viteConfig.server?.middlewareMode) {\n // when serving, we must ensure that router basepath and viteAppBase are aligned\n if (\n !joinPaths(['/', startConfig.router.basepath, '/']).startsWith(\n joinPaths(['/', resolvedStartConfig.viteAppBase, '/']),\n )\n ) {\n this.error(\n '[tanstack-start]: During `vite dev`, `router.basepath` must start with the vite `base` config value',\n )\n }\n }\n }\n\n const TSS_SERVER_FN_BASE = joinPaths([\n '/',\n startConfig.router.basepath,\n startConfig.serverFns.base,\n '/',\n ])\n const resolvedSrcDirectory = join(root, startConfig.srcDirectory)\n resolvedStartConfig.srcDirectory = resolvedSrcDirectory\n\n const startFilePath = resolveEntry({\n type: 'start entry',\n configuredEntry: startConfig.start.entry,\n defaultEntry: 'start',\n resolvedSrcDirectory,\n required: false,\n })\n resolvedStartConfig.startFilePath = startFilePath\n\n const routerFilePath = resolveEntry({\n type: 'router entry',\n configuredEntry: startConfig.router.entry,\n defaultEntry: 'router',\n resolvedSrcDirectory,\n required: true,\n })\n resolvedStartConfig.routerFilePath = routerFilePath\n\n const clientEntryPath = resolveEntry({\n type: 'client entry',\n configuredEntry: startConfig.client.entry,\n defaultEntry: 'client',\n resolvedSrcDirectory,\n required: false,\n })\n\n const serverEntryPath = resolveEntry({\n type: 'server entry',\n configuredEntry: startConfig.server.entry,\n defaultEntry: 'server',\n resolvedSrcDirectory,\n required: false,\n })\n\n const clientAlias = vite.normalizePath(\n clientEntryPath ?? corePluginOpts.defaultEntryPaths.client,\n )\n const serverAlias = vite.normalizePath(\n serverEntryPath ?? corePluginOpts.defaultEntryPaths.server,\n )\n const startAlias = vite.normalizePath(\n startFilePath ?? corePluginOpts.defaultEntryPaths.start,\n )\n const routerAlias = vite.normalizePath(routerFilePath)\n\n const entryAliasConfiguration: Record<\n (typeof ENTRY_POINTS)[keyof typeof ENTRY_POINTS],\n string\n > = {\n [ENTRY_POINTS.client]: clientAlias,\n [ENTRY_POINTS.server]: serverAlias,\n [ENTRY_POINTS.start]: startAlias,\n [ENTRY_POINTS.router]: routerAlias,\n }\n\n const startPackageName =\n `@tanstack/${corePluginOpts.framework}-start` as const\n\n // crawl packages that have start in \"peerDependencies\"\n // see https://github.com/svitejs/vitefu/blob/d8d82fa121e3b2215ba437107093c77bde51b63b/src/index.js#L95-L101\n\n // this is currently uncached; could be implemented similarly as vite handles lock file changes\n // see https://github.com/vitejs/vite/blob/557f797d29422027e8c451ca50dd84bf8c41b5f0/packages/vite/src/node/optimizer/index.ts#L1282\n\n const crawlFrameworkPkgsResult = await crawlFrameworkPkgs({\n root: process.cwd(),\n isBuild: command === 'build',\n isFrameworkPkgByJson(pkgJson) {\n const peerDependencies = pkgJson['peerDependencies']\n\n if (peerDependencies) {\n if (\n startPackageName in peerDependencies ||\n '@tanstack/start-client-core' in peerDependencies\n ) {\n return true\n }\n }\n\n return false\n },\n })\n\n return {\n // see https://vite.dev/config/shared-options.html#apptype\n // this will prevent vite from injecting middlewares that we don't want\n appType: viteConfig.appType ?? 'custom',\n environments: {\n [VITE_ENVIRONMENT_NAMES.client]: {\n consumer: 'client',\n build: {\n rollupOptions: {\n input: {\n main: ENTRY_POINTS.client,\n },\n },\n outDir: getClientOutputDirectory(viteConfig),\n },\n optimizeDeps: {\n exclude: crawlFrameworkPkgsResult.optimizeDeps.exclude,\n // Ensure user code can be crawled for dependencies\n entries: [clientAlias, routerAlias].map((entry) =>\n // Entries are treated as `tinyglobby` patterns so need to be escaped\n escapePath(entry),\n ),\n },\n },\n [VITE_ENVIRONMENT_NAMES.server]: {\n consumer: 'server',\n build: {\n ssr: true,\n rollupOptions: {\n input:\n viteConfig.environments?.[VITE_ENVIRONMENT_NAMES.server]\n ?.build?.rollupOptions?.input ?? serverAlias,\n },\n outDir: getServerOutputDirectory(viteConfig),\n commonjsOptions: {\n include: [/node_modules/],\n },\n copyPublicDir:\n viteConfig.environments?.[VITE_ENVIRONMENT_NAMES.server]\n ?.build?.copyPublicDir ?? false,\n },\n optimizeDeps: {\n // Ensure user code can be crawled for dependencies\n entries: [serverAlias, startAlias, routerAlias].map((entry) =>\n // Entries are treated as `tinyglobby` patterns so need to be escaped\n escapePath(entry),\n ),\n },\n },\n },\n\n resolve: {\n noExternal: [\n // ENTRY_POINTS.start,\n '@tanstack/start**',\n `@tanstack/${corePluginOpts.framework}-start**`,\n ...crawlFrameworkPkgsResult.ssr.noExternal.sort(),\n ],\n alias: {\n ...entryAliasConfiguration,\n },\n },\n /* prettier-ignore */\n define: {\n // define is an esbuild function that replaces the any instances of given keys with the given values\n // i.e: __FRAMEWORK_NAME__ can be replaced with JSON.stringify(\"TanStack Start\")\n // This is not the same as injecting environment variables.\n\n ...defineReplaceEnv('TSS_SERVER_FN_BASE', TSS_SERVER_FN_BASE),\n ...defineReplaceEnv('TSS_CLIENT_OUTPUT_DIR', getClientOutputDirectory(viteConfig)),\n ...defineReplaceEnv('TSS_ROUTER_BASEPATH', startConfig.router.basepath),\n ...(command === 'serve' ? defineReplaceEnv('TSS_SHELL', startConfig.spa?.enabled ? 'true' : 'false') : {}),\n ...defineReplaceEnv('TSS_DEV_SERVER', command === 'serve' ? 'true' : 'false'),\n },\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n const client = builder.environments[VITE_ENVIRONMENT_NAMES.client]\n const server = builder.environments[VITE_ENVIRONMENT_NAMES.server]\n\n if (!client) {\n throw new Error('Client environment not found')\n }\n\n if (!server) {\n throw new Error('SSR environment not found')\n }\n\n if (!client.isBuilt) {\n // Build the client bundle first\n await builder.build(client)\n }\n if (!server.isBuilt) {\n // Build the SSR bundle\n await builder.build(server)\n }\n },\n },\n }\n },\n buildApp: {\n order: 'post',\n async handler(builder) {\n const { startConfig } = getConfig()\n await postServerBuild({ builder, startConfig })\n },\n },\n },\n tanStackStartRouter(startPluginOpts, getConfig, corePluginOpts),\n // N.B. TanStackStartCompilerPlugin must be before the TanStackServerFnPlugin\n startCompilerPlugin({ framework: corePluginOpts.framework, environments }),\n createServerFnPlugin({\n framework: corePluginOpts.framework,\n directive,\n environments,\n }),\n\n TanStackServerFnPlugin({\n // This is the ID that will be available to look up and import\n // our server function manifest and resolve its module\n manifestVirtualImportId: VIRTUAL_MODULES.serverFnManifest,\n directive,\n generateFunctionId: startPluginOpts?.serverFns?.generateFunctionId,\n callers: [\n {\n envConsumer: 'client',\n getRuntimeCode: () =>\n `import { createClientRpc } from '@tanstack/${corePluginOpts.framework}-start/client-rpc'`,\n replacer: (d) => `createClientRpc('${d.functionId}')`,\n envName: VITE_ENVIRONMENT_NAMES.client,\n },\n {\n envConsumer: 'server',\n getRuntimeCode: () =>\n `import { createSsrRpc } from '@tanstack/${corePluginOpts.framework}-start/ssr-rpc'`,\n envName: VITE_ENVIRONMENT_NAMES.server,\n replacer: (d) => `createSsrRpc('${d.functionId}')`,\n getServerFnById: corePluginOpts.serverFn?.ssr?.getServerFnById,\n },\n ],\n provider: {\n getRuntimeCode: () =>\n `import { createServerRpc } from '@tanstack/${corePluginOpts.framework}-start/server-rpc'`,\n replacer: (d) => `createServerRpc('${d.functionId}', ${d.fn})`,\n envName:\n corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server,\n },\n }),\n loadEnvPlugin(),\n startManifestPlugin({\n getClientBundle: () => getBundle(VITE_ENVIRONMENT_NAMES.client),\n getConfig,\n }),\n devServerPlugin({ getConfig }),\n previewServerPlugin(),\n {\n name: 'tanstack-start:core:capture-bundle',\n applyToEnvironment(e) {\n return (\n e.name === VITE_ENVIRONMENT_NAMES.client ||\n e.name === VITE_ENVIRONMENT_NAMES.server\n )\n },\n enforce: 'post',\n generateBundle(_options, bundle) {\n const environment = this.environment.name as ViteEnvironmentNames\n if (!Object.values(VITE_ENVIRONMENT_NAMES).includes(environment)) {\n throw new Error(`Unknown environment: ${environment}`)\n }\n capturedBundle[environment] = bundle\n },\n },\n ]\n}\n\nfunction defineReplaceEnv<TKey extends string, TValue extends string>(\n key: TKey,\n value: TValue,\n): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } {\n return {\n [`process.env.${key}`]: JSON.stringify(value),\n [`import.meta.env.${key}`]: JSON.stringify(value),\n } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue }\n}\n"],"names":["startConfig"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { joinPaths } from '@tanstack/router-core'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { TanStackServerFnPlugin } from '@tanstack/server-functions-plugin'\nimport * as vite from 'vite'\nimport { crawlFrameworkPkgs } from 'vitefu'\nimport { join } from 'pathe'\nimport { escapePath } from 'tinyglobby'\nimport { startManifestPlugin } from './start-manifest-plugin/plugin'\nimport { startCompilerPlugin } from './start-compiler-plugin/plugin'\nimport { ENTRY_POINTS, VITE_ENVIRONMENT_NAMES } from './constants'\nimport { tanStackStartRouter } from './start-router-plugin/plugin'\nimport { loadEnvPlugin } from './load-env-plugin/plugin'\nimport { devServerPlugin } from './dev-server-plugin/plugin'\nimport { previewServerPlugin } from './preview-server-plugin/plugin'\nimport { parseStartConfig } from './schema'\nimport { resolveEntry } from './resolve-entries'\nimport {\n getClientOutputDirectory,\n getServerOutputDirectory,\n} from './output-directory'\nimport { postServerBuild } from './post-server-build'\nimport { createServerFnPlugin } from './create-server-fn-plugin/plugin'\nimport type { ViteEnvironmentNames } from './constants'\nimport type {\n TanStackStartInputConfig,\n TanStackStartOutputConfig,\n} from './schema'\nimport type { PluginOption } from 'vite'\nimport type { CompileStartFrameworkOptions } from './start-compiler-plugin/compilers'\n\nexport interface TanStackStartVitePluginCoreOptions {\n framework: CompileStartFrameworkOptions\n defaultEntryPaths: {\n client: string\n server: string\n start: string\n }\n serverFn?: {\n directive?: string\n ssr?: {\n getServerFnById?: string\n }\n providerEnv?: string\n }\n}\n\nexport interface ResolvedStartConfig {\n root: string\n startFilePath: string | undefined\n routerFilePath: string\n srcDirectory: string\n viteAppBase: string\n serverFnProviderEnv: string\n}\n\nexport type GetConfigFn = () => {\n startConfig: TanStackStartOutputConfig\n resolvedStartConfig: ResolvedStartConfig\n corePluginOpts: TanStackStartVitePluginCoreOptions\n}\n\nfunction isFullUrl(str: string): boolean {\n try {\n new URL(str)\n return true\n } catch {\n return false\n }\n}\n\nexport function TanStackStartVitePluginCore(\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n startPluginOpts: TanStackStartInputConfig,\n): Array<PluginOption> {\n // Determine the provider environment for server functions\n // If providerEnv is set, use that; otherwise default to SSR as the provider\n const serverFnProviderEnv =\n corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server\n const ssrIsProvider = serverFnProviderEnv === VITE_ENVIRONMENT_NAMES.server\n\n const resolvedStartConfig: ResolvedStartConfig = {\n root: '',\n startFilePath: undefined,\n routerFilePath: '',\n srcDirectory: '',\n viteAppBase: '',\n serverFnProviderEnv,\n }\n\n const directive = corePluginOpts.serverFn?.directive ?? 'use server'\n\n let startConfig: TanStackStartOutputConfig | null\n const getConfig: GetConfigFn = () => {\n if (!resolvedStartConfig.root) {\n throw new Error(`Cannot get config before root is resolved`)\n }\n if (!startConfig) {\n startConfig = parseStartConfig(\n startPluginOpts,\n corePluginOpts,\n resolvedStartConfig.root,\n )\n }\n return { startConfig, resolvedStartConfig, corePluginOpts }\n }\n\n const capturedBundle: Partial<\n Record<ViteEnvironmentNames, vite.Rollup.OutputBundle>\n > = {}\n\n function getBundle(envName: ViteEnvironmentNames): vite.Rollup.OutputBundle {\n const bundle = capturedBundle[envName]\n if (!bundle) {\n throw new Error(`No bundle captured for environment: ${envName}`)\n }\n return bundle\n }\n\n const environments: Array<{ name: string; type: 'client' | 'server' }> = [\n { name: VITE_ENVIRONMENT_NAMES.client, type: 'client' },\n { name: VITE_ENVIRONMENT_NAMES.server, type: 'server' },\n ]\n if (\n corePluginOpts.serverFn?.providerEnv &&\n !environments.find((e) => e.name === corePluginOpts.serverFn?.providerEnv)\n ) {\n environments.push({\n name: corePluginOpts.serverFn.providerEnv,\n type: 'server',\n })\n }\n return [\n {\n name: 'tanstack-start-core:config',\n enforce: 'pre',\n async config(viteConfig, { command }) {\n resolvedStartConfig.viteAppBase = viteConfig.base ?? '/'\n if (!isFullUrl(resolvedStartConfig.viteAppBase)) {\n resolvedStartConfig.viteAppBase = joinPaths([\n '/',\n viteConfig.base,\n '/',\n ])\n }\n const root = viteConfig.root || process.cwd()\n resolvedStartConfig.root = root\n\n const { startConfig } = getConfig()\n if (startConfig.router.basepath === undefined) {\n if (!isFullUrl(resolvedStartConfig.viteAppBase)) {\n startConfig.router.basepath =\n resolvedStartConfig.viteAppBase.replace(/^\\/|\\/$/g, '')\n } else {\n startConfig.router.basepath = '/'\n }\n } else {\n if (command === 'serve' && !viteConfig.server?.middlewareMode) {\n // when serving, we must ensure that router basepath and viteAppBase are aligned\n if (\n !joinPaths(['/', startConfig.router.basepath, '/']).startsWith(\n joinPaths(['/', resolvedStartConfig.viteAppBase, '/']),\n )\n ) {\n this.error(\n '[tanstack-start]: During `vite dev`, `router.basepath` must start with the vite `base` config value',\n )\n }\n }\n }\n\n const TSS_SERVER_FN_BASE = joinPaths([\n '/',\n startConfig.router.basepath,\n startConfig.serverFns.base,\n '/',\n ])\n const resolvedSrcDirectory = join(root, startConfig.srcDirectory)\n resolvedStartConfig.srcDirectory = resolvedSrcDirectory\n\n const startFilePath = resolveEntry({\n type: 'start entry',\n configuredEntry: startConfig.start.entry,\n defaultEntry: 'start',\n resolvedSrcDirectory,\n required: false,\n })\n resolvedStartConfig.startFilePath = startFilePath\n\n const routerFilePath = resolveEntry({\n type: 'router entry',\n configuredEntry: startConfig.router.entry,\n defaultEntry: 'router',\n resolvedSrcDirectory,\n required: true,\n })\n resolvedStartConfig.routerFilePath = routerFilePath\n\n const clientEntryPath = resolveEntry({\n type: 'client entry',\n configuredEntry: startConfig.client.entry,\n defaultEntry: 'client',\n resolvedSrcDirectory,\n required: false,\n })\n\n const serverEntryPath = resolveEntry({\n type: 'server entry',\n configuredEntry: startConfig.server.entry,\n defaultEntry: 'server',\n resolvedSrcDirectory,\n required: false,\n })\n\n const clientAlias = vite.normalizePath(\n clientEntryPath ?? corePluginOpts.defaultEntryPaths.client,\n )\n const serverAlias = vite.normalizePath(\n serverEntryPath ?? corePluginOpts.defaultEntryPaths.server,\n )\n const startAlias = vite.normalizePath(\n startFilePath ?? corePluginOpts.defaultEntryPaths.start,\n )\n const routerAlias = vite.normalizePath(routerFilePath)\n\n const entryAliasConfiguration: Record<\n (typeof ENTRY_POINTS)[keyof typeof ENTRY_POINTS],\n string\n > = {\n [ENTRY_POINTS.client]: clientAlias,\n [ENTRY_POINTS.server]: serverAlias,\n [ENTRY_POINTS.start]: startAlias,\n [ENTRY_POINTS.router]: routerAlias,\n }\n\n const startPackageName =\n `@tanstack/${corePluginOpts.framework}-start` as const\n\n // crawl packages that have start in \"peerDependencies\"\n // see https://github.com/svitejs/vitefu/blob/d8d82fa121e3b2215ba437107093c77bde51b63b/src/index.js#L95-L101\n\n // this is currently uncached; could be implemented similarly as vite handles lock file changes\n // see https://github.com/vitejs/vite/blob/557f797d29422027e8c451ca50dd84bf8c41b5f0/packages/vite/src/node/optimizer/index.ts#L1282\n\n const crawlFrameworkPkgsResult = await crawlFrameworkPkgs({\n root: process.cwd(),\n isBuild: command === 'build',\n isFrameworkPkgByJson(pkgJson) {\n const peerDependencies = pkgJson['peerDependencies']\n\n if (peerDependencies) {\n if (\n startPackageName in peerDependencies ||\n '@tanstack/start-client-core' in peerDependencies\n ) {\n return true\n }\n }\n\n return false\n },\n })\n\n return {\n // see https://vite.dev/config/shared-options.html#apptype\n // this will prevent vite from injecting middlewares that we don't want\n appType: viteConfig.appType ?? 'custom',\n environments: {\n [VITE_ENVIRONMENT_NAMES.client]: {\n consumer: 'client',\n build: {\n rollupOptions: {\n input: {\n main: ENTRY_POINTS.client,\n },\n },\n outDir: getClientOutputDirectory(viteConfig),\n },\n optimizeDeps: {\n exclude: crawlFrameworkPkgsResult.optimizeDeps.exclude,\n // Ensure user code can be crawled for dependencies\n entries: [clientAlias, routerAlias].map((entry) =>\n // Entries are treated as `tinyglobby` patterns so need to be escaped\n escapePath(entry),\n ),\n },\n },\n [VITE_ENVIRONMENT_NAMES.server]: {\n consumer: 'server',\n build: {\n ssr: true,\n rollupOptions: {\n input:\n viteConfig.environments?.[VITE_ENVIRONMENT_NAMES.server]\n ?.build?.rollupOptions?.input ?? serverAlias,\n },\n outDir: getServerOutputDirectory(viteConfig),\n commonjsOptions: {\n include: [/node_modules/],\n },\n copyPublicDir:\n viteConfig.environments?.[VITE_ENVIRONMENT_NAMES.server]\n ?.build?.copyPublicDir ?? false,\n },\n optimizeDeps: {\n // Ensure user code can be crawled for dependencies\n entries: [serverAlias, startAlias, routerAlias].map((entry) =>\n // Entries are treated as `tinyglobby` patterns so need to be escaped\n escapePath(entry),\n ),\n },\n },\n },\n\n resolve: {\n noExternal: [\n // ENTRY_POINTS.start,\n '@tanstack/start**',\n `@tanstack/${corePluginOpts.framework}-start**`,\n ...crawlFrameworkPkgsResult.ssr.noExternal.sort(),\n ],\n alias: {\n ...entryAliasConfiguration,\n },\n },\n /* prettier-ignore */\n define: {\n // define is an esbuild function that replaces the any instances of given keys with the given values\n // i.e: __FRAMEWORK_NAME__ can be replaced with JSON.stringify(\"TanStack Start\")\n // This is not the same as injecting environment variables.\n\n ...defineReplaceEnv('TSS_SERVER_FN_BASE', TSS_SERVER_FN_BASE),\n ...defineReplaceEnv('TSS_CLIENT_OUTPUT_DIR', getClientOutputDirectory(viteConfig)),\n ...defineReplaceEnv('TSS_ROUTER_BASEPATH', startConfig.router.basepath),\n ...(command === 'serve' ? defineReplaceEnv('TSS_SHELL', startConfig.spa?.enabled ? 'true' : 'false') : {}),\n ...defineReplaceEnv('TSS_DEV_SERVER', command === 'serve' ? 'true' : 'false'),\n },\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n const client = builder.environments[VITE_ENVIRONMENT_NAMES.client]\n const server = builder.environments[VITE_ENVIRONMENT_NAMES.server]\n\n if (!client) {\n throw new Error('Client environment not found')\n }\n\n if (!server) {\n throw new Error('SSR environment not found')\n }\n\n if (!client.isBuilt) {\n // Build the client bundle first\n await builder.build(client)\n }\n if (!server.isBuilt) {\n // Build the SSR bundle\n await builder.build(server)\n }\n\n // If a custom provider environment is configured (not SSR),\n // build it last so the manifest includes functions from all environments\n if (!ssrIsProvider) {\n const providerEnv = builder.environments[serverFnProviderEnv]\n if (!providerEnv) {\n throw new Error(\n `Provider environment \"${serverFnProviderEnv}\" not found`,\n )\n }\n if (!providerEnv.isBuilt) {\n // Build the provider environment last\n // This ensures all server functions are discovered from client/ssr builds\n await builder.build(providerEnv)\n }\n }\n },\n },\n }\n },\n buildApp: {\n order: 'post',\n async handler(builder) {\n const { startConfig } = getConfig()\n await postServerBuild({ builder, startConfig })\n },\n },\n },\n tanStackStartRouter(startPluginOpts, getConfig, corePluginOpts),\n // N.B. TanStackStartCompilerPlugin must be before the TanStackServerFnPlugin\n startCompilerPlugin({ framework: corePluginOpts.framework, environments }),\n createServerFnPlugin({\n framework: corePluginOpts.framework,\n directive,\n environments,\n }),\n\n TanStackServerFnPlugin({\n // This is the ID that will be available to look up and import\n // our server function manifest and resolve its module\n manifestVirtualImportId: VIRTUAL_MODULES.serverFnManifest,\n directive,\n generateFunctionId: startPluginOpts?.serverFns?.generateFunctionId,\n callers: [\n {\n envConsumer: 'client',\n getRuntimeCode: () =>\n `import { createClientRpc } from '@tanstack/${corePluginOpts.framework}-start/client-rpc'`,\n replacer: (d) => `createClientRpc('${d.functionId}')`,\n envName: VITE_ENVIRONMENT_NAMES.client,\n },\n {\n envConsumer: 'server' as const,\n getRuntimeCode: () =>\n `import { createSsrRpc } from '@tanstack/${corePluginOpts.framework}-start/ssr-rpc'`,\n envName: VITE_ENVIRONMENT_NAMES.server,\n replacer: (d: any) =>\n // When the function is client-referenced, it's in the manifest - use manifest lookup\n // When SSR is NOT the provider, always use manifest lookup (no import() for different env)\n // Otherwise, use the importer for functions only referenced on the server when SSR is the provider\n d.isClientReferenced || !ssrIsProvider\n ? `createSsrRpc('${d.functionId}')`\n : `createSsrRpc('${d.functionId}', () => import(${JSON.stringify(d.extractedFilename)}).then(m => m['${d.functionName}']))`,\n },\n ],\n provider: {\n getRuntimeCode: () =>\n `import { createServerRpc } from '@tanstack/${corePluginOpts.framework}-start/server-rpc'`,\n replacer: (d) => `createServerRpc('${d.functionId}', ${d.fn})`,\n envName: serverFnProviderEnv,\n },\n }),\n loadEnvPlugin(),\n startManifestPlugin({\n getClientBundle: () => getBundle(VITE_ENVIRONMENT_NAMES.client),\n getConfig,\n }),\n devServerPlugin({ getConfig }),\n previewServerPlugin(),\n {\n name: 'tanstack-start:core:capture-bundle',\n applyToEnvironment(e) {\n return (\n e.name === VITE_ENVIRONMENT_NAMES.client ||\n e.name === VITE_ENVIRONMENT_NAMES.server\n )\n },\n enforce: 'post',\n generateBundle(_options, bundle) {\n const environment = this.environment.name as ViteEnvironmentNames\n if (!Object.values(VITE_ENVIRONMENT_NAMES).includes(environment)) {\n throw new Error(`Unknown environment: ${environment}`)\n }\n capturedBundle[environment] = bundle\n },\n },\n ]\n}\n\nfunction defineReplaceEnv<TKey extends string, TValue extends string>(\n key: TKey,\n value: TValue,\n): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } {\n return {\n [`process.env.${key}`]: JSON.stringify(value),\n [`import.meta.env.${key}`]: JSON.stringify(value),\n } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue }\n}\n"],"names":["startConfig"],"mappings":"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"}
@@ -62,7 +62,7 @@ function startManifestPlugin(opts) {
62
62
  handler(id) {
63
63
  const { resolvedStartConfig } = opts.getConfig();
64
64
  if (id === resolvedModuleId) {
65
- if (this.environment.config.consumer !== "server") {
65
+ if (this.environment.name !== resolvedStartConfig.serverFnProviderEnv) {
66
66
  return `export default {}`;
67
67
  }
68
68
  if (this.environment.config.command === "serve") {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../../src/start-manifest-plugin/plugin.ts"],"sourcesContent":["import { joinURL } from 'ufo'\nimport { rootRouteId } from '@tanstack/router-core'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { tsrSplit } from '@tanstack/router-plugin'\nimport { resolveViteId } from '../utils'\nimport { ENTRY_POINTS } from '../constants'\nimport type { GetConfigFn } from '../plugin'\nimport type { PluginOption, Rollup } from 'vite'\nimport type { Manifest, RouterManagedTag } from '@tanstack/router-core'\n\nconst getCSSRecursively = (\n chunk: Rollup.OutputChunk,\n chunksByFileName: Map<string, Rollup.OutputChunk>,\n basePath: string,\n cache: Map<Rollup.OutputChunk, Array<RouterManagedTag>>,\n visited = new Set<Rollup.OutputChunk>(),\n) => {\n if (visited.has(chunk)) {\n return []\n }\n visited.add(chunk)\n const cachedResult = cache.get(chunk)\n if (cachedResult) {\n return cachedResult\n }\n const result: Array<RouterManagedTag> = []\n\n // Get all css imports from the file\n for (const cssFile of chunk.viteMetadata?.importedCss ?? []) {\n result.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n href: joinURL(basePath, cssFile),\n type: 'text/css',\n },\n })\n }\n\n // Recursively get CSS from imports\n for (const importedFileName of chunk.imports) {\n const importedChunk = chunksByFileName.get(importedFileName)\n if (importedChunk) {\n result.push(\n ...getCSSRecursively(\n importedChunk,\n chunksByFileName,\n basePath,\n cache,\n visited,\n ),\n )\n }\n }\n\n cache.set(chunk, result)\n return result\n}\n\nconst resolvedModuleId = resolveViteId(VIRTUAL_MODULES.startManifest)\nexport function startManifestPlugin(opts: {\n getClientBundle: () => Rollup.OutputBundle\n getConfig: GetConfigFn\n}): PluginOption {\n return {\n name: 'tanstack-start:start-manifest-plugin',\n enforce: 'pre',\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.startManifest) },\n handler(id) {\n if (id === VIRTUAL_MODULES.startManifest) {\n return resolvedModuleId\n }\n return undefined\n },\n },\n load: {\n filter: {\n id: new RegExp(resolvedModuleId),\n },\n handler(id) {\n const { resolvedStartConfig } = opts.getConfig()\n if (id === resolvedModuleId) {\n if (this.environment.config.consumer !== 'server') {\n // this will ultimately fail the build if the plugin is used outside the server environment\n // TODO: do we need special handling for `serve`?\n return `export default {}`\n }\n\n // If we're in development, return a dummy manifest\n if (this.environment.config.command === 'serve') {\n return `export const tsrStartManifest = () => ({\n routes: {},\n clientEntry: '${joinURL(resolvedStartConfig.viteAppBase, '@id', ENTRY_POINTS.client)}',\n })`\n }\n\n // This the manifest pulled from the generated route tree and later used by the Router.\n // i.e what's located in `src/routeTree.gen.ts`\n const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST\n\n const cssPerChunkCache = new Map<\n Rollup.OutputChunk,\n Array<RouterManagedTag>\n >()\n\n // This is where hydration will start, from when the SSR'd page reaches the browser.\n let entryFile: Rollup.OutputChunk | undefined\n\n const clientBundle = opts.getClientBundle()\n const chunksByFileName = new Map<string, Rollup.OutputChunk>()\n\n const routeChunks: Record<\n string /** fullPath of route file **/,\n Array<Rollup.OutputChunk>\n > = {}\n for (const bundleEntry of Object.values(clientBundle)) {\n if (bundleEntry.type === 'chunk') {\n chunksByFileName.set(bundleEntry.fileName, bundleEntry)\n if (bundleEntry.isEntry) {\n if (entryFile) {\n throw new Error(\n `multiple entries detected: ${entryFile.fileName} ${bundleEntry.fileName}`,\n )\n }\n entryFile = bundleEntry\n }\n const routePieces = bundleEntry.moduleIds.flatMap((m) => {\n const [id, query] = m.split('?')\n if (id === undefined) {\n throw new Error('expected id to be defined')\n }\n if (query === undefined) {\n return []\n }\n const searchParams = new URLSearchParams(query)\n const split = searchParams.get(tsrSplit)\n\n if (split !== null) {\n return {\n id,\n split,\n }\n }\n return []\n })\n if (routePieces.length > 0) {\n routePieces.forEach((r) => {\n let array = routeChunks[r.id]\n if (array === undefined) {\n array = []\n routeChunks[r.id] = array\n }\n array.push(bundleEntry)\n })\n }\n }\n }\n\n const manifest: Manifest = { routes: {} }\n // Add preloads to the routes from the vite manifest\n Object.entries(routeTreeRoutes).forEach(([routeId, v]) => {\n if (!v.filePath) {\n throw new Error(`expected filePath to be set for ${routeId}`)\n }\n const chunks = routeChunks[v.filePath]\n if (chunks) {\n chunks.forEach((chunk) => {\n // Map the relevant imports to their route paths,\n // so that it can be imported in the browser.\n const preloads = chunk.imports.map((d) => {\n const preloadPath = joinURL(\n resolvedStartConfig.viteAppBase,\n d,\n )\n return preloadPath\n })\n\n // Since this is the most important JS entry for the route,\n // it should be moved to the front of the preloads so that\n // it has the best chance of being loaded first.\n preloads.unshift(\n joinURL(resolvedStartConfig.viteAppBase, chunk.fileName),\n )\n\n const assets = getCSSRecursively(\n chunk,\n chunksByFileName,\n resolvedStartConfig.viteAppBase,\n cssPerChunkCache,\n )\n\n manifest.routes[routeId] = {\n ...v,\n assets,\n preloads,\n }\n })\n } else {\n manifest.routes[routeId] = v\n }\n })\n\n if (!entryFile) {\n throw new Error('No entry file found')\n }\n\n manifest.routes[rootRouteId] = manifest.routes[rootRouteId] || {}\n manifest.routes[rootRouteId].preloads = [\n joinURL(resolvedStartConfig.viteAppBase, entryFile.fileName),\n ...entryFile.imports.map((d) =>\n joinURL(resolvedStartConfig.viteAppBase, d),\n ),\n ]\n\n // Gather all the CSS files from the entry file in\n // the `css` key and add them to the root route\n const entryCssAssetsList = getCSSRecursively(\n entryFile,\n chunksByFileName,\n resolvedStartConfig.viteAppBase,\n cssPerChunkCache,\n )\n\n manifest.routes[rootRouteId].assets = [\n ...(manifest.routes[rootRouteId].assets || []),\n ...entryCssAssetsList,\n ]\n\n const recurseRoute = (\n route: {\n preloads?: Array<string>\n children?: Array<any>\n },\n seenPreloads = {} as Record<string, true>,\n ) => {\n route.preloads = route.preloads?.filter((preload) => {\n if (seenPreloads[preload]) {\n return false\n }\n seenPreloads[preload] = true\n return true\n })\n\n if (route.children) {\n route.children.forEach((child) => {\n const childRoute = manifest.routes[child]!\n recurseRoute(childRoute, { ...seenPreloads })\n })\n }\n }\n\n recurseRoute(manifest.routes[rootRouteId])\n\n // Filter out routes that have neither assets nor preloads\n Object.keys(manifest.routes).forEach((routeId) => {\n const route = manifest.routes[routeId]!\n const hasAssets = route.assets && route.assets.length > 0\n const hasPreloads = route.preloads && route.preloads.length > 0\n if (!hasAssets && !hasPreloads) {\n delete routeTreeRoutes[routeId]\n }\n })\n\n const startManifest = {\n routes: manifest.routes,\n clientEntry: joinURL(\n resolvedStartConfig.viteAppBase,\n entryFile.fileName,\n ),\n }\n\n return `export const tsrStartManifest = () => (${JSON.stringify(startManifest)})`\n }\n\n return undefined\n },\n },\n }\n}\n"],"names":["id"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../../src/start-manifest-plugin/plugin.ts"],"sourcesContent":["import { joinURL } from 'ufo'\nimport { rootRouteId } from '@tanstack/router-core'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { tsrSplit } from '@tanstack/router-plugin'\nimport { resolveViteId } from '../utils'\nimport { ENTRY_POINTS } from '../constants'\nimport type { GetConfigFn } from '../plugin'\nimport type { PluginOption, Rollup } from 'vite'\nimport type { Manifest, RouterManagedTag } from '@tanstack/router-core'\n\nconst getCSSRecursively = (\n chunk: Rollup.OutputChunk,\n chunksByFileName: Map<string, Rollup.OutputChunk>,\n basePath: string,\n cache: Map<Rollup.OutputChunk, Array<RouterManagedTag>>,\n visited = new Set<Rollup.OutputChunk>(),\n) => {\n if (visited.has(chunk)) {\n return []\n }\n visited.add(chunk)\n const cachedResult = cache.get(chunk)\n if (cachedResult) {\n return cachedResult\n }\n const result: Array<RouterManagedTag> = []\n\n // Get all css imports from the file\n for (const cssFile of chunk.viteMetadata?.importedCss ?? []) {\n result.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n href: joinURL(basePath, cssFile),\n type: 'text/css',\n },\n })\n }\n\n // Recursively get CSS from imports\n for (const importedFileName of chunk.imports) {\n const importedChunk = chunksByFileName.get(importedFileName)\n if (importedChunk) {\n result.push(\n ...getCSSRecursively(\n importedChunk,\n chunksByFileName,\n basePath,\n cache,\n visited,\n ),\n )\n }\n }\n\n cache.set(chunk, result)\n return result\n}\n\nconst resolvedModuleId = resolveViteId(VIRTUAL_MODULES.startManifest)\nexport function startManifestPlugin(opts: {\n getClientBundle: () => Rollup.OutputBundle\n getConfig: GetConfigFn\n}): PluginOption {\n return {\n name: 'tanstack-start:start-manifest-plugin',\n enforce: 'pre',\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.startManifest) },\n handler(id) {\n if (id === VIRTUAL_MODULES.startManifest) {\n return resolvedModuleId\n }\n return undefined\n },\n },\n load: {\n filter: {\n id: new RegExp(resolvedModuleId),\n },\n handler(id) {\n const { resolvedStartConfig } = opts.getConfig()\n if (id === resolvedModuleId) {\n if (\n this.environment.name !== resolvedStartConfig.serverFnProviderEnv\n ) {\n // this will ultimately fail the build if the plugin is used outside the provider environment\n // TODO: do we need special handling for `serve`?\n return `export default {}`\n }\n\n // If we're in development, return a dummy manifest\n if (this.environment.config.command === 'serve') {\n return `export const tsrStartManifest = () => ({\n routes: {},\n clientEntry: '${joinURL(resolvedStartConfig.viteAppBase, '@id', ENTRY_POINTS.client)}',\n })`\n }\n\n // This the manifest pulled from the generated route tree and later used by the Router.\n // i.e what's located in `src/routeTree.gen.ts`\n const routeTreeRoutes = globalThis.TSS_ROUTES_MANIFEST\n\n const cssPerChunkCache = new Map<\n Rollup.OutputChunk,\n Array<RouterManagedTag>\n >()\n\n // This is where hydration will start, from when the SSR'd page reaches the browser.\n let entryFile: Rollup.OutputChunk | undefined\n\n const clientBundle = opts.getClientBundle()\n const chunksByFileName = new Map<string, Rollup.OutputChunk>()\n\n const routeChunks: Record<\n string /** fullPath of route file **/,\n Array<Rollup.OutputChunk>\n > = {}\n for (const bundleEntry of Object.values(clientBundle)) {\n if (bundleEntry.type === 'chunk') {\n chunksByFileName.set(bundleEntry.fileName, bundleEntry)\n if (bundleEntry.isEntry) {\n if (entryFile) {\n throw new Error(\n `multiple entries detected: ${entryFile.fileName} ${bundleEntry.fileName}`,\n )\n }\n entryFile = bundleEntry\n }\n const routePieces = bundleEntry.moduleIds.flatMap((m) => {\n const [id, query] = m.split('?')\n if (id === undefined) {\n throw new Error('expected id to be defined')\n }\n if (query === undefined) {\n return []\n }\n const searchParams = new URLSearchParams(query)\n const split = searchParams.get(tsrSplit)\n\n if (split !== null) {\n return {\n id,\n split,\n }\n }\n return []\n })\n if (routePieces.length > 0) {\n routePieces.forEach((r) => {\n let array = routeChunks[r.id]\n if (array === undefined) {\n array = []\n routeChunks[r.id] = array\n }\n array.push(bundleEntry)\n })\n }\n }\n }\n\n const manifest: Manifest = { routes: {} }\n // Add preloads to the routes from the vite manifest\n Object.entries(routeTreeRoutes).forEach(([routeId, v]) => {\n if (!v.filePath) {\n throw new Error(`expected filePath to be set for ${routeId}`)\n }\n const chunks = routeChunks[v.filePath]\n if (chunks) {\n chunks.forEach((chunk) => {\n // Map the relevant imports to their route paths,\n // so that it can be imported in the browser.\n const preloads = chunk.imports.map((d) => {\n const preloadPath = joinURL(\n resolvedStartConfig.viteAppBase,\n d,\n )\n return preloadPath\n })\n\n // Since this is the most important JS entry for the route,\n // it should be moved to the front of the preloads so that\n // it has the best chance of being loaded first.\n preloads.unshift(\n joinURL(resolvedStartConfig.viteAppBase, chunk.fileName),\n )\n\n const assets = getCSSRecursively(\n chunk,\n chunksByFileName,\n resolvedStartConfig.viteAppBase,\n cssPerChunkCache,\n )\n\n manifest.routes[routeId] = {\n ...v,\n assets,\n preloads,\n }\n })\n } else {\n manifest.routes[routeId] = v\n }\n })\n\n if (!entryFile) {\n throw new Error('No entry file found')\n }\n\n manifest.routes[rootRouteId] = manifest.routes[rootRouteId] || {}\n manifest.routes[rootRouteId].preloads = [\n joinURL(resolvedStartConfig.viteAppBase, entryFile.fileName),\n ...entryFile.imports.map((d) =>\n joinURL(resolvedStartConfig.viteAppBase, d),\n ),\n ]\n\n // Gather all the CSS files from the entry file in\n // the `css` key and add them to the root route\n const entryCssAssetsList = getCSSRecursively(\n entryFile,\n chunksByFileName,\n resolvedStartConfig.viteAppBase,\n cssPerChunkCache,\n )\n\n manifest.routes[rootRouteId].assets = [\n ...(manifest.routes[rootRouteId].assets || []),\n ...entryCssAssetsList,\n ]\n\n const recurseRoute = (\n route: {\n preloads?: Array<string>\n children?: Array<any>\n },\n seenPreloads = {} as Record<string, true>,\n ) => {\n route.preloads = route.preloads?.filter((preload) => {\n if (seenPreloads[preload]) {\n return false\n }\n seenPreloads[preload] = true\n return true\n })\n\n if (route.children) {\n route.children.forEach((child) => {\n const childRoute = manifest.routes[child]!\n recurseRoute(childRoute, { ...seenPreloads })\n })\n }\n }\n\n recurseRoute(manifest.routes[rootRouteId])\n\n // Filter out routes that have neither assets nor preloads\n Object.keys(manifest.routes).forEach((routeId) => {\n const route = manifest.routes[routeId]!\n const hasAssets = route.assets && route.assets.length > 0\n const hasPreloads = route.preloads && route.preloads.length > 0\n if (!hasAssets && !hasPreloads) {\n delete routeTreeRoutes[routeId]\n }\n })\n\n const startManifest = {\n routes: manifest.routes,\n clientEntry: joinURL(\n resolvedStartConfig.viteAppBase,\n entryFile.fileName,\n ),\n }\n\n return `export const tsrStartManifest = () => (${JSON.stringify(startManifest)})`\n }\n\n return undefined\n },\n },\n }\n}\n"],"names":["id"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/start-plugin-core",
3
- "version": "1.142.0",
3
+ "version": "1.142.1",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -59,13 +59,13 @@
59
59
  "vitefu": "^1.1.1",
60
60
  "xmlbuilder2": "^4.0.0",
61
61
  "zod": "^3.24.2",
62
- "@tanstack/router-core": "1.141.8",
63
62
  "@tanstack/router-generator": "1.142.0",
64
- "@tanstack/server-functions-plugin": "1.141.3",
63
+ "@tanstack/router-core": "1.141.8",
65
64
  "@tanstack/router-utils": "1.141.0",
66
65
  "@tanstack/router-plugin": "1.142.0",
67
- "@tanstack/start-client-core": "1.141.8",
68
- "@tanstack/start-server-core": "1.141.8"
66
+ "@tanstack/server-functions-plugin": "1.142.1",
67
+ "@tanstack/start-client-core": "1.142.1",
68
+ "@tanstack/start-server-core": "1.142.1"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/babel__code-frame": "^7.0.6",
@@ -201,7 +201,15 @@ export class ServerFnCompiler {
201
201
  return this.moduleCache.delete(id)
202
202
  }
203
203
 
204
- public async compile({ code, id }: { code: string; id: string }) {
204
+ public async compile({
205
+ code,
206
+ id,
207
+ isProviderFile,
208
+ }: {
209
+ code: string
210
+ id: string
211
+ isProviderFile: boolean
212
+ }) {
205
213
  if (!this.initialized) {
206
214
  await this.init(id)
207
215
  }
@@ -257,6 +265,7 @@ export class ServerFnCompiler {
257
265
  env: this.options.env,
258
266
  code,
259
267
  directive: this.options.directive,
268
+ isProviderFile,
260
269
  })
261
270
  } else {
262
271
  handleCreateMiddleware(p.nodePath, { env: this.options.env })
@@ -11,6 +11,11 @@ export function handleCreateServerFn(
11
11
  env: 'client' | 'server'
12
12
  code: string
13
13
  directive: string
14
+ /**
15
+ * Whether this file is a provider file (extracted server function file).
16
+ * Only provider files should have the handler implementation as a second argument.
17
+ */
18
+ isProviderFile: boolean
14
19
  },
15
20
  ) {
16
21
  // Traverse the member expression and find the call expressions for
@@ -151,7 +156,11 @@ export function handleCreateServerFn(
151
156
  ),
152
157
  )
153
158
 
154
- if (opts.env === 'server') {
159
+ // Add the serverFn as a second argument on the server side,
160
+ // but ONLY for provider files (extracted server function files).
161
+ // Caller files must NOT have the second argument because the implementation is already available in the extracted chunk
162
+ // and including it would duplicate code
163
+ if (opts.env === 'server' && opts.isProviderFile) {
155
164
  callExpressionPaths.handler.node.arguments.push(handlerFn)
156
165
  }
157
166
  }
@@ -39,12 +39,18 @@ const getLookupConfigurationsForEnv = (
39
39
  }
40
40
  }
41
41
  const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
42
+
43
+ function buildDirectiveSplitParam(directive: string) {
44
+ return `tsr-directive-${directive.replace(/[^a-zA-Z0-9]/g, '-')}`
45
+ }
46
+
42
47
  export function createServerFnPlugin(opts: {
43
48
  framework: CompileStartFrameworkOptions
44
49
  directive: string
45
50
  environments: Array<{ name: string; type: 'client' | 'server' }>
46
51
  }): PluginOption {
47
52
  const compilers: Record<string /* envName */, ServerFnCompiler> = {}
53
+ const directiveSplitParam = buildDirectiveSplitParam(opts.directive)
48
54
 
49
55
  function perEnvServerFnPlugin(environment: {
50
56
  name: string
@@ -120,8 +126,10 @@ export function createServerFnPlugin(opts: {
120
126
  compilers[this.environment.name] = compiler
121
127
  }
122
128
 
129
+ const isProviderFile = id.includes(directiveSplitParam)
130
+
123
131
  id = cleanId(id)
124
- const result = await compiler.compile({ id, code })
132
+ const result = await compiler.compile({ id, code, isProviderFile })
125
133
  return result
126
134
  },
127
135
  },
package/src/plugin.ts CHANGED
@@ -50,11 +50,13 @@ export interface ResolvedStartConfig {
50
50
  routerFilePath: string
51
51
  srcDirectory: string
52
52
  viteAppBase: string
53
+ serverFnProviderEnv: string
53
54
  }
54
55
 
55
56
  export type GetConfigFn = () => {
56
57
  startConfig: TanStackStartOutputConfig
57
58
  resolvedStartConfig: ResolvedStartConfig
59
+ corePluginOpts: TanStackStartVitePluginCoreOptions
58
60
  }
59
61
 
60
62
  function isFullUrl(str: string): boolean {
@@ -70,12 +72,19 @@ export function TanStackStartVitePluginCore(
70
72
  corePluginOpts: TanStackStartVitePluginCoreOptions,
71
73
  startPluginOpts: TanStackStartInputConfig,
72
74
  ): Array<PluginOption> {
75
+ // Determine the provider environment for server functions
76
+ // If providerEnv is set, use that; otherwise default to SSR as the provider
77
+ const serverFnProviderEnv =
78
+ corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server
79
+ const ssrIsProvider = serverFnProviderEnv === VITE_ENVIRONMENT_NAMES.server
80
+
73
81
  const resolvedStartConfig: ResolvedStartConfig = {
74
82
  root: '',
75
83
  startFilePath: undefined,
76
84
  routerFilePath: '',
77
85
  srcDirectory: '',
78
86
  viteAppBase: '',
87
+ serverFnProviderEnv,
79
88
  }
80
89
 
81
90
  const directive = corePluginOpts.serverFn?.directive ?? 'use server'
@@ -92,7 +101,7 @@ export function TanStackStartVitePluginCore(
92
101
  resolvedStartConfig.root,
93
102
  )
94
103
  }
95
- return { startConfig, resolvedStartConfig }
104
+ return { startConfig, resolvedStartConfig, corePluginOpts }
96
105
  }
97
106
 
98
107
  const capturedBundle: Partial<
@@ -347,6 +356,22 @@ export function TanStackStartVitePluginCore(
347
356
  // Build the SSR bundle
348
357
  await builder.build(server)
349
358
  }
359
+
360
+ // If a custom provider environment is configured (not SSR),
361
+ // build it last so the manifest includes functions from all environments
362
+ if (!ssrIsProvider) {
363
+ const providerEnv = builder.environments[serverFnProviderEnv]
364
+ if (!providerEnv) {
365
+ throw new Error(
366
+ `Provider environment "${serverFnProviderEnv}" not found`,
367
+ )
368
+ }
369
+ if (!providerEnv.isBuilt) {
370
+ // Build the provider environment last
371
+ // This ensures all server functions are discovered from client/ssr builds
372
+ await builder.build(providerEnv)
373
+ }
374
+ }
350
375
  },
351
376
  },
352
377
  }
@@ -383,20 +408,24 @@ export function TanStackStartVitePluginCore(
383
408
  envName: VITE_ENVIRONMENT_NAMES.client,
384
409
  },
385
410
  {
386
- envConsumer: 'server',
411
+ envConsumer: 'server' as const,
387
412
  getRuntimeCode: () =>
388
413
  `import { createSsrRpc } from '@tanstack/${corePluginOpts.framework}-start/ssr-rpc'`,
389
414
  envName: VITE_ENVIRONMENT_NAMES.server,
390
- replacer: (d) => `createSsrRpc('${d.functionId}')`,
391
- getServerFnById: corePluginOpts.serverFn?.ssr?.getServerFnById,
415
+ replacer: (d: any) =>
416
+ // When the function is client-referenced, it's in the manifest - use manifest lookup
417
+ // When SSR is NOT the provider, always use manifest lookup (no import() for different env)
418
+ // Otherwise, use the importer for functions only referenced on the server when SSR is the provider
419
+ d.isClientReferenced || !ssrIsProvider
420
+ ? `createSsrRpc('${d.functionId}')`
421
+ : `createSsrRpc('${d.functionId}', () => import(${JSON.stringify(d.extractedFilename)}).then(m => m['${d.functionName}']))`,
392
422
  },
393
423
  ],
394
424
  provider: {
395
425
  getRuntimeCode: () =>
396
426
  `import { createServerRpc } from '@tanstack/${corePluginOpts.framework}-start/server-rpc'`,
397
427
  replacer: (d) => `createServerRpc('${d.functionId}', ${d.fn})`,
398
- envName:
399
- corePluginOpts.serverFn?.providerEnv || VITE_ENVIRONMENT_NAMES.server,
428
+ envName: serverFnProviderEnv,
400
429
  },
401
430
  }),
402
431
  loadEnvPlugin(),
@@ -81,8 +81,10 @@ export function startManifestPlugin(opts: {
81
81
  handler(id) {
82
82
  const { resolvedStartConfig } = opts.getConfig()
83
83
  if (id === resolvedModuleId) {
84
- if (this.environment.config.consumer !== 'server') {
85
- // this will ultimately fail the build if the plugin is used outside the server environment
84
+ if (
85
+ this.environment.name !== resolvedStartConfig.serverFnProviderEnv
86
+ ) {
87
+ // this will ultimately fail the build if the plugin is used outside the provider environment
86
88
  // TODO: do we need special handling for `serve`?
87
89
  return `export default {}`
88
90
  }