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

Javascript 条件编译/要求使用browserify(死代码消除),javascript,browserify,commonjs,uglifyjs,envify,Javascript,Browserify,Commonjs,Uglifyjs,Envify,我知道您不能有条件地要求使用browserify的模块,因为它们是在编译时绑定的,而不是在运行时绑定的。有条件地剥离模块怎么样 假设我有一个应用程序,可以让你创建图片库。还可以编辑库(重新排列图像等)。但画廊的渲染和编辑是耦合的,不能完全分离。但是对于部署库,我不需要编辑功能,我知道使用了哪些模块。我想创建两个不同的捆绑包,一个具有编辑功能,另一个不具有编辑功能,方法是消除大部分编辑代码。我所做的就是使用envify和uglify的死代码消除将我自己的代码从较小的包中排除 Before(thin

我知道您不能有条件地
要求
使用browserify的模块,因为它们是在编译时绑定的,而不是在运行时绑定的。有条件地剥离模块怎么样

假设我有一个应用程序,可以让你创建图片库。还可以编辑库(重新排列图像等)。但画廊的渲染和编辑是耦合的,不能完全分离。但是对于部署库,我不需要编辑功能,我知道使用了哪些模块。我想创建两个不同的捆绑包,一个具有编辑功能,另一个不具有编辑功能,方法是消除大部分编辑代码。我所做的就是使用
envify
和uglify的死代码消除将我自己的代码从较小的包中排除

Before(thing.js)

之后(thing.js)

这非常有效,编辑器包已经更小了。因为我知道另一个bundle永远不会使用
thing
的功能,所以可以不导出任何内容,只导出一个空模块

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

Before(thing.js)

之后(thing.js)


总而言之:我的包现在包含
pica
库,但没有人需要它。需要它的代码是死代码,但uglify显然无法理解它可以完全删除
pica

我想我已经找到了一个足够有效的解决方案。作为奖励,它不需要接触现有代码(例如添加
process.env.
check)。我编写了一个browserify转换,它给出了一个模块/文件列表,将它们的
require
调用替换为
{}
。这样,它们将从生成的包中完全移除。不管怎么说,这只是一次黑客攻击。我知道

之前:

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

var thing = {};
var pica = {};
使用它只需要几行代码,因为它已经提供了一个
makeRequireTransform
helper。我将把代码扔到这里,并建议任何人都不要使用它,除非你确切知道自己在做什么

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"
    ]
},

我认为你所追求的是一种转变

Uglifyify使您能够在每个文件包含在捆绑包中之前对其应用Uglify的“挤压”转换,这意味着您可以删除条件要求的死代码路径


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

可能对您有用?@casr谢谢!我认为它在这里不适用。给定文档中的示例,我希望从bundle x中删除w和z,因为我知道
console.log(z(5)*w(2))将永远不会执行。尽管如此,它仍将处于捆绑状态。我在做一些愚蠢的疯狂的事情。但是,嘿,我从非编辑器包中删除了20%!你完全正确!这正是我最初想要的。我将坚持使用我现在的解决方案,因为它会产生更小的包。但是uglifyify是一个不太老套的版本。这应该会产生与自定义转换步骤相同大小的包,并具有自动处理项目更改的附加好处。如果您得到的bundle比这个要小,那么很可能您的bundle已经删除了它实际上所依赖的代码
var thing = require('./thing.js');
var pica = require('pica');
var thing = {};
var pica = {};
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;
"browserify": {
    "transform": [
        "babelify",
        [
            "./derequire.js",
            {
                "modules": [
                    "pica",
                    "exif-js",
                    "./src/thing.js",
                    "components/TextEditor.jsx",
                    "lib/FileUploader.js"
                ]
            }
        ],
        "browserify-css",
        "imgurify",
        "glslify"
    ]
},