Условная компиляция / требуется с использованием browserify (устранение мертвого кода)

#javascript #browserify #commonjs #uglifyjs #envify

#javascript #browserify #commonjs #uglifyjs #envify

Вопрос:

Я знаю, что вы не можете использовать модуль с browserify условно require , потому что они объединяются во время компиляции, а не во время выполнения. Как насчет условного удаления модулей?

Допустим, у меня есть приложение, которое позволяет создавать галереи изображений. Галереи также можно редактировать (изменять порядок изображений и т.д.). Но рендеринг галереи и редактирование связаны и не могут быть полностью разделены. Но для развертывания галерей мне не нужны функции редактирования, и я знаю, какие модули используются. Я хочу создать два разных пакета, один с возможностями редактирования, а другой без, удалив большую часть кода редактирования. Что я сделал, так это использовал 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;
}
  

Это отлично работает, и пакет редактора уже меньше. И поскольку я знаю, что другой пакет никогда не будет использовать функциональность 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 полностью.

Комментарии:

1. Возможно, factor-bundle это будет полезно для вас?

2. @casr спасибо! Я не думаю, что это может быть применено здесь. Учитывая пример в документах, я хочу удалить w и z из пакета x, потому что я знаю, что console.log(z(5) * w(2)); никогда не будет выполнен. Хотя он все равно будет в комплекте. Я вроде как делаю глупые сумасшедшие вещи здесь. Но, эй, я удалил 20% из пакета без редактирования!

Ответ №1:

Я думаю, что вам нужно преобразование, подобное uglifyify .

Uglifyify дает вам преимущество применения преобразования Uglify «squeeze» к каждому файлу перед его включением в пакет, что означает, что вы можете удалять пути к мертвому коду для условных требований.

Обратите внимание, что вы все равно захотите выполнить uglifyjs результирующий вывод.

Комментарии:

1. Вы абсолютно правы! Это делает именно то, что я изначально хотел. Я буду придерживаться решения, которое у меня есть сейчас, поскольку это приводит к еще меньшему объему пакета. Но uglifyify — менее взломанная версия.

2. В результате должны получиться пакеты того же размера, что и на вашем пользовательском этапе преобразования, с дополнительным преимуществом автоматической работы с изменениями в проекте. Если вы получаете пакеты меньшего размера, чем этот, то, скорее всего, в ваших пакетах был удален код, на который он фактически опирается

Ответ №2:

Я думаю, что нашел решение, которое работает достаточно хорошо. В качестве бонуса не требуется прикасаться к существующему коду (например, добавление 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"
    ]
},