1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
| /** * @author Jay * @since 2022-12-28 * @description 删除没有使用的代码 */
const types = require("@babel/types"); const parser = require("@babel/parser"); const traverse = require("@babel/traverse").default; const generate = require("@babel/generator").default;
function removeUnusedCode(code) { // 解析 const ast = parser.parse(code, { sourceType: "module", // module plugins: ["jsx"], // jsx });
// 生成ast traverse(ast, { // 处理 const var let VariableDeclaration(path) { const { node } = path; const { declarations } = node;
try { node.declarations = declarations.filter((declaration) => { const { id } = declaration; if (types.isObjectPattern(id)) { // path.scope.getBinding(name).referenced 判断变量是否被引用 // 通过filter移除掉没有使用的变量 id.properties = id.properties.filter((property) => { const binding = path.scope.getBinding(property.key.name); // referenced 变量是否被引用 // constantViolations 变量被重新定义的地方 const { referenced, constantViolations } = binding; if (!referenced && constantViolations.length > 0) { constantViolations.map((violationPath) => { // 如果变量未使用过,被修改的语句也需要一起移除 violationPath.remove(); }); } return referenced; }); // 如果对象中所有变量都没有被应用,则该对象整个移除 return id.properties.length > 0; } else { // const a = 1; // @ts-ignore const binding = path.scope.getBinding(id.name); const { referenced, constantViolations } = binding; if (!referenced && constantViolations.length > 0) { constantViolations.map((violationPath) => { violationPath.remove(); }); } return referenced; } });
if (node.declarations.length === 0) { path.remove(); } } catch (error) {} }, // 处理 import ImportDeclaration(path) { const { node } = path; const { specifiers } = node; if (!specifiers.length) { return; } node.specifiers = specifiers.filter((specifier) => { const { local } = specifier;
// React 不删除 if (local.name === "React") return true;
const binding = path.scope.getBinding(local.name); return !!binding.referenced; }); if (node.specifiers.length === 0) { path.remove(); } }, // 处理 function FunctionDeclaration(path) { const { node } = path; const { id } = node; const binding = path.scope.getBinding(id.name); if (!binding?.referenced) { path.remove(); } },
// 函数调用表达式 // CallExpression(path) { // // 删除console // if (path.node.callee && t.isIdentifier(path.node.callee.property, { name: "console" })) { // path.remove(); // }
// // if (path.node.callee && t.isIdentifier(path.node.callee.property, { name: "log" })) { // // // path.remove(); // // // console.log(path.node.callee.property); // // path.node.callee.property.name = "info"; // // } // }, });
// 生成code 字符串 return generate(ast, { retainLines: true, compact: false, auxiliaryCommentAfter: undefined, jsescOption: { es6: false, concise: false, }, }).code; }
module.exports = removeUnusedCode;
const s = ` const a = 1; const b = 1;
console.log(a);
const aa = () => {};
import React, { Component, PureComponent } from "react";
export class Hello extends Component { constructor(props) { super(props); this.state = { list: [], //列表 }; }
render() { return <div>test123</div>; } }
export default Hello;
`;
const ss = ` import React from "react"; import { hot } from "react-hot-loader/root"; import { Provider } from "react-redux"; import createStore from "@/redux/store/configureStore"; import Routes from "@/routes"; import "./themes";
class App extends React.Component { render() { return ( <Provider store={createStore()}> <Routes /> </Provider> ); } }
export default hot(App); `;
const result = removeUnusedCode(ss); console.log(result);
|