@tanstack/router-vite-plugin 1.26.14 → 1.26.21

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.
@@ -64,7 +64,7 @@ async function compileFile(opts) {
64
64
  visitor: {
65
65
  Program: {
66
66
  enter(programPath, state) {
67
- const splitUrl = `${constants.splitPrefix}:${state.filename}?${constants.splitPrefix}`;
67
+ const splitUrl = `${constants.splitPrefix}:${opts.filename}?${constants.splitPrefix}`;
68
68
  programPath.traverse(
69
69
  {
70
70
  CallExpression: (path) => {
@@ -1 +1 @@
1
- {"version":3,"file":"compilers.cjs","sources":["../../src/compilers.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport * as template from '@babel/template'\nimport * as babel from '@babel/core'\nimport { splitPrefix } from './constants'\nimport { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'\n\ntype SplitModulesById = Record<\n string,\n { id: string; node: t.FunctionExpression }\n>\n\ninterface State {\n filename: string\n opts: {\n minify: boolean\n root: string\n }\n imported: Record<string, boolean>\n refs: Set<any>\n serverIndex: number\n splitIndex: number\n splitModulesById: SplitModulesById\n}\n\nexport type CompileFn = (compileOpts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n}) => Promise<{\n code: string\n map: any\n}>\n\nexport function makeCompile(makeOpts: { root: string }) {\n return async (opts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n }): Promise<{\n code: string\n map: any\n }> => {\n const res = await babel.transform(opts.code, {\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [\n '@babel/plugin-syntax-typescript',\n {\n isTSX: true,\n },\n ],\n ...opts.getBabelConfig().plugins,\n ],\n root: makeOpts.root,\n filename: opts.filename,\n sourceMaps: true,\n })\n\n if (res?.code) {\n return {\n code: res.code,\n map: res.map,\n }\n }\n\n return {\n code: opts.code,\n map: null,\n }\n }\n}\n\nexport async function compileFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitUrl = `${splitPrefix}:${state.filename}?${splitPrefix}`\n\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (\n path.node.callee.name === 'createRoute' ||\n path.node.callee.name === 'createFileRoute'\n ) {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n let found = false\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === 'component') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyRouteComponent } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitComponentImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyRouteComponent($$splitComponentImporter, 'component')`,\n )() as any\n\n programPath.pushContainer('body', [\n template.smart(\n `function DummyComponent() { return null }`,\n )() as t.Statement,\n ])\n\n found = true\n } else if (prop.key.name === 'loader') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyFn } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitLoaderImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyFn($$splitLoaderImporter, 'loader')`,\n )() as any\n\n found = true\n }\n }\n }\n })\n }\n\n if (found as boolean) {\n programPath.pushContainer('body', [\n template.smart(\n `function TSR_Dummy_Component() {}`,\n )() as t.Statement,\n ])\n }\n }\n }\n }\n },\n },\n state,\n )\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n\n// Reusable function to get literal value or resolve variable to literal\nfunction resolveIdentifier(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (\n binding\n // && binding.kind === 'const'\n ) {\n const declarator = binding.path.node\n if (t.isObjectExpression(declarator.init)) {\n return declarator.init\n } else if (t.isFunctionDeclaration(declarator.init)) {\n return declarator.init\n }\n }\n return undefined\n }\n\n return node\n}\n\nfunction removeIdentifierLiteral(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (binding) {\n binding.path.remove()\n }\n }\n}\n\nconst splitNodeTypes = ['component', 'loader'] as const\ntype SplitNodeType = (typeof splitNodeTypes)[number]\n\nexport async function splitFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n // ref: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitNodesByType: Record<\n SplitNodeType,\n t.Node | undefined\n > = {\n component: undefined,\n loader: undefined,\n }\n\n // Find the node\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (path.node.callee.name === 'createFileRoute') {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n splitNodeTypes.forEach((type) => {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === type) {\n splitNodesByType[type] = prop.value\n }\n }\n })\n }\n })\n\n // Remove all of the options\n options.properties = []\n }\n }\n }\n }\n },\n },\n state,\n )\n\n splitNodeTypes.forEach((splitType) => {\n let splitNode = splitNodesByType[splitType]\n\n if (!splitNode) {\n return\n }\n\n while (t.isIdentifier(splitNode)) {\n const binding = programPath.scope.getBinding(\n splitNode.name,\n )\n splitNode = binding?.path.node\n }\n\n // Add the node to the program\n if (splitNode) {\n if (t.isFunctionDeclaration(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n t.functionExpression(\n splitNode.id || null, // Anonymize the function expression\n splitNode.params,\n splitNode.body,\n splitNode.generator,\n splitNode.async,\n ),\n ),\n ]),\n )\n } else if (\n t.isFunctionExpression(splitNode) ||\n t.isArrowFunctionExpression(splitNode)\n ) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode as any,\n ),\n ]),\n )\n } else if (t.isImportSpecifier(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode.local,\n ),\n ]),\n )\n } else {\n console.log(splitNode)\n throw new Error(\n `Unexpected splitNode type: ${splitNode.type}`,\n )\n }\n }\n\n // If the splitNode exists at the top of the program\n // then we need to remove that copy\n programPath.node.body = programPath.node.body.filter(\n (node) => {\n // console.log(node)\n return node !== splitNode\n },\n )\n\n // Export the node\n programPath.pushContainer('body', [\n t.exportNamedDeclaration(null, [\n t.exportSpecifier(\n t.identifier(splitType),\n t.identifier(splitType),\n ),\n ]),\n ])\n })\n\n // convert exports to imports from the original file\n programPath.traverse({\n ExportNamedDeclaration(path) {\n // e.g. export const x = 1 or export { x }\n // becomes\n // import { x } from '${opts.id}'\n\n if (path.node.declaration) {\n if (t.isVariableDeclaration(path.node.declaration)) {\n path.replaceWith(\n t.importDeclaration(\n path.node.declaration.declarations.map((decl) =>\n t.importSpecifier(\n t.identifier((decl.id as any).name),\n t.identifier((decl.id as any).name),\n ),\n ),\n t.stringLiteral(\n opts.filename.split(\n `?${splitPrefix}`,\n )[0] as string,\n ),\n ),\n )\n }\n }\n },\n })\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n"],"names":["babel","splitPrefix","t","template","eliminateUnreferencedIdentifiers"],"mappings":"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"}
1
+ {"version":3,"file":"compilers.cjs","sources":["../../src/compilers.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport * as template from '@babel/template'\nimport * as babel from '@babel/core'\nimport { splitPrefix } from './constants'\nimport { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'\n\ntype SplitModulesById = Record<\n string,\n { id: string; node: t.FunctionExpression }\n>\n\ninterface State {\n filename: string\n opts: {\n minify: boolean\n root: string\n }\n imported: Record<string, boolean>\n refs: Set<any>\n serverIndex: number\n splitIndex: number\n splitModulesById: SplitModulesById\n}\n\nexport type CompileFn = (compileOpts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n}) => Promise<{\n code: string\n map: any\n}>\n\nexport function makeCompile(makeOpts: { root: string }) {\n return async (opts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n }): Promise<{\n code: string\n map: any\n }> => {\n const res = await babel.transform(opts.code, {\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [\n '@babel/plugin-syntax-typescript',\n {\n isTSX: true,\n },\n ],\n ...opts.getBabelConfig().plugins,\n ],\n root: makeOpts.root,\n filename: opts.filename,\n sourceMaps: true,\n })\n\n if (res?.code) {\n return {\n code: res.code,\n map: res.map,\n }\n }\n\n return {\n code: opts.code,\n map: null,\n }\n }\n}\n\nexport async function compileFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`\n\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (\n path.node.callee.name === 'createRoute' ||\n path.node.callee.name === 'createFileRoute'\n ) {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n let found = false\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === 'component') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyRouteComponent } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitComponentImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyRouteComponent($$splitComponentImporter, 'component')`,\n )() as any\n\n programPath.pushContainer('body', [\n template.smart(\n `function DummyComponent() { return null }`,\n )() as t.Statement,\n ])\n\n found = true\n } else if (prop.key.name === 'loader') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyFn } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitLoaderImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyFn($$splitLoaderImporter, 'loader')`,\n )() as any\n\n found = true\n }\n }\n }\n })\n }\n\n if (found as boolean) {\n programPath.pushContainer('body', [\n template.smart(\n `function TSR_Dummy_Component() {}`,\n )() as t.Statement,\n ])\n }\n }\n }\n }\n },\n },\n state,\n )\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n\n// Reusable function to get literal value or resolve variable to literal\nfunction resolveIdentifier(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (\n binding\n // && binding.kind === 'const'\n ) {\n const declarator = binding.path.node\n if (t.isObjectExpression(declarator.init)) {\n return declarator.init\n } else if (t.isFunctionDeclaration(declarator.init)) {\n return declarator.init\n }\n }\n return undefined\n }\n\n return node\n}\n\nfunction removeIdentifierLiteral(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (binding) {\n binding.path.remove()\n }\n }\n}\n\nconst splitNodeTypes = ['component', 'loader'] as const\ntype SplitNodeType = (typeof splitNodeTypes)[number]\n\nexport async function splitFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n // ref: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitNodesByType: Record<\n SplitNodeType,\n t.Node | undefined\n > = {\n component: undefined,\n loader: undefined,\n }\n\n // Find the node\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (path.node.callee.name === 'createFileRoute') {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n splitNodeTypes.forEach((type) => {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === type) {\n splitNodesByType[type] = prop.value\n }\n }\n })\n }\n })\n\n // Remove all of the options\n options.properties = []\n }\n }\n }\n }\n },\n },\n state,\n )\n\n splitNodeTypes.forEach((splitType) => {\n let splitNode = splitNodesByType[splitType]\n\n if (!splitNode) {\n return\n }\n\n while (t.isIdentifier(splitNode)) {\n const binding = programPath.scope.getBinding(\n splitNode.name,\n )\n splitNode = binding?.path.node\n }\n\n // Add the node to the program\n if (splitNode) {\n if (t.isFunctionDeclaration(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n t.functionExpression(\n splitNode.id || null, // Anonymize the function expression\n splitNode.params,\n splitNode.body,\n splitNode.generator,\n splitNode.async,\n ),\n ),\n ]),\n )\n } else if (\n t.isFunctionExpression(splitNode) ||\n t.isArrowFunctionExpression(splitNode)\n ) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode as any,\n ),\n ]),\n )\n } else if (t.isImportSpecifier(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode.local,\n ),\n ]),\n )\n } else {\n console.log(splitNode)\n throw new Error(\n `Unexpected splitNode type: ${splitNode.type}`,\n )\n }\n }\n\n // If the splitNode exists at the top of the program\n // then we need to remove that copy\n programPath.node.body = programPath.node.body.filter(\n (node) => {\n // console.log(node)\n return node !== splitNode\n },\n )\n\n // Export the node\n programPath.pushContainer('body', [\n t.exportNamedDeclaration(null, [\n t.exportSpecifier(\n t.identifier(splitType),\n t.identifier(splitType),\n ),\n ]),\n ])\n })\n\n // convert exports to imports from the original file\n programPath.traverse({\n ExportNamedDeclaration(path) {\n // e.g. export const x = 1 or export { x }\n // becomes\n // import { x } from '${opts.id}'\n\n if (path.node.declaration) {\n if (t.isVariableDeclaration(path.node.declaration)) {\n path.replaceWith(\n t.importDeclaration(\n path.node.declaration.declarations.map((decl) =>\n t.importSpecifier(\n t.identifier((decl.id as any).name),\n t.identifier((decl.id as any).name),\n ),\n ),\n t.stringLiteral(\n opts.filename.split(\n `?${splitPrefix}`,\n )[0] as string,\n ),\n ),\n )\n }\n }\n },\n })\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n"],"names":["babel","splitPrefix","t","template","eliminateUnreferencedIdentifiers"],"mappings":"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"}
@@ -23,23 +23,32 @@ function TanStackRouterVite(inlineConfig = {}) {
23
23
  TanStackRouterViteCodeSplitter(inlineConfig)
24
24
  ];
25
25
  }
26
+ let lock = false;
26
27
  function TanStackRouterViteGenerator(inlineConfig = {}) {
27
28
  let ROOT = process.cwd();
28
29
  let userConfig;
29
30
  const generate = async () => {
31
+ if (lock) {
32
+ return;
33
+ }
34
+ lock = true;
30
35
  try {
31
36
  await routerGenerator.generator(userConfig);
32
37
  } catch (err) {
33
38
  console.error(err);
34
39
  console.info();
35
40
  }
41
+ lock = false;
36
42
  };
37
- const handleFile = async (file) => {
43
+ const handleFile = async (file, event) => {
38
44
  const filePath = path.normalize(file);
39
45
  if (filePath === path.join(ROOT, CONFIG_FILE_NAME)) {
40
46
  userConfig = await getConfig(inlineConfig, ROOT);
41
47
  return;
42
48
  }
49
+ if (event === "update" && filePath === path.resolve(userConfig.generatedRouteTree)) {
50
+ return;
51
+ }
43
52
  const routesDirectoryPath = path.isAbsolute(userConfig.routesDirectory) ? userConfig.routesDirectory : path.join(ROOT, userConfig.routesDirectory);
44
53
  if (filePath.startsWith(routesDirectoryPath)) {
45
54
  await generate();
@@ -57,7 +66,7 @@ function TanStackRouterViteGenerator(inlineConfig = {}) {
57
66
  watchChange: async (file, context) => {
58
67
  if (userConfig.enableRouteGeneration ?? true) {
59
68
  if (["create", "update", "delete"].includes(context.event)) {
60
- await handleFile(file);
69
+ await handleFile(file, context.event);
61
70
  }
62
71
  }
63
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { isAbsolute, join, normalize } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport { z } from 'zod'\nimport {\n generator,\n configSchema as generatorConfigSchema,\n getConfig as getGeneratorConfig,\n} from '@tanstack/router-generator'\nimport { compileFile, makeCompile, splitFile } from './compilers'\nimport { splitPrefix } from './constants'\nimport type { Plugin } from 'vite'\n\nexport const configSchema = generatorConfigSchema.extend({\n enableRouteGeneration: z.boolean().optional(),\n experimental: z\n .object({\n enableCodeSplitting: z.boolean().optional(),\n })\n .optional(),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nconst CONFIG_FILE_NAME = 'tsr.config.json'\nconst debug = false as any\n\nconst getConfig = async (inlineConfig: Partial<Config>, root: string) => {\n const config = await getGeneratorConfig(inlineConfig, root)\n\n return configSchema.parse({ ...inlineConfig, ...config })\n}\n\nexport function TanStackRouterVite(\n inlineConfig: Partial<Config> = {},\n): Array<Plugin> {\n return [\n TanStackRouterViteGenerator(inlineConfig),\n TanStackRouterViteCodeSplitter(inlineConfig),\n ]\n}\n\nexport function TanStackRouterViteGenerator(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n const generate = async () => {\n try {\n await generator(userConfig)\n } catch (err) {\n console.error(err)\n console.info()\n }\n }\n\n const handleFile = async (file: string) => {\n const filePath = normalize(file)\n if (filePath === join(ROOT, CONFIG_FILE_NAME)) {\n userConfig = await getConfig(inlineConfig, ROOT)\n return\n }\n const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)\n ? userConfig.routesDirectory\n : join(ROOT, userConfig.routesDirectory)\n if (filePath.startsWith(routesDirectoryPath)) {\n await generate()\n }\n }\n\n return {\n name: 'vite-plugin-tanstack-router-generator',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n\n if (userConfig.enableRouteGeneration ?? true) {\n await generate()\n }\n },\n watchChange: async (file, context) => {\n if (userConfig.enableRouteGeneration ?? true) {\n if (['create', 'update', 'delete'].includes(context.event)) {\n await handleFile(file)\n }\n }\n },\n }\n}\n\nfunction fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {\n const routesDirectoryPath = isAbsolute(routesDirectory)\n ? routesDirectory\n : join(process.cwd(), routesDirectory)\n\n return filePath.startsWith(routesDirectoryPath)\n}\n\nexport function TanStackRouterViteCodeSplitter(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n return {\n name: 'vite-plugin-tanstack-router-code-splitter',\n enforce: 'pre',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n },\n resolveId(source) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n if (source.startsWith(splitPrefix + ':')) {\n return source.replace(splitPrefix + ':', '')\n }\n return null\n },\n async transform(code, id, transformOptions) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n id = fileURLToPath(url).replace(/\\\\/g, '/')\n\n const compile = makeCompile({\n root: ROOT,\n })\n\n if (id.includes(splitPrefix)) {\n if (debug) console.info('Splitting route: ', id)\n // const ref = new URLSearchParams(id.split('?')[1]).get('ref') || ''\n\n const compiled = await splitFile({\n code,\n compile,\n filename: id,\n // ref,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Split Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n } else if (\n fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&\n (code.includes('createRoute(') || code.includes('createFileRoute('))\n ) {\n if (code.includes('@react-refresh')) {\n throw new Error(\n `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/router-vite-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: \ne.g.\n\nplugins: [\n TanStackRouterVite(), // Place this before viteReact()\n viteReact(),\n]\n`,\n )\n }\n\n if (debug) console.info('Handling createRoute: ', id)\n const compiled = await compileFile({\n code,\n compile,\n filename: id,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Compiled Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n }\n\n return null\n },\n }\n}\n"],"names":["generatorConfigSchema","z","getGeneratorConfig","generator","normalize","join","isAbsolute","splitPrefix","url","pathToFileURL","fileURLToPath","makeCompile","splitFile","compileFile"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { isAbsolute, join, normalize, resolve } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport { z } from 'zod'\nimport {\n generator,\n configSchema as generatorConfigSchema,\n getConfig as getGeneratorConfig,\n} from '@tanstack/router-generator'\nimport { compileFile, makeCompile, splitFile } from './compilers'\nimport { splitPrefix } from './constants'\nimport type { Plugin } from 'vite'\n\nexport const configSchema = generatorConfigSchema.extend({\n enableRouteGeneration: z.boolean().optional(),\n experimental: z\n .object({\n enableCodeSplitting: z.boolean().optional(),\n })\n .optional(),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nconst CONFIG_FILE_NAME = 'tsr.config.json'\nconst debug = false as any\n\nconst getConfig = async (inlineConfig: Partial<Config>, root: string) => {\n const config = await getGeneratorConfig(inlineConfig, root)\n\n return configSchema.parse({ ...inlineConfig, ...config })\n}\n\nexport function TanStackRouterVite(\n inlineConfig: Partial<Config> = {},\n): Array<Plugin> {\n return [\n TanStackRouterViteGenerator(inlineConfig),\n TanStackRouterViteCodeSplitter(inlineConfig),\n ]\n}\n\nlet lock = false\n\nexport function TanStackRouterViteGenerator(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n const generate = async () => {\n if (lock) {\n return\n }\n lock = true\n try {\n await generator(userConfig)\n } catch (err) {\n console.error(err)\n console.info()\n }\n lock = false\n }\n\n const handleFile = async (\n file: string,\n event: 'create' | 'update' | 'delete',\n ) => {\n const filePath = normalize(file)\n if (filePath === join(ROOT, CONFIG_FILE_NAME)) {\n userConfig = await getConfig(inlineConfig, ROOT)\n return\n }\n if (\n event === 'update' &&\n filePath === resolve(userConfig.generatedRouteTree)\n ) {\n // skip generating routes if the generated route tree is updated\n return\n }\n const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)\n ? userConfig.routesDirectory\n : join(ROOT, userConfig.routesDirectory)\n if (filePath.startsWith(routesDirectoryPath)) {\n await generate()\n }\n }\n\n return {\n name: 'vite-plugin-tanstack-router-generator',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n\n if (userConfig.enableRouteGeneration ?? true) {\n await generate()\n }\n },\n watchChange: async (file, context) => {\n if (userConfig.enableRouteGeneration ?? true) {\n if (['create', 'update', 'delete'].includes(context.event)) {\n await handleFile(file, context.event)\n }\n }\n },\n }\n}\n\nfunction fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {\n const routesDirectoryPath = isAbsolute(routesDirectory)\n ? routesDirectory\n : join(process.cwd(), routesDirectory)\n\n return filePath.startsWith(routesDirectoryPath)\n}\n\nexport function TanStackRouterViteCodeSplitter(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n return {\n name: 'vite-plugin-tanstack-router-code-splitter',\n enforce: 'pre',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n },\n resolveId(source) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n if (source.startsWith(splitPrefix + ':')) {\n return source.replace(splitPrefix + ':', '')\n }\n return null\n },\n async transform(code, id, transformOptions) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n id = fileURLToPath(url).replace(/\\\\/g, '/')\n\n const compile = makeCompile({\n root: ROOT,\n })\n\n if (id.includes(splitPrefix)) {\n if (debug) console.info('Splitting route: ', id)\n // const ref = new URLSearchParams(id.split('?')[1]).get('ref') || ''\n\n const compiled = await splitFile({\n code,\n compile,\n filename: id,\n // ref,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Split Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n } else if (\n fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&\n (code.includes('createRoute(') || code.includes('createFileRoute('))\n ) {\n if (code.includes('@react-refresh')) {\n throw new Error(\n `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/router-vite-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: \ne.g.\n\nplugins: [\n TanStackRouterVite(), // Place this before viteReact()\n viteReact(),\n]\n`,\n )\n }\n\n if (debug) console.info('Handling createRoute: ', id)\n const compiled = await compileFile({\n code,\n compile,\n filename: id,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Compiled Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n }\n\n return null\n },\n }\n}\n"],"names":["generatorConfigSchema","z","getGeneratorConfig","generator","normalize","join","resolve","isAbsolute","splitPrefix","url","pathToFileURL","fileURLToPath","makeCompile","splitFile","compileFile"],"mappings":"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"}
@@ -43,7 +43,7 @@ async function compileFile(opts) {
43
43
  visitor: {
44
44
  Program: {
45
45
  enter(programPath, state) {
46
- const splitUrl = `${splitPrefix}:${state.filename}?${splitPrefix}`;
46
+ const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`;
47
47
  programPath.traverse(
48
48
  {
49
49
  CallExpression: (path) => {
@@ -1 +1 @@
1
- {"version":3,"file":"compilers.js","sources":["../../src/compilers.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport * as template from '@babel/template'\nimport * as babel from '@babel/core'\nimport { splitPrefix } from './constants'\nimport { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'\n\ntype SplitModulesById = Record<\n string,\n { id: string; node: t.FunctionExpression }\n>\n\ninterface State {\n filename: string\n opts: {\n minify: boolean\n root: string\n }\n imported: Record<string, boolean>\n refs: Set<any>\n serverIndex: number\n splitIndex: number\n splitModulesById: SplitModulesById\n}\n\nexport type CompileFn = (compileOpts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n}) => Promise<{\n code: string\n map: any\n}>\n\nexport function makeCompile(makeOpts: { root: string }) {\n return async (opts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n }): Promise<{\n code: string\n map: any\n }> => {\n const res = await babel.transform(opts.code, {\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [\n '@babel/plugin-syntax-typescript',\n {\n isTSX: true,\n },\n ],\n ...opts.getBabelConfig().plugins,\n ],\n root: makeOpts.root,\n filename: opts.filename,\n sourceMaps: true,\n })\n\n if (res?.code) {\n return {\n code: res.code,\n map: res.map,\n }\n }\n\n return {\n code: opts.code,\n map: null,\n }\n }\n}\n\nexport async function compileFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitUrl = `${splitPrefix}:${state.filename}?${splitPrefix}`\n\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (\n path.node.callee.name === 'createRoute' ||\n path.node.callee.name === 'createFileRoute'\n ) {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n let found = false\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === 'component') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyRouteComponent } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitComponentImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyRouteComponent($$splitComponentImporter, 'component')`,\n )() as any\n\n programPath.pushContainer('body', [\n template.smart(\n `function DummyComponent() { return null }`,\n )() as t.Statement,\n ])\n\n found = true\n } else if (prop.key.name === 'loader') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyFn } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitLoaderImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyFn($$splitLoaderImporter, 'loader')`,\n )() as any\n\n found = true\n }\n }\n }\n })\n }\n\n if (found as boolean) {\n programPath.pushContainer('body', [\n template.smart(\n `function TSR_Dummy_Component() {}`,\n )() as t.Statement,\n ])\n }\n }\n }\n }\n },\n },\n state,\n )\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n\n// Reusable function to get literal value or resolve variable to literal\nfunction resolveIdentifier(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (\n binding\n // && binding.kind === 'const'\n ) {\n const declarator = binding.path.node\n if (t.isObjectExpression(declarator.init)) {\n return declarator.init\n } else if (t.isFunctionDeclaration(declarator.init)) {\n return declarator.init\n }\n }\n return undefined\n }\n\n return node\n}\n\nfunction removeIdentifierLiteral(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (binding) {\n binding.path.remove()\n }\n }\n}\n\nconst splitNodeTypes = ['component', 'loader'] as const\ntype SplitNodeType = (typeof splitNodeTypes)[number]\n\nexport async function splitFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n // ref: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitNodesByType: Record<\n SplitNodeType,\n t.Node | undefined\n > = {\n component: undefined,\n loader: undefined,\n }\n\n // Find the node\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (path.node.callee.name === 'createFileRoute') {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n splitNodeTypes.forEach((type) => {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === type) {\n splitNodesByType[type] = prop.value\n }\n }\n })\n }\n })\n\n // Remove all of the options\n options.properties = []\n }\n }\n }\n }\n },\n },\n state,\n )\n\n splitNodeTypes.forEach((splitType) => {\n let splitNode = splitNodesByType[splitType]\n\n if (!splitNode) {\n return\n }\n\n while (t.isIdentifier(splitNode)) {\n const binding = programPath.scope.getBinding(\n splitNode.name,\n )\n splitNode = binding?.path.node\n }\n\n // Add the node to the program\n if (splitNode) {\n if (t.isFunctionDeclaration(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n t.functionExpression(\n splitNode.id || null, // Anonymize the function expression\n splitNode.params,\n splitNode.body,\n splitNode.generator,\n splitNode.async,\n ),\n ),\n ]),\n )\n } else if (\n t.isFunctionExpression(splitNode) ||\n t.isArrowFunctionExpression(splitNode)\n ) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode as any,\n ),\n ]),\n )\n } else if (t.isImportSpecifier(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode.local,\n ),\n ]),\n )\n } else {\n console.log(splitNode)\n throw new Error(\n `Unexpected splitNode type: ${splitNode.type}`,\n )\n }\n }\n\n // If the splitNode exists at the top of the program\n // then we need to remove that copy\n programPath.node.body = programPath.node.body.filter(\n (node) => {\n // console.log(node)\n return node !== splitNode\n },\n )\n\n // Export the node\n programPath.pushContainer('body', [\n t.exportNamedDeclaration(null, [\n t.exportSpecifier(\n t.identifier(splitType),\n t.identifier(splitType),\n ),\n ]),\n ])\n })\n\n // convert exports to imports from the original file\n programPath.traverse({\n ExportNamedDeclaration(path) {\n // e.g. export const x = 1 or export { x }\n // becomes\n // import { x } from '${opts.id}'\n\n if (path.node.declaration) {\n if (t.isVariableDeclaration(path.node.declaration)) {\n path.replaceWith(\n t.importDeclaration(\n path.node.declaration.declarations.map((decl) =>\n t.importSpecifier(\n t.identifier((decl.id as any).name),\n t.identifier((decl.id as any).name),\n ),\n ),\n t.stringLiteral(\n opts.filename.split(\n `?${splitPrefix}`,\n )[0] as string,\n ),\n ),\n )\n }\n }\n },\n })\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compilers.js","sources":["../../src/compilers.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport * as template from '@babel/template'\nimport * as babel from '@babel/core'\nimport { splitPrefix } from './constants'\nimport { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'\n\ntype SplitModulesById = Record<\n string,\n { id: string; node: t.FunctionExpression }\n>\n\ninterface State {\n filename: string\n opts: {\n minify: boolean\n root: string\n }\n imported: Record<string, boolean>\n refs: Set<any>\n serverIndex: number\n splitIndex: number\n splitModulesById: SplitModulesById\n}\n\nexport type CompileFn = (compileOpts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n}) => Promise<{\n code: string\n map: any\n}>\n\nexport function makeCompile(makeOpts: { root: string }) {\n return async (opts: {\n code: string\n filename: string\n getBabelConfig: () => { plugins: Array<any> }\n }): Promise<{\n code: string\n map: any\n }> => {\n const res = await babel.transform(opts.code, {\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [\n '@babel/plugin-syntax-typescript',\n {\n isTSX: true,\n },\n ],\n ...opts.getBabelConfig().plugins,\n ],\n root: makeOpts.root,\n filename: opts.filename,\n sourceMaps: true,\n })\n\n if (res?.code) {\n return {\n code: res.code,\n map: res.map,\n }\n }\n\n return {\n code: opts.code,\n map: null,\n }\n }\n}\n\nexport async function compileFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`\n\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (\n path.node.callee.name === 'createRoute' ||\n path.node.callee.name === 'createFileRoute'\n ) {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n let found = false\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === 'component') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyRouteComponent } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitComponentImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyRouteComponent($$splitComponentImporter, 'component')`,\n )() as any\n\n programPath.pushContainer('body', [\n template.smart(\n `function DummyComponent() { return null }`,\n )() as t.Statement,\n ])\n\n found = true\n } else if (prop.key.name === 'loader') {\n const value = prop.value\n\n if (t.isIdentifier(value)) {\n removeIdentifierLiteral(path, value)\n }\n\n // Prepend the import statement to the program along with the importer function\n\n programPath.unshiftContainer('body', [\n template.smart(\n `import { lazyFn } from '@tanstack/react-router'`,\n )() as t.Statement,\n template.smart(\n `const $$splitLoaderImporter = () => import('${splitUrl}')`,\n )() as t.Statement,\n ])\n\n prop.value = template.expression(\n `lazyFn($$splitLoaderImporter, 'loader')`,\n )() as any\n\n found = true\n }\n }\n }\n })\n }\n\n if (found as boolean) {\n programPath.pushContainer('body', [\n template.smart(\n `function TSR_Dummy_Component() {}`,\n )() as t.Statement,\n ])\n }\n }\n }\n }\n },\n },\n state,\n )\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n\n// Reusable function to get literal value or resolve variable to literal\nfunction resolveIdentifier(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (\n binding\n // && binding.kind === 'const'\n ) {\n const declarator = binding.path.node\n if (t.isObjectExpression(declarator.init)) {\n return declarator.init\n } else if (t.isFunctionDeclaration(declarator.init)) {\n return declarator.init\n }\n }\n return undefined\n }\n\n return node\n}\n\nfunction removeIdentifierLiteral(path: any, node: any) {\n if (t.isIdentifier(node)) {\n const binding = path.scope.getBinding(node.name)\n if (binding) {\n binding.path.remove()\n }\n }\n}\n\nconst splitNodeTypes = ['component', 'loader'] as const\ntype SplitNodeType = (typeof splitNodeTypes)[number]\n\nexport async function splitFile(opts: {\n code: string\n compile: CompileFn\n filename: string\n // ref: string\n}) {\n return await opts.compile({\n code: opts.code,\n filename: opts.filename,\n getBabelConfig: () => ({\n plugins: [\n [\n {\n visitor: {\n Program: {\n enter(programPath: babel.NodePath<t.Program>, state: State) {\n const splitNodesByType: Record<\n SplitNodeType,\n t.Node | undefined\n > = {\n component: undefined,\n loader: undefined,\n }\n\n // Find the node\n programPath.traverse(\n {\n CallExpression: (path) => {\n if (path.node.callee.type === 'Identifier') {\n if (path.node.callee.name === 'createFileRoute') {\n if (\n path.parentPath.node.type === 'CallExpression'\n ) {\n const options = resolveIdentifier(\n path,\n path.parentPath.node.arguments[0],\n )\n\n if (t.isObjectExpression(options)) {\n options.properties.forEach((prop) => {\n if (t.isObjectProperty(prop)) {\n splitNodeTypes.forEach((type) => {\n if (t.isIdentifier(prop.key)) {\n if (prop.key.name === type) {\n splitNodesByType[type] = prop.value\n }\n }\n })\n }\n })\n\n // Remove all of the options\n options.properties = []\n }\n }\n }\n }\n },\n },\n state,\n )\n\n splitNodeTypes.forEach((splitType) => {\n let splitNode = splitNodesByType[splitType]\n\n if (!splitNode) {\n return\n }\n\n while (t.isIdentifier(splitNode)) {\n const binding = programPath.scope.getBinding(\n splitNode.name,\n )\n splitNode = binding?.path.node\n }\n\n // Add the node to the program\n if (splitNode) {\n if (t.isFunctionDeclaration(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n t.functionExpression(\n splitNode.id || null, // Anonymize the function expression\n splitNode.params,\n splitNode.body,\n splitNode.generator,\n splitNode.async,\n ),\n ),\n ]),\n )\n } else if (\n t.isFunctionExpression(splitNode) ||\n t.isArrowFunctionExpression(splitNode)\n ) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode as any,\n ),\n ]),\n )\n } else if (t.isImportSpecifier(splitNode)) {\n programPath.pushContainer(\n 'body',\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(splitType),\n splitNode.local,\n ),\n ]),\n )\n } else {\n console.log(splitNode)\n throw new Error(\n `Unexpected splitNode type: ${splitNode.type}`,\n )\n }\n }\n\n // If the splitNode exists at the top of the program\n // then we need to remove that copy\n programPath.node.body = programPath.node.body.filter(\n (node) => {\n // console.log(node)\n return node !== splitNode\n },\n )\n\n // Export the node\n programPath.pushContainer('body', [\n t.exportNamedDeclaration(null, [\n t.exportSpecifier(\n t.identifier(splitType),\n t.identifier(splitType),\n ),\n ]),\n ])\n })\n\n // convert exports to imports from the original file\n programPath.traverse({\n ExportNamedDeclaration(path) {\n // e.g. export const x = 1 or export { x }\n // becomes\n // import { x } from '${opts.id}'\n\n if (path.node.declaration) {\n if (t.isVariableDeclaration(path.node.declaration)) {\n path.replaceWith(\n t.importDeclaration(\n path.node.declaration.declarations.map((decl) =>\n t.importSpecifier(\n t.identifier((decl.id as any).name),\n t.identifier((decl.id as any).name),\n ),\n ),\n t.stringLiteral(\n opts.filename.split(\n `?${splitPrefix}`,\n )[0] as string,\n ),\n ),\n )\n }\n }\n },\n })\n\n eliminateUnreferencedIdentifiers(programPath)\n },\n },\n },\n },\n {\n root: process.cwd(),\n minify: process.env.NODE_ENV === 'production',\n },\n ],\n ].filter(Boolean),\n }),\n })\n}\n"],"names":[],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { normalize, join, isAbsolute } from "path";
1
+ import { normalize, join, resolve, isAbsolute } from "path";
2
2
  import { pathToFileURL, fileURLToPath } from "url";
3
3
  import { z } from "zod";
4
4
  import { configSchema as configSchema$1, getConfig as getConfig$1, generator } from "@tanstack/router-generator";
@@ -21,23 +21,32 @@ function TanStackRouterVite(inlineConfig = {}) {
21
21
  TanStackRouterViteCodeSplitter(inlineConfig)
22
22
  ];
23
23
  }
24
+ let lock = false;
24
25
  function TanStackRouterViteGenerator(inlineConfig = {}) {
25
26
  let ROOT = process.cwd();
26
27
  let userConfig;
27
28
  const generate = async () => {
29
+ if (lock) {
30
+ return;
31
+ }
32
+ lock = true;
28
33
  try {
29
34
  await generator(userConfig);
30
35
  } catch (err) {
31
36
  console.error(err);
32
37
  console.info();
33
38
  }
39
+ lock = false;
34
40
  };
35
- const handleFile = async (file) => {
41
+ const handleFile = async (file, event) => {
36
42
  const filePath = normalize(file);
37
43
  if (filePath === join(ROOT, CONFIG_FILE_NAME)) {
38
44
  userConfig = await getConfig(inlineConfig, ROOT);
39
45
  return;
40
46
  }
47
+ if (event === "update" && filePath === resolve(userConfig.generatedRouteTree)) {
48
+ return;
49
+ }
41
50
  const routesDirectoryPath = isAbsolute(userConfig.routesDirectory) ? userConfig.routesDirectory : join(ROOT, userConfig.routesDirectory);
42
51
  if (filePath.startsWith(routesDirectoryPath)) {
43
52
  await generate();
@@ -55,7 +64,7 @@ function TanStackRouterViteGenerator(inlineConfig = {}) {
55
64
  watchChange: async (file, context) => {
56
65
  if (userConfig.enableRouteGeneration ?? true) {
57
66
  if (["create", "update", "delete"].includes(context.event)) {
58
- await handleFile(file);
67
+ await handleFile(file, context.event);
59
68
  }
60
69
  }
61
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { isAbsolute, join, normalize } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport { z } from 'zod'\nimport {\n generator,\n configSchema as generatorConfigSchema,\n getConfig as getGeneratorConfig,\n} from '@tanstack/router-generator'\nimport { compileFile, makeCompile, splitFile } from './compilers'\nimport { splitPrefix } from './constants'\nimport type { Plugin } from 'vite'\n\nexport const configSchema = generatorConfigSchema.extend({\n enableRouteGeneration: z.boolean().optional(),\n experimental: z\n .object({\n enableCodeSplitting: z.boolean().optional(),\n })\n .optional(),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nconst CONFIG_FILE_NAME = 'tsr.config.json'\nconst debug = false as any\n\nconst getConfig = async (inlineConfig: Partial<Config>, root: string) => {\n const config = await getGeneratorConfig(inlineConfig, root)\n\n return configSchema.parse({ ...inlineConfig, ...config })\n}\n\nexport function TanStackRouterVite(\n inlineConfig: Partial<Config> = {},\n): Array<Plugin> {\n return [\n TanStackRouterViteGenerator(inlineConfig),\n TanStackRouterViteCodeSplitter(inlineConfig),\n ]\n}\n\nexport function TanStackRouterViteGenerator(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n const generate = async () => {\n try {\n await generator(userConfig)\n } catch (err) {\n console.error(err)\n console.info()\n }\n }\n\n const handleFile = async (file: string) => {\n const filePath = normalize(file)\n if (filePath === join(ROOT, CONFIG_FILE_NAME)) {\n userConfig = await getConfig(inlineConfig, ROOT)\n return\n }\n const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)\n ? userConfig.routesDirectory\n : join(ROOT, userConfig.routesDirectory)\n if (filePath.startsWith(routesDirectoryPath)) {\n await generate()\n }\n }\n\n return {\n name: 'vite-plugin-tanstack-router-generator',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n\n if (userConfig.enableRouteGeneration ?? true) {\n await generate()\n }\n },\n watchChange: async (file, context) => {\n if (userConfig.enableRouteGeneration ?? true) {\n if (['create', 'update', 'delete'].includes(context.event)) {\n await handleFile(file)\n }\n }\n },\n }\n}\n\nfunction fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {\n const routesDirectoryPath = isAbsolute(routesDirectory)\n ? routesDirectory\n : join(process.cwd(), routesDirectory)\n\n return filePath.startsWith(routesDirectoryPath)\n}\n\nexport function TanStackRouterViteCodeSplitter(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n return {\n name: 'vite-plugin-tanstack-router-code-splitter',\n enforce: 'pre',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n },\n resolveId(source) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n if (source.startsWith(splitPrefix + ':')) {\n return source.replace(splitPrefix + ':', '')\n }\n return null\n },\n async transform(code, id, transformOptions) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n id = fileURLToPath(url).replace(/\\\\/g, '/')\n\n const compile = makeCompile({\n root: ROOT,\n })\n\n if (id.includes(splitPrefix)) {\n if (debug) console.info('Splitting route: ', id)\n // const ref = new URLSearchParams(id.split('?')[1]).get('ref') || ''\n\n const compiled = await splitFile({\n code,\n compile,\n filename: id,\n // ref,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Split Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n } else if (\n fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&\n (code.includes('createRoute(') || code.includes('createFileRoute('))\n ) {\n if (code.includes('@react-refresh')) {\n throw new Error(\n `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/router-vite-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: \ne.g.\n\nplugins: [\n TanStackRouterVite(), // Place this before viteReact()\n viteReact(),\n]\n`,\n )\n }\n\n if (debug) console.info('Handling createRoute: ', id)\n const compiled = await compileFile({\n code,\n compile,\n filename: id,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Compiled Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n }\n\n return null\n },\n }\n}\n"],"names":["generatorConfigSchema","getGeneratorConfig"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { isAbsolute, join, normalize, resolve } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport { z } from 'zod'\nimport {\n generator,\n configSchema as generatorConfigSchema,\n getConfig as getGeneratorConfig,\n} from '@tanstack/router-generator'\nimport { compileFile, makeCompile, splitFile } from './compilers'\nimport { splitPrefix } from './constants'\nimport type { Plugin } from 'vite'\n\nexport const configSchema = generatorConfigSchema.extend({\n enableRouteGeneration: z.boolean().optional(),\n experimental: z\n .object({\n enableCodeSplitting: z.boolean().optional(),\n })\n .optional(),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nconst CONFIG_FILE_NAME = 'tsr.config.json'\nconst debug = false as any\n\nconst getConfig = async (inlineConfig: Partial<Config>, root: string) => {\n const config = await getGeneratorConfig(inlineConfig, root)\n\n return configSchema.parse({ ...inlineConfig, ...config })\n}\n\nexport function TanStackRouterVite(\n inlineConfig: Partial<Config> = {},\n): Array<Plugin> {\n return [\n TanStackRouterViteGenerator(inlineConfig),\n TanStackRouterViteCodeSplitter(inlineConfig),\n ]\n}\n\nlet lock = false\n\nexport function TanStackRouterViteGenerator(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n const generate = async () => {\n if (lock) {\n return\n }\n lock = true\n try {\n await generator(userConfig)\n } catch (err) {\n console.error(err)\n console.info()\n }\n lock = false\n }\n\n const handleFile = async (\n file: string,\n event: 'create' | 'update' | 'delete',\n ) => {\n const filePath = normalize(file)\n if (filePath === join(ROOT, CONFIG_FILE_NAME)) {\n userConfig = await getConfig(inlineConfig, ROOT)\n return\n }\n if (\n event === 'update' &&\n filePath === resolve(userConfig.generatedRouteTree)\n ) {\n // skip generating routes if the generated route tree is updated\n return\n }\n const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)\n ? userConfig.routesDirectory\n : join(ROOT, userConfig.routesDirectory)\n if (filePath.startsWith(routesDirectoryPath)) {\n await generate()\n }\n }\n\n return {\n name: 'vite-plugin-tanstack-router-generator',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n\n if (userConfig.enableRouteGeneration ?? true) {\n await generate()\n }\n },\n watchChange: async (file, context) => {\n if (userConfig.enableRouteGeneration ?? true) {\n if (['create', 'update', 'delete'].includes(context.event)) {\n await handleFile(file, context.event)\n }\n }\n },\n }\n}\n\nfunction fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {\n const routesDirectoryPath = isAbsolute(routesDirectory)\n ? routesDirectory\n : join(process.cwd(), routesDirectory)\n\n return filePath.startsWith(routesDirectoryPath)\n}\n\nexport function TanStackRouterViteCodeSplitter(\n inlineConfig: Partial<Config> = {},\n): Plugin {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n return {\n name: 'vite-plugin-tanstack-router-code-splitter',\n enforce: 'pre',\n configResolved: async (config) => {\n ROOT = config.root\n userConfig = await getConfig(inlineConfig, ROOT)\n },\n resolveId(source) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n if (source.startsWith(splitPrefix + ':')) {\n return source.replace(splitPrefix + ':', '')\n }\n return null\n },\n async transform(code, id, transformOptions) {\n if (!userConfig.experimental?.enableCodeSplitting) {\n return null\n }\n\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n id = fileURLToPath(url).replace(/\\\\/g, '/')\n\n const compile = makeCompile({\n root: ROOT,\n })\n\n if (id.includes(splitPrefix)) {\n if (debug) console.info('Splitting route: ', id)\n // const ref = new URLSearchParams(id.split('?')[1]).get('ref') || ''\n\n const compiled = await splitFile({\n code,\n compile,\n filename: id,\n // ref,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Split Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n } else if (\n fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&\n (code.includes('createRoute(') || code.includes('createFileRoute('))\n ) {\n if (code.includes('@react-refresh')) {\n throw new Error(\n `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/router-vite-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: \ne.g.\n\nplugins: [\n TanStackRouterVite(), // Place this before viteReact()\n viteReact(),\n]\n`,\n )\n }\n\n if (debug) console.info('Handling createRoute: ', id)\n const compiled = await compileFile({\n code,\n compile,\n filename: id,\n })\n\n if (debug) console.info('')\n if (debug) console.info('Compiled Output')\n if (debug) console.info('')\n if (debug) console.info(compiled.code)\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n if (debug) console.info('')\n\n return compiled\n }\n\n return null\n },\n }\n}\n"],"names":["generatorConfigSchema","getGeneratorConfig"],"mappings":";;;;;;AAYa,MAAA,eAAeA,eAAsB,OAAO;AAAA,EACvD,uBAAuB,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC5C,cAAc,EACX,OAAO;AAAA,IACN,qBAAqB,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC3C,CAAA,EACA,SAAS;AACd,CAAC;AAID,MAAM,mBAAmB;AAGzB,MAAM,YAAY,OAAO,cAA+B,SAAiB;AACvE,QAAM,SAAS,MAAMC,YAAmB,cAAc,IAAI;AAE1D,SAAO,aAAa,MAAM,EAAE,GAAG,cAAc,GAAG,QAAQ;AAC1D;AAEgB,SAAA,mBACd,eAAgC,IACjB;AACR,SAAA;AAAA,IACL,4BAA4B,YAAY;AAAA,IACxC,+BAA+B,YAAY;AAAA,EAAA;AAE/C;AAEA,IAAI,OAAO;AAEK,SAAA,4BACd,eAAgC,IACxB;AACJ,MAAA,OAAe,QAAQ;AACvB,MAAA;AAEJ,QAAM,WAAW,YAAY;AAC3B,QAAI,MAAM;AACR;AAAA,IACF;AACO,WAAA;AACH,QAAA;AACF,YAAM,UAAU,UAAU;AAAA,aACnB,KAAK;AACZ,cAAQ,MAAM,GAAG;AACjB,cAAQ,KAAK;AAAA,IACf;AACO,WAAA;AAAA,EAAA;AAGH,QAAA,aAAa,OACjB,MACA,UACG;AACG,UAAA,WAAW,UAAU,IAAI;AAC/B,QAAI,aAAa,KAAK,MAAM,gBAAgB,GAAG;AAChC,mBAAA,MAAM,UAAU,cAAc,IAAI;AAC/C;AAAA,IACF;AACA,QACE,UAAU,YACV,aAAa,QAAQ,WAAW,kBAAkB,GAClD;AAEA;AAAA,IACF;AACM,UAAA,sBAAsB,WAAW,WAAW,eAAe,IAC7D,WAAW,kBACX,KAAK,MAAM,WAAW,eAAe;AACrC,QAAA,SAAS,WAAW,mBAAmB,GAAG;AAC5C,YAAM,SAAS;AAAA,IACjB;AAAA,EAAA;AAGK,SAAA;AAAA,IACL,MAAM;AAAA,IACN,gBAAgB,OAAO,WAAW;AAChC,aAAO,OAAO;AACD,mBAAA,MAAM,UAAU,cAAc,IAAI;AAE3C,UAAA,WAAW,yBAAyB,MAAM;AAC5C,cAAM,SAAS;AAAA,MACjB;AAAA,IACF;AAAA,IACA,aAAa,OAAO,MAAM,YAAY;AAChC,UAAA,WAAW,yBAAyB,MAAM;AACxC,YAAA,CAAC,UAAU,UAAU,QAAQ,EAAE,SAAS,QAAQ,KAAK,GAAG;AACpD,gBAAA,WAAW,MAAM,QAAQ,KAAK;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EAAA;AAEJ;AAEA,SAAS,wBAAwB,UAAkB,iBAAyB;AACpE,QAAA,sBAAsB,WAAW,eAAe,IAClD,kBACA,KAAK,QAAQ,OAAO,eAAe;AAEhC,SAAA,SAAS,WAAW,mBAAmB;AAChD;AAEgB,SAAA,+BACd,eAAgC,IACxB;AACJ,MAAA,OAAe,QAAQ;AACvB,MAAA;AAEG,SAAA;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,gBAAgB,OAAO,WAAW;AAChC,aAAO,OAAO;AACD,mBAAA,MAAM,UAAU,cAAc,IAAI;AAAA,IACjD;AAAA,IACA,UAAU,QAAQ;;AACZ,UAAA,GAAC,gBAAW,iBAAX,mBAAyB,sBAAqB;AAC1C,eAAA;AAAA,MACT;AAEA,UAAI,OAAO,WAAW,cAAc,GAAG,GAAG;AACxC,eAAO,OAAO,QAAQ,cAAc,KAAK,EAAE;AAAA,MAC7C;AACO,aAAA;AAAA,IACT;AAAA,IACA,MAAM,UAAU,MAAM,IAAI,kBAAkB;;AACtC,UAAA,GAAC,gBAAW,iBAAX,mBAAyB,sBAAqB;AAC1C,eAAA;AAAA,MACT;AAEM,YAAA,MAAM,cAAc,EAAE;AACxB,UAAA,aAAa,OAAO,GAAG;AAC3B,WAAK,cAAc,GAAG,EAAE,QAAQ,OAAO,GAAG;AAE1C,YAAM,UAAU,YAAY;AAAA,QAC1B,MAAM;AAAA,MAAA,CACP;AAEG,UAAA,GAAG,SAAS,WAAW,GAAG;AAItB,cAAA,WAAW,MAAM,UAAU;AAAA,UAC/B;AAAA,UACA;AAAA,UACA,UAAU;AAAA;AAAA,QAAA,CAEX;AAeM,eAAA;AAAA,MAEP,WAAA,wBAAwB,IAAI,WAAW,eAAe,MACrD,KAAK,SAAS,cAAc,KAAK,KAAK,SAAS,kBAAkB,IAClE;AACI,YAAA,KAAK,SAAS,gBAAgB,GAAG;AACnC,gBAAM,IAAI;AAAA,YACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA;AAAA,QASJ;AAGM,cAAA,WAAW,MAAM,YAAY;AAAA,UACjC;AAAA,UACA;AAAA,UACA,UAAU;AAAA,QAAA,CACX;AAiBM,eAAA;AAAA,MACT;AAEO,aAAA;AAAA,IACT;AAAA,EAAA;AAEJ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-vite-plugin",
3
- "version": "1.26.14",
3
+ "version": "1.26.21",
4
4
  "description": "",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -64,7 +64,7 @@
64
64
  "@types/babel__traverse": "^7.20.5",
65
65
  "@vitejs/plugin-react": "^4.2.1",
66
66
  "zod": "^3.22.4",
67
- "@tanstack/router-generator": "1.26.10"
67
+ "@tanstack/router-generator": "1.26.16"
68
68
  },
69
69
  "scripts": {
70
70
  "clean": "rimraf ./dist && rimraf ./coverage",
package/src/compilers.ts CHANGED
@@ -85,7 +85,7 @@ export async function compileFile(opts: {
85
85
  visitor: {
86
86
  Program: {
87
87
  enter(programPath: babel.NodePath<t.Program>, state: State) {
88
- const splitUrl = `${splitPrefix}:${state.filename}?${splitPrefix}`
88
+ const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`
89
89
 
90
90
  programPath.traverse(
91
91
  {
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { isAbsolute, join, normalize } from 'path'
1
+ import { isAbsolute, join, normalize, resolve } from 'path'
2
2
  import { fileURLToPath, pathToFileURL } from 'url'
3
3
  import { z } from 'zod'
4
4
  import {
@@ -39,6 +39,8 @@ export function TanStackRouterVite(
39
39
  ]
40
40
  }
41
41
 
42
+ let lock = false
43
+
42
44
  export function TanStackRouterViteGenerator(
43
45
  inlineConfig: Partial<Config> = {},
44
46
  ): Plugin {
@@ -46,20 +48,35 @@ export function TanStackRouterViteGenerator(
46
48
  let userConfig: Config
47
49
 
48
50
  const generate = async () => {
51
+ if (lock) {
52
+ return
53
+ }
54
+ lock = true
49
55
  try {
50
56
  await generator(userConfig)
51
57
  } catch (err) {
52
58
  console.error(err)
53
59
  console.info()
54
60
  }
61
+ lock = false
55
62
  }
56
63
 
57
- const handleFile = async (file: string) => {
64
+ const handleFile = async (
65
+ file: string,
66
+ event: 'create' | 'update' | 'delete',
67
+ ) => {
58
68
  const filePath = normalize(file)
59
69
  if (filePath === join(ROOT, CONFIG_FILE_NAME)) {
60
70
  userConfig = await getConfig(inlineConfig, ROOT)
61
71
  return
62
72
  }
73
+ if (
74
+ event === 'update' &&
75
+ filePath === resolve(userConfig.generatedRouteTree)
76
+ ) {
77
+ // skip generating routes if the generated route tree is updated
78
+ return
79
+ }
63
80
  const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)
64
81
  ? userConfig.routesDirectory
65
82
  : join(ROOT, userConfig.routesDirectory)
@@ -81,7 +98,7 @@ export function TanStackRouterViteGenerator(
81
98
  watchChange: async (file, context) => {
82
99
  if (userConfig.enableRouteGeneration ?? true) {
83
100
  if (['create', 'update', 'delete'].includes(context.event)) {
84
- await handleFile(file)
101
+ await handleFile(file, context.event)
85
102
  }
86
103
  }
87
104
  },