@tanstack/router-plugin 1.40.3 → 1.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,151 +1,318 @@
1
1
  import * as t from "@babel/types";
2
2
  import babel__default from "@babel/core";
3
- import generate from "@babel/generator";
3
+ import _generate from "@babel/generator";
4
4
  import * as template from "@babel/template";
5
+ import { deadCodeElimination } from "babel-dead-code-elimination";
5
6
  import { splitPrefix } from "./constants.js";
6
- import { eliminateUnreferencedIdentifiers } from "./eliminateUnreferencedIdentifiers.js";
7
- async function compileFile(opts) {
8
- return await opts.compileAst({
9
- code: opts.code,
10
- filename: opts.filename,
11
- getBabelConfig: () => ({
12
- plugins: [
13
- [
7
+ import { parseAst } from "./ast.js";
8
+ let generate = _generate["default"];
9
+ if (!generate) {
10
+ generate = _generate;
11
+ }
12
+ function compileCodeSplitReferenceRoute(opts) {
13
+ const ast = parseAst(opts);
14
+ if (!ast) {
15
+ throw new Error(
16
+ `Failed to compile ast for compileCodeSplitReferenceRoute() for the file: ${opts.filename}`
17
+ );
18
+ }
19
+ babel__default.traverse(ast, {
20
+ Program: {
21
+ enter(programPath, programState) {
22
+ const state = programState;
23
+ const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`;
24
+ let existingCompImportPath = null;
25
+ let existingLoaderImportPath = null;
26
+ programPath.traverse(
14
27
  {
15
- visitor: {
16
- Program: {
17
- enter(programPath, state) {
18
- const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`;
19
- let existingCompImportPath = null;
20
- let existingLoaderImportPath = null;
21
- programPath.traverse(
22
- {
23
- CallExpression: (path) => {
24
- if (!t.isIdentifier(path.node.callee)) {
25
- return;
26
- }
27
- if (!(path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute")) {
28
- return;
29
- }
30
- if (t.isCallExpression(path.parentPath.node)) {
31
- const options = resolveIdentifier(
32
- path,
33
- path.parentPath.node.arguments[0]
34
- );
35
- let found = false;
36
- const hasImportedOrDefinedIdentifier = (name) => {
37
- return programPath.scope.hasBinding(name);
38
- };
39
- if (t.isObjectExpression(options)) {
40
- options.properties.forEach((prop) => {
41
- if (t.isObjectProperty(prop)) {
42
- if (t.isIdentifier(prop.key)) {
43
- if (prop.key.name === "component") {
44
- const value = prop.value;
45
- if (t.isIdentifier(value)) {
46
- existingCompImportPath = getImportSpecifierAndPathFromLocalName(
47
- programPath,
48
- value.name
49
- ).path;
50
- removeIdentifierLiteral(path, value);
51
- }
52
- if (!hasImportedOrDefinedIdentifier(
53
- "lazyRouteComponent"
54
- )) {
55
- programPath.unshiftContainer("body", [
56
- template.statement(
57
- `import { lazyRouteComponent } from '@tanstack/react-router'`
58
- )()
59
- ]);
60
- }
61
- if (!hasImportedOrDefinedIdentifier(
62
- "$$splitComponentImporter"
63
- )) {
64
- programPath.unshiftContainer("body", [
65
- template.statement(
66
- `const $$splitComponentImporter = () => import('${splitUrl}')`
67
- )()
68
- ]);
69
- }
70
- prop.value = template.expression(
71
- `lazyRouteComponent($$splitComponentImporter, 'component')`
72
- )();
73
- programPath.pushContainer("body", [
74
- template.statement(
75
- `function DummyComponent() { return null }`
76
- )()
77
- ]);
78
- found = true;
79
- } else if (prop.key.name === "loader") {
80
- const value = prop.value;
81
- if (t.isIdentifier(value)) {
82
- existingLoaderImportPath = getImportSpecifierAndPathFromLocalName(
83
- programPath,
84
- value.name
85
- ).path;
86
- removeIdentifierLiteral(path, value);
87
- }
88
- if (!hasImportedOrDefinedIdentifier("lazyFn")) {
89
- programPath.unshiftContainer("body", [
90
- template.smart(
91
- `import { lazyFn } from '@tanstack/react-router'`
92
- )()
93
- ]);
94
- }
95
- if (!hasImportedOrDefinedIdentifier(
96
- "$$splitLoaderImporter"
97
- )) {
98
- programPath.unshiftContainer("body", [
99
- template.statement(
100
- `const $$splitLoaderImporter = () => import('${splitUrl}')`
101
- )()
102
- ]);
103
- }
104
- prop.value = template.expression(
105
- `lazyFn($$splitLoaderImporter, 'loader')`
106
- )();
107
- found = true;
108
- }
109
- }
110
- }
111
- programPath.scope.crawl();
112
- });
28
+ CallExpression: (path) => {
29
+ if (!t.isIdentifier(path.node.callee)) {
30
+ return;
31
+ }
32
+ if (!(path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute")) {
33
+ return;
34
+ }
35
+ if (t.isCallExpression(path.parentPath.node)) {
36
+ const options = resolveIdentifier(
37
+ path,
38
+ path.parentPath.node.arguments[0]
39
+ );
40
+ let found = false;
41
+ const hasImportedOrDefinedIdentifier = (name) => {
42
+ return programPath.scope.hasBinding(name);
43
+ };
44
+ if (t.isObjectExpression(options)) {
45
+ options.properties.forEach((prop) => {
46
+ if (t.isObjectProperty(prop)) {
47
+ if (t.isIdentifier(prop.key)) {
48
+ if (prop.key.name === "component") {
49
+ const value = prop.value;
50
+ if (t.isIdentifier(value)) {
51
+ existingCompImportPath = getImportSpecifierAndPathFromLocalName(
52
+ programPath,
53
+ value.name
54
+ ).path;
55
+ removeIdentifierLiteral(path, value);
113
56
  }
114
- if (found) {
115
- programPath.pushContainer("body", [
57
+ if (!hasImportedOrDefinedIdentifier(
58
+ "lazyRouteComponent"
59
+ )) {
60
+ programPath.unshiftContainer("body", [
116
61
  template.statement(
117
- `function TSR_Dummy_Component() {}`
62
+ `import { lazyRouteComponent } from '@tanstack/react-router'`
118
63
  )()
119
64
  ]);
120
65
  }
66
+ if (!hasImportedOrDefinedIdentifier(
67
+ "$$splitComponentImporter"
68
+ )) {
69
+ programPath.unshiftContainer("body", [
70
+ template.statement(
71
+ `const $$splitComponentImporter = () => import('${splitUrl}')`
72
+ )()
73
+ ]);
74
+ }
75
+ prop.value = template.expression(
76
+ `lazyRouteComponent($$splitComponentImporter, 'component')`
77
+ )();
78
+ programPath.pushContainer("body", [
79
+ template.statement(
80
+ `function DummyComponent() { return null }`
81
+ )()
82
+ ]);
83
+ found = true;
84
+ } else if (prop.key.name === "loader") {
85
+ const value = prop.value;
86
+ if (t.isIdentifier(value)) {
87
+ existingLoaderImportPath = getImportSpecifierAndPathFromLocalName(
88
+ programPath,
89
+ value.name
90
+ ).path;
91
+ removeIdentifierLiteral(path, value);
92
+ }
93
+ if (!hasImportedOrDefinedIdentifier("lazyFn")) {
94
+ programPath.unshiftContainer("body", [
95
+ template.smart(
96
+ `import { lazyFn } from '@tanstack/react-router'`
97
+ )()
98
+ ]);
99
+ }
100
+ if (!hasImportedOrDefinedIdentifier(
101
+ "$$splitLoaderImporter"
102
+ )) {
103
+ programPath.unshiftContainer("body", [
104
+ template.statement(
105
+ `const $$splitLoaderImporter = () => import('${splitUrl}')`
106
+ )()
107
+ ]);
108
+ }
109
+ prop.value = template.expression(
110
+ `lazyFn($$splitLoaderImporter, 'loader')`
111
+ )();
112
+ found = true;
121
113
  }
122
114
  }
123
- },
124
- state
125
- );
126
- eliminateUnreferencedIdentifiers(programPath);
127
- if (existingCompImportPath || existingLoaderImportPath) {
128
- programPath.traverse({
129
- ImportDeclaration(path) {
130
- if (path.node.specifiers.length > 0)
131
- return;
132
- if (path.node.source.value === existingCompImportPath || path.node.source.value === existingLoaderImportPath) {
133
- path.remove();
134
- }
135
- }
136
- });
137
- }
115
+ }
116
+ programPath.scope.crawl();
117
+ });
118
+ }
119
+ if (found) {
120
+ programPath.pushContainer("body", [
121
+ template.statement(`function TSR_Dummy_Component() {}`)()
122
+ ]);
138
123
  }
139
124
  }
140
125
  }
141
126
  },
127
+ state
128
+ );
129
+ if (existingCompImportPath || existingLoaderImportPath) {
130
+ programPath.traverse({
131
+ ImportDeclaration(path) {
132
+ if (path.node.specifiers.length > 0) return;
133
+ if (path.node.source.value === existingCompImportPath || path.node.source.value === existingLoaderImportPath) {
134
+ path.remove();
135
+ }
136
+ }
137
+ });
138
+ }
139
+ }
140
+ }
141
+ });
142
+ deadCodeElimination(ast);
143
+ return generate(ast, {
144
+ sourceMaps: true,
145
+ minified: process.env.NODE_ENV === "production"
146
+ });
147
+ }
148
+ const splitNodeTypes = ["component", "loader"];
149
+ function compileCodeSplitVirtualRoute(opts) {
150
+ const ast = parseAst(opts);
151
+ if (!ast) {
152
+ throw new Error(
153
+ `Failed to compile ast for compileCodeSplitVirtualRoute() for the file: ${opts.filename}`
154
+ );
155
+ }
156
+ babel__default.traverse(ast, {
157
+ Program: {
158
+ enter(programPath, programState) {
159
+ const state = programState;
160
+ const splitNodesByType = {
161
+ component: void 0,
162
+ loader: void 0
163
+ };
164
+ programPath.traverse(
142
165
  {
143
- root: process.cwd(),
144
- minify: process.env.NODE_ENV === "production"
166
+ CallExpression: (path) => {
167
+ if (!t.isIdentifier(path.node.callee)) {
168
+ return;
169
+ }
170
+ if (!(path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute")) {
171
+ return;
172
+ }
173
+ if (t.isCallExpression(path.parentPath.node)) {
174
+ const options = resolveIdentifier(
175
+ path,
176
+ path.parentPath.node.arguments[0]
177
+ );
178
+ if (t.isObjectExpression(options)) {
179
+ options.properties.forEach((prop) => {
180
+ if (t.isObjectProperty(prop)) {
181
+ splitNodeTypes.forEach((type) => {
182
+ if (t.isIdentifier(prop.key)) {
183
+ if (prop.key.name === type) {
184
+ splitNodesByType[type] = prop.value;
185
+ }
186
+ }
187
+ });
188
+ }
189
+ });
190
+ options.properties = [];
191
+ }
192
+ }
193
+ }
194
+ },
195
+ state
196
+ );
197
+ splitNodeTypes.forEach((splitType) => {
198
+ let splitNode = splitNodesByType[splitType];
199
+ if (!splitNode) {
200
+ return;
201
+ }
202
+ while (t.isIdentifier(splitNode)) {
203
+ const binding = programPath.scope.getBinding(splitNode.name);
204
+ splitNode = binding == null ? void 0 : binding.path.node;
145
205
  }
146
- ]
147
- ].filter(Boolean)
148
- })
206
+ if (splitNode) {
207
+ if (t.isFunctionDeclaration(splitNode)) {
208
+ programPath.pushContainer(
209
+ "body",
210
+ t.variableDeclaration("const", [
211
+ t.variableDeclarator(
212
+ t.identifier(splitType),
213
+ t.functionExpression(
214
+ splitNode.id || null,
215
+ // Anonymize the function expression
216
+ splitNode.params,
217
+ splitNode.body,
218
+ splitNode.generator,
219
+ splitNode.async
220
+ )
221
+ )
222
+ ])
223
+ );
224
+ } else if (t.isFunctionExpression(splitNode) || t.isArrowFunctionExpression(splitNode)) {
225
+ programPath.pushContainer(
226
+ "body",
227
+ t.variableDeclaration("const", [
228
+ t.variableDeclarator(
229
+ t.identifier(splitType),
230
+ splitNode
231
+ )
232
+ ])
233
+ );
234
+ } else if (t.isImportSpecifier(splitNode) || t.isImportDefaultSpecifier(splitNode)) {
235
+ programPath.pushContainer(
236
+ "body",
237
+ t.variableDeclaration("const", [
238
+ t.variableDeclarator(
239
+ t.identifier(splitType),
240
+ splitNode.local
241
+ )
242
+ ])
243
+ );
244
+ } else if (t.isCallExpression(splitNode)) {
245
+ const outputSplitNodeCode = generate(splitNode).code;
246
+ const splitNodeAst = babel__default.parse(outputSplitNodeCode);
247
+ if (!splitNodeAst) {
248
+ throw new Error(
249
+ `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}"`
250
+ );
251
+ }
252
+ const statement = splitNodeAst.program.body[0];
253
+ if (!statement) {
254
+ throw new Error(
255
+ `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}" as no statement was found in the program body`
256
+ );
257
+ }
258
+ if (t.isExpressionStatement(statement)) {
259
+ const expression = statement.expression;
260
+ programPath.pushContainer(
261
+ "body",
262
+ t.variableDeclaration("const", [
263
+ t.variableDeclarator(t.identifier(splitType), expression)
264
+ ])
265
+ );
266
+ } else {
267
+ throw new Error(
268
+ `Unexpected expression type encounter for "${splitType}" in the node type "${splitNode.type}"`
269
+ );
270
+ }
271
+ } else {
272
+ console.info("Unexpected splitNode type:", splitNode);
273
+ throw new Error(`Unexpected splitNode type ☝️: ${splitNode.type}`);
274
+ }
275
+ }
276
+ programPath.node.body = programPath.node.body.filter((node) => {
277
+ return node !== splitNode;
278
+ });
279
+ programPath.pushContainer("body", [
280
+ t.exportNamedDeclaration(null, [
281
+ t.exportSpecifier(
282
+ t.identifier(splitType),
283
+ t.identifier(splitType)
284
+ )
285
+ ])
286
+ ]);
287
+ });
288
+ programPath.traverse({
289
+ ExportNamedDeclaration(path) {
290
+ if (path.node.declaration) {
291
+ if (t.isVariableDeclaration(path.node.declaration)) {
292
+ path.replaceWith(
293
+ t.importDeclaration(
294
+ path.node.declaration.declarations.map(
295
+ (decl) => t.importSpecifier(
296
+ t.identifier(decl.id.name),
297
+ t.identifier(decl.id.name)
298
+ )
299
+ ),
300
+ t.stringLiteral(
301
+ opts.filename.split(`?${splitPrefix}`)[0]
302
+ )
303
+ )
304
+ );
305
+ }
306
+ }
307
+ }
308
+ });
309
+ }
310
+ }
311
+ });
312
+ deadCodeElimination(ast);
313
+ return generate(ast, {
314
+ sourceMaps: true,
315
+ minified: process.env.NODE_ENV === "production"
149
316
  });
150
317
  }
151
318
  function getImportSpecifierAndPathFromLocalName(programPath, name) {
@@ -187,194 +354,8 @@ function removeIdentifierLiteral(path, node) {
187
354
  }
188
355
  }
189
356
  }
190
- const splitNodeTypes = ["component", "loader"];
191
- async function splitFile(opts) {
192
- return await opts.compileAst({
193
- code: opts.code,
194
- filename: opts.filename,
195
- getBabelConfig: () => ({
196
- plugins: [
197
- [
198
- {
199
- visitor: {
200
- Program: {
201
- enter(programPath, state) {
202
- const splitNodesByType = {
203
- component: void 0,
204
- loader: void 0
205
- };
206
- programPath.traverse(
207
- {
208
- CallExpression: (path) => {
209
- if (!t.isIdentifier(path.node.callee)) {
210
- return;
211
- }
212
- if (!(path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute")) {
213
- return;
214
- }
215
- if (t.isCallExpression(path.parentPath.node)) {
216
- const options = resolveIdentifier(
217
- path,
218
- path.parentPath.node.arguments[0]
219
- );
220
- if (t.isObjectExpression(options)) {
221
- options.properties.forEach((prop) => {
222
- if (t.isObjectProperty(prop)) {
223
- splitNodeTypes.forEach((type) => {
224
- if (t.isIdentifier(prop.key)) {
225
- if (prop.key.name === type) {
226
- splitNodesByType[type] = prop.value;
227
- }
228
- }
229
- });
230
- }
231
- });
232
- options.properties = [];
233
- }
234
- }
235
- }
236
- },
237
- state
238
- );
239
- splitNodeTypes.forEach((splitType) => {
240
- let splitNode = splitNodesByType[splitType];
241
- if (!splitNode) {
242
- return;
243
- }
244
- while (t.isIdentifier(splitNode)) {
245
- const binding = programPath.scope.getBinding(
246
- splitNode.name
247
- );
248
- splitNode = binding == null ? void 0 : binding.path.node;
249
- }
250
- if (splitNode) {
251
- if (t.isFunctionDeclaration(splitNode)) {
252
- programPath.pushContainer(
253
- "body",
254
- t.variableDeclaration("const", [
255
- t.variableDeclarator(
256
- t.identifier(splitType),
257
- t.functionExpression(
258
- splitNode.id || null,
259
- // Anonymize the function expression
260
- splitNode.params,
261
- splitNode.body,
262
- splitNode.generator,
263
- splitNode.async
264
- )
265
- )
266
- ])
267
- );
268
- } else if (t.isFunctionExpression(splitNode) || t.isArrowFunctionExpression(splitNode)) {
269
- programPath.pushContainer(
270
- "body",
271
- t.variableDeclaration("const", [
272
- t.variableDeclarator(
273
- t.identifier(splitType),
274
- splitNode
275
- )
276
- ])
277
- );
278
- } else if (t.isImportSpecifier(splitNode) || t.isImportDefaultSpecifier(splitNode)) {
279
- programPath.pushContainer(
280
- "body",
281
- t.variableDeclaration("const", [
282
- t.variableDeclarator(
283
- t.identifier(splitType),
284
- splitNode.local
285
- )
286
- ])
287
- );
288
- } else if (t.isCallExpression(splitNode)) {
289
- const outputSplitNodeCode = generate(splitNode).code;
290
- const splitNodeAst = babel__default.parse(outputSplitNodeCode);
291
- if (!splitNodeAst) {
292
- throw new Error(
293
- `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}"`
294
- );
295
- }
296
- const statement = splitNodeAst.program.body[0];
297
- if (!statement) {
298
- throw new Error(
299
- `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}" as no statement was found in the program body`
300
- );
301
- }
302
- if (t.isExpressionStatement(statement)) {
303
- const expression = statement.expression;
304
- programPath.pushContainer(
305
- "body",
306
- t.variableDeclaration("const", [
307
- t.variableDeclarator(
308
- t.identifier(splitType),
309
- expression
310
- )
311
- ])
312
- );
313
- } else {
314
- throw new Error(
315
- `Unexpected expression type encounter for "${splitType}" in the node type "${splitNode.type}"`
316
- );
317
- }
318
- } else {
319
- console.info("Unexpected splitNode type:", splitNode);
320
- throw new Error(
321
- `Unexpected splitNode type ☝️: ${splitNode.type}`
322
- );
323
- }
324
- }
325
- programPath.node.body = programPath.node.body.filter(
326
- (node) => {
327
- return node !== splitNode;
328
- }
329
- );
330
- programPath.pushContainer("body", [
331
- t.exportNamedDeclaration(null, [
332
- t.exportSpecifier(
333
- t.identifier(splitType),
334
- t.identifier(splitType)
335
- )
336
- ])
337
- ]);
338
- });
339
- programPath.traverse({
340
- ExportNamedDeclaration(path) {
341
- if (path.node.declaration) {
342
- if (t.isVariableDeclaration(path.node.declaration)) {
343
- path.replaceWith(
344
- t.importDeclaration(
345
- path.node.declaration.declarations.map(
346
- (decl) => t.importSpecifier(
347
- t.identifier(decl.id.name),
348
- t.identifier(decl.id.name)
349
- )
350
- ),
351
- t.stringLiteral(
352
- opts.filename.split(
353
- `?${splitPrefix}`
354
- )[0]
355
- )
356
- )
357
- );
358
- }
359
- }
360
- }
361
- });
362
- eliminateUnreferencedIdentifiers(programPath);
363
- }
364
- }
365
- }
366
- },
367
- {
368
- root: process.cwd(),
369
- minify: process.env.NODE_ENV === "production"
370
- }
371
- ]
372
- ].filter(Boolean)
373
- })
374
- });
375
- }
376
357
  export {
377
- compileFile,
378
- splitFile
358
+ compileCodeSplitReferenceRoute,
359
+ compileCodeSplitVirtualRoute
379
360
  };
380
361
  //# sourceMappingURL=compilers.js.map