UNPKG

react-saasify-chrisvxd

Version:

React components for Saasify web clients.

115 lines (93 loc) 3.45 kB
"use strict"; const t = require('@babel/types'); /** * This is a small small implementation of dead code removal specialized to handle * removing unused exports. All other dead code removal happens in workers on each * individual file by babel-minify. */ function treeShake(scope) { // Keep passing over all bindings in the scope until we don't remove any. // This handles cases where we remove one binding which had a reference to // another one. That one will get removed in the next pass if it is now unreferenced. let removed; do { removed = false; // Recrawl to get all bindings. scope.crawl(); Object.keys(scope.bindings).forEach(name => { let binding = getUnusedBinding(scope.path, name); // If it is not safe to remove the binding don't touch it. if (!binding) { return; } // Remove the binding and all references to it. binding.path.remove(); binding.referencePaths.concat(binding.constantViolations).forEach(remove); scope.removeBinding(name); removed = true; }); } while (removed); } module.exports = treeShake; // Check if a binding is safe to remove and returns it if it is. function getUnusedBinding(path, name) { let binding = path.scope.getBinding(name); if (!binding) { return null; } let pure = isPure(binding); if (!binding.referenced && pure) { return binding; } // Is there any references which aren't simple assignments? let bailout = binding.referencePaths.some(path => !isExportAssignment(path) && !isUnusedWildcard(path)); if (!bailout && pure) { return binding; } return null; } function isPure(binding) { if (binding.path.isVariableDeclarator() && binding.path.get('id').isIdentifier()) { let init = binding.path.get('init'); return init.isPure() || init.isIdentifier() || init.isThisExpression(); } return binding.path.isPure(); } function isExportAssignment(path) { return (// match "path.any = any;" path.parentPath.isMemberExpression() && path.parentPath.parentPath.isAssignmentExpression() && path.parentPath.parentPath.node.left === path.parentPath.node ); } function isUnusedWildcard(path) { let parent = path.parent; return (// match `$parcel$exportWildcard` calls t.isCallExpression(parent) && t.isIdentifier(parent.callee, { name: '$parcel$exportWildcard' }) && parent.arguments[0] === path.node && // check if the $id$exports variable is used !getUnusedBinding(path, parent.arguments[1].name) ); } function remove(path) { if (path.isAssignmentExpression()) { if (path.parentPath.isSequenceExpression()) { if (path.parent.expressions.length == 1) { // replace sequence expression with it's sole child path.parentPath.replaceWith(path); remove(path.parentPath); } else { path.remove(); } } else if (!path.parentPath.isExpressionStatement()) { path.replaceWith(path.node.right); } else { path.remove(); } } else if (isExportAssignment(path)) { remove(path.parentPath.parentPath); } else if (isUnusedWildcard(path)) { remove(path.parentPath); } else if (!path.removed) { if (path.parentPath.isSequenceExpression() && path.parent.expressions.length === 1) { // replace sequence expression with it's sole child path.parentPath.replaceWith(path); remove(path.parentPath); } else { path.remove(); } } }