首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Uglify JS -压缩未使用的变量

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

Stack Overflow用户
提问于 2013-06-05 20:30:40
回答 1查看 1.9K关注 0票数 3

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

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

代码语言:javascript
复制
helpers = {
    doSomething: function () { ... },
    doSomethingElese: function () { ... }
}

..。如果helpers.doSomething()从未被访问过,有什么方法可以删除它吗?

我想我想给压缩器权限来改变我的对象。

如果可能的话,有什么想法吗?或者其他可以帮助你的工具?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-16 07:41:12

使用像Uglify2或Esprima这样的静态分析器来完成这项任务在某种程度上是不容易的,因为有很多情况下将调用难以确定的函数。为了展示复杂性,这里有这个网站:

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

其试图至少标识未使用的功能。但是,该网站上提供的代码不会对您的示例起作用,因为它查找的是FunctionDeclarations而不是FunctionExpressions。它还会寻找CallExpression作为标识符,而忽略示例中使用的MemberExpression。这里还有一个作用域的问题,它没有考虑到不同作用域中具有相同名称的函数-完全合法的Javascript,但使用该代码会失去保真度,因为它会错过一些未使用的函数,因为它们被调用时并没有被调用。

要处理作用域问题,您可以使用ESTR (https://github.com/clausreinke/estr)来帮助确定变量的作用域和未使用的函数的作用域。然后,您需要使用诸如escodegen之类的东西来删除未使用的函数。

作为你的起点,我已经修改了该网站上的代码,以适应你提供的非常具体的情况,但请注意,它将有范围问题。

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

代码语言:javascript
复制
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这样的文件中,然后这样调用它:

代码语言:javascript
复制
node deadfunc.js test.js

其中,test.js包含:

代码语言:javascript
复制
helpers = { 
    doSomething:function(){ },
    doSomethingElse:function(){ } 
};
helpers.doSomethingElse();

您将获得以下输出:

代码语言:javascript
复制
OK: test.js
Function doSomething declared but not called

最后要注意的一件事是:试图查找未使用的变量和函数可能是一个兔子洞,因为您有从字符串创建eval和函数的情况。你还必须考虑应用和调用等,这就是为什么,我假设,我们今天的静态分析器中没有这个功能。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16940013

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档