@tanstack/router-plugin 1.39.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/cjs/ast.cjs +51 -0
  4. package/dist/cjs/ast.cjs.map +1 -0
  5. package/dist/cjs/ast.d.cts +22 -0
  6. package/dist/cjs/code-splitter.cjs +157 -0
  7. package/dist/cjs/code-splitter.cjs.map +1 -0
  8. package/dist/cjs/code-splitter.d.cts +22 -0
  9. package/dist/cjs/compilers.cjs +327 -0
  10. package/dist/cjs/compilers.cjs.map +1 -0
  11. package/dist/cjs/compilers.d.cts +18 -0
  12. package/dist/cjs/config.cjs +16 -0
  13. package/dist/cjs/config.cjs.map +1 -0
  14. package/dist/cjs/config.d.cts +79 -0
  15. package/dist/cjs/constants.cjs +7 -0
  16. package/dist/cjs/constants.cjs.map +1 -0
  17. package/dist/cjs/constants.d.cts +2 -0
  18. package/dist/cjs/eliminateUnreferencedIdentifiers.cjs +149 -0
  19. package/dist/cjs/eliminateUnreferencedIdentifiers.cjs.map +1 -0
  20. package/dist/cjs/eliminateUnreferencedIdentifiers.d.cts +9 -0
  21. package/dist/cjs/index.cjs +7 -0
  22. package/dist/cjs/index.cjs.map +1 -0
  23. package/dist/cjs/index.d.cts +2 -0
  24. package/dist/cjs/router-generator.cjs +67 -0
  25. package/dist/cjs/router-generator.cjs.map +1 -0
  26. package/dist/cjs/router-generator.d.cts +18 -0
  27. package/dist/cjs/vite.cjs +16 -0
  28. package/dist/cjs/vite.cjs.map +1 -0
  29. package/dist/cjs/vite.d.cts +41 -0
  30. package/dist/esm/ast.d.ts +22 -0
  31. package/dist/esm/ast.js +34 -0
  32. package/dist/esm/ast.js.map +1 -0
  33. package/dist/esm/code-splitter.d.ts +22 -0
  34. package/dist/esm/code-splitter.js +157 -0
  35. package/dist/esm/code-splitter.js.map +1 -0
  36. package/dist/esm/compilers.d.ts +18 -0
  37. package/dist/esm/compilers.js +309 -0
  38. package/dist/esm/compilers.js.map +1 -0
  39. package/dist/esm/config.d.ts +79 -0
  40. package/dist/esm/config.js +16 -0
  41. package/dist/esm/config.js.map +1 -0
  42. package/dist/esm/constants.d.ts +2 -0
  43. package/dist/esm/constants.js +7 -0
  44. package/dist/esm/constants.js.map +1 -0
  45. package/dist/esm/eliminateUnreferencedIdentifiers.d.ts +9 -0
  46. package/dist/esm/eliminateUnreferencedIdentifiers.js +132 -0
  47. package/dist/esm/eliminateUnreferencedIdentifiers.js.map +1 -0
  48. package/dist/esm/index.d.ts +2 -0
  49. package/dist/esm/index.js +7 -0
  50. package/dist/esm/index.js.map +1 -0
  51. package/dist/esm/router-generator.d.ts +18 -0
  52. package/dist/esm/router-generator.js +67 -0
  53. package/dist/esm/router-generator.js.map +1 -0
  54. package/dist/esm/vite.d.ts +41 -0
  55. package/dist/esm/vite.js +16 -0
  56. package/dist/esm/vite.js.map +1 -0
  57. package/package.json +88 -0
  58. package/src/ast.ts +49 -0
  59. package/src/code-splitter.ts +162 -0
  60. package/src/compilers.ts +414 -0
  61. package/src/config.ts +25 -0
  62. package/src/constants.ts +2 -0
  63. package/src/eliminateUnreferencedIdentifiers.ts +211 -0
  64. package/src/index.ts +2 -0
  65. package/src/router-generator.ts +92 -0
  66. package/src/vite.ts +19 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sources":["../../src/constants.ts"],"sourcesContent":["export const CONFIG_FILE_NAME = 'tsr.config.json'\nexport const splitPrefix = 'tsr-split'\n"],"names":[],"mappings":"AAAO,MAAM,mBAAmB;AACzB,MAAM,cAAc;"}
@@ -0,0 +1,9 @@
1
+ import { types as BabelTypes } from '@babel/core';
2
+ import { NodePath } from '@babel/traverse';
3
+
4
+ type IdentifierPath = NodePath<BabelTypes.Identifier>;
5
+ /**
6
+ * @param refs - If provided, only these identifiers will be considered for removal.
7
+ */
8
+ export declare const eliminateUnreferencedIdentifiers: (programPath: NodePath<BabelTypes.Program>, refs?: Set<IdentifierPath>) => void;
9
+ export {};
@@ -0,0 +1,132 @@
1
+ import * as t from "@babel/types";
2
+ const eliminateUnreferencedIdentifiers = (programPath, refs) => {
3
+ let referencesRemovedInThisPass;
4
+ const shouldBeRemoved = (ident) => {
5
+ if (isIdentifierReferenced(ident))
6
+ return false;
7
+ return true;
8
+ };
9
+ const sweepFunction = (path) => {
10
+ const identifier = getIdentifier(path);
11
+ if ((identifier == null ? void 0 : identifier.node) && shouldBeRemoved(identifier)) {
12
+ ++referencesRemovedInThisPass;
13
+ if (t.isAssignmentExpression(path.parentPath.node) || t.isVariableDeclarator(path.parentPath.node)) {
14
+ path.parentPath.remove();
15
+ } else {
16
+ path.remove();
17
+ }
18
+ }
19
+ };
20
+ const sweepImport = (path) => {
21
+ const local = path.get("local");
22
+ if (shouldBeRemoved(local)) {
23
+ ++referencesRemovedInThisPass;
24
+ path.remove();
25
+ if (path.parent.specifiers.length === 0) {
26
+ path.parentPath.remove();
27
+ }
28
+ }
29
+ };
30
+ const handleObjectPattern = (pattern) => {
31
+ const properties = pattern.get("properties");
32
+ properties.forEach((property) => {
33
+ if (property.node.type === "ObjectProperty") {
34
+ const value = property.get("value");
35
+ if (t.isIdentifier(value)) {
36
+ if (shouldBeRemoved(value)) {
37
+ property.remove();
38
+ }
39
+ } else if (t.isObjectPattern(value)) {
40
+ handleObjectPattern(value);
41
+ }
42
+ } else if (t.isRestElement(property.node)) {
43
+ const argument = property.get("argument");
44
+ if (t.isIdentifier(argument) && shouldBeRemoved(argument)) {
45
+ property.remove();
46
+ }
47
+ }
48
+ });
49
+ };
50
+ do {
51
+ referencesRemovedInThisPass = 0;
52
+ programPath.scope.crawl();
53
+ programPath.traverse({
54
+ VariableDeclarator(path) {
55
+ if (path.node.id.type === "Identifier") {
56
+ const local = path.get("id");
57
+ if (shouldBeRemoved(local)) {
58
+ ++referencesRemovedInThisPass;
59
+ path.remove();
60
+ }
61
+ } else if (path.node.id.type === "ObjectPattern") {
62
+ handleObjectPattern(
63
+ path.get("id")
64
+ );
65
+ } else if (path.node.id.type === "ArrayPattern") {
66
+ const pattern = path.get("id");
67
+ let hasRemoved = false;
68
+ pattern.get("elements").forEach((element, index) => {
69
+ let identifierPath;
70
+ if (t.isIdentifier(element.node)) {
71
+ identifierPath = element;
72
+ } else if (t.isRestElement(element.node)) {
73
+ identifierPath = element.get(
74
+ "argument"
75
+ );
76
+ } else {
77
+ return;
78
+ }
79
+ if (shouldBeRemoved(identifierPath)) {
80
+ hasRemoved = true;
81
+ pattern.node.elements[index] = null;
82
+ }
83
+ });
84
+ if (hasRemoved && pattern.node.elements.every((element) => element === null)) {
85
+ path.remove();
86
+ ++referencesRemovedInThisPass;
87
+ }
88
+ }
89
+ },
90
+ FunctionDeclaration: sweepFunction,
91
+ FunctionExpression: sweepFunction,
92
+ ArrowFunctionExpression: sweepFunction,
93
+ ImportSpecifier: sweepImport,
94
+ ImportDefaultSpecifier: sweepImport,
95
+ ImportNamespaceSpecifier: sweepImport
96
+ });
97
+ } while (referencesRemovedInThisPass);
98
+ };
99
+ function getIdentifier(path) {
100
+ const parentPath = path.parentPath;
101
+ if (parentPath.type === "VariableDeclarator") {
102
+ const variablePath = parentPath;
103
+ const name = variablePath.get("id");
104
+ return name.node.type === "Identifier" ? name : null;
105
+ }
106
+ if (parentPath.type === "AssignmentExpression") {
107
+ const variablePath = parentPath;
108
+ const name = variablePath.get("left");
109
+ return name.node.type === "Identifier" ? name : null;
110
+ }
111
+ if (path.node.type === "ArrowFunctionExpression") {
112
+ return null;
113
+ }
114
+ if (path.node.type === "FunctionExpression") {
115
+ return null;
116
+ }
117
+ return path.node.id && path.node.id.type === "Identifier" ? path.get("id") : null;
118
+ }
119
+ function isIdentifierReferenced(ident) {
120
+ const binding = ident.scope.getBinding(ident.node.name);
121
+ if (binding == null ? void 0 : binding.referenced) {
122
+ if (binding.path.type === "FunctionDeclaration") {
123
+ return !binding.constantViolations.concat(binding.referencePaths).every((ref) => ref.findParent((parent) => parent === binding.path));
124
+ }
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ export {
130
+ eliminateUnreferencedIdentifiers
131
+ };
132
+ //# sourceMappingURL=eliminateUnreferencedIdentifiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eliminateUnreferencedIdentifiers.js","sources":["../../src/eliminateUnreferencedIdentifiers.ts"],"sourcesContent":["// Copied from https://github.com/pcattori/vite-env-only/blob/main/src/dce.ts\n// Adapted with some minor changes for the purpose of this project\n\nimport * as t from '@babel/types'\nimport type { types as BabelTypes } from '@babel/core'\nimport type { NodePath } from '@babel/traverse'\n\ntype IdentifierPath = NodePath<BabelTypes.Identifier>\n\n/**\n * @param refs - If provided, only these identifiers will be considered for removal.\n */\nexport const eliminateUnreferencedIdentifiers = (\n programPath: NodePath<BabelTypes.Program>,\n refs?: Set<IdentifierPath>,\n) => {\n let referencesRemovedInThisPass: number\n\n const shouldBeRemoved = (ident: IdentifierPath) => {\n if (isIdentifierReferenced(ident)) return false\n if (!refs) return true\n return refs.has(ident)\n }\n\n const sweepFunction = (\n path: NodePath<\n | BabelTypes.FunctionDeclaration\n | BabelTypes.FunctionExpression\n | BabelTypes.ArrowFunctionExpression\n >,\n ) => {\n const identifier = getIdentifier(path)\n if (identifier?.node && shouldBeRemoved(identifier)) {\n ++referencesRemovedInThisPass\n\n if (\n t.isAssignmentExpression(path.parentPath.node) ||\n t.isVariableDeclarator(path.parentPath.node)\n ) {\n path.parentPath.remove()\n } else {\n path.remove()\n }\n }\n }\n\n const sweepImport = (\n path: NodePath<\n | BabelTypes.ImportSpecifier\n | BabelTypes.ImportDefaultSpecifier\n | BabelTypes.ImportNamespaceSpecifier\n >,\n ) => {\n const local = path.get('local')\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n path.remove()\n if (\n (path.parent as BabelTypes.ImportDeclaration).specifiers.length === 0\n ) {\n path.parentPath.remove()\n }\n }\n }\n\n const handleObjectPattern = (pattern: NodePath<BabelTypes.ObjectPattern>) => {\n const properties = pattern.get('properties')\n properties.forEach((property) => {\n if (property.node.type === 'ObjectProperty') {\n const value = property.get('value') as any\n if (t.isIdentifier(value)) {\n if (shouldBeRemoved(value as any)) {\n property.remove()\n }\n } else if (t.isObjectPattern(value)) {\n handleObjectPattern(value as any)\n }\n } else if (t.isRestElement(property.node)) {\n const argument = property.get('argument')\n if (\n t.isIdentifier(argument as any) &&\n shouldBeRemoved(argument as NodePath<BabelTypes.Identifier>)\n ) {\n property.remove()\n }\n }\n })\n }\n\n // Traverse again to remove unused references. This happens at least once,\n // then repeats until no more references are removed.\n do {\n referencesRemovedInThisPass = 0\n\n programPath.scope.crawl()\n\n programPath.traverse({\n VariableDeclarator(path) {\n if (path.node.id.type === 'Identifier') {\n const local = path.get('id') as NodePath<BabelTypes.Identifier>\n if (shouldBeRemoved(local)) {\n ++referencesRemovedInThisPass\n path.remove()\n }\n } else if (path.node.id.type === 'ObjectPattern') {\n handleObjectPattern(\n path.get('id') as NodePath<BabelTypes.ObjectPattern>,\n )\n } else if (path.node.id.type === 'ArrayPattern') {\n const pattern = path.get('id') as NodePath<BabelTypes.ArrayPattern>\n\n let hasRemoved = false as boolean\n\n pattern.get('elements').forEach((element, index) => {\n // if (!element) return // Skip holes in the pattern\n\n let identifierPath: NodePath<BabelTypes.Identifier>\n\n if (t.isIdentifier(element.node)) {\n identifierPath = element as NodePath<BabelTypes.Identifier>\n } else if (t.isRestElement(element.node)) {\n identifierPath = element.get(\n 'argument',\n ) as NodePath<BabelTypes.Identifier>\n } else {\n // For now, ignore other types like AssignmentPattern\n return\n }\n\n if (shouldBeRemoved(identifierPath)) {\n hasRemoved = true\n pattern.node.elements[index] = null // Remove the element by setting it to null\n }\n })\n\n // If any elements were removed and no elements are left, remove the entire declaration\n if (\n hasRemoved &&\n pattern.node.elements.every((element) => element === null)\n ) {\n path.remove()\n ++referencesRemovedInThisPass\n }\n }\n },\n FunctionDeclaration: sweepFunction,\n FunctionExpression: sweepFunction,\n ArrowFunctionExpression: sweepFunction,\n ImportSpecifier: sweepImport,\n ImportDefaultSpecifier: sweepImport,\n ImportNamespaceSpecifier: sweepImport,\n })\n } while (referencesRemovedInThisPass)\n}\n\nfunction getIdentifier(\n path: NodePath<\n | BabelTypes.FunctionDeclaration\n | BabelTypes.FunctionExpression\n | BabelTypes.ArrowFunctionExpression\n >,\n): NodePath<BabelTypes.Identifier> | null {\n const parentPath = path.parentPath\n if (parentPath.type === 'VariableDeclarator') {\n const variablePath = parentPath as NodePath<BabelTypes.VariableDeclarator>\n const name = variablePath.get('id')\n return name.node.type === 'Identifier'\n ? (name as NodePath<BabelTypes.Identifier>)\n : null\n }\n\n if (parentPath.type === 'AssignmentExpression') {\n const variablePath = parentPath as NodePath<BabelTypes.AssignmentExpression>\n const name = variablePath.get('left')\n return name.node.type === 'Identifier'\n ? (name as NodePath<BabelTypes.Identifier>)\n : null\n }\n\n if (path.node.type === 'ArrowFunctionExpression') {\n return null\n }\n\n if (path.node.type === 'FunctionExpression') {\n return null\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return path.node.id && path.node.id.type === 'Identifier'\n ? (path.get('id') as NodePath<BabelTypes.Identifier>)\n : null\n}\n\nfunction isIdentifierReferenced(\n ident: NodePath<BabelTypes.Identifier>,\n): boolean {\n const binding = ident.scope.getBinding(ident.node.name)\n if (binding?.referenced) {\n // Functions can reference themselves, so we need to check if there's a\n // binding outside the function scope or not.\n if (binding.path.type === 'FunctionDeclaration') {\n return !binding.constantViolations\n .concat(binding.referencePaths)\n // Check that every reference is contained within the function:\n .every((ref) => ref.findParent((parent) => parent === binding.path))\n }\n\n return true\n }\n return false\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { unpluginRouterCodeSplitter } from './code-splitter.js';
2
+ export { unpluginRouterGenerator } from './router-generator.js';
@@ -0,0 +1,7 @@
1
+ import { unpluginRouterCodeSplitter } from "./code-splitter.js";
2
+ import { unpluginRouterGenerator } from "./router-generator.js";
3
+ export {
4
+ unpluginRouterCodeSplitter,
5
+ unpluginRouterGenerator
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,18 @@
1
+ export declare const unpluginRouterGenerator: import('unplugin').UnpluginInstance<Partial<{
2
+ routeFileIgnorePrefix: string;
3
+ routesDirectory: string;
4
+ generatedRouteTree: string;
5
+ quoteStyle: "single" | "double";
6
+ semicolons: boolean;
7
+ disableTypes: boolean;
8
+ addExtensions: boolean;
9
+ disableLogging: boolean;
10
+ routeTreeFileHeader: string[];
11
+ routeTreeFileFooter: string[];
12
+ enableRouteGeneration?: boolean | undefined;
13
+ experimental?: {
14
+ enableCodeSplitting?: boolean | undefined;
15
+ } | undefined;
16
+ routeFilePrefix?: string | undefined;
17
+ routeFileIgnorePattern?: string | undefined;
18
+ }>, boolean>;
@@ -0,0 +1,67 @@
1
+ import { normalize, join, resolve, isAbsolute } from "node:path";
2
+ import { createUnplugin } from "unplugin";
3
+ import { generator } from "@tanstack/router-generator";
4
+ import { getConfig } from "./config.js";
5
+ import { CONFIG_FILE_NAME } from "./constants.js";
6
+ let lock = false;
7
+ const checkLock = () => lock;
8
+ const setLock = (bool) => {
9
+ lock = bool;
10
+ };
11
+ const unpluginFactory = (options = {}) => {
12
+ let ROOT = process.cwd();
13
+ let userConfig = options;
14
+ const generate = async () => {
15
+ if (checkLock()) {
16
+ return;
17
+ }
18
+ setLock(true);
19
+ try {
20
+ await generator(userConfig);
21
+ } catch (err) {
22
+ console.error(err);
23
+ console.info();
24
+ } finally {
25
+ setLock(false);
26
+ }
27
+ };
28
+ const handleFile = async (file, event) => {
29
+ const filePath = normalize(file);
30
+ if (filePath === join(ROOT, CONFIG_FILE_NAME)) {
31
+ userConfig = await getConfig(options, ROOT);
32
+ return;
33
+ }
34
+ if (event === "update" && filePath === resolve(userConfig.generatedRouteTree)) {
35
+ return;
36
+ }
37
+ const routesDirectoryPath = isAbsolute(userConfig.routesDirectory) ? userConfig.routesDirectory : join(ROOT, userConfig.routesDirectory);
38
+ if (filePath.startsWith(routesDirectoryPath)) {
39
+ await generate();
40
+ }
41
+ };
42
+ const run = async (cb) => {
43
+ if (userConfig.enableRouteGeneration ?? true) {
44
+ await cb();
45
+ }
46
+ };
47
+ return {
48
+ name: "router-generator-plugin",
49
+ async watchChange(id, { event }) {
50
+ await run(async () => {
51
+ await handleFile(id, event);
52
+ });
53
+ },
54
+ vite: {
55
+ async configResolved(config) {
56
+ ROOT = config.root;
57
+ userConfig = await getConfig(options, ROOT);
58
+ await run(generate);
59
+ }
60
+ }
61
+ };
62
+ };
63
+ const unpluginRouterGenerator = /* @__PURE__ */ createUnplugin(unpluginFactory);
64
+ export {
65
+ unpluginRouterGenerator
66
+ };
67
+ //# sourceMappingURL=router-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-generator.js","sources":["../../src/router-generator.ts"],"sourcesContent":["import { isAbsolute, join, normalize, resolve } from 'node:path'\nimport { createUnplugin } from 'unplugin'\nimport { generator } from '@tanstack/router-generator'\n\nimport { getConfig } from './config'\nimport { CONFIG_FILE_NAME } from './constants'\nimport type { PluginOptions } from './config'\nimport type { UnpluginFactory } from 'unplugin'\n\nlet lock = false\nconst checkLock = () => lock\nconst setLock = (bool: boolean) => {\n lock = bool\n}\n\nconst unpluginFactory: UnpluginFactory<Partial<PluginOptions>> = (\n options = {},\n) => {\n let ROOT: string = process.cwd()\n let userConfig = options as PluginOptions\n\n const generate = async () => {\n if (checkLock()) {\n return\n }\n\n setLock(true)\n\n try {\n await generator(userConfig)\n } catch (err) {\n console.error(err)\n console.info()\n } finally {\n setLock(false)\n }\n }\n\n const handleFile = async (\n file: string,\n event: 'create' | 'update' | 'delete',\n ) => {\n const filePath = normalize(file)\n\n if (filePath === join(ROOT, CONFIG_FILE_NAME)) {\n userConfig = await getConfig(options, ROOT)\n return\n }\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\n const routesDirectoryPath = isAbsolute(userConfig.routesDirectory)\n ? userConfig.routesDirectory\n : join(ROOT, userConfig.routesDirectory)\n\n if (filePath.startsWith(routesDirectoryPath)) {\n await generate()\n }\n }\n\n const run: (cb: () => Promise<void> | void) => Promise<void> = async (cb) => {\n if (userConfig.enableRouteGeneration ?? true) {\n await cb()\n }\n }\n\n return {\n name: 'router-generator-plugin',\n async watchChange(id, { event }) {\n await run(async () => {\n await handleFile(id, event)\n })\n },\n vite: {\n async configResolved(config) {\n ROOT = config.root\n userConfig = await getConfig(options, ROOT)\n\n await run(generate)\n },\n },\n }\n}\n\nexport const unpluginRouterGenerator =\n /* #__PURE__ */ createUnplugin(unpluginFactory)\n"],"names":[],"mappings":";;;;;AASA,IAAI,OAAO;AACX,MAAM,YAAY,MAAM;AACxB,MAAM,UAAU,CAAC,SAAkB;AAC1B,SAAA;AACT;AAEA,MAAM,kBAA2D,CAC/D,UAAU,OACP;AACC,MAAA,OAAe,QAAQ;AAC3B,MAAI,aAAa;AAEjB,QAAM,WAAW,YAAY;AAC3B,QAAI,aAAa;AACf;AAAA,IACF;AAEA,YAAQ,IAAI;AAER,QAAA;AACF,YAAM,UAAU,UAAU;AAAA,aACnB,KAAK;AACZ,cAAQ,MAAM,GAAG;AACjB,cAAQ,KAAK;AAAA,IAAA,UACb;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EAAA;AAGI,QAAA,aAAa,OACjB,MACA,UACG;AACG,UAAA,WAAW,UAAU,IAAI;AAE/B,QAAI,aAAa,KAAK,MAAM,gBAAgB,GAAG;AAChC,mBAAA,MAAM,UAAU,SAAS,IAAI;AAC1C;AAAA,IACF;AAEA,QACE,UAAU,YACV,aAAa,QAAQ,WAAW,kBAAkB,GAClD;AAEA;AAAA,IACF;AAEM,UAAA,sBAAsB,WAAW,WAAW,eAAe,IAC7D,WAAW,kBACX,KAAK,MAAM,WAAW,eAAe;AAErC,QAAA,SAAS,WAAW,mBAAmB,GAAG;AAC5C,YAAM,SAAS;AAAA,IACjB;AAAA,EAAA;AAGI,QAAA,MAAyD,OAAO,OAAO;AACvE,QAAA,WAAW,yBAAyB,MAAM;AAC5C,YAAM,GAAG;AAAA,IACX;AAAA,EAAA;AAGK,SAAA;AAAA,IACL,MAAM;AAAA,IACN,MAAM,YAAY,IAAI,EAAE,SAAS;AAC/B,YAAM,IAAI,YAAY;AACd,cAAA,WAAW,IAAI,KAAK;AAAA,MAAA,CAC3B;AAAA,IACH;AAAA,IACA,MAAM;AAAA,MACJ,MAAM,eAAe,QAAQ;AAC3B,eAAO,OAAO;AACD,qBAAA,MAAM,UAAU,SAAS,IAAI;AAE1C,cAAM,IAAI,QAAQ;AAAA,MACpB;AAAA,IACF;AAAA,EAAA;AAEJ;AAEa,MAAA,yDACoB,eAAe;"}
@@ -0,0 +1,41 @@
1
+ import { PluginOptions } from './config.js';
2
+ import { VitePlugin } from 'unplugin';
3
+
4
+ export declare const TanStackRouterGeneratorVite: (options: Partial<{
5
+ routeFileIgnorePrefix: string;
6
+ routesDirectory: string;
7
+ generatedRouteTree: string;
8
+ quoteStyle: "single" | "double";
9
+ semicolons: boolean;
10
+ disableTypes: boolean;
11
+ addExtensions: boolean;
12
+ disableLogging: boolean;
13
+ routeTreeFileHeader: string[];
14
+ routeTreeFileFooter: string[];
15
+ enableRouteGeneration?: boolean | undefined;
16
+ experimental?: {
17
+ enableCodeSplitting?: boolean | undefined;
18
+ } | undefined;
19
+ routeFilePrefix?: string | undefined;
20
+ routeFileIgnorePattern?: string | undefined;
21
+ }>) => VitePlugin<any> | VitePlugin<any>[];
22
+ export declare const TanStackRouterCodeSplitterVite: (options: Partial<{
23
+ routeFileIgnorePrefix: string;
24
+ routesDirectory: string;
25
+ generatedRouteTree: string;
26
+ quoteStyle: "single" | "double";
27
+ semicolons: boolean;
28
+ disableTypes: boolean;
29
+ addExtensions: boolean;
30
+ disableLogging: boolean;
31
+ routeTreeFileHeader: string[];
32
+ routeTreeFileFooter: string[];
33
+ enableRouteGeneration?: boolean | undefined;
34
+ experimental?: {
35
+ enableCodeSplitting?: boolean | undefined;
36
+ } | undefined;
37
+ routeFilePrefix?: string | undefined;
38
+ routeFileIgnorePattern?: string | undefined;
39
+ }>) => VitePlugin<any> | VitePlugin<any>[];
40
+ export declare function TanStackRouterVite(inlineConfig: Partial<PluginOptions>): Array<VitePlugin>;
41
+ export type Config = PluginOptions;
@@ -0,0 +1,16 @@
1
+ import { unpluginRouterCodeSplitter } from "./code-splitter.js";
2
+ import { unpluginRouterGenerator } from "./router-generator.js";
3
+ const TanStackRouterGeneratorVite = unpluginRouterGenerator.vite;
4
+ const TanStackRouterCodeSplitterVite = unpluginRouterCodeSplitter.vite;
5
+ function TanStackRouterVite(inlineConfig) {
6
+ return [
7
+ TanStackRouterGeneratorVite(inlineConfig),
8
+ TanStackRouterCodeSplitterVite(inlineConfig)
9
+ ];
10
+ }
11
+ export {
12
+ TanStackRouterCodeSplitterVite,
13
+ TanStackRouterGeneratorVite,
14
+ TanStackRouterVite
15
+ };
16
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","sources":["../../src/vite.ts"],"sourcesContent":["import { unpluginRouterCodeSplitter } from './code-splitter'\nimport { unpluginRouterGenerator } from './router-generator'\n\nimport type { PluginOptions } from './config'\nimport type { VitePlugin } from 'unplugin'\n\nexport const TanStackRouterGeneratorVite = unpluginRouterGenerator.vite\nexport const TanStackRouterCodeSplitterVite = unpluginRouterCodeSplitter.vite\n\nexport function TanStackRouterVite(\n inlineConfig: Partial<PluginOptions>,\n): Array<VitePlugin> {\n return [\n TanStackRouterGeneratorVite(inlineConfig) as VitePlugin,\n TanStackRouterCodeSplitterVite(inlineConfig) as VitePlugin,\n ]\n}\n\nexport type Config = PluginOptions\n"],"names":[],"mappings":";;AAMO,MAAM,8BAA8B,wBAAwB;AAC5D,MAAM,iCAAiC,2BAA2B;AAElE,SAAS,mBACd,cACmB;AACZ,SAAA;AAAA,IACL,4BAA4B,YAAY;AAAA,IACxC,+BAA+B,YAAY;AAAA,EAAA;AAE/C;"}
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "@tanstack/router-plugin",
3
+ "version": "1.39.2",
4
+ "description": "",
5
+ "author": "Tanner Linsley",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/TanStack/router.git",
10
+ "directory": "packages/start-vite-plugin"
11
+ },
12
+ "homepage": "https://tanstack.com/router",
13
+ "funding": {
14
+ "type": "github",
15
+ "url": "https://github.com/sponsors/tannerlinsley"
16
+ },
17
+ "type": "module",
18
+ "types": "dist/esm/index.d.ts",
19
+ "main": "dist/cjs/index.cjs",
20
+ "module": "dist/esm/index.js",
21
+ "exports": {
22
+ ".": {
23
+ "import": {
24
+ "types": "./dist/esm/index.d.ts",
25
+ "default": "./dist/esm/index.js"
26
+ },
27
+ "require": {
28
+ "types": "./dist/cjs/index.d.cts",
29
+ "default": "./dist/cjs/index.cjs"
30
+ }
31
+ },
32
+ "./vite": {
33
+ "import": {
34
+ "types": "./dist/esm/vite.d.ts",
35
+ "default": "./dist/esm/vite.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/cjs/vite.d.cts",
39
+ "default": "./dist/cjs/vite.cjs"
40
+ }
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
44
+ "sideEffects": false,
45
+ "keywords": [
46
+ "react",
47
+ "location",
48
+ "router",
49
+ "routing",
50
+ "async",
51
+ "async router",
52
+ "typescript"
53
+ ],
54
+ "engines": {
55
+ "node": ">=12"
56
+ },
57
+ "files": [
58
+ "dist",
59
+ "src/**"
60
+ ],
61
+ "peerDependencies": {
62
+ "vite": ">=5"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "vite": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "dependencies": {
70
+ "@babel/core": "^7.23.7",
71
+ "@babel/generator": "^7.23.6",
72
+ "@babel/plugin-syntax-jsx": "^7.24.1",
73
+ "@babel/plugin-syntax-typescript": "^7.24.1",
74
+ "@babel/plugin-transform-react-jsx": "^7.23.4",
75
+ "@babel/plugin-transform-typescript": "^7.24.1",
76
+ "@babel/template": "^7.24.0",
77
+ "@babel/traverse": "^7.24.1",
78
+ "@babel/types": "^7.24.0",
79
+ "@types/babel__core": "^7.20.5",
80
+ "@types/babel__generator": "^7.6.8",
81
+ "@types/babel__template": "^7.4.4",
82
+ "@types/babel__traverse": "^7.20.5",
83
+ "unplugin": "^1.10.1",
84
+ "zod": "^3.22.4",
85
+ "@tanstack/router-generator": "^1.37.0"
86
+ },
87
+ "scripts": {}
88
+ }
package/src/ast.ts ADDED
@@ -0,0 +1,49 @@
1
+ import * as babel from '@babel/core'
2
+
3
+ export type CompileAstFn = (compileOpts: {
4
+ code: string
5
+ filename: string
6
+ getBabelConfig: () => { plugins: Array<any> }
7
+ }) => Promise<{
8
+ code: string
9
+ map: any
10
+ }>
11
+
12
+ export function compileAst(makeOpts: { root: string }) {
13
+ return async (opts: {
14
+ code: string
15
+ filename: string
16
+ getBabelConfig: () => { plugins: Array<any> }
17
+ }): Promise<{
18
+ code: string
19
+ map: any
20
+ }> => {
21
+ const res = babel.transformSync(opts.code, {
22
+ plugins: [
23
+ ['@babel/plugin-syntax-jsx', {}],
24
+ [
25
+ '@babel/plugin-syntax-typescript',
26
+ {
27
+ isTSX: true,
28
+ },
29
+ ],
30
+ ...opts.getBabelConfig().plugins,
31
+ ],
32
+ root: makeOpts.root,
33
+ filename: opts.filename,
34
+ sourceMaps: true,
35
+ })
36
+
37
+ if (res?.code) {
38
+ return {
39
+ code: res.code,
40
+ map: res.map,
41
+ }
42
+ }
43
+
44
+ return {
45
+ code: opts.code,
46
+ map: null,
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,162 @@
1
+ import { isAbsolute, join } from 'node:path'
2
+ import { fileURLToPath, pathToFileURL } from 'node:url'
3
+ import { createUnplugin } from 'unplugin'
4
+
5
+ import { compileAst } from './ast'
6
+ import { compileFile, splitFile } from './compilers'
7
+ import { getConfig } from './config'
8
+ import { splitPrefix } from './constants'
9
+
10
+ import type { PluginOptions } from './config'
11
+ import type { UnpluginFactory } from 'unplugin'
12
+
13
+ function capitalizeFirst(str: string): string {
14
+ return str.charAt(0).toUpperCase() + str.slice(1)
15
+ }
16
+
17
+ function fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {
18
+ const routesDirectoryPath = isAbsolute(routesDirectory)
19
+ ? routesDirectory
20
+ : join(process.cwd(), routesDirectory)
21
+
22
+ return filePath.startsWith(routesDirectoryPath)
23
+ }
24
+
25
+ const bannedBeforeExternalPlugins = [
26
+ {
27
+ identifier: '@react-refresh',
28
+ pkg: '@vitejs/plugin-react',
29
+ usage: 'viteReact()',
30
+ },
31
+ ]
32
+
33
+ class FoundPluginInBeforeCode extends Error {
34
+ constructor(
35
+ externalPlugin: (typeof bannedBeforeExternalPlugins)[number],
36
+ framework: string,
37
+ ) {
38
+ super(`We detected that the '${externalPlugin.pkg}' was passed before '@tanstack/router-plugin'. Please make sure that '@tanstack/router-plugin' is passed before '${externalPlugin.pkg}' and try again:
39
+ e.g.
40
+ plugins: [
41
+ TanStackRouter${capitalizeFirst(framework)}(), // Place this before ${externalPlugin.usage}
42
+ ${externalPlugin.usage},
43
+ ]
44
+ `)
45
+ }
46
+ }
47
+
48
+ export const unpluginFactory: UnpluginFactory<Partial<PluginOptions>> = (
49
+ options = {},
50
+ { framework },
51
+ ) => {
52
+ const debug = Boolean(process.env.TSR_VITE_DEBUG)
53
+
54
+ let ROOT: string = process.cwd()
55
+ let userConfig = options as PluginOptions
56
+
57
+ const handleSplittingFile = async (code: string, id: string) => {
58
+ const compiledAst = compileAst({
59
+ root: ROOT,
60
+ })
61
+
62
+ if (debug) console.info('Splitting route: ', id)
63
+
64
+ const compiled = await splitFile({
65
+ code,
66
+ compileAst: compiledAst,
67
+ filename: id,
68
+ })
69
+
70
+ if (debug) console.info('')
71
+ if (debug) console.info('Split Output')
72
+ if (debug) console.info('')
73
+ if (debug) console.info(compiled.code)
74
+ if (debug) console.info('')
75
+ if (debug) console.info('')
76
+ if (debug) console.info('')
77
+ if (debug) console.info('')
78
+ if (debug) console.info('')
79
+ if (debug) console.info('')
80
+ if (debug) console.info('')
81
+ if (debug) console.info('')
82
+
83
+ return compiled
84
+ }
85
+
86
+ const handleCompilingFile = async (code: string, id: string) => {
87
+ const compiledAst = compileAst({
88
+ root: ROOT,
89
+ })
90
+
91
+ if (debug) console.info('Handling createRoute: ', id)
92
+
93
+ const compiled = await compileFile({
94
+ code,
95
+ compileAst: compiledAst,
96
+ filename: id,
97
+ })
98
+
99
+ if (debug) console.info('')
100
+ if (debug) console.info('Compiled Output')
101
+ if (debug) console.info('')
102
+ if (debug) console.info(compiled.code)
103
+ if (debug) console.info('')
104
+ if (debug) console.info('')
105
+ if (debug) console.info('')
106
+ if (debug) console.info('')
107
+ if (debug) console.info('')
108
+ if (debug) console.info('')
109
+ if (debug) console.info('')
110
+ if (debug) console.info('')
111
+ if (debug) console.info('')
112
+ if (debug) console.info('')
113
+
114
+ return compiled
115
+ }
116
+
117
+ return {
118
+ name: 'router-code-splitter-plugin',
119
+ enforce: 'pre',
120
+ resolveId(source) {
121
+ if (!userConfig.experimental?.enableCodeSplitting) {
122
+ return null
123
+ }
124
+
125
+ if (source.startsWith(splitPrefix + ':')) {
126
+ return source.replace(splitPrefix + ':', '')
127
+ }
128
+ return null
129
+ },
130
+ async transform(code, id) {
131
+ const url = pathToFileURL(id)
132
+ url.searchParams.delete('v')
133
+ id = fileURLToPath(url).replace(/\\/g, '/')
134
+
135
+ if (id.includes(splitPrefix)) {
136
+ return await handleSplittingFile(code, id)
137
+ } else if (
138
+ fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&
139
+ (code.includes('createRoute(') || code.includes('createFileRoute('))
140
+ ) {
141
+ for (const externalPlugin of bannedBeforeExternalPlugins) {
142
+ if (code.includes(externalPlugin.identifier)) {
143
+ throw new FoundPluginInBeforeCode(externalPlugin, framework)
144
+ }
145
+ }
146
+
147
+ return await handleCompilingFile(code, id)
148
+ }
149
+
150
+ return null
151
+ },
152
+ vite: {
153
+ async configResolved(config) {
154
+ ROOT = config.root
155
+ userConfig = await getConfig(options, ROOT)
156
+ },
157
+ },
158
+ }
159
+ }
160
+
161
+ export const unpluginRouterCodeSplitter =
162
+ /* #__PURE__ */ createUnplugin(unpluginFactory)