mirror of
https://github.com/status-im/metro.git
synced 2025-01-12 03:54:21 +00:00
Recursively traverse every time we strip a block
Summary: It turns out that block removal can create dead variables, which can in turn further process and improve other block removal. This diff takes care of ensuring that this process happens iteratively until no further blocks can be removed. It also moves block removal to `Program.exit`. This is important to avoid removing "unused" blocks, which are non-atomically added by other plugins (e.g. Babel's class plugin first adds a `function` that will later be used as a helper, but the dead code removal was kicked-in before adding its usage, and was getting removed). Reviewed By: davidaurelio Differential Revision: D8069299 fbshipit-source-id: d86c9be2a76fced9a6529a1d5aaaad4430d0f194
This commit is contained in:
parent
263118c84b
commit
5841122d27
@ -143,7 +143,7 @@ describe('constant expressions', () => {
|
||||
var a = 'b';
|
||||
}
|
||||
`;
|
||||
expect(fold('arbitrary.js', code)).toEqual('{var a=3;var b=a+4;}');
|
||||
expect(fold('arbitrary.js', code)).toEqual('{var a=3;var b=7;}');
|
||||
});
|
||||
|
||||
it('can optimize nested if-else constructs', () => {
|
||||
@ -235,6 +235,18 @@ describe('constant expressions', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('recursively strips off functions', () => {
|
||||
const code = `
|
||||
function x() {}
|
||||
|
||||
if (false) {
|
||||
x();
|
||||
}
|
||||
`;
|
||||
|
||||
expect(fold('arbitrary.js', code)).toEqual('');
|
||||
});
|
||||
|
||||
it('verifies that mixes of variables and functions properly minifies', () => {
|
||||
const code = `
|
||||
var x = 2;
|
||||
|
@ -16,23 +16,25 @@ function constantFoldingPlugin(context: {types: BabelTypes}) {
|
||||
const t = context.types;
|
||||
|
||||
const FunctionDeclaration = {
|
||||
exit(path: Object) {
|
||||
exit(path: Object, state: Object) {
|
||||
const binding = path.scope.getBinding(path.node.id.name);
|
||||
|
||||
if (binding && !binding.referenced) {
|
||||
state.stripped = true;
|
||||
path.remove();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const FunctionExpression = {
|
||||
exit(path: Object) {
|
||||
exit(path: Object, state: Object) {
|
||||
const parentPath = path.parentPath;
|
||||
|
||||
if (t.isVariableDeclarator(parentPath)) {
|
||||
const binding = parentPath.scope.getBinding(parentPath.node.id.name);
|
||||
|
||||
if (binding && !binding.referenced) {
|
||||
state.stripped = true;
|
||||
parentPath.remove();
|
||||
}
|
||||
}
|
||||
@ -40,11 +42,13 @@ function constantFoldingPlugin(context: {types: BabelTypes}) {
|
||||
};
|
||||
|
||||
const Conditional = {
|
||||
exit(path: Object) {
|
||||
exit(path: Object, state: Object) {
|
||||
const node = path.node;
|
||||
const result = path.get('test').evaluate();
|
||||
|
||||
if (result.confident) {
|
||||
state.stripped = true;
|
||||
|
||||
if (result.value || node.alternate) {
|
||||
path.replaceWith(result.value ? node.consequent : node.alternate);
|
||||
} else if (!result.value) {
|
||||
@ -90,25 +94,42 @@ function constantFoldingPlugin(context: {types: BabelTypes}) {
|
||||
};
|
||||
|
||||
const Program = {
|
||||
exit(path: Object) {
|
||||
path.traverse({
|
||||
ArrowFunctionExpression: FunctionExpression,
|
||||
FunctionDeclaration,
|
||||
FunctionExpression,
|
||||
});
|
||||
enter(path: Object, state: Object) {
|
||||
state.stripped = false;
|
||||
},
|
||||
|
||||
exit(path: Object, state: Object) {
|
||||
path.traverse(
|
||||
{
|
||||
ArrowFunctionExpression: FunctionExpression,
|
||||
ConditionalExpression: Conditional,
|
||||
FunctionDeclaration,
|
||||
FunctionExpression,
|
||||
IfStatement: Conditional,
|
||||
},
|
||||
state,
|
||||
);
|
||||
|
||||
if (state.stripped) {
|
||||
path.scope.crawl();
|
||||
|
||||
// Re-traverse all program, if we removed any blocks. Manually re-call
|
||||
// enter and exit, because traversing a Program node won't call them.
|
||||
Program.enter(path, state);
|
||||
path.traverse(visitor);
|
||||
Program.exit(path, state);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
BinaryExpression: Expression,
|
||||
ConditionalExpression: Conditional,
|
||||
IfStatement: Conditional,
|
||||
LogicalExpression,
|
||||
Program,
|
||||
UnaryExpression: Expression,
|
||||
},
|
||||
const visitor = {
|
||||
BinaryExpression: Expression,
|
||||
LogicalExpression,
|
||||
Program: {...Program}, // Babel mutates objects passed.
|
||||
UnaryExpression: Expression,
|
||||
};
|
||||
|
||||
return {visitor};
|
||||
}
|
||||
|
||||
module.exports = constantFoldingPlugin;
|
||||
|
Loading…
x
Reference in New Issue
Block a user