@tanstack/router-vite-plugin 1.39.3 → 1.39.4

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,132 +0,0 @@
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
@@ -1 +0,0 @@
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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"}
package/src/compilers.ts DELETED
@@ -1,462 +0,0 @@
1
- import * as t from '@babel/types'
2
- import * as template from '@babel/template'
3
- import * as babel from '@babel/core'
4
- import { splitPrefix } from './constants'
5
- import { eliminateUnreferencedIdentifiers } from './eliminateUnreferencedIdentifiers'
6
-
7
- type SplitModulesById = Record<
8
- string,
9
- { id: string; node: t.FunctionExpression }
10
- >
11
-
12
- interface State {
13
- filename: string
14
- opts: {
15
- minify: boolean
16
- root: string
17
- }
18
- imported: Record<string, boolean>
19
- refs: Set<any>
20
- serverIndex: number
21
- splitIndex: number
22
- splitModulesById: SplitModulesById
23
- }
24
-
25
- export type CompileFn = (compileOpts: {
26
- code: string
27
- filename: string
28
- getBabelConfig: () => { plugins: Array<any> }
29
- }) => Promise<{
30
- code: string
31
- map: any
32
- }>
33
-
34
- export function makeCompile(makeOpts: { root: string }) {
35
- return async (opts: {
36
- code: string
37
- filename: string
38
- getBabelConfig: () => { plugins: Array<any> }
39
- }): Promise<{
40
- code: string
41
- map: any
42
- }> => {
43
- const res = await babel.transform(opts.code, {
44
- plugins: [
45
- ['@babel/plugin-syntax-jsx', {}],
46
- [
47
- '@babel/plugin-syntax-typescript',
48
- {
49
- isTSX: true,
50
- },
51
- ],
52
- ...opts.getBabelConfig().plugins,
53
- ],
54
- root: makeOpts.root,
55
- filename: opts.filename,
56
- sourceMaps: true,
57
- })
58
-
59
- if (res?.code) {
60
- return {
61
- code: res.code,
62
- map: res.map,
63
- }
64
- }
65
-
66
- return {
67
- code: opts.code,
68
- map: null,
69
- }
70
- }
71
- }
72
-
73
- export async function compileFile(opts: {
74
- code: string
75
- compile: CompileFn
76
- filename: string
77
- }) {
78
- return await opts.compile({
79
- code: opts.code,
80
- filename: opts.filename,
81
- getBabelConfig: () => ({
82
- plugins: [
83
- [
84
- {
85
- visitor: {
86
- Program: {
87
- enter(programPath: babel.NodePath<t.Program>, state: State) {
88
- const splitUrl = `${splitPrefix}:${opts.filename}?${splitPrefix}`
89
-
90
- programPath.traverse(
91
- {
92
- CallExpression: (path) => {
93
- if (path.node.callee.type === 'Identifier') {
94
- if (
95
- path.node.callee.name === 'createRoute' ||
96
- path.node.callee.name === 'createFileRoute'
97
- ) {
98
- if (
99
- path.parentPath.node.type === 'CallExpression'
100
- ) {
101
- const options = resolveIdentifier(
102
- path,
103
- path.parentPath.node.arguments[0],
104
- )
105
-
106
- let found = false
107
-
108
- const hasImportedOrDefinedIdentifier = (
109
- name: string,
110
- ) => {
111
- return programPath.scope.hasBinding(name)
112
- }
113
-
114
- if (t.isObjectExpression(options)) {
115
- options.properties.forEach((prop) => {
116
- if (t.isObjectProperty(prop)) {
117
- if (t.isIdentifier(prop.key)) {
118
- if (prop.key.name === 'component') {
119
- const value = prop.value
120
-
121
- if (t.isIdentifier(value)) {
122
- removeIdentifierLiteral(path, value)
123
- }
124
-
125
- // Prepend the import statement to the program along with the importer function
126
- // Check to see if lazyRouteComponent is already imported before attempting
127
- // to import it again
128
-
129
- if (
130
- !hasImportedOrDefinedIdentifier(
131
- 'lazyRouteComponent',
132
- )
133
- ) {
134
- programPath.unshiftContainer('body', [
135
- template.smart(
136
- `import { lazyRouteComponent } from '@tanstack/react-router'`,
137
- )() as t.Statement,
138
- ])
139
- }
140
-
141
- if (
142
- !hasImportedOrDefinedIdentifier(
143
- '$$splitComponentImporter',
144
- )
145
- ) {
146
- programPath.unshiftContainer('body', [
147
- template.smart(
148
- `const $$splitComponentImporter = () => import('${splitUrl}')`,
149
- )() as t.Statement,
150
- ])
151
- }
152
-
153
- prop.value = template.expression(
154
- `lazyRouteComponent($$splitComponentImporter, 'component')`,
155
- )() as any
156
-
157
- programPath.pushContainer('body', [
158
- template.smart(
159
- `function DummyComponent() { return null }`,
160
- )() as t.Statement,
161
- ])
162
-
163
- found = true
164
- } else if (prop.key.name === 'loader') {
165
- const value = prop.value
166
-
167
- if (t.isIdentifier(value)) {
168
- removeIdentifierLiteral(path, value)
169
- }
170
-
171
- // Prepend the import statement to the program along with the importer function
172
-
173
- if (
174
- !hasImportedOrDefinedIdentifier(
175
- 'lazyFn',
176
- )
177
- ) {
178
- programPath.unshiftContainer('body', [
179
- template.smart(
180
- `import { lazyFn } from '@tanstack/react-router'`,
181
- )() as t.Statement,
182
- ])
183
- }
184
-
185
- if (
186
- !hasImportedOrDefinedIdentifier(
187
- '$$splitLoaderImporter',
188
- )
189
- ) {
190
- programPath.unshiftContainer('body', [
191
- template.smart(
192
- `const $$splitLoaderImporter = () => import('${splitUrl}')`,
193
- )() as t.Statement,
194
- ])
195
- }
196
-
197
- prop.value = template.expression(
198
- `lazyFn($$splitLoaderImporter, 'loader')`,
199
- )() as any
200
-
201
- found = true
202
- }
203
- }
204
- }
205
-
206
- programPath.scope.crawl()
207
- })
208
- }
209
-
210
- if (found as boolean) {
211
- programPath.pushContainer('body', [
212
- template.smart(
213
- `function TSR_Dummy_Component() {}`,
214
- )() as t.Statement,
215
- ])
216
- }
217
- }
218
- }
219
- }
220
- },
221
- },
222
- state,
223
- )
224
-
225
- eliminateUnreferencedIdentifiers(programPath)
226
- },
227
- },
228
- },
229
- },
230
- {
231
- root: process.cwd(),
232
- minify: process.env.NODE_ENV === 'production',
233
- },
234
- ],
235
- ].filter(Boolean),
236
- }),
237
- })
238
- }
239
-
240
- // Reusable function to get literal value or resolve variable to literal
241
- function resolveIdentifier(path: any, node: any) {
242
- if (t.isIdentifier(node)) {
243
- const binding = path.scope.getBinding(node.name)
244
- if (
245
- binding
246
- // && binding.kind === 'const'
247
- ) {
248
- const declarator = binding.path.node
249
- if (t.isObjectExpression(declarator.init)) {
250
- return declarator.init
251
- } else if (t.isFunctionDeclaration(declarator.init)) {
252
- return declarator.init
253
- }
254
- }
255
- return undefined
256
- }
257
-
258
- return node
259
- }
260
-
261
- function removeIdentifierLiteral(path: any, node: any) {
262
- if (t.isIdentifier(node)) {
263
- const binding = path.scope.getBinding(node.name)
264
- if (binding) {
265
- binding.path.remove()
266
- }
267
- }
268
- }
269
-
270
- const splitNodeTypes = ['component', 'loader'] as const
271
- type SplitNodeType = (typeof splitNodeTypes)[number]
272
-
273
- export async function splitFile(opts: {
274
- code: string
275
- compile: CompileFn
276
- filename: string
277
- // ref: string
278
- }) {
279
- return await opts.compile({
280
- code: opts.code,
281
- filename: opts.filename,
282
- getBabelConfig: () => ({
283
- plugins: [
284
- [
285
- {
286
- visitor: {
287
- Program: {
288
- enter(programPath: babel.NodePath<t.Program>, state: State) {
289
- const splitNodesByType: Record<
290
- SplitNodeType,
291
- t.Node | undefined
292
- > = {
293
- component: undefined,
294
- loader: undefined,
295
- }
296
-
297
- // Find the node
298
- programPath.traverse(
299
- {
300
- CallExpression: (path) => {
301
- if (path.node.callee.type === 'Identifier') {
302
- if (
303
- path.node.callee.name === 'createRoute' ||
304
- path.node.callee.name === 'createFileRoute'
305
- ) {
306
- if (
307
- path.parentPath.node.type === 'CallExpression'
308
- ) {
309
- const options = resolveIdentifier(
310
- path,
311
- path.parentPath.node.arguments[0],
312
- )
313
-
314
- if (t.isObjectExpression(options)) {
315
- options.properties.forEach((prop) => {
316
- if (t.isObjectProperty(prop)) {
317
- splitNodeTypes.forEach((type) => {
318
- if (t.isIdentifier(prop.key)) {
319
- if (prop.key.name === type) {
320
- splitNodesByType[type] = prop.value
321
- }
322
- }
323
- })
324
- }
325
- })
326
-
327
- // Remove all of the options
328
- options.properties = []
329
- }
330
- }
331
- }
332
- }
333
- },
334
- },
335
- state,
336
- )
337
-
338
- splitNodeTypes.forEach((splitType) => {
339
- let splitNode = splitNodesByType[splitType]
340
-
341
- if (!splitNode) {
342
- return
343
- }
344
-
345
- while (t.isIdentifier(splitNode)) {
346
- const binding = programPath.scope.getBinding(
347
- splitNode.name,
348
- )
349
- splitNode = binding?.path.node
350
- }
351
-
352
- // Add the node to the program
353
- if (splitNode) {
354
- if (t.isFunctionDeclaration(splitNode)) {
355
- programPath.pushContainer(
356
- 'body',
357
- t.variableDeclaration('const', [
358
- t.variableDeclarator(
359
- t.identifier(splitType),
360
- t.functionExpression(
361
- splitNode.id || null, // Anonymize the function expression
362
- splitNode.params,
363
- splitNode.body,
364
- splitNode.generator,
365
- splitNode.async,
366
- ),
367
- ),
368
- ]),
369
- )
370
- } else if (
371
- t.isFunctionExpression(splitNode) ||
372
- t.isArrowFunctionExpression(splitNode)
373
- ) {
374
- programPath.pushContainer(
375
- 'body',
376
- t.variableDeclaration('const', [
377
- t.variableDeclarator(
378
- t.identifier(splitType),
379
- splitNode as any,
380
- ),
381
- ]),
382
- )
383
- } else if (t.isImportSpecifier(splitNode)) {
384
- programPath.pushContainer(
385
- 'body',
386
- t.variableDeclaration('const', [
387
- t.variableDeclarator(
388
- t.identifier(splitType),
389
- splitNode.local,
390
- ),
391
- ]),
392
- )
393
- } else {
394
- console.info(splitNode)
395
- throw new Error(
396
- `Unexpected splitNode type ☝️: ${splitNode.type}`,
397
- )
398
- }
399
- }
400
-
401
- // If the splitNode exists at the top of the program
402
- // then we need to remove that copy
403
- programPath.node.body = programPath.node.body.filter(
404
- (node) => {
405
- return node !== splitNode
406
- },
407
- )
408
-
409
- // Export the node
410
- programPath.pushContainer('body', [
411
- t.exportNamedDeclaration(null, [
412
- t.exportSpecifier(
413
- t.identifier(splitType),
414
- t.identifier(splitType),
415
- ),
416
- ]),
417
- ])
418
- })
419
-
420
- // convert exports to imports from the original file
421
- programPath.traverse({
422
- ExportNamedDeclaration(path) {
423
- // e.g. export const x = 1 or export { x }
424
- // becomes
425
- // import { x } from '${opts.id}'
426
-
427
- if (path.node.declaration) {
428
- if (t.isVariableDeclaration(path.node.declaration)) {
429
- path.replaceWith(
430
- t.importDeclaration(
431
- path.node.declaration.declarations.map((decl) =>
432
- t.importSpecifier(
433
- t.identifier((decl.id as any).name),
434
- t.identifier((decl.id as any).name),
435
- ),
436
- ),
437
- t.stringLiteral(
438
- opts.filename.split(
439
- `?${splitPrefix}`,
440
- )[0] as string,
441
- ),
442
- ),
443
- )
444
- }
445
- }
446
- },
447
- })
448
-
449
- eliminateUnreferencedIdentifiers(programPath)
450
- },
451
- },
452
- },
453
- },
454
- {
455
- root: process.cwd(),
456
- minify: process.env.NODE_ENV === 'production',
457
- },
458
- ],
459
- ].filter(Boolean),
460
- }),
461
- })
462
- }
package/src/constants.ts DELETED
@@ -1 +0,0 @@
1
- export const splitPrefix = 'tsr-split'