Как связать изоморфный код commonJS с webpack

У меня есть проект, который использует формат модуля nodeJS (commonJS) и также должен (частично) запускаться в браузере.

У меня есть неизоморфные пути кода, в которые я условно включаю модули:

var impl;
try {
    // in node, use node-impl
   impl = require('../node-impl');
} catch (err) {
    // running in browser, use browser-impl
    impl = require('../browser-impl');
}

Теперь я хочу использовать webpack для создания пакета, который запускается в браузере. Поэтому мне нужно определить внешние (специфичные для nodeJS) модули как external в webpack.config.js, чтобы они не попадали в пакет:

external: {
    '../node-impl': true
}

Я подтвердил, что код "../node-impl" на самом деле не включен в комплект, но полученный код выглядит так:

/***/ },
/* 33 */
/***/ function(module, exports) {

    module.exports = ../node-impl;

/***/ },

Это синтаксически неправильный JS, и браузер выдаст там синтаксическую ошибку.

Как этот сценарий правильно обрабатывается с помощью webpack.js? Имейте в виду, что я не хочу использовать веб-пакет для работы с nodeJS, с помощью веб-пакета следует создавать только пакеты браузера.


person Dynalon    schedule 02.02.2016    source источник


Ответы (3)


// Your actual situation: var impl; try { impl = require('../node-impl'); } catch(e) { impl = require('../browser-impl'); }

Вам необходимо выполнить рефакторинг этого фрагмента, чтобы:

var impl = require('../node-impl');

После этой доработки ваш код сможет работать только в среде node js, это хорошо, потому что мы собираемся имитировать этот запрос при объединении для браузеров ... // webpack.browser.config.js module.exports = { resolve: { alias: { '../node-impl': '../browser-impl' } } };

Webpack - Resolve.Alias ​​ Или используя package.json#browser, или https://webpack.github.io/docs/configuration.html#resolve-packagealias

person Hitmands    schedule 02.02.2016
comment
Но это связано с вызовом webpack в моем коде nodeJS - мне это не нравится. Код работает без какого-либо веб-пакета на узле, и я бы предпочел не вводить код, специфичный для веб-пакета. - person Dynalon; 02.02.2016
comment
Хотя это работает для тех зависимостей, которые доступны в браузере, все же nodeJS impl выдаст исключение синтаксиса, поскольку выпущенный код в моем исходном вопросе все еще на месте - person Dynalon; 02.02.2016
comment
Я приведу вам еще один пример - person Hitmands; 02.02.2016
comment
Проблема НЕ в том, что для пакета браузера не найден какой-то модуль. Проблема в том, что webpack помещает модули, перечисленные в разделе externals, следующим образом: module.exports = ../node-impl - это недопустимый код JS, и он немедленно завершится ошибкой перед выполнением любого кода. - person Dynalon; 02.02.2016
comment
Я вас не понимаю, извините ... externals: {"../node-impl": "window.something"} должно работать. - person Hitmands; 02.02.2016
comment
Поскольку, как следует из названия, node-impl содержит код, специфичный для node-JS, который НЕ должен входить в пакет браузера! И поэтому он не может находиться в window.nodeImpl или где-либо еще. Я могу сделать это только externals: { "../node-impl": true }, но тогда выданный код не является допустимым кодом JS из-за начальных точек - person Dynalon; 02.02.2016
comment
мое последнее обновление должно соответствовать тому, что вы ищете. - person Hitmands; 02.02.2016

Я не думаю, что это предназначение внешнего конфига. Согласно документам,

Укажите зависимости, которые не должны разрешаться веб-пакетом, но должны стать зависимостями результирующего пакета. Тип зависимости зависит от output.libraryTarget.

Итак, вы говорите webpack, что ваша сборка требует этого модуля, но не для его включения. Он его пропускает, но пытается потребовать его.

Вероятно, есть несколько способов сделать то, что вы хотите. Стоит упомянуть, что вы можете легко заставить webpack создавать несколько сборок с разной / общей конфигурацией из одного файла конфигурации, что открывает множество возможностей. Но я бы предложил использовать DefinePlugin для определить логическую «константу», которая представляет контекст выполнения (например, IN_BROWSER = true). Проверьте эту константу в своем условном выражении вокруг require(). Парсер Webpack не такой умный, но он может оценивать логические переменные, поэтому он правильно разрешит условное выражение и потребует только соответствующий модуль. (Использование не-логического типа, такого как CONTEXT = 'browser', слишком запутанно для webpack, и он будет анализировать каждый оператор require.) Затем вы можете использовать плагин Uglify, чтобы удалить «мертвый код» в условном выражении, чтобы он не раздувал вашу производственную сборку .

person Brendan Gannon    schedule 03.02.2016

С помощью @Hitmands я мог придумать решение, которое все еще не идеально, но соответствует моим потребностям. Я представляю фиктивный nonexistingmodule и объявляю его внешним; Затем я объявляю node-impl определенные модули доступными как nonexistingmodule:

externals: {
    'nonexistingmodule': true,
    '../node-impl': 'nonexistingmodule'
}

Таким образом, я могу сохранить шаблон try/catch для загрузки конкретных реализаций, и он по-прежнему будет работать на узле. В браузере загрузка nonexistingmodule не выполняется, и модуль browser-impl загружается - как я и задумал.

Я большой поклонник «не реорганизуйте код для соответствия инструменту», поэтому я выберу это решение.

person Dynalon    schedule 04.02.2016