有条件的编译/要求使用browserify(死代码消除)

时间:2016-10-24 09:40:45

标签: javascript browserify commonjs uglifyjs envify

我知道你不能有条件require一个带有browserify的模块,因为它们是在编译时绑定的,而不是运行时。条件剥离模块怎么样?

假设我有一个允许您创建图片库的应用程序。还可以编辑图库(重新排序图像等)。但是图库的渲染和编辑是耦合的,不能完全分开。但是为了部署画廊,我不需要编辑功能,我知道使用了哪些模块。我想创建两个不同的包,一个具有编辑功能,另一个没有删除大部分编辑代码。我所做的是使用envify和uglify的死代码消除来从较小的包中排除我自己的代码。

之前(thing.js)

//...some code that only the editor needs...
module.exports = thing;

之后(thing.js)

if(process.env.INCLUDE_EDITOR === 'yes') {
    //...some code that only the editor needs...
    module.exports = thing;
}

这很好用,编辑器包已经很小了。而且因为我知道另一个bundle永远不会使用thing的功能,所以只输出一个空模块就可以了。

现在问题就在于此。如果thing.js需要一个模块,比如说pica,它仍然会捆绑,即使在删除死代码之后没有人使用它

之前(thing.js)

var pica = require('pica');
//...some code that uses pica...
module.exports = thing;

之后(thing.js)

if(process.env.INCLUDE_EDITOR === 'yes') {
    var pica = require('pica');
    //...some code that uses pica...
    module.exports = thing;
}

总结一下:我的包现在包含pica库,但没有人需要它。需要它的代码是死代码,但是uglify显然不能理解它可以完全删除pica

2 个答案:

答案 0 :(得分:1)

我认为你所追求的是uglifyify之类的转换。

  

Uglifyify为您提供了在每个文件包含在捆绑包中之前对每个文件应用Uglify的“挤压”转换的好处,这意味着您可以删除条件要求的死代码路径。

请注意,您仍然希望在结果输出上运行uglifyjs

答案 1 :(得分:0)

我想我找到了一个效果很好的解决方案。作为奖励,它不需要触及现有代码(例如,添加process.env.支票)。我编写了一个browserify转换,给定一个模块/文件列表,用require替换他们的{}调用。这样,它们就会从生成的包中完全删除。无论如何,这只是一个黑客攻击。我知道。

在:

var thing = require('./thing.js');
var pica = require('pica');

后:

var thing = {};
var pica = {};

使用https://www.npmjs.com/package/browserify-transform-tools这只是几行代码,因为它已经提供了makeRequireTransform帮助器。我要在这里转储代码并建议没有人应该使用它,除非你确切知道你在做什么。

derequire.js

var path = require('path');
var resolve = require('resolve');
var transformTools = require('browserify-transform-tools');

var options = {
    evaluateArguments: true,
    jsFilesOnly: true
};

var cache = {};
var resolveDerequire = function(moduleName) {
    var fromCache = cache[moduleName];

    if(fromCache) {
        return fromCache;
    }

    return require.resolve(moduleName);
};

var transform = transformTools.makeRequireTransform('derequire', options, function(args, transformOptions, done) {
    var requiredModule = args[0];
    var basedir = path.dirname(transformOptions.file);

    var shouldDerequire = transformOptions.config.modules.some(function(moduleToRequire) {
        try {
            //The normal require which respects NODE_PATH.
            return require.resolve(requiredModule) === resolveDerequire(moduleToRequire);
        } catch(ex1) {
            try {
                //A local require relative to the current file.
                return resolve.sync(requiredModule, {basedir: basedir}) === resolveDerequire(moduleToRequire);
            } catch(ex2) {
                console.error(ex1, ex2);
                return false;
            }
        }
    });

    if(shouldDerequire) {
        done(null, '{}');
    } else {
        done();
    }
});


module.exports = transform;

变换的package.json配置

"browserify": {
    "transform": [
        "babelify",
        [
            "./derequire.js",
            {
                "modules": [
                    "pica",
                    "exif-js",
                    "./src/thing.js",
                    "components/TextEditor.jsx",
                    "lib/FileUploader.js"
                ]
            }
        ],
        "browserify-css",
        "imgurify",
        "glslify"
    ]
},