@tanstack/router-plugin 1.168.5 → 1.168.7

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 (44) hide show
  1. package/dist/cjs/core/code-splitter/compilers.cjs +32 -233
  2. package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -1
  3. package/dist/cjs/core/code-splitter/compilers.d.cts +2 -57
  4. package/dist/cjs/core/code-splitter/plugins.d.cts +1 -0
  5. package/dist/cjs/core/config.cjs +1 -1
  6. package/dist/cjs/core/config.cjs.map +1 -1
  7. package/dist/cjs/core/config.d.cts +44 -163
  8. package/dist/cjs/core/hmr/handle-route-update.cjs +17 -18
  9. package/dist/cjs/core/hmr/handle-route-update.cjs.map +1 -1
  10. package/dist/cjs/core/router-code-splitter-plugin.cjs +5 -6
  11. package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
  12. package/dist/cjs/esbuild.d.cts +26 -26
  13. package/dist/cjs/index.cjs +2 -0
  14. package/dist/cjs/index.d.cts +2 -0
  15. package/dist/cjs/vite.d.cts +26 -26
  16. package/dist/esm/core/code-splitter/compilers.d.ts +2 -57
  17. package/dist/esm/core/code-splitter/compilers.js +15 -216
  18. package/dist/esm/core/code-splitter/compilers.js.map +1 -1
  19. package/dist/esm/core/code-splitter/plugins.d.ts +1 -0
  20. package/dist/esm/core/config.d.ts +44 -163
  21. package/dist/esm/core/config.js +1 -1
  22. package/dist/esm/core/config.js.map +1 -1
  23. package/dist/esm/core/hmr/handle-route-update.js +17 -18
  24. package/dist/esm/core/hmr/handle-route-update.js.map +1 -1
  25. package/dist/esm/core/router-code-splitter-plugin.js +5 -6
  26. package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
  27. package/dist/esm/esbuild.d.ts +26 -26
  28. package/dist/esm/index.d.ts +2 -0
  29. package/dist/esm/index.js +2 -1
  30. package/dist/esm/vite.d.ts +26 -26
  31. package/package.json +7 -7
  32. package/src/core/code-splitter/compilers.ts +51 -411
  33. package/src/core/code-splitter/plugins.ts +3 -0
  34. package/src/core/config.ts +12 -1
  35. package/src/core/hmr/handle-route-update.ts +30 -35
  36. package/src/core/router-code-splitter-plugin.ts +11 -9
  37. package/src/index.ts +5 -0
  38. package/dist/cjs/core/code-splitter/path-ids.cjs +0 -32
  39. package/dist/cjs/core/code-splitter/path-ids.cjs.map +0 -1
  40. package/dist/cjs/core/code-splitter/path-ids.d.cts +0 -2
  41. package/dist/esm/core/code-splitter/path-ids.d.ts +0 -2
  42. package/dist/esm/core/code-splitter/path-ids.js +0 -31
  43. package/dist/esm/core/code-splitter/path-ids.js.map +0 -1
  44. package/src/core/code-splitter/path-ids.ts +0 -39
@@ -4,4 +4,6 @@ export { unpluginRouterGeneratorFactory } from './core/router-generator-plugin.c
4
4
  export { createRouterPluginContext } from './core/router-plugin-context.cjs';
5
5
  export type { Config, ConfigInput, ConfigOutput, CodeSplittingOptions, DeletableNodes, HmrOptions, } from './core/config.cjs';
6
6
  export type { RouterPluginContext } from './core/router-plugin-context.cjs';
7
+ export { getObjectPropertyKeyName } from './core/utils.cjs';
8
+ export type { ReferenceRouteCompilerPlugin, ReferenceRouteCompilerPluginContext, } from './core/code-splitter/plugins.cjs';
7
9
  export { tsrSplit, splitRouteIdentNodes, defaultCodeSplitGroupings, } from './core/constants.cjs';
@@ -31,7 +31,7 @@ declare const tanStackRouterCodeSplitter: (options?: RouterPluginOptions, router
31
31
  * ```
32
32
  */
33
33
  declare const tanstackRouter: (options?: Partial<{
34
- target: "react" | "solid" | "vue";
34
+ target: "vue" | "react" | "solid";
35
35
  routeFileIgnorePrefix: string;
36
36
  routesDirectory: string;
37
37
  quoteStyle: "single" | "double";
@@ -52,21 +52,11 @@ declare const tanstackRouter: (options?: Partial<{
52
52
  enableRouteTreeFormatting: boolean;
53
53
  tmpDir: string;
54
54
  importRoutesUsingAbsolutePaths: boolean;
55
- enableRouteGeneration?: boolean | undefined;
56
- codeSplittingOptions?: CodeSplittingOptions | undefined;
57
- plugin?: {
58
- vite?: {
59
- environmentName?: string | undefined;
60
- } | undefined;
61
- hmr?: {
62
- style?: "vite" | "webpack" | undefined;
63
- } | undefined;
64
- } | undefined;
65
55
  virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
66
56
  routeFilePrefix?: string | undefined;
67
57
  routeFileIgnorePattern?: string | undefined;
68
- pathParamsAllowedCharacters?: (";" | ":" | "@" | "&" | "=" | "+" | "$" | ",")[] | undefined;
69
- routeTreeFileFooter?: string[] | ((...args: unknown[]) => string[]) | undefined;
58
+ pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
59
+ routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
70
60
  autoCodeSplitting?: boolean | undefined;
71
61
  customScaffolding?: {
72
62
  routeTemplate?: string | undefined;
@@ -76,12 +66,22 @@ declare const tanstackRouter: (options?: Partial<{
76
66
  enableCodeSplitting?: boolean | undefined;
77
67
  } | undefined;
78
68
  plugins?: import('@tanstack/router-generator').GeneratorPlugin[] | undefined;
69
+ enableRouteGeneration?: boolean | undefined;
70
+ codeSplittingOptions?: CodeSplittingOptions | undefined;
71
+ plugin?: {
72
+ hmr?: {
73
+ style?: "vite" | "webpack" | undefined;
74
+ } | undefined;
75
+ vite?: {
76
+ environmentName?: string | undefined;
77
+ } | undefined;
78
+ } | undefined;
79
79
  } | (() => Config)> | undefined) => import('vite').Plugin<any> | import('vite').Plugin<any>[];
80
80
  /**
81
81
  * @deprecated Use `tanstackRouter` instead.
82
82
  */
83
83
  declare const TanStackRouterVite: (options?: Partial<{
84
- target: "react" | "solid" | "vue";
84
+ target: "vue" | "react" | "solid";
85
85
  routeFileIgnorePrefix: string;
86
86
  routesDirectory: string;
87
87
  quoteStyle: "single" | "double";
@@ -102,21 +102,11 @@ declare const TanStackRouterVite: (options?: Partial<{
102
102
  enableRouteTreeFormatting: boolean;
103
103
  tmpDir: string;
104
104
  importRoutesUsingAbsolutePaths: boolean;
105
- enableRouteGeneration?: boolean | undefined;
106
- codeSplittingOptions?: CodeSplittingOptions | undefined;
107
- plugin?: {
108
- vite?: {
109
- environmentName?: string | undefined;
110
- } | undefined;
111
- hmr?: {
112
- style?: "vite" | "webpack" | undefined;
113
- } | undefined;
114
- } | undefined;
115
105
  virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
116
106
  routeFilePrefix?: string | undefined;
117
107
  routeFileIgnorePattern?: string | undefined;
118
- pathParamsAllowedCharacters?: (";" | ":" | "@" | "&" | "=" | "+" | "$" | ",")[] | undefined;
119
- routeTreeFileFooter?: string[] | ((...args: unknown[]) => string[]) | undefined;
108
+ pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
109
+ routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
120
110
  autoCodeSplitting?: boolean | undefined;
121
111
  customScaffolding?: {
122
112
  routeTemplate?: string | undefined;
@@ -126,6 +116,16 @@ declare const TanStackRouterVite: (options?: Partial<{
126
116
  enableCodeSplitting?: boolean | undefined;
127
117
  } | undefined;
128
118
  plugins?: import('@tanstack/router-generator').GeneratorPlugin[] | undefined;
119
+ enableRouteGeneration?: boolean | undefined;
120
+ codeSplittingOptions?: CodeSplittingOptions | undefined;
121
+ plugin?: {
122
+ hmr?: {
123
+ style?: "vite" | "webpack" | undefined;
124
+ } | undefined;
125
+ vite?: {
126
+ environmentName?: string | undefined;
127
+ } | undefined;
128
+ } | undefined;
129
129
  } | (() => Config)> | undefined) => import('vite').Plugin<any> | import('vite').Plugin<any>[];
130
130
  export default tanstackRouter;
131
131
  export { configSchema, getConfig, tanStackRouterCodeSplitter, tanstackRouterGenerator, TanStackRouterVite, tanstackRouter, };
@@ -1,28 +1,9 @@
1
1
  import { CompileCodeSplitReferenceRouteOptions, ReferenceRouteCompilerPlugin } from './plugins.js';
2
2
  import { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils';
3
3
  import { CodeSplitGroupings, SplitRouteIdentNodes } from '../constants.js';
4
- import * as t from '@babel/types';
4
+ export { buildDeclarationMap, buildDependencyGraph, collectIdentifiersFromNode, collectLocalBindingsFromStatement, collectModuleLevelRefsFromNode, expandDestructuredDeclarations, expandSharedDestructuredDeclarators, expandTransitively, removeBindingsTransitivelyDependingOn, } from '@tanstack/router-utils';
5
+ export declare function removeBindingsDependingOnRoute(bindings: Set<string>, dependencyGraph: Map<string, Set<string>>): void;
5
6
  export declare function addSharedSearchParamToFilename(filename: string): string;
6
- /**
7
- * Recursively walk an AST node and collect referenced identifier-like names.
8
- * Much cheaper than babel.traverse — no path/scope overhead.
9
- *
10
- * Notes:
11
- * - Uses @babel/types `isReferenced` to avoid collecting non-references like
12
- * object keys, member expression properties, or binding identifiers.
13
- * - Also handles JSX identifiers for component references.
14
- */
15
- export declare function collectIdentifiersFromNode(node: t.Node): Set<string>;
16
- /**
17
- * Build a map from binding name → declaration AST node for all
18
- * locally-declared module-level bindings. Built once, O(1) lookup.
19
- */
20
- export declare function buildDeclarationMap(ast: t.File): Map<string, t.Node>;
21
- /**
22
- * Build a dependency graph: for each local binding, the set of other local
23
- * bindings its declaration references. Built once via simple node walking.
24
- */
25
- export declare function buildDependencyGraph(declMap: Map<string, t.Node>, localBindings: Set<string>): Map<string, Set<string>>;
26
7
  /**
27
8
  * Computes module-level bindings that are shared between split and non-split
28
9
  * route properties. These bindings need to be extracted into a shared virtual
@@ -37,42 +18,6 @@ export declare function computeSharedBindings(opts: {
37
18
  filename?: string;
38
19
  codeSplitGroupings: CodeSplitGroupings;
39
20
  }): Set<string>;
40
- /**
41
- * If bindings from the same destructured declarator are referenced by
42
- * different groups, mark all bindings from that declarator as shared.
43
- */
44
- export declare function expandSharedDestructuredDeclarators(ast: t.File, refsByGroup: Map<string, Set<number>>, shared: Set<string>): void;
45
- /**
46
- * Collect locally-declared module-level binding names from a statement.
47
- * Pure node inspection, no traversal.
48
- */
49
- export declare function collectLocalBindingsFromStatement(node: t.Statement | t.ModuleDeclaration, bindings: Set<string>): void;
50
- /**
51
- * Collect direct module-level binding names referenced from a given AST node.
52
- * Uses a simple recursive walk instead of babel.traverse.
53
- */
54
- export declare function collectModuleLevelRefsFromNode(node: t.Node, localModuleLevelBindings: Set<string>): Set<string>;
55
- /**
56
- * Expand the shared set transitively using a prebuilt dependency graph.
57
- * No AST traversals — pure graph BFS.
58
- */
59
- export declare function expandTransitively(shared: Set<string>, depGraph: Map<string, Set<string>>): void;
60
- /**
61
- * Remove any bindings from `shared` that transitively depend on `Route`.
62
- * The Route singleton must remain in the reference file; if a shared binding
63
- * references it (directly or transitively), extracting that binding would
64
- * duplicate Route in the shared module.
65
- *
66
- * Uses `depGraph` which must include `Route` as a node so the dependency
67
- * chain is visible.
68
- */
69
- export declare function removeBindingsDependingOnRoute(shared: Set<string>, depGraph: Map<string, Set<string>>): void;
70
- /**
71
- * If any binding from a destructured declaration is shared,
72
- * ensure all bindings from that same declaration are also shared.
73
- * Pure node inspection of program.body, no traversal.
74
- */
75
- export declare function expandDestructuredDeclarations(ast: t.File, shared: Set<string>): void;
76
21
  export declare function compileCodeSplitReferenceRoute(opts: ParseAstOptions & CompileCodeSplitReferenceRouteOptions & {
77
22
  compilerPlugins?: Array<ReferenceRouteCompilerPlugin>;
78
23
  }): GeneratorResult | null;
@@ -1,9 +1,8 @@
1
1
  import { tsrShared, tsrSplit } from "../constants.js";
2
2
  import { createRouteHmrStatement } from "../hmr/select-adapter.js";
3
3
  import { getObjectPropertyKeyName } from "../utils.js";
4
- import { createIdentifier } from "./path-ids.js";
5
4
  import { getFrameworkOptions } from "./framework-options.js";
6
- import { deadCodeElimination, findReferencedIdentifiers, generateFromAst, parseAst } from "@tanstack/router-utils";
5
+ import { buildDeclarationMap, buildDependencyGraph, collectIdentifiersFromPattern, collectLocalBindingsFromStatement, collectModuleLevelRefsFromNode, createIdentifier, deadCodeElimination, expandDestructuredDeclarations, expandSharedDestructuredDeclarators, expandTransitively, findReferencedIdentifiers, generateFromAst, parseAst, removeBindingsTransitivelyDependingOn, retainModuleLevelDeclarations, stripUnreferencedTopLevelExpressionStatements, unwrapExportedDeclarations } from "@tanstack/router-utils";
7
6
  import * as t from "@babel/types";
8
7
  import * as babel from "@babel/core";
9
8
  import * as template from "@babel/template";
@@ -64,69 +63,6 @@ var splittableCreateRouteFns = ["createFileRoute"];
64
63
  var unsplittableCreateRouteFns = ["createRootRoute", "createRootRouteWithContext"];
65
64
  var allCreateRouteFns = [...splittableCreateRouteFns, ...unsplittableCreateRouteFns];
66
65
  /**
67
- * Recursively walk an AST node and collect referenced identifier-like names.
68
- * Much cheaper than babel.traverse — no path/scope overhead.
69
- *
70
- * Notes:
71
- * - Uses @babel/types `isReferenced` to avoid collecting non-references like
72
- * object keys, member expression properties, or binding identifiers.
73
- * - Also handles JSX identifiers for component references.
74
- */
75
- function collectIdentifiersFromNode(node) {
76
- const ids = /* @__PURE__ */ new Set();
77
- (function walk(n, parent, grandparent, parentKey) {
78
- if (!n) return;
79
- if (t.isIdentifier(n)) {
80
- if (!parent || t.isReferenced(n, parent, grandparent)) ids.add(n.name);
81
- return;
82
- }
83
- if (t.isJSXIdentifier(n)) {
84
- if (parent && t.isJSXAttribute(parent) && parentKey === "name") return;
85
- if (parent && t.isJSXMemberExpression(parent) && parentKey === "property") return;
86
- const first = n.name[0];
87
- if (first && first === first.toLowerCase()) return;
88
- ids.add(n.name);
89
- return;
90
- }
91
- for (const key of t.VISITOR_KEYS[n.type] || []) {
92
- const child = n[key];
93
- if (Array.isArray(child)) {
94
- for (const c of child) if (c && typeof c.type === "string") walk(c, n, parent, key);
95
- } else if (child && typeof child.type === "string") walk(child, n, parent, key);
96
- }
97
- })(node);
98
- return ids;
99
- }
100
- /**
101
- * Build a map from binding name → declaration AST node for all
102
- * locally-declared module-level bindings. Built once, O(1) lookup.
103
- */
104
- function buildDeclarationMap(ast) {
105
- const map = /* @__PURE__ */ new Map();
106
- for (const stmt of ast.program.body) {
107
- const decl = t.isExportNamedDeclaration(stmt) && stmt.declaration ? stmt.declaration : stmt;
108
- if (t.isVariableDeclaration(decl)) for (const declarator of decl.declarations) for (const name of collectIdentifiersFromPattern(declarator.id)) map.set(name, declarator);
109
- else if (t.isFunctionDeclaration(decl) && decl.id) map.set(decl.id.name, decl);
110
- else if (t.isClassDeclaration(decl) && decl.id) map.set(decl.id.name, decl);
111
- }
112
- return map;
113
- }
114
- /**
115
- * Build a dependency graph: for each local binding, the set of other local
116
- * bindings its declaration references. Built once via simple node walking.
117
- */
118
- function buildDependencyGraph(declMap, localBindings) {
119
- const graph = /* @__PURE__ */ new Map();
120
- for (const [name, declNode] of declMap) {
121
- if (!localBindings.has(name)) continue;
122
- const allIds = collectIdentifiersFromNode(declNode);
123
- const deps = /* @__PURE__ */ new Set();
124
- for (const id of allIds) if (id !== name && localBindings.has(id)) deps.add(id);
125
- graph.set(name, deps);
126
- }
127
- return graph;
128
- }
129
- /**
130
66
  * Computes module-level bindings that are shared between split and non-split
131
67
  * route properties. These bindings need to be extracted into a shared virtual
132
68
  * module to avoid double-initialization.
@@ -202,117 +138,10 @@ function computeSharedBindings(opts) {
202
138
  expandSharedDestructuredDeclarators(ast, refsByGroup, shared);
203
139
  if (shared.size === 0) return shared;
204
140
  expandDestructuredDeclarations(ast, shared);
205
- removeBindingsDependingOnRoute(shared, fullDepGraph);
141
+ removeBindingsTransitivelyDependingOn(shared, fullDepGraph, ["Route"]);
206
142
  return shared;
207
143
  }
208
144
  /**
209
- * If bindings from the same destructured declarator are referenced by
210
- * different groups, mark all bindings from that declarator as shared.
211
- */
212
- function expandSharedDestructuredDeclarators(ast, refsByGroup, shared) {
213
- for (const stmt of ast.program.body) {
214
- const decl = t.isExportNamedDeclaration(stmt) && stmt.declaration ? stmt.declaration : stmt;
215
- if (!t.isVariableDeclaration(decl)) continue;
216
- for (const declarator of decl.declarations) {
217
- if (!t.isObjectPattern(declarator.id) && !t.isArrayPattern(declarator.id)) continue;
218
- const names = collectIdentifiersFromPattern(declarator.id);
219
- const usedGroups = /* @__PURE__ */ new Set();
220
- for (const name of names) {
221
- const groups = refsByGroup.get(name);
222
- if (!groups) continue;
223
- for (const g of groups) usedGroups.add(g);
224
- }
225
- if (usedGroups.size >= 2) for (const name of names) shared.add(name);
226
- }
227
- }
228
- }
229
- /**
230
- * Collect locally-declared module-level binding names from a statement.
231
- * Pure node inspection, no traversal.
232
- */
233
- function collectLocalBindingsFromStatement(node, bindings) {
234
- const decl = t.isExportNamedDeclaration(node) && node.declaration ? node.declaration : node;
235
- if (t.isVariableDeclaration(decl)) for (const declarator of decl.declarations) for (const name of collectIdentifiersFromPattern(declarator.id)) bindings.add(name);
236
- else if (t.isFunctionDeclaration(decl) && decl.id) bindings.add(decl.id.name);
237
- else if (t.isClassDeclaration(decl) && decl.id) bindings.add(decl.id.name);
238
- }
239
- /**
240
- * Collect direct module-level binding names referenced from a given AST node.
241
- * Uses a simple recursive walk instead of babel.traverse.
242
- */
243
- function collectModuleLevelRefsFromNode(node, localModuleLevelBindings) {
244
- const allIds = collectIdentifiersFromNode(node);
245
- const refs = /* @__PURE__ */ new Set();
246
- for (const name of allIds) if (localModuleLevelBindings.has(name)) refs.add(name);
247
- return refs;
248
- }
249
- /**
250
- * Expand the shared set transitively using a prebuilt dependency graph.
251
- * No AST traversals — pure graph BFS.
252
- */
253
- function expandTransitively(shared, depGraph) {
254
- const queue = [...shared];
255
- const visited = /* @__PURE__ */ new Set();
256
- while (queue.length > 0) {
257
- const name = queue.pop();
258
- if (visited.has(name)) continue;
259
- visited.add(name);
260
- const deps = depGraph.get(name);
261
- if (!deps) continue;
262
- for (const dep of deps) if (!shared.has(dep)) {
263
- shared.add(dep);
264
- queue.push(dep);
265
- }
266
- }
267
- }
268
- /**
269
- * Remove any bindings from `shared` that transitively depend on `Route`.
270
- * The Route singleton must remain in the reference file; if a shared binding
271
- * references it (directly or transitively), extracting that binding would
272
- * duplicate Route in the shared module.
273
- *
274
- * Uses `depGraph` which must include `Route` as a node so the dependency
275
- * chain is visible.
276
- */
277
- function removeBindingsDependingOnRoute(shared, depGraph) {
278
- const reverseGraph = /* @__PURE__ */ new Map();
279
- for (const [name, deps] of depGraph) for (const dep of deps) {
280
- let parents = reverseGraph.get(dep);
281
- if (!parents) {
282
- parents = /* @__PURE__ */ new Set();
283
- reverseGraph.set(dep, parents);
284
- }
285
- parents.add(name);
286
- }
287
- const visited = /* @__PURE__ */ new Set();
288
- const queue = ["Route"];
289
- while (queue.length > 0) {
290
- const cur = queue.pop();
291
- if (visited.has(cur)) continue;
292
- visited.add(cur);
293
- const parents = reverseGraph.get(cur);
294
- if (!parents) continue;
295
- for (const parent of parents) if (!visited.has(parent)) queue.push(parent);
296
- }
297
- for (const name of [...shared]) if (visited.has(name)) shared.delete(name);
298
- }
299
- /**
300
- * If any binding from a destructured declaration is shared,
301
- * ensure all bindings from that same declaration are also shared.
302
- * Pure node inspection of program.body, no traversal.
303
- */
304
- function expandDestructuredDeclarations(ast, shared) {
305
- for (const stmt of ast.program.body) {
306
- const decl = t.isExportNamedDeclaration(stmt) && stmt.declaration ? stmt.declaration : stmt;
307
- if (!t.isVariableDeclaration(decl)) continue;
308
- for (const declarator of decl.declarations) {
309
- if (!t.isObjectPattern(declarator.id) && !t.isArrayPattern(declarator.id)) continue;
310
- const names = collectIdentifiersFromPattern(declarator.id);
311
- if (names.some((n) => shared.has(n))) for (const n of names) shared.add(n);
312
- }
313
- }
314
- }
315
- /**
316
145
  * Find which shared bindings are user-exported in the original source.
317
146
  * These need to be re-exported from the shared module.
318
147
  */
@@ -408,6 +237,16 @@ function compileCodeSplitReferenceRoute(opts) {
408
237
  };
409
238
  if (t.isObjectExpression(routeOptions)) {
410
239
  const insertionPath = path.getStatementParent() ?? path;
240
+ opts.compilerPlugins?.forEach((plugin) => {
241
+ if ((plugin.onRouteOptions?.({
242
+ programPath,
243
+ callExpressionPath: path,
244
+ insertionPath,
245
+ routeOptions,
246
+ createRouteFn,
247
+ opts
248
+ }))?.modified) modified = true;
249
+ });
411
250
  if (opts.deleteNodes && opts.deleteNodes.size > 0) routeOptions.properties = routeOptions.properties.filter((prop) => {
412
251
  if (t.isObjectProperty(prop)) {
413
252
  const key = getObjectPropertyKeyName(prop);
@@ -683,14 +522,7 @@ function compileCodeSplitVirtualRoute(opts) {
683
522
  }
684
523
  } } });
685
524
  deadCodeElimination(ast, refIdents);
686
- {
687
- const locallyBound = /* @__PURE__ */ new Set();
688
- for (const stmt of ast.program.body) collectLocalBindingsFromStatement(stmt, locallyBound);
689
- ast.program.body = ast.program.body.filter((stmt) => {
690
- if (!t.isExpressionStatement(stmt)) return true;
691
- return [...collectIdentifiersFromNode(stmt)].some((name) => locallyBound.has(name));
692
- });
693
- }
525
+ stripUnreferencedTopLevelExpressionStatements(ast);
694
526
  if (ast.program.body.length === 0) ast.program.directives = [];
695
527
  const result = generateFromAst(ast, {
696
528
  sourceMaps: true,
@@ -715,24 +547,8 @@ function compileCodeSplitSharedRoute(opts) {
715
547
  const keepBindings = new Set(opts.sharedBindings);
716
548
  keepBindings.delete("Route");
717
549
  expandTransitively(keepBindings, depGraph);
718
- ast.program.body = ast.program.body.filter((stmt) => {
719
- if (t.isImportDeclaration(stmt)) return true;
720
- const decl = t.isExportNamedDeclaration(stmt) && stmt.declaration ? stmt.declaration : stmt;
721
- if (t.isVariableDeclaration(decl)) {
722
- decl.declarations = decl.declarations.filter((declarator) => {
723
- return collectIdentifiersFromPattern(declarator.id).some((n) => keepBindings.has(n));
724
- });
725
- if (decl.declarations.length === 0) return false;
726
- if (t.isExportNamedDeclaration(stmt) && stmt.declaration) return true;
727
- return true;
728
- } else if (t.isFunctionDeclaration(decl) && decl.id) return keepBindings.has(decl.id.name);
729
- else if (t.isClassDeclaration(decl) && decl.id) return keepBindings.has(decl.id.name);
730
- return false;
731
- });
732
- ast.program.body = ast.program.body.map((stmt) => {
733
- if (t.isExportNamedDeclaration(stmt) && stmt.declaration) return stmt.declaration;
734
- return stmt;
735
- });
550
+ retainModuleLevelDeclarations(ast, keepBindings);
551
+ unwrapExportedDeclarations(ast);
736
552
  const exportSpecifiers = [...opts.sharedBindings].sort((a, b) => a.localeCompare(b)).map((name) => t.exportSpecifier(t.identifier(name), t.identifier(name)));
737
553
  if (exportSpecifiers.length > 0) {
738
554
  const exportDecl = t.exportNamedDeclaration(null, exportSpecifiers);
@@ -816,23 +632,6 @@ function getImportSpecifierAndPathFromLocalName(programPath, name) {
816
632
  path
817
633
  };
818
634
  }
819
- /**
820
- * Recursively collects all identifier names from a destructuring pattern
821
- * (ObjectPattern, ArrayPattern, AssignmentPattern, RestElement).
822
- */
823
- function collectIdentifiersFromPattern(node) {
824
- if (!node) return [];
825
- if (t.isIdentifier(node)) return [node.name];
826
- if (t.isAssignmentPattern(node)) return collectIdentifiersFromPattern(node.left);
827
- if (t.isRestElement(node)) return collectIdentifiersFromPattern(node.argument);
828
- if (t.isObjectPattern(node)) return node.properties.flatMap((prop) => {
829
- if (t.isObjectProperty(prop)) return collectIdentifiersFromPattern(prop.value);
830
- if (t.isRestElement(prop)) return collectIdentifiersFromPattern(prop.argument);
831
- return [];
832
- });
833
- if (t.isArrayPattern(node)) return node.elements.flatMap((element) => collectIdentifiersFromPattern(element));
834
- return [];
835
- }
836
635
  function resolveIdentifier(path, node) {
837
636
  if (t.isIdentifier(node)) {
838
637
  const binding = path.scope.getBinding(node.name);