gpt4 book ai didi

javascript - Uglify JS - 压缩未使用的变量

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:49:52 32 4
gpt4 key购买 nike

Uglify 有一个“压缩”选项,可以删除未使用的变量...

但是,如果我将一些函数存储在这样的对象中......

helpers = {
doSomething: function () { ... },
doSomethingElese: function () { ... }
}

...如果 helpers.doSomething() 从未被访问过,有没有办法删除它?

我想我想授予压缩器更改我的对象的权限。

有什么想法吗?或者任何其他可以提供帮助的工具?

最佳答案

使用像 Uglify2 或 Esprima 这样的静态分析器来完成这个任务有点不平凡,因为有很多情况会调用一个难以确定的函数。为了显示复杂性,有这个网站:

http://sevinf.github.io/blog/2012/09/29/esprima-tutorial/

它试图至少识别未使用的函数。但是,该网站上提供的代码不适用于您的示例,因为它正在寻找 FunctionDeclarations 而不是 FunctionExpressions。它还在寻找 CallExpression 作为标识符,同时忽略 CallExpression,即您的示例使用的 MemberExpression。还有一个作用域问题,它没有考虑不同作用域中具有相同名称的函数——完全合法的 Javascript,但是你使用该代码会失去保真度,因为它会错过一些未使用的函数,认为它们在调用时被调用不是。

要处理范围问题,您可以使用 ESTR ( https://github.com/clausreinke/estr ) 来帮助确定变量的范围以及未使用的函数。然后你需要使用类似 escodegen 的东西来删除未使用的函数。

作为您的起点,我已经调整了该网站上的代码以适用于您提供的非常具体的情况,但请注意,它会有范围问题。

这是为 Node.js 编写的,因此您需要使用 npm 获取 esprima 才能使用提供的示例,当然还要使用 node 执行它。

var fs = require('fs');
var esprima = require('esprima');

if (process.argv.length < 3) {
console.log('Usage: node ' + process.argv[1] + ' <filename>');
process.exit(1);
}


notifydeadcode = function(data){
function traverse(node, func) {
func(node);
for (var key in node) {
if (node.hasOwnProperty(key)) {
var child = node[key];
if (typeof child === 'object' && child !== null) {
if (Array.isArray(child)) {
child.forEach(function(node) {
traverse(node, func);
});
} else {
traverse(child, func);
}
}
}
}
}

function analyzeCode(code) {
var ast = esprima.parse(code);
var functionsStats = {};
var addStatsEntry = function(funcName) {
if (!functionsStats[funcName]) {
functionsStats[funcName] = {calls: 0, declarations:0};
}
};

var pnode = null;
traverse(ast, function(node) {
if (node.type === 'FunctionExpression') {
if(pnode.type == 'Identifier'){
var expr = pnode.name;
addStatsEntry(expr);
functionsStats[expr].declarations++;
}
} else if (node.type === 'FunctionDeclaration') {
addStatsEntry(node.id.name);
functionsStats[node.id.name].declarations++;
} else if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
addStatsEntry(node.callee.name);
functionsStats[node.callee.name].calls++;
}else if (node.type === 'CallExpression' && node.callee.type === 'MemberExpression'){
var lexpr = node.callee.property.name;
addStatsEntry(lexpr);
functionsStats[lexpr].calls++;
}
pnode = node;
});
processResults(functionsStats);
}

function processResults(results) {
//console.log(JSON.stringify(results));
for (var name in results) {
if (results.hasOwnProperty(name)) {
var stats = results[name];
if (stats.declarations === 0) {
console.log('Function', name, 'undeclared');
} else if (stats.declarations > 1) {
console.log('Function', name, 'decalred multiple times');
} else if (stats.calls === 0) {
console.log('Function', name, 'declared but not called');
}
}
}
}
analyzeCode(data);
}

// Read the file and print its contents.
var filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
if (err) throw err;
console.log('OK: ' + filename);
notifydeadcode(data);
});

所以如果你把它放在像 deadfunc.js 这样的文件中,然后像这样调用它:

node deadfunc.js test.js

其中 test.js 包含:

helpers = { 
doSomething:function(){ },
doSomethingElse:function(){ }
};
helpers.doSomethingElse();

你会得到输出:

OK: test.js
Function doSomething declared but not called

要注意的最后一件事:尝试查找未使用的变量和函数可能是一个兔子洞,因为您会遇到诸如从字符串创建的 eval 和 Functions 之类的情况。您还必须考虑 apply 和 call 等。这就是为什么,我想,我们今天的静态分析器没有这种能力。

关于javascript - Uglify JS - 压缩未使用的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16940013/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com