@tanstack/start-plugin-core 1.132.6 → 1.132.8
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.
- package/dist/esm/create-server-fn-plugin/compiler.d.ts +3 -1
- package/dist/esm/create-server-fn-plugin/compiler.js +22 -11
- package/dist/esm/create-server-fn-plugin/compiler.js.map +1 -1
- package/dist/esm/create-server-fn-plugin/plugin.js +33 -16
- package/dist/esm/create-server-fn-plugin/plugin.js.map +1 -1
- package/dist/esm/schema.d.ts +3 -3
- package/dist/esm/start-compiler-plugin/compilers.js +6 -0
- package/dist/esm/start-compiler-plugin/compilers.js.map +1 -1
- package/dist/esm/start-compiler-plugin/constants.d.ts +1 -1
- package/dist/esm/start-compiler-plugin/constants.js +2 -1
- package/dist/esm/start-compiler-plugin/constants.js.map +1 -1
- package/dist/esm/start-router-plugin/plugin.js +1 -0
- package/dist/esm/start-router-plugin/plugin.js.map +1 -1
- package/package.json +5 -5
- package/src/create-server-fn-plugin/compiler.ts +34 -14
- package/src/create-server-fn-plugin/plugin.ts +39 -17
- package/src/start-compiler-plugin/compilers.ts +6 -0
- package/src/start-compiler-plugin/constants.ts +1 -0
- package/src/start-router-plugin/plugin.ts +1 -0
|
@@ -22,7 +22,7 @@ type ExportEntry = {
|
|
|
22
22
|
targetId: string;
|
|
23
23
|
};
|
|
24
24
|
type Kind = 'None' | `Root` | `Builder` | LookupKind;
|
|
25
|
-
type LookupKind = 'ServerFn' | 'Middleware';
|
|
25
|
+
export type LookupKind = 'ServerFn' | 'Middleware';
|
|
26
26
|
export type LookupConfig = {
|
|
27
27
|
libName: string;
|
|
28
28
|
rootExport: string;
|
|
@@ -38,9 +38,11 @@ export declare class ServerFnCompiler {
|
|
|
38
38
|
private options;
|
|
39
39
|
private moduleCache;
|
|
40
40
|
private initialized;
|
|
41
|
+
private validLookupKinds;
|
|
41
42
|
constructor(options: {
|
|
42
43
|
env: 'client' | 'server';
|
|
43
44
|
lookupConfigurations: Array<LookupConfig>;
|
|
45
|
+
lookupKinds: Set<LookupKind>;
|
|
44
46
|
loadModule: (id: string) => Promise<void>;
|
|
45
47
|
resolveId: (id: string, importer?: string) => Promise<string | null>;
|
|
46
48
|
});
|
|
@@ -4,14 +4,20 @@ import babel__default from "@babel/core";
|
|
|
4
4
|
import { findReferencedIdentifiers, deadCodeElimination } from "babel-dead-code-elimination";
|
|
5
5
|
import { handleCreateServerFn } from "./handleCreateServerFn.js";
|
|
6
6
|
import { handleCreateMiddleware } from "./handleCreateMiddleware.js";
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const LookupSetup = {
|
|
8
|
+
ServerFn: { candidateCallIdentifier: /* @__PURE__ */ new Set(["handler"]) },
|
|
9
|
+
Middleware: {
|
|
10
|
+
candidateCallIdentifier: /* @__PURE__ */ new Set(["server", "client", "createMiddlewares"])
|
|
11
|
+
}
|
|
12
|
+
};
|
|
9
13
|
class ServerFnCompiler {
|
|
10
14
|
constructor(options) {
|
|
11
15
|
this.options = options;
|
|
16
|
+
this.validLookupKinds = options.lookupKinds;
|
|
12
17
|
}
|
|
13
18
|
moduleCache = /* @__PURE__ */ new Map();
|
|
14
19
|
initialized = false;
|
|
20
|
+
validLookupKinds;
|
|
15
21
|
async init(id) {
|
|
16
22
|
await Promise.all(
|
|
17
23
|
this.options.lookupConfigurations.map(async (config) => {
|
|
@@ -137,7 +143,7 @@ class ServerFnCompiler {
|
|
|
137
143
|
const toRewrite = [];
|
|
138
144
|
for (const handler of candidates) {
|
|
139
145
|
const kind = await this.resolveExprKind(handler, id);
|
|
140
|
-
if (validLookupKinds.
|
|
146
|
+
if (this.validLookupKinds.has(kind)) {
|
|
141
147
|
toRewrite.push({ callExpression: handler, kind });
|
|
142
148
|
}
|
|
143
149
|
}
|
|
@@ -179,7 +185,10 @@ class ServerFnCompiler {
|
|
|
179
185
|
const candidates = [];
|
|
180
186
|
for (const binding of bindings.values()) {
|
|
181
187
|
if (binding.type === "var") {
|
|
182
|
-
const handler = isCandidateCallExpression(
|
|
188
|
+
const handler = isCandidateCallExpression(
|
|
189
|
+
binding.init,
|
|
190
|
+
this.validLookupKinds
|
|
191
|
+
);
|
|
183
192
|
if (handler) {
|
|
184
193
|
candidates.push(handler);
|
|
185
194
|
}
|
|
@@ -260,7 +269,7 @@ class ServerFnCompiler {
|
|
|
260
269
|
if (calleeKind === `Root` || calleeKind === `Builder`) {
|
|
261
270
|
return `Builder`;
|
|
262
271
|
}
|
|
263
|
-
for (const kind of validLookupKinds) {
|
|
272
|
+
for (const kind of this.validLookupKinds) {
|
|
264
273
|
if (calleeKind === kind) {
|
|
265
274
|
return kind;
|
|
266
275
|
}
|
|
@@ -289,13 +298,13 @@ class ServerFnCompiler {
|
|
|
289
298
|
}
|
|
290
299
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {
|
|
291
300
|
const prop = callee.property.name;
|
|
292
|
-
if (
|
|
301
|
+
if (this.validLookupKinds.has("ServerFn") && LookupSetup["ServerFn"].candidateCallIdentifier.has(prop)) {
|
|
293
302
|
const base = await this.resolveExprKind(callee.object, fileId, visited);
|
|
294
303
|
if (base === "Root" || base === "Builder") {
|
|
295
304
|
return "ServerFn";
|
|
296
305
|
}
|
|
297
306
|
return "None";
|
|
298
|
-
} else if (
|
|
307
|
+
} else if (this.validLookupKinds.has("Middleware") && LookupSetup["Middleware"].candidateCallIdentifier.has(prop)) {
|
|
299
308
|
const base = await this.resolveExprKind(callee.object, fileId, visited);
|
|
300
309
|
if (base === "Root" || base === "Builder" || base === "Middleware") {
|
|
301
310
|
return "Middleware";
|
|
@@ -347,16 +356,18 @@ class ServerFnCompiler {
|
|
|
347
356
|
return cached;
|
|
348
357
|
}
|
|
349
358
|
}
|
|
350
|
-
function isCandidateCallExpression(node) {
|
|
359
|
+
function isCandidateCallExpression(node, lookupKinds) {
|
|
351
360
|
if (!t.isCallExpression(node)) return void 0;
|
|
352
361
|
const callee = node.callee;
|
|
353
362
|
if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {
|
|
354
363
|
return void 0;
|
|
355
364
|
}
|
|
356
|
-
|
|
357
|
-
|
|
365
|
+
for (const kind of lookupKinds) {
|
|
366
|
+
if (LookupSetup[kind].candidateCallIdentifier.has(callee.property.name)) {
|
|
367
|
+
return node;
|
|
368
|
+
}
|
|
358
369
|
}
|
|
359
|
-
return
|
|
370
|
+
return void 0;
|
|
360
371
|
}
|
|
361
372
|
export {
|
|
362
373
|
ServerFnCompiler
|
|
@@ -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\ntype LookupKind = 'ServerFn' | 'Middleware'\n\nconst validLookupKinds: Array<LookupKind> = ['ServerFn', 'Middleware']\nconst candidateCallIdentifier = ['handler', 'server', 'client']\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 constructor(\n private options: {\n env: 'client' | 'server'\n lookupConfigurations: Array<LookupConfig>\n loadModule: (id: string) => Promise<void>\n resolveId: (id: string, importer?: string) => Promise<string | null>\n },\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 (validLookupKinds.includes(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, { env: this.options.env, code })\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(binding.init)\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 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 (prop === 'handler') {\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 prop === 'client' ||\n prop === 'server' ||\n prop === 'createMiddleware'\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): 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 if (!candidateCallIdentifier.includes(callee.property.name)) {\n return undefined\n }\n\n return node\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 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, { env: this.options.env, code })\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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"}
|
|
@@ -3,6 +3,31 @@ import { ServerFnCompiler } from "./compiler.js";
|
|
|
3
3
|
function cleanId(id) {
|
|
4
4
|
return id.split("?")[0];
|
|
5
5
|
}
|
|
6
|
+
const LookupKindsPerEnv = {
|
|
7
|
+
client: /* @__PURE__ */ new Set(["Middleware", "ServerFn"]),
|
|
8
|
+
server: /* @__PURE__ */ new Set(["ServerFn"])
|
|
9
|
+
};
|
|
10
|
+
const getLookupConfigurationsForEnv = (env, framework) => {
|
|
11
|
+
const createServerFnConfig = {
|
|
12
|
+
libName: `@tanstack/${framework}-start`,
|
|
13
|
+
rootExport: "createServerFn"
|
|
14
|
+
};
|
|
15
|
+
if (env === "client") {
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
libName: `@tanstack/${framework}-start`,
|
|
19
|
+
rootExport: "createMiddleware"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
libName: `@tanstack/${framework}-start`,
|
|
23
|
+
rootExport: "createStart"
|
|
24
|
+
},
|
|
25
|
+
createServerFnConfig
|
|
26
|
+
];
|
|
27
|
+
} else {
|
|
28
|
+
return [createServerFnConfig];
|
|
29
|
+
}
|
|
30
|
+
};
|
|
6
31
|
function createServerFnPlugin(framework) {
|
|
7
32
|
const SERVER_FN_LOOKUP = "server-fn-module-lookup";
|
|
8
33
|
const compilers = {};
|
|
@@ -42,8 +67,9 @@ function createServerFnPlugin(framework) {
|
|
|
42
67
|
exclude: new RegExp(`${SERVER_FN_LOOKUP}$`)
|
|
43
68
|
},
|
|
44
69
|
code: {
|
|
45
|
-
//
|
|
46
|
-
|
|
70
|
+
// TODO apply this plugin with a different filter per environment so that .createMiddleware() calls are not scanned in server env
|
|
71
|
+
// only scan files that mention `.handler(` | `.createMiddleware()`
|
|
72
|
+
include: [/\.handler\(/, /.createMiddleware\(\)/]
|
|
47
73
|
}
|
|
48
74
|
},
|
|
49
75
|
async handler(code, id) {
|
|
@@ -56,20 +82,11 @@ function createServerFnPlugin(framework) {
|
|
|
56
82
|
})();
|
|
57
83
|
compiler = new ServerFnCompiler({
|
|
58
84
|
env,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
libName: `@tanstack/${framework}-start`,
|
|
66
|
-
rootExport: "createServerFn"
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
libName: `@tanstack/${framework}-start`,
|
|
70
|
-
rootExport: "createStart"
|
|
71
|
-
}
|
|
72
|
-
],
|
|
85
|
+
lookupKinds: LookupKindsPerEnv[env],
|
|
86
|
+
lookupConfigurations: getLookupConfigurationsForEnv(
|
|
87
|
+
env,
|
|
88
|
+
framework
|
|
89
|
+
),
|
|
73
90
|
loadModule: async (id2) => {
|
|
74
91
|
if (this.environment.mode === "build") {
|
|
75
92
|
const loaded = await this.load({ id: id2 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["../../../src/create-server-fn-plugin/plugin.ts"],"sourcesContent":["import { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { ServerFnCompiler } from './compiler'\nimport type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'\nimport type { ViteEnvironmentNames } from '../constants'\nimport type { PluginOption } from 'vite'\n\nfunction cleanId(id: string): string {\n return id.split('?')[0]!\n}\n\nexport function createServerFnPlugin(\n framework: CompileStartFrameworkOptions,\n): PluginOption {\n const SERVER_FN_LOOKUP = 'server-fn-module-lookup'\n\n const compilers: Partial<Record<ViteEnvironmentNames, ServerFnCompiler>> = {}\n return [\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 [\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ].includes(env.name as ViteEnvironmentNames)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler =\n compilers[this.environment.name as ViteEnvironmentNames]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n {\n name: 'tanstack-start-core::server-fn',\n enforce: 'pre',\n\n applyToEnvironment(env) {\n return [\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ].includes(env.name as ViteEnvironmentNames)\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n code: {\n // only scan files that mention `.handler(` | `.
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["../../../src/create-server-fn-plugin/plugin.ts"],"sourcesContent":["import { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { ServerFnCompiler } from './compiler'\nimport type { LookupConfig, LookupKind } from './compiler'\nimport type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'\nimport type { ViteEnvironmentNames } from '../constants'\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}\nexport function createServerFnPlugin(\n framework: CompileStartFrameworkOptions,\n): PluginOption {\n const SERVER_FN_LOOKUP = 'server-fn-module-lookup'\n\n const compilers: Partial<Record<ViteEnvironmentNames, ServerFnCompiler>> = {}\n return [\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 [\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ].includes(env.name as ViteEnvironmentNames)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler =\n compilers[this.environment.name as ViteEnvironmentNames]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n {\n name: 'tanstack-start-core::server-fn',\n enforce: 'pre',\n\n applyToEnvironment(env) {\n return [\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ].includes(env.name as ViteEnvironmentNames)\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n code: {\n // TODO apply this plugin with a different filter per environment so that .createMiddleware() calls are not scanned in server env\n // only scan files that mention `.handler(` | `.createMiddleware()`\n include: [/\\.handler\\(/, /.createMiddleware\\(\\)/],\n },\n },\n async handler(code, id) {\n let compiler =\n compilers[this.environment.name as ViteEnvironmentNames]\n if (!compiler) {\n const env =\n this.environment.name === VITE_ENVIRONMENT_NAMES.client\n ? 'client'\n : this.environment.name === VITE_ENVIRONMENT_NAMES.server\n ? 'server'\n : (() => {\n throw new Error(\n `Environment ${this.environment.name} not configured`,\n )\n })()\n\n compiler = new ServerFnCompiler({\n env,\n lookupKinds: LookupKindsPerEnv[env],\n lookupConfigurations: getLookupConfigurationsForEnv(\n env,\n 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 as ViteEnvironmentNames] = 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 =\n compilers[this.environment.name as ViteEnvironmentNames]\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"],"names":["id"],"mappings":"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"}
|
package/dist/esm/schema.d.ts
CHANGED
|
@@ -52,10 +52,10 @@ export declare function parseStartConfig(opts: z.input<typeof tanstackStartOptio
|
|
|
52
52
|
base: string;
|
|
53
53
|
dir: string;
|
|
54
54
|
};
|
|
55
|
-
srcDirectory: string;
|
|
56
55
|
start: {
|
|
57
56
|
entry?: string | undefined;
|
|
58
57
|
};
|
|
58
|
+
srcDirectory: string;
|
|
59
59
|
serverFns: {
|
|
60
60
|
base: string;
|
|
61
61
|
};
|
|
@@ -3026,10 +3026,10 @@ declare const tanstackStartOptionsSchema: z.ZodDefault<z.ZodOptional<z.ZodObject
|
|
|
3026
3026
|
base: string;
|
|
3027
3027
|
dir: string;
|
|
3028
3028
|
};
|
|
3029
|
-
srcDirectory: string;
|
|
3030
3029
|
start: {
|
|
3031
3030
|
entry?: string | undefined;
|
|
3032
3031
|
};
|
|
3032
|
+
srcDirectory: string;
|
|
3033
3033
|
router: {
|
|
3034
3034
|
entry?: string | undefined;
|
|
3035
3035
|
} & {
|
|
@@ -3352,10 +3352,10 @@ declare const tanstackStartOptionsSchema: z.ZodDefault<z.ZodOptional<z.ZodObject
|
|
|
3352
3352
|
base?: string | undefined;
|
|
3353
3353
|
dir?: string | undefined;
|
|
3354
3354
|
} | undefined;
|
|
3355
|
-
srcDirectory?: string | undefined;
|
|
3356
3355
|
start?: {
|
|
3357
3356
|
entry?: string | undefined;
|
|
3358
3357
|
} | undefined;
|
|
3358
|
+
srcDirectory?: string | undefined;
|
|
3359
3359
|
router?: ({
|
|
3360
3360
|
entry?: string | undefined;
|
|
3361
3361
|
} & {
|
|
@@ -2,6 +2,7 @@ import * as babel from "@babel/core";
|
|
|
2
2
|
import * as t from "@babel/types";
|
|
3
3
|
import { findReferencedIdentifiers, deadCodeElimination } from "babel-dead-code-elimination";
|
|
4
4
|
import { parseAst, generateFromAst } from "@tanstack/router-utils";
|
|
5
|
+
import { handleCreateMiddleware } from "../create-server-fn-plugin/handleCreateMiddleware.js";
|
|
5
6
|
import { transformFuncs } from "./constants.js";
|
|
6
7
|
import { handleCreateIsomorphicFnCallExpression } from "./isomorphicFn.js";
|
|
7
8
|
import { handleCreateClientOnlyFnCallExpression, handleCreateServerOnlyFnCallExpression } from "./envOnly.js";
|
|
@@ -22,6 +23,11 @@ function compileStartOutputFactory(framework) {
|
|
|
22
23
|
name: "createIsomorphicFn",
|
|
23
24
|
handleCallExpression: handleCreateIsomorphicFnCallExpression,
|
|
24
25
|
paths: []
|
|
26
|
+
},
|
|
27
|
+
createMiddleware: {
|
|
28
|
+
name: "createMiddleware",
|
|
29
|
+
handleCallExpression: handleCreateMiddleware,
|
|
30
|
+
paths: []
|
|
25
31
|
}
|
|
26
32
|
};
|
|
27
33
|
const ast = parseAst(opts);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compilers.js","sources":["../../../src/start-compiler-plugin/compilers.ts"],"sourcesContent":["import * as babel from '@babel/core'\nimport * as t from '@babel/types'\n\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport { transformFuncs } from './constants'\nimport { handleCreateIsomorphicFnCallExpression } from './isomorphicFn'\nimport {\n handleCreateClientOnlyFnCallExpression,\n handleCreateServerOnlyFnCallExpression,\n} from './envOnly'\nimport type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils'\n\nexport type CompileStartFrameworkOptions = 'react' | 'solid'\n\ntype Identifiers = { [K in (typeof transformFuncs)[number]]: IdentifierConfig }\n\nexport function compileStartOutputFactory(\n framework: CompileStartFrameworkOptions,\n) {\n return function compileStartOutput(opts: CompileOptions): GeneratorResult {\n const identifiers: Identifiers = {\n createServerOnlyFn: {\n name: 'createServerOnlyFn',\n handleCallExpression: handleCreateServerOnlyFnCallExpression,\n paths: [],\n },\n createClientOnlyFn: {\n name: 'createClientOnlyFn',\n handleCallExpression: handleCreateClientOnlyFnCallExpression,\n paths: [],\n },\n createIsomorphicFn: {\n name: 'createIsomorphicFn',\n handleCallExpression: handleCreateIsomorphicFnCallExpression,\n paths: [],\n },\n }\n\n const ast = parseAst(opts)\n\n const doDce = opts.dce ?? true\n // find referenced identifiers *before* we transform anything\n const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined\n\n babel.traverse(ast, {\n Program: {\n enter(programPath) {\n programPath.traverse({\n ImportDeclaration: (path) => {\n if (path.node.source.value !== `@tanstack/${framework}-start`) {\n return\n }\n\n // handle a destructured imports being renamed like \"import { createServerFn as myCreateServerFn } from '@tanstack/react-start';\"\n path.node.specifiers.forEach((specifier) => {\n transformFuncs.forEach((identifierKey) => {\n const identifier = identifiers[identifierKey]\n\n if (\n specifier.type === 'ImportSpecifier' &&\n specifier.imported.type === 'Identifier'\n ) {\n if (specifier.imported.name === identifierKey) {\n identifier.name = specifier.local.name\n }\n }\n\n // handle namespace imports like \"import * as TanStackStart from '@tanstack/react-start';\"\n if (specifier.type === 'ImportNamespaceSpecifier') {\n identifier.name = `${specifier.local.name}.${identifierKey}`\n }\n })\n })\n },\n CallExpression: (path) => {\n transformFuncs.forEach((identifierKey) => {\n // Check to see if the call expression is a call to the\n // identifiers[identifierKey].name\n if (\n t.isIdentifier(path.node.callee) &&\n path.node.callee.name === identifiers[identifierKey].name\n ) {\n // The identifier could be a call to the original function\n // in the source code. If this is case, we need to ignore it.\n // Check the scope to see if the identifier is a function declaration.\n // if it is, then we can ignore it.\n\n if (\n path.scope.getBinding(identifiers[identifierKey].name)?.path\n .node.type === 'FunctionDeclaration'\n ) {\n return\n }\n\n return identifiers[identifierKey].paths.push(path)\n }\n\n // handle namespace imports like \"import * as TanStackStart from '@tanstack/react-start';\"\n // which are then called like \"TanStackStart.createServerFn()\"\n if (t.isMemberExpression(path.node.callee)) {\n if (\n t.isIdentifier(path.node.callee.object) &&\n t.isIdentifier(path.node.callee.property)\n ) {\n const callname = [\n path.node.callee.object.name,\n path.node.callee.property.name,\n ].join('.')\n\n if (callname === identifiers[identifierKey].name) {\n identifiers[identifierKey].paths.push(path)\n }\n }\n }\n\n return\n })\n },\n })\n\n transformFuncs.forEach((identifierKey) => {\n identifiers[identifierKey].paths.forEach((path) => {\n identifiers[identifierKey].handleCallExpression(\n path as babel.NodePath<t.CallExpression>,\n opts,\n )\n })\n })\n },\n },\n })\n\n if (doDce) {\n deadCodeElimination(ast, refIdents)\n }\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: opts.filename,\n filename: opts.filename,\n })\n }\n}\n\nexport type CompileOptions = ParseAstOptions & {\n env: 'server' | 'client'\n dce?: boolean\n filename: string\n}\n\nexport type IdentifierConfig = {\n name: string\n handleCallExpression: (\n path: babel.NodePath<t.CallExpression>,\n opts: CompileOptions,\n ) => void\n paths: Array<babel.NodePath>\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compilers.js","sources":["../../../src/start-compiler-plugin/compilers.ts"],"sourcesContent":["import * as babel from '@babel/core'\nimport * as t from '@babel/types'\n\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport { handleCreateMiddleware } from '../create-server-fn-plugin/handleCreateMiddleware'\nimport { transformFuncs } from './constants'\nimport { handleCreateIsomorphicFnCallExpression } from './isomorphicFn'\nimport {\n handleCreateClientOnlyFnCallExpression,\n handleCreateServerOnlyFnCallExpression,\n} from './envOnly'\nimport type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils'\n\nexport type CompileStartFrameworkOptions = 'react' | 'solid'\n\ntype Identifiers = { [K in (typeof transformFuncs)[number]]: IdentifierConfig }\n\nexport function compileStartOutputFactory(\n framework: CompileStartFrameworkOptions,\n) {\n return function compileStartOutput(opts: CompileOptions): GeneratorResult {\n const identifiers: Identifiers = {\n createServerOnlyFn: {\n name: 'createServerOnlyFn',\n handleCallExpression: handleCreateServerOnlyFnCallExpression,\n paths: [],\n },\n createClientOnlyFn: {\n name: 'createClientOnlyFn',\n handleCallExpression: handleCreateClientOnlyFnCallExpression,\n paths: [],\n },\n createIsomorphicFn: {\n name: 'createIsomorphicFn',\n handleCallExpression: handleCreateIsomorphicFnCallExpression,\n paths: [],\n },\n createMiddleware: {\n name: 'createMiddleware',\n handleCallExpression: handleCreateMiddleware,\n paths: [],\n },\n }\n\n const ast = parseAst(opts)\n\n const doDce = opts.dce ?? true\n // find referenced identifiers *before* we transform anything\n const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined\n\n babel.traverse(ast, {\n Program: {\n enter(programPath) {\n programPath.traverse({\n ImportDeclaration: (path) => {\n if (path.node.source.value !== `@tanstack/${framework}-start`) {\n return\n }\n\n // handle a destructured imports being renamed like \"import { createServerFn as myCreateServerFn } from '@tanstack/react-start';\"\n path.node.specifiers.forEach((specifier) => {\n transformFuncs.forEach((identifierKey) => {\n const identifier = identifiers[identifierKey]\n\n if (\n specifier.type === 'ImportSpecifier' &&\n specifier.imported.type === 'Identifier'\n ) {\n if (specifier.imported.name === identifierKey) {\n identifier.name = specifier.local.name\n }\n }\n\n // handle namespace imports like \"import * as TanStackStart from '@tanstack/react-start';\"\n if (specifier.type === 'ImportNamespaceSpecifier') {\n identifier.name = `${specifier.local.name}.${identifierKey}`\n }\n })\n })\n },\n CallExpression: (path) => {\n transformFuncs.forEach((identifierKey) => {\n // Check to see if the call expression is a call to the\n // identifiers[identifierKey].name\n if (\n t.isIdentifier(path.node.callee) &&\n path.node.callee.name === identifiers[identifierKey].name\n ) {\n // The identifier could be a call to the original function\n // in the source code. If this is case, we need to ignore it.\n // Check the scope to see if the identifier is a function declaration.\n // if it is, then we can ignore it.\n\n if (\n path.scope.getBinding(identifiers[identifierKey].name)?.path\n .node.type === 'FunctionDeclaration'\n ) {\n return\n }\n\n return identifiers[identifierKey].paths.push(path)\n }\n\n // handle namespace imports like \"import * as TanStackStart from '@tanstack/react-start';\"\n // which are then called like \"TanStackStart.createServerFn()\"\n if (t.isMemberExpression(path.node.callee)) {\n if (\n t.isIdentifier(path.node.callee.object) &&\n t.isIdentifier(path.node.callee.property)\n ) {\n const callname = [\n path.node.callee.object.name,\n path.node.callee.property.name,\n ].join('.')\n\n if (callname === identifiers[identifierKey].name) {\n identifiers[identifierKey].paths.push(path)\n }\n }\n }\n\n return\n })\n },\n })\n\n transformFuncs.forEach((identifierKey) => {\n identifiers[identifierKey].paths.forEach((path) => {\n identifiers[identifierKey].handleCallExpression(\n path as babel.NodePath<t.CallExpression>,\n opts,\n )\n })\n })\n },\n },\n })\n\n if (doDce) {\n deadCodeElimination(ast, refIdents)\n }\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: opts.filename,\n filename: opts.filename,\n })\n }\n}\n\nexport type CompileOptions = ParseAstOptions & {\n env: 'server' | 'client'\n dce?: boolean\n filename: string\n}\n\nexport type IdentifierConfig = {\n name: string\n handleCallExpression: (\n path: babel.NodePath<t.CallExpression>,\n opts: CompileOptions,\n ) => void\n paths: Array<babel.NodePath>\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const transformFuncs: readonly ["createServerOnlyFn", "createClientOnlyFn", "createIsomorphicFn"];
|
|
1
|
+
export declare const transformFuncs: readonly ["createServerOnlyFn", "createClientOnlyFn", "createIsomorphicFn", "createMiddleware"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":["../../../src/start-compiler-plugin/constants.ts"],"sourcesContent":["export const transformFuncs = [\n 'createServerOnlyFn',\n 'createClientOnlyFn',\n 'createIsomorphicFn',\n] as const\n"],"names":[],"mappings":"AAAO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF;"}
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../../src/start-compiler-plugin/constants.ts"],"sourcesContent":["export const transformFuncs = [\n 'createServerOnlyFn',\n 'createClientOnlyFn',\n 'createIsomorphicFn',\n 'createMiddleware',\n] as const\n"],"names":[],"mappings":"AAAO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["../../../src/start-router-plugin/plugin.ts"],"sourcesContent":["import {\n tanStackRouterCodeSplitter,\n tanstackRouterAutoImport,\n tanstackRouterGenerator,\n} from '@tanstack/router-plugin/vite'\nimport { normalizePath } from 'vite'\nimport path from 'pathe'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { routesManifestPlugin } from './generator-plugins/routes-manifest-plugin'\nimport { pruneServerOnlySubtrees } from './pruneServerOnlySubtrees'\nimport { SERVER_PROP } from './constants'\nimport type {\n Generator,\n GeneratorPlugin,\n RouteNode,\n} from '@tanstack/router-generator'\nimport type { DevEnvironment, Plugin, PluginOption } from 'vite'\nimport type { TanStackStartInputConfig } from '../schema'\nimport type { GetConfigFn, TanStackStartVitePluginCoreOptions } from '../plugin'\n\nfunction isServerOnlyNode(node: RouteNode | undefined) {\n if (!node?.createFileRouteProps) {\n return false\n }\n return (\n node.createFileRouteProps.has(SERVER_PROP) &&\n node.createFileRouteProps.size === 1\n )\n}\n\nfunction moduleDeclaration({\n startFilePath,\n routerFilePath,\n corePluginOpts,\n generatedRouteTreePath,\n}: {\n startFilePath: string | undefined\n routerFilePath: string\n corePluginOpts: TanStackStartVitePluginCoreOptions\n generatedRouteTreePath: string\n}): string {\n function getImportPath(absolutePath: string) {\n let relativePath = path.relative(\n path.dirname(generatedRouteTreePath),\n absolutePath,\n )\n\n if (!relativePath.startsWith('.')) {\n relativePath = './' + relativePath\n }\n\n // convert to POSIX-style for ESM imports (important on Windows)\n relativePath = relativePath.split(path.sep).join('/')\n return relativePath\n }\n\n const result: Array<string> = [\n `import type { getRouter } from '${getImportPath(routerFilePath)}'`,\n ]\n if (startFilePath) {\n result.push(\n `import type { startInstance } from '${getImportPath(startFilePath)}'`,\n )\n }\n // make sure we import something from start to get the server route declaration merge\n else {\n result.push(\n `import type { createStart } from '@tanstack/${corePluginOpts.framework}-start'`,\n )\n }\n result.push(\n `declare module '@tanstack/${corePluginOpts.framework}-start' {\n interface Register {\n router: Awaited<ReturnType<typeof getRouter>>`,\n )\n if (startFilePath) {\n result.push(\n ` config: Awaited<ReturnType<typeof startInstance.getOptions>>`,\n )\n }\n result.push(` }\n}`)\n\n return result.join('\\n')\n}\n\nexport function tanStackStartRouter(\n startPluginOpts: TanStackStartInputConfig,\n getConfig: GetConfigFn,\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n): Array<PluginOption> {\n const getGeneratedRouteTreePath = () => {\n const { startConfig } = getConfig()\n return path.resolve(startConfig.router.generatedRouteTree)\n }\n\n let clientEnvironment: DevEnvironment | null = null\n function invalidate() {\n if (!clientEnvironment) {\n return\n }\n\n const mod = clientEnvironment.moduleGraph.getModuleById(\n getGeneratedRouteTreePath(),\n )\n if (mod) {\n clientEnvironment.moduleGraph.invalidateModule(mod)\n }\n clientEnvironment.hot.send({ type: 'full-reload', path: '*' })\n }\n\n let generatorInstance: Generator | null = null\n\n const clientTreeGeneratorPlugin: GeneratorPlugin = {\n name: 'start-client-tree-plugin',\n init({ generator }) {\n generatorInstance = generator\n },\n afterTransform({ node, prevNode }) {\n if (isServerOnlyNode(node) !== isServerOnlyNode(prevNode)) {\n invalidate()\n }\n },\n }\n\n let routeTreeFileFooter: Array<string> | null = null\n\n function getRouteTreeFileFooter() {\n if (routeTreeFileFooter) {\n return routeTreeFileFooter\n }\n const { startConfig, resolvedStartConfig } = getConfig()\n const ogRouteTreeFileFooter = startConfig.router.routeTreeFileFooter\n if (ogRouteTreeFileFooter) {\n if (Array.isArray(ogRouteTreeFileFooter)) {\n routeTreeFileFooter = ogRouteTreeFileFooter\n } else {\n routeTreeFileFooter = ogRouteTreeFileFooter()\n }\n }\n routeTreeFileFooter = [\n moduleDeclaration({\n generatedRouteTreePath: getGeneratedRouteTreePath(),\n corePluginOpts,\n startFilePath: resolvedStartConfig.startFilePath,\n routerFilePath: resolvedStartConfig.routerFilePath,\n }),\n ...(routeTreeFileFooter ?? []),\n ]\n return routeTreeFileFooter\n }\n\n let resolvedGeneratedRouteTreePath: string | null = null\n const clientTreePlugin: Plugin = {\n name: 'tanstack-start:route-tree-client-plugin',\n enforce: 'pre',\n applyToEnvironment: (env) => env.name === VITE_ENVIRONMENT_NAMES.client,\n configureServer(server) {\n clientEnvironment = server.environments[VITE_ENVIRONMENT_NAMES.client]\n },\n config() {\n type LoadObjectHook = Extract<\n typeof clientTreePlugin.load,\n { filter?: unknown }\n >\n resolvedGeneratedRouteTreePath = normalizePath(\n getGeneratedRouteTreePath(),\n )\n ;(clientTreePlugin.load as LoadObjectHook).filter = {\n id: { include: new RegExp(resolvedGeneratedRouteTreePath) },\n }\n },\n\n load: {\n filter: {\n // this will be set in the config hook above since it relies on `config` hook being called first\n },\n async handler() {\n if (!generatorInstance) {\n throw new Error('Generator instance not initialized')\n }\n const crawlingResult = await generatorInstance.getCrawlingResult()\n if (!crawlingResult) {\n throw new Error('Crawling result not available')\n }\n const prunedAcc = pruneServerOnlySubtrees(crawlingResult)\n const acc = {\n ...crawlingResult.acc,\n ...prunedAcc,\n }\n const buildResult = generatorInstance.buildRouteTree({\n ...crawlingResult,\n acc,\n config: {\n // importRoutesUsingAbsolutePaths: true,\n // addExtensions: true,\n disableTypes: true,\n enableRouteTreeFormatting: false,\n routeTreeFileHeader: [],\n routeTreeFileFooter: [],\n },\n })\n return { code: buildResult.routeTreeContent, map: null }\n },\n },\n }\n return [\n clientTreePlugin,\n tanstackRouterGenerator(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n target: corePluginOpts.framework,\n routeTreeFileFooter: getRouteTreeFileFooter,\n plugins: [clientTreeGeneratorPlugin, routesManifestPlugin()],\n }\n }),\n tanStackRouterCodeSplitter(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n codeSplittingOptions: {\n ...routerConfig.codeSplittingOptions,\n deleteNodes: ['ssr', 'server'],\n addHmr: true,\n },\n plugin: {\n vite: { environmentName: VITE_ENVIRONMENT_NAMES.client },\n },\n }\n }),\n tanStackRouterCodeSplitter(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n codeSplittingOptions: {\n ...routerConfig.codeSplittingOptions,\n addHmr: false,\n },\n plugin: {\n vite: { environmentName: VITE_ENVIRONMENT_NAMES.server },\n },\n }\n }),\n tanstackRouterAutoImport(startPluginOpts?.router),\n ]\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["../../../src/start-router-plugin/plugin.ts"],"sourcesContent":["import {\n tanStackRouterCodeSplitter,\n tanstackRouterAutoImport,\n tanstackRouterGenerator,\n} from '@tanstack/router-plugin/vite'\nimport { normalizePath } from 'vite'\nimport path from 'pathe'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { routesManifestPlugin } from './generator-plugins/routes-manifest-plugin'\nimport { pruneServerOnlySubtrees } from './pruneServerOnlySubtrees'\nimport { SERVER_PROP } from './constants'\nimport type {\n Generator,\n GeneratorPlugin,\n RouteNode,\n} from '@tanstack/router-generator'\nimport type { DevEnvironment, Plugin, PluginOption } from 'vite'\nimport type { TanStackStartInputConfig } from '../schema'\nimport type { GetConfigFn, TanStackStartVitePluginCoreOptions } from '../plugin'\n\nfunction isServerOnlyNode(node: RouteNode | undefined) {\n if (!node?.createFileRouteProps) {\n return false\n }\n return (\n node.createFileRouteProps.has(SERVER_PROP) &&\n node.createFileRouteProps.size === 1\n )\n}\n\nfunction moduleDeclaration({\n startFilePath,\n routerFilePath,\n corePluginOpts,\n generatedRouteTreePath,\n}: {\n startFilePath: string | undefined\n routerFilePath: string\n corePluginOpts: TanStackStartVitePluginCoreOptions\n generatedRouteTreePath: string\n}): string {\n function getImportPath(absolutePath: string) {\n let relativePath = path.relative(\n path.dirname(generatedRouteTreePath),\n absolutePath,\n )\n\n if (!relativePath.startsWith('.')) {\n relativePath = './' + relativePath\n }\n\n // convert to POSIX-style for ESM imports (important on Windows)\n relativePath = relativePath.split(path.sep).join('/')\n return relativePath\n }\n\n const result: Array<string> = [\n `import type { getRouter } from '${getImportPath(routerFilePath)}'`,\n ]\n if (startFilePath) {\n result.push(\n `import type { startInstance } from '${getImportPath(startFilePath)}'`,\n )\n }\n // make sure we import something from start to get the server route declaration merge\n else {\n result.push(\n `import type { createStart } from '@tanstack/${corePluginOpts.framework}-start'`,\n )\n }\n result.push(\n `declare module '@tanstack/${corePluginOpts.framework}-start' {\n interface Register {\n ssr: true\n router: Awaited<ReturnType<typeof getRouter>>`,\n )\n if (startFilePath) {\n result.push(\n ` config: Awaited<ReturnType<typeof startInstance.getOptions>>`,\n )\n }\n result.push(` }\n}`)\n\n return result.join('\\n')\n}\n\nexport function tanStackStartRouter(\n startPluginOpts: TanStackStartInputConfig,\n getConfig: GetConfigFn,\n corePluginOpts: TanStackStartVitePluginCoreOptions,\n): Array<PluginOption> {\n const getGeneratedRouteTreePath = () => {\n const { startConfig } = getConfig()\n return path.resolve(startConfig.router.generatedRouteTree)\n }\n\n let clientEnvironment: DevEnvironment | null = null\n function invalidate() {\n if (!clientEnvironment) {\n return\n }\n\n const mod = clientEnvironment.moduleGraph.getModuleById(\n getGeneratedRouteTreePath(),\n )\n if (mod) {\n clientEnvironment.moduleGraph.invalidateModule(mod)\n }\n clientEnvironment.hot.send({ type: 'full-reload', path: '*' })\n }\n\n let generatorInstance: Generator | null = null\n\n const clientTreeGeneratorPlugin: GeneratorPlugin = {\n name: 'start-client-tree-plugin',\n init({ generator }) {\n generatorInstance = generator\n },\n afterTransform({ node, prevNode }) {\n if (isServerOnlyNode(node) !== isServerOnlyNode(prevNode)) {\n invalidate()\n }\n },\n }\n\n let routeTreeFileFooter: Array<string> | null = null\n\n function getRouteTreeFileFooter() {\n if (routeTreeFileFooter) {\n return routeTreeFileFooter\n }\n const { startConfig, resolvedStartConfig } = getConfig()\n const ogRouteTreeFileFooter = startConfig.router.routeTreeFileFooter\n if (ogRouteTreeFileFooter) {\n if (Array.isArray(ogRouteTreeFileFooter)) {\n routeTreeFileFooter = ogRouteTreeFileFooter\n } else {\n routeTreeFileFooter = ogRouteTreeFileFooter()\n }\n }\n routeTreeFileFooter = [\n moduleDeclaration({\n generatedRouteTreePath: getGeneratedRouteTreePath(),\n corePluginOpts,\n startFilePath: resolvedStartConfig.startFilePath,\n routerFilePath: resolvedStartConfig.routerFilePath,\n }),\n ...(routeTreeFileFooter ?? []),\n ]\n return routeTreeFileFooter\n }\n\n let resolvedGeneratedRouteTreePath: string | null = null\n const clientTreePlugin: Plugin = {\n name: 'tanstack-start:route-tree-client-plugin',\n enforce: 'pre',\n applyToEnvironment: (env) => env.name === VITE_ENVIRONMENT_NAMES.client,\n configureServer(server) {\n clientEnvironment = server.environments[VITE_ENVIRONMENT_NAMES.client]\n },\n config() {\n type LoadObjectHook = Extract<\n typeof clientTreePlugin.load,\n { filter?: unknown }\n >\n resolvedGeneratedRouteTreePath = normalizePath(\n getGeneratedRouteTreePath(),\n )\n ;(clientTreePlugin.load as LoadObjectHook).filter = {\n id: { include: new RegExp(resolvedGeneratedRouteTreePath) },\n }\n },\n\n load: {\n filter: {\n // this will be set in the config hook above since it relies on `config` hook being called first\n },\n async handler() {\n if (!generatorInstance) {\n throw new Error('Generator instance not initialized')\n }\n const crawlingResult = await generatorInstance.getCrawlingResult()\n if (!crawlingResult) {\n throw new Error('Crawling result not available')\n }\n const prunedAcc = pruneServerOnlySubtrees(crawlingResult)\n const acc = {\n ...crawlingResult.acc,\n ...prunedAcc,\n }\n const buildResult = generatorInstance.buildRouteTree({\n ...crawlingResult,\n acc,\n config: {\n // importRoutesUsingAbsolutePaths: true,\n // addExtensions: true,\n disableTypes: true,\n enableRouteTreeFormatting: false,\n routeTreeFileHeader: [],\n routeTreeFileFooter: [],\n },\n })\n return { code: buildResult.routeTreeContent, map: null }\n },\n },\n }\n return [\n clientTreePlugin,\n tanstackRouterGenerator(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n target: corePluginOpts.framework,\n routeTreeFileFooter: getRouteTreeFileFooter,\n plugins: [clientTreeGeneratorPlugin, routesManifestPlugin()],\n }\n }),\n tanStackRouterCodeSplitter(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n codeSplittingOptions: {\n ...routerConfig.codeSplittingOptions,\n deleteNodes: ['ssr', 'server'],\n addHmr: true,\n },\n plugin: {\n vite: { environmentName: VITE_ENVIRONMENT_NAMES.client },\n },\n }\n }),\n tanStackRouterCodeSplitter(() => {\n const routerConfig = getConfig().startConfig.router\n return {\n ...routerConfig,\n codeSplittingOptions: {\n ...routerConfig.codeSplittingOptions,\n addHmr: false,\n },\n plugin: {\n vite: { environmentName: VITE_ENVIRONMENT_NAMES.server },\n },\n }\n }),\n tanstackRouterAutoImport(startPluginOpts?.router),\n ]\n}\n"],"names":[],"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.132.
|
|
3
|
+
"version": "1.132.8",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,12 +58,12 @@
|
|
|
58
58
|
"vitefu": "^1.1.1",
|
|
59
59
|
"xmlbuilder2": "^3.1.1",
|
|
60
60
|
"zod": "^3.24.2",
|
|
61
|
-
"@tanstack/router-core": "1.132.
|
|
62
|
-
"@tanstack/router-plugin": "1.132.
|
|
61
|
+
"@tanstack/router-core": "1.132.7",
|
|
62
|
+
"@tanstack/router-plugin": "1.132.7",
|
|
63
63
|
"@tanstack/router-utils": "1.132.0",
|
|
64
|
+
"@tanstack/router-generator": "1.132.7",
|
|
64
65
|
"@tanstack/server-functions-plugin": "1.132.0",
|
|
65
|
-
"@tanstack/
|
|
66
|
-
"@tanstack/start-server-core": "1.132.6"
|
|
66
|
+
"@tanstack/start-server-core": "1.132.7"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/babel__code-frame": "^7.0.6",
|
|
@@ -29,10 +29,18 @@ type ExportEntry =
|
|
|
29
29
|
|
|
30
30
|
type Kind = 'None' | `Root` | `Builder` | LookupKind
|
|
31
31
|
|
|
32
|
-
type LookupKind = 'ServerFn' | 'Middleware'
|
|
32
|
+
export type LookupKind = 'ServerFn' | 'Middleware'
|
|
33
|
+
|
|
34
|
+
const LookupSetup: Record<
|
|
35
|
+
LookupKind,
|
|
36
|
+
{ candidateCallIdentifier: Set<string> }
|
|
37
|
+
> = {
|
|
38
|
+
ServerFn: { candidateCallIdentifier: new Set(['handler']) },
|
|
39
|
+
Middleware: {
|
|
40
|
+
candidateCallIdentifier: new Set(['server', 'client', 'createMiddlewares']),
|
|
41
|
+
},
|
|
42
|
+
}
|
|
33
43
|
|
|
34
|
-
const validLookupKinds: Array<LookupKind> = ['ServerFn', 'Middleware']
|
|
35
|
-
const candidateCallIdentifier = ['handler', 'server', 'client']
|
|
36
44
|
export type LookupConfig = {
|
|
37
45
|
libName: string
|
|
38
46
|
rootExport: string
|
|
@@ -48,14 +56,18 @@ interface ModuleInfo {
|
|
|
48
56
|
export class ServerFnCompiler {
|
|
49
57
|
private moduleCache = new Map<string, ModuleInfo>()
|
|
50
58
|
private initialized = false
|
|
59
|
+
private validLookupKinds: Set<LookupKind>
|
|
51
60
|
constructor(
|
|
52
61
|
private options: {
|
|
53
62
|
env: 'client' | 'server'
|
|
54
63
|
lookupConfigurations: Array<LookupConfig>
|
|
64
|
+
lookupKinds: Set<LookupKind>
|
|
55
65
|
loadModule: (id: string) => Promise<void>
|
|
56
66
|
resolveId: (id: string, importer?: string) => Promise<string | null>
|
|
57
67
|
},
|
|
58
|
-
) {
|
|
68
|
+
) {
|
|
69
|
+
this.validLookupKinds = options.lookupKinds
|
|
70
|
+
}
|
|
59
71
|
|
|
60
72
|
private async init(id: string) {
|
|
61
73
|
await Promise.all(
|
|
@@ -207,7 +219,7 @@ export class ServerFnCompiler {
|
|
|
207
219
|
}> = []
|
|
208
220
|
for (const handler of candidates) {
|
|
209
221
|
const kind = await this.resolveExprKind(handler, id)
|
|
210
|
-
if (validLookupKinds.
|
|
222
|
+
if (this.validLookupKinds.has(kind as LookupKind)) {
|
|
211
223
|
toRewrite.push({ callExpression: handler, kind: kind as LookupKind })
|
|
212
224
|
}
|
|
213
225
|
}
|
|
@@ -261,7 +273,10 @@ export class ServerFnCompiler {
|
|
|
261
273
|
|
|
262
274
|
for (const binding of bindings.values()) {
|
|
263
275
|
if (binding.type === 'var') {
|
|
264
|
-
const handler = isCandidateCallExpression(
|
|
276
|
+
const handler = isCandidateCallExpression(
|
|
277
|
+
binding.init,
|
|
278
|
+
this.validLookupKinds,
|
|
279
|
+
)
|
|
265
280
|
if (handler) {
|
|
266
281
|
candidates.push(handler)
|
|
267
282
|
}
|
|
@@ -368,7 +383,7 @@ export class ServerFnCompiler {
|
|
|
368
383
|
if (calleeKind === `Root` || calleeKind === `Builder`) {
|
|
369
384
|
return `Builder`
|
|
370
385
|
}
|
|
371
|
-
for (const kind of validLookupKinds) {
|
|
386
|
+
for (const kind of this.validLookupKinds) {
|
|
372
387
|
if (calleeKind === kind) {
|
|
373
388
|
return kind
|
|
374
389
|
}
|
|
@@ -407,16 +422,18 @@ export class ServerFnCompiler {
|
|
|
407
422
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {
|
|
408
423
|
const prop = callee.property.name
|
|
409
424
|
|
|
410
|
-
if (
|
|
425
|
+
if (
|
|
426
|
+
this.validLookupKinds.has('ServerFn') &&
|
|
427
|
+
LookupSetup['ServerFn'].candidateCallIdentifier.has(prop)
|
|
428
|
+
) {
|
|
411
429
|
const base = await this.resolveExprKind(callee.object, fileId, visited)
|
|
412
430
|
if (base === 'Root' || base === 'Builder') {
|
|
413
431
|
return 'ServerFn'
|
|
414
432
|
}
|
|
415
433
|
return 'None'
|
|
416
434
|
} else if (
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
prop === 'createMiddleware'
|
|
435
|
+
this.validLookupKinds.has('Middleware') &&
|
|
436
|
+
LookupSetup['Middleware'].candidateCallIdentifier.has(prop)
|
|
420
437
|
) {
|
|
421
438
|
const base = await this.resolveExprKind(callee.object, fileId, visited)
|
|
422
439
|
if (base === 'Root' || base === 'Builder' || base === 'Middleware') {
|
|
@@ -483,6 +500,7 @@ export class ServerFnCompiler {
|
|
|
483
500
|
|
|
484
501
|
function isCandidateCallExpression(
|
|
485
502
|
node: t.Node | null | undefined,
|
|
503
|
+
lookupKinds: Set<LookupKind>,
|
|
486
504
|
): undefined | t.CallExpression {
|
|
487
505
|
if (!t.isCallExpression(node)) return undefined
|
|
488
506
|
|
|
@@ -490,9 +508,11 @@ function isCandidateCallExpression(
|
|
|
490
508
|
if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {
|
|
491
509
|
return undefined
|
|
492
510
|
}
|
|
493
|
-
|
|
494
|
-
|
|
511
|
+
for (const kind of lookupKinds) {
|
|
512
|
+
if (LookupSetup[kind].candidateCallIdentifier.has(callee.property.name)) {
|
|
513
|
+
return node
|
|
514
|
+
}
|
|
495
515
|
}
|
|
496
516
|
|
|
497
|
-
return
|
|
517
|
+
return undefined
|
|
498
518
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VITE_ENVIRONMENT_NAMES } from '../constants'
|
|
2
2
|
import { ServerFnCompiler } from './compiler'
|
|
3
|
+
import type { LookupConfig, LookupKind } from './compiler'
|
|
3
4
|
import type { CompileStartFrameworkOptions } from '../start-compiler-plugin/compilers'
|
|
4
5
|
import type { ViteEnvironmentNames } from '../constants'
|
|
5
6
|
import type { PluginOption } from 'vite'
|
|
@@ -8,6 +9,36 @@ function cleanId(id: string): string {
|
|
|
8
9
|
return id.split('?')[0]!
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
const LookupKindsPerEnv: Record<'client' | 'server', Set<LookupKind>> = {
|
|
13
|
+
client: new Set(['Middleware', 'ServerFn'] as const),
|
|
14
|
+
server: new Set(['ServerFn'] as const),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const getLookupConfigurationsForEnv = (
|
|
18
|
+
env: 'client' | 'server',
|
|
19
|
+
framework: CompileStartFrameworkOptions,
|
|
20
|
+
): Array<LookupConfig> => {
|
|
21
|
+
const createServerFnConfig: LookupConfig = {
|
|
22
|
+
libName: `@tanstack/${framework}-start`,
|
|
23
|
+
rootExport: 'createServerFn',
|
|
24
|
+
}
|
|
25
|
+
if (env === 'client') {
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
libName: `@tanstack/${framework}-start`,
|
|
29
|
+
rootExport: 'createMiddleware',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
libName: `@tanstack/${framework}-start`,
|
|
33
|
+
rootExport: 'createStart',
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
createServerFnConfig,
|
|
37
|
+
]
|
|
38
|
+
} else {
|
|
39
|
+
return [createServerFnConfig]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
11
42
|
export function createServerFnPlugin(
|
|
12
43
|
framework: CompileStartFrameworkOptions,
|
|
13
44
|
): PluginOption {
|
|
@@ -52,8 +83,9 @@ export function createServerFnPlugin(
|
|
|
52
83
|
exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),
|
|
53
84
|
},
|
|
54
85
|
code: {
|
|
55
|
-
//
|
|
56
|
-
|
|
86
|
+
// TODO apply this plugin with a different filter per environment so that .createMiddleware() calls are not scanned in server env
|
|
87
|
+
// only scan files that mention `.handler(` | `.createMiddleware()`
|
|
88
|
+
include: [/\.handler\(/, /.createMiddleware\(\)/],
|
|
57
89
|
},
|
|
58
90
|
},
|
|
59
91
|
async handler(code, id) {
|
|
@@ -73,21 +105,11 @@ export function createServerFnPlugin(
|
|
|
73
105
|
|
|
74
106
|
compiler = new ServerFnCompiler({
|
|
75
107
|
env,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{
|
|
83
|
-
libName: `@tanstack/${framework}-start`,
|
|
84
|
-
rootExport: 'createServerFn',
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
libName: `@tanstack/${framework}-start`,
|
|
88
|
-
rootExport: 'createStart',
|
|
89
|
-
},
|
|
90
|
-
],
|
|
108
|
+
lookupKinds: LookupKindsPerEnv[env],
|
|
109
|
+
lookupConfigurations: getLookupConfigurationsForEnv(
|
|
110
|
+
env,
|
|
111
|
+
framework,
|
|
112
|
+
),
|
|
91
113
|
loadModule: async (id: string) => {
|
|
92
114
|
if (this.environment.mode === 'build') {
|
|
93
115
|
const loaded = await this.load({ id })
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
findReferencedIdentifiers,
|
|
7
7
|
} from 'babel-dead-code-elimination'
|
|
8
8
|
import { generateFromAst, parseAst } from '@tanstack/router-utils'
|
|
9
|
+
import { handleCreateMiddleware } from '../create-server-fn-plugin/handleCreateMiddleware'
|
|
9
10
|
import { transformFuncs } from './constants'
|
|
10
11
|
import { handleCreateIsomorphicFnCallExpression } from './isomorphicFn'
|
|
11
12
|
import {
|
|
@@ -38,6 +39,11 @@ export function compileStartOutputFactory(
|
|
|
38
39
|
handleCallExpression: handleCreateIsomorphicFnCallExpression,
|
|
39
40
|
paths: [],
|
|
40
41
|
},
|
|
42
|
+
createMiddleware: {
|
|
43
|
+
name: 'createMiddleware',
|
|
44
|
+
handleCallExpression: handleCreateMiddleware,
|
|
45
|
+
paths: [],
|
|
46
|
+
},
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
const ast = parseAst(opts)
|