Условная сборка на основе среды с использованием Webpack
у меня есть некоторые вещи для разработки - например, насмешки, которые я хотел бы не раздувать мой распределенный файл сборки.
в RequireJS вы можете передать конфигурацию в файле плагина и условно требовать вещи на основе этого.
для webpack, похоже, нет способа сделать это. Во-первых, чтобы создать конфигурацию среды выполнения для среды, которую я использовал разрешить.псевдоним для перестановки требуется в зависимости от окружающей среды, например:
// All settings.
var all = {
fish: 'salmon'
};
// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));
затем при создании конфигурации webpack я могу динамически назначить какой файл envsettings
указывает на (т. е. webpackConfig.resolve.alias.envsettings = './' + env
).
if (settings.mock) {
// Short-circuit ajax calls.
// Require in all the mock modules.
}
но, очевидно, я не хочу создавать эти макетные файлы, если среда не является макетом.
Я мог бы вручную переставить все эти требования в файл заглушки с помощью resolve.снова псевдоним - но есть ли способ, который чувствует себя менее хакерским?
любые идеи как я могу это сделать? Спасибо.
7 ответов:
можно использовать определить плагин.
Я использую его, делая что-то столь же простое, как это в вашем файле сборки webpack, где
env
- путь к файлу, который экспортирует объект параметры:// Webpack build config plugins: [ new webpack.DefinePlugin({ ENV: require(path.join(__dirname, './path-to-env-files/', env)) }) ] // Settings file located at `path-to-env-files/dev.js` module.exports = { debug: true };
а потом это в вашем коде
if (ENV.debug) { console.log('Yo!'); }
он удалит этот код из вашего файла сборки, если условие ложно. Вы можете увидеть рабочий пример сборки Webpack здесь.
другой способ-использовать JS файл как
proxy
, и пусть этот файл загружает интересующий модуль вcommonjs
, и экспортировать его какes2015 module
, например:// file: myModule.dev.js module.exports = "this is in dev" // file: myModule.prod.js module.exports = "this is in prod" // file: myModule.js let loadedModule if(WEBPACK_IS_DEVELOPMENT){ loadedModule = require('./myModule.dev.js') }else{ loadedModule = require('./myModule.prod.js') } export const myString = loadedModule
тогда вы можете использовать модуль ES2015 в вашем приложении обычно:
// myApp.js import { myString } from './store/myModule.js' myString // <- "this is in dev"
Не уверен, почему " webpack.DefinePlugin " ответ является лучшим везде для определения импорта на основе среды / требует.
The при таком подходе вы все еще доставляете все эти модули клиенту - > проверьте с webpack-bundle-analyezer например. И не сокращая свой пакет.размер js вообще :)
Так что действительно работает хорошо и гораздо логичнее: NormalModuleReplacementPlugin
поэтому вместо того, чтобы делать условное требование on_client - > просто не включайте не нужные файлы в пакет в первую очередь
надеюсь, что это поможет
использовать
ifdef-loader
. В исходных файлах вы можете делать такие вещи, как/// #if ENV === 'production' console.log('production!'); /// #endif
соответствующего
webpack
конфигурацияconst preprocessor = { ENV: process.env.NODE_ENV || 'development', }; const ifdef_query = require('querystring').encode({ json: JSON.stringify(preprocessor) }); const config = { // ... module: { rules: [ // ... { test: /\.js$/, exclude: /node_modules/, use: { loader: `ifdef-loader?${ifdef_query}`, }, }, ], }, // ... };
я в конечном итоге с помощью чего-то похожего на Мэтт Деррик' Ответ, но волновался по поводу двух моментов:
- полная конфигурация вводится каждый раз, когда я использую
ENV
(что плохо для больших конфигов).- мне нужно определить несколько точек входа, потому что
require(env)
указывает на разные файлы.
то, что я придумал-это простой композитор, который строит объект конфигурации и вводит его в конфигурацию модуль.
Вот файловая структура, которую я использую для этого:config/ └── main.js └── dev.js └── production.js src/ └── app.js └── config.js └── ... webpack.config.js
The
main.js
содержит все настройки по умолчанию:// main.js const mainConfig = { apiEndPoint: 'https://api.example.com', ... } module.exports = mainConfig;
The
dev.js
иproduction.js
только держите конфигурационный материал, который переопределяет основную конфигурацию:// dev.js const devConfig = { apiEndPoint: 'http://localhost:4000' } module.exports = devConfig;
важной частью является
webpack.config.js
который составляет конфигурацию и использует DefinePlugin для создания переменной среды__APP_CONFIG__
, который содержит в составе конфигурации объект:const argv = require('yargs').argv; const _ = require('lodash'); const webpack = require('webpack'); // Import all app configs const appConfig = require('./config/main'); const appConfigDev = require('./config/dev'); const appConfigProduction = require('./config/production'); const ENV = argv.env || 'dev'; function composeConfig(env) { if (env === 'dev') { return _.merge({}, appConfig, appConfigDev); } if (env === 'production') { return _.merge({}, appConfig, appConfigProduction); } } // Webpack config object module.exports = { entry: './src/app.js', ... plugins: [ new webpack.DefinePlugin({ __APP_CONFIG__: JSON.stringify(composeConfig(ENV)) }) ] };
последний шаг теперь
config.js
, это выглядит так (используя синтаксис экспорта импорта es6 здесь, потому что его под webpack):const config = __APP_CONFIG__; export default config;
в своем
app.js
теперь вы можете использоватьimport config from './config';
чтобы получить объект конфигурации.
хотя это не лучшее решение, оно может работать для некоторых ваших потребностей. Если вы хотите запустить другой код в узле и браузере, используя это работало для меня:
if (typeof window !== 'undefined') return } //run node only code now