@tanstack/router-plugin 1.41.0 → 1.43.5

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,150 +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) return;
131
- if (path.node.source.value === existingCompImportPath || path.node.source.value === existingLoaderImportPath) {
132
- path.remove();
133
- }
134
- }
135
- });
136
- }
115
+ }
116
+ programPath.scope.crawl();
117
+ });
118
+ }
119
+ if (found) {
120
+ programPath.pushContainer("body", [
121
+ template.statement(`function TSR_Dummy_Component() {}`)()
122
+ ]);
137
123
  }
138
124
  }
139
125
  }
140
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(
141
165
  {
142
- root: process.cwd(),
143
- 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;
144
205
  }
145
- ]
146
- ].filter(Boolean)
147
- })
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"
148
316
  });
149
317
  }
150
318
  function getImportSpecifierAndPathFromLocalName(programPath, name) {
@@ -186,194 +354,8 @@ function removeIdentifierLiteral(path, node) {
186
354
  }
187
355
  }
188
356
  }
189
- const splitNodeTypes = ["component", "loader"];
190
- async function splitFile(opts) {
191
- return await opts.compileAst({
192
- code: opts.code,
193
- filename: opts.filename,
194
- getBabelConfig: () => ({
195
- plugins: [
196
- [
197
- {
198
- visitor: {
199
- Program: {
200
- enter(programPath, state) {
201
- const splitNodesByType = {
202
- component: void 0,
203
- loader: void 0
204
- };
205
- programPath.traverse(
206
- {
207
- CallExpression: (path) => {
208
- if (!t.isIdentifier(path.node.callee)) {
209
- return;
210
- }
211
- if (!(path.node.callee.name === "createRoute" || path.node.callee.name === "createFileRoute")) {
212
- return;
213
- }
214
- if (t.isCallExpression(path.parentPath.node)) {
215
- const options = resolveIdentifier(
216
- path,
217
- path.parentPath.node.arguments[0]
218
- );
219
- if (t.isObjectExpression(options)) {
220
- options.properties.forEach((prop) => {
221
- if (t.isObjectProperty(prop)) {
222
- splitNodeTypes.forEach((type) => {
223
- if (t.isIdentifier(prop.key)) {
224
- if (prop.key.name === type) {
225
- splitNodesByType[type] = prop.value;
226
- }
227
- }
228
- });
229
- }
230
- });
231
- options.properties = [];
232
- }
233
- }
234
- }
235
- },
236
- state
237
- );
238
- splitNodeTypes.forEach((splitType) => {
239
- let splitNode = splitNodesByType[splitType];
240
- if (!splitNode) {
241
- return;
242
- }
243
- while (t.isIdentifier(splitNode)) {
244
- const binding = programPath.scope.getBinding(
245
- splitNode.name
246
- );
247
- splitNode = binding == null ? void 0 : binding.path.node;
248
- }
249
- if (splitNode) {
250
- if (t.isFunctionDeclaration(splitNode)) {
251
- programPath.pushContainer(
252
- "body",
253
- t.variableDeclaration("const", [
254
- t.variableDeclarator(
255
- t.identifier(splitType),
256
- t.functionExpression(
257
- splitNode.id || null,
258
- // Anonymize the function expression
259
- splitNode.params,
260
- splitNode.body,
261
- splitNode.generator,
262
- splitNode.async
263
- )
264
- )
265
- ])
266
- );
267
- } else if (t.isFunctionExpression(splitNode) || t.isArrowFunctionExpression(splitNode)) {
268
- programPath.pushContainer(
269
- "body",
270
- t.variableDeclaration("const", [
271
- t.variableDeclarator(
272
- t.identifier(splitType),
273
- splitNode
274
- )
275
- ])
276
- );
277
- } else if (t.isImportSpecifier(splitNode) || t.isImportDefaultSpecifier(splitNode)) {
278
- programPath.pushContainer(
279
- "body",
280
- t.variableDeclaration("const", [
281
- t.variableDeclarator(
282
- t.identifier(splitType),
283
- splitNode.local
284
- )
285
- ])
286
- );
287
- } else if (t.isCallExpression(splitNode)) {
288
- const outputSplitNodeCode = generate(splitNode).code;
289
- const splitNodeAst = babel__default.parse(outputSplitNodeCode);
290
- if (!splitNodeAst) {
291
- throw new Error(
292
- `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}"`
293
- );
294
- }
295
- const statement = splitNodeAst.program.body[0];
296
- if (!statement) {
297
- throw new Error(
298
- `Failed to parse the generated code for "${splitType}" in the node type "${splitNode.type}" as no statement was found in the program body`
299
- );
300
- }
301
- if (t.isExpressionStatement(statement)) {
302
- const expression = statement.expression;
303
- programPath.pushContainer(
304
- "body",
305
- t.variableDeclaration("const", [
306
- t.variableDeclarator(
307
- t.identifier(splitType),
308
- expression
309
- )
310
- ])
311
- );
312
- } else {
313
- throw new Error(
314
- `Unexpected expression type encounter for "${splitType}" in the node type "${splitNode.type}"`
315
- );
316
- }
317
- } else {
318
- console.info("Unexpected splitNode type:", splitNode);
319
- throw new Error(
320
- `Unexpected splitNode type ☝️: ${splitNode.type}`
321
- );
322
- }
323
- }
324
- programPath.node.body = programPath.node.body.filter(
325
- (node) => {
326
- return node !== splitNode;
327
- }
328
- );
329
- programPath.pushContainer("body", [
330
- t.exportNamedDeclaration(null, [
331
- t.exportSpecifier(
332
- t.identifier(splitType),
333
- t.identifier(splitType)
334
- )
335
- ])
336
- ]);
337
- });
338
- programPath.traverse({
339
- ExportNamedDeclaration(path) {
340
- if (path.node.declaration) {
341
- if (t.isVariableDeclaration(path.node.declaration)) {
342
- path.replaceWith(
343
- t.importDeclaration(
344
- path.node.declaration.declarations.map(
345
- (decl) => t.importSpecifier(
346
- t.identifier(decl.id.name),
347
- t.identifier(decl.id.name)
348
- )
349
- ),
350
- t.stringLiteral(
351
- opts.filename.split(
352
- `?${splitPrefix}`
353
- )[0]
354
- )
355
- )
356
- );
357
- }
358
- }
359
- }
360
- });
361
- eliminateUnreferencedIdentifiers(programPath);
362
- }
363
- }
364
- }
365
- },
366
- {
367
- root: process.cwd(),
368
- minify: process.env.NODE_ENV === "production"
369
- }
370
- ]
371
- ].filter(Boolean)
372
- })
373
- });
374
- }
375
357
  export {
376
- compileFile,
377
- splitFile
358
+ compileCodeSplitReferenceRoute,
359
+ compileCodeSplitVirtualRoute
378
360
  };
379
361
  //# sourceMappingURL=compilers.js.map