Skip to content

Commit c6b161b

Browse files
committed
Fix treeshaking
1 parent 2911155 commit c6b161b

File tree

3 files changed

+48
-31
lines changed

3 files changed

+48
-31
lines changed

packages/start/src/directives/bubble-function-declaration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export function bubbleFunctionDeclaration(path: babel.NodePath<t.FunctionDeclara
1818
]),
1919
);
2020
path.scope.registerDeclaration(tmp);
21-
tmp.skip();
21+
// tmp.skip();
2222
if (path.parentPath.isExportNamedDeclaration()) {
2323
path.parentPath.replaceWith(
2424
t.exportNamedDeclaration(undefined, [t.exportSpecifier(decl.id, decl.id)]),

packages/start/src/directives/plugin.ts

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getImportIdentifier } from "./get-import-identifier.ts";
88
import { getRootStatementPath } from "./get-root-statement-path.ts";
99
import { isStatementTopLevel } from "./is-statement-top-level.ts";
1010
import { isPathValid, unwrapPath } from "./paths.ts";
11+
import { removeUnusedVariables } from "./remove-unused-variables.ts";
1112
import type { ImportDefinition } from "./types.ts";
1213

1314
export interface StateContext {
@@ -124,6 +125,8 @@ function transformFunction(
124125
]),
125126
);
126127
}
128+
129+
path.scope.crawl();
127130
}
128131

129132
function traceBinding(path: babel.NodePath, name: string): Binding | undefined {
@@ -166,23 +169,6 @@ function transformBindingForServer(ctx: StateContext, binding: Binding) {
166169
}
167170
}
168171

169-
function treeshake(path: babel.NodePath, name: string): void {
170-
const binding = path.scope.getBinding(name);
171-
172-
if (!(binding && binding.references + binding.constantViolations.length > 0)) {
173-
if (isPathValid(path.parentPath, t.isImportDeclaration)) {
174-
const parent = path.parentPath;
175-
if (parent.node.specifiers.length === 1) {
176-
parent.remove();
177-
} else {
178-
path.remove();
179-
}
180-
} else {
181-
path.remove();
182-
}
183-
}
184-
}
185-
186172
interface State extends babel.PluginPass {
187173
opts: StateContext;
188174
}
@@ -377,20 +363,11 @@ export function directivesPlugin(): babel.PluginObj<State> {
377363
transformFunction(ctx.opts, path, false);
378364
},
379365
});
380-
381366
program.scope.crawl();
382-
// Tree-shaking
383-
program.traverse({
384-
ImportDefaultSpecifier(path) {
385-
treeshake(path, path.node.local.name);
386-
},
387-
ImportNamespaceSpecifier(path) {
388-
treeshake(path, path.node.local.name);
389-
},
390-
ImportSpecifier(path) {
391-
treeshake(path, path.node.local.name);
392-
},
393-
});
367+
368+
if (ctx.opts.count > 0) {
369+
removeUnusedVariables(program);
370+
}
394371
}
395372
},
396373
},
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type * as babel from "@babel/core";
2+
import type * as t from "@babel/types";
3+
4+
export function removeUnusedVariables(program: babel.NodePath<t.Program>) {
5+
// TODO(Alexis):
6+
// This implementation is simple but slow
7+
// We repeat removing unused variables from each pass
8+
// until no potential unused variables are left.
9+
// There might be a simpler implementation.
10+
let dirty = true;
11+
12+
while (dirty) {
13+
dirty = false;
14+
program.traverse({
15+
BindingIdentifier(path) {
16+
const binding = path.scope.getBinding(path.node.name);
17+
18+
if (binding) {
19+
switch (binding.kind) {
20+
case "const":
21+
case "let":
22+
case "var":
23+
case "hoisted":
24+
case "module":
25+
if (binding.references === 0 && !binding.path.removed) {
26+
binding.path.remove();
27+
dirty = true;
28+
}
29+
break;
30+
case "local":
31+
case "param":
32+
case "unknown":
33+
break;
34+
}
35+
}
36+
},
37+
});
38+
program.scope.crawl();
39+
}
40+
}

0 commit comments

Comments
 (0)