वेबपैक का उपयोग करके पर्यावरण के आधार पर सशर्त निर्माण


93

मेरे पास विकास के लिए कुछ चीजें हैं - उदाहरण के लिए जो मैं अपनी वितरित बिल्ड फ़ाइल को ब्लोट नहीं करना चाहूंगा।

आवश्यकताएँ में आप एक प्लगइन फ़ाइल में एक विन्यास पारित कर सकते हैं और उस पर आधारित में conditonally चीजों की आवश्यकता होती है।

वेबपैक के लिए ऐसा करने का कोई तरीका प्रतीत नहीं होता है। सबसे पहले एक पर्यावरण के लिए एक क्रम config बनाने के लिए मैं का इस्तेमाल किया है resolve.alias एक की आवश्यकता होती है पर्यावरण, जैसे के आधार पर repoint रहे हैं:

// All settings.
var all = {
    fish: 'salmon'
};

// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));

तब वेबपैक कॉन्फिगरेशन बनाते समय मैं डायनामिकली यह बता सकता हूं कि कौन सी फाइल envsettings(यानी webpackConfig.resolve.alias.envsettings = './' + env) को इंगित करती है ।

हालाँकि मैं कुछ ऐसा करना चाहूंगा:

if (settings.mock) {
    // Short-circuit ajax calls.
    // Require in all the mock modules.
}

लेकिन स्पष्ट रूप से मैं उन नकली फ़ाइलों में निर्माण नहीं करना चाहता हूं यदि पर्यावरण नकली नहीं है।

मैं संभवतः उन सभी को मैन्युअल रूप से रिपीट कर सकता हूं जिनके लिए रिज़ॉल्यूशन का उपयोग करके स्टब फ़ाइल की आवश्यकता होती है।

किसी भी विचार मैं ऐसा कैसे कर सकते हैं? धन्यवाद।


ध्यान दें कि अभी के लिए मैंने वातावरण पर खाली (स्टब) फ़ाइल को इंगित करने के लिए उपनाम का उपयोग किया है जो मैं नहीं चाहता (जैसे कि आवश्यकता है ('मॉक') गैर-नकली एनवीएस पर एक खाली फ़ाइल को इंगित करेगा। थोड़ा हैकी लगता है लेकिन काम करता है।
डोमिनिक

जवाबों:


59

आप परिभाषित प्लगइन का उपयोग कर सकते हैं ।

मैं इसे अपने वेबपैक बिल्ड फ़ाइल में सरल रूप में कुछ करके उपयोग करता हूं जहां 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!');
}

यदि स्थिति गलत है तो यह आपकी बिल्ड फ़ाइल से इस कोड को हटा देगा। आप यहां एक काम कर रहे वेबपैक का उदाहरण देख सकते हैं ।


मैं इस समाधान से थोड़ा भ्रमित हूं। यह उल्लेख नहीं करता है कि मैं कैसे सेट करने वाला हूँ env। उस उदाहरण के माध्यम से देखने पर ऐसा लगता है जैसे वे उस झंडे को गुलाल और यारों के माध्यम से संभाल रहे हैं जो हर कोई उपयोग नहीं कर रहा है।
आंद्रे

1
यह लिंटर के साथ कैसे काम करता है? क्या आपको मैन्युअल रूप से नए ग्लोबल वैरिएबल को परिभाषित करना होगा जो डेफिनिट प्लगइन में जोड़े जाते हैं?
मार्क

2
@ चिह्न हाँ। "globals": { "ENV": true }अपने .eslintrc
मैट डेरिक

मैं एक घटक में ईएनवी चर का उपयोग कैसे करूंगा? मैंने ऊपर दिए गए समाधान की कोशिश की, लेकिन मुझे अभी भी त्रुटि मिलती है कि ENV परिभाषित नहीं है
jasan

18
यह निर्माण फ़ाइलों से बाहर कोड पट्टी नहीं है! मैंने इसका परीक्षण किया और कोड यहाँ है।
लियोनेल

42

सुनिश्चित नहीं हैं कि क्यों "webpack.DefinePlugin" उत्तर पर्यावरण आधारित आयात / आवश्यकता को परिभाषित करने के लिए हर जगह शीर्ष पर है।

समस्या यह है कि दृष्टिकोण के साथ कि आप अभी भी ग्राहक के लिए उन सभी मॉड्यूल प्रदान कर रहे हैं है -> के साथ जांच webpack गठरी-analyezer उदाहरण के लिए। और अपने बंडल के आकार को कम नहीं करना। :)

तो क्या वास्तव में अच्छी तरह से और बहुत अधिक तार्किक काम करता है: NormalModuleReplacementPlugin

तो बजाय on_client सशर्त की आवश्यकता है -> पहली जगह में बंडल के लिए आवश्यक फ़ाइलों को शामिल न करें

उम्मीद है की वो मदद करदे


अच्छा है कि प्लगइन के बारे में पता नहीं था!
डोमिनिक

इस परिदृश्य के साथ आपके पास प्रति वातावरण कई बिल्ड नहीं होंगे? उदाहरण के लिए यदि मेरे पास देव / क्यूए / यूएटी / उत्पादन वातावरण के लिए वेब सेवा का पता है, तो मुझे प्रत्येक पर्यावरण के लिए 4 अलग कंटेनर, 1 की आवश्यकता होगी। आदर्श रूप से आपके पास एक कंटेनर होगा और इसे एक पर्यावरण चर के साथ लॉन्च करना होगा ताकि यह निर्दिष्ट किया जा सके कि कौन सा लोड लोड करना है।
ब्रेट माथे

नहीं वास्तव में नहीं। ठीक यही आप प्लगइन के साथ भी करते हैं -> आप अपने वातावरण को एनवी वर्जन के माध्यम से निर्दिष्ट करते हैं और यह केवल एक कंटेनर का निर्माण करता है, लेकिन विशेष रूप से बिना अतिरेक के वातावरण के लिए। निश्चित रूप से यह भी इस बात पर निर्भर करता है कि आप अपने वेबपैक को कैसे सेटअप करते हैं और जाहिर है कि आप सभी बिल्ड बना सकते हैं, लेकिन यह वह नहीं है जो इस प्लगइन के बारे में है और करता है।
रोमन ज़ाइलोव

33

का उपयोग करें 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}`,
        },
      },
    ],
  },
  // ...
};

2
मैंने इस जवाब को स्वीकार कर लिया है क्योंकि स्वीकृत उत्तर उम्मीद के मुताबिक कोड नहीं निकालता है और प्रीप्रोसेसर की तरह सिंटैक्स को सशर्त तत्व के रूप में पहचाना जाने की अधिक संभावना है।
क्रिश्चियन आइविसेविच

1
बहुत बहुत धन्यवाद! यह एक सम्मोहन की तरह काम करता है। ContextReplacementPlugin, NormalModuleReplacementPlugin, और अन्य सामान के साथ कई घंटे के प्रयोग - सभी विफल रहे। और यहाँ ifdef- लोडर है, जिससे मेरा दिन बच रहा है।
जीरन-डायोविस

27

मैंने मैट डेरिक के उत्तर के समान कुछ का उपयोग करके समाप्त कर दिया , लेकिन दो बिंदुओं के बारे में चिंतित था:

  1. मेरे द्वारा उपयोग किए जाने पर हर बार पूर्ण कॉन्फ़िगरेशन इंजेक्ट किया जाता है ENV (जो बड़े कॉन्फ़िगरेशन के लिए खराब है)।
  2. मुझे कई प्रविष्टि बिंदुओं को परिभाषित करना होगा क्योंकि require(env)विभिन्न फाइलों के बिंदु।

मैं एक साधारण संगीतकार के साथ आया हूं जो एक कॉन्फिग ऑब्जेक्ट बनाता है और इसे एक कॉन्फिगर मॉड्यूल में इंजेक्ट करता है।
यहाँ फ़ाइल संरचना है, Iam इसके लिए उपयोग कर रहा है:

config/
 └── main.js
 └── dev.js
 └── production.js
src/
 └── app.js
 └── config.js
 └── ...
webpack.config.js

main.jsरखती है सभी डिफ़ॉल्ट config सामान:

// main.js
const mainConfig = {
  apiEndPoint: 'https://api.example.com',
  ...
}

module.exports = mainConfig;

dev.jsऔर production.jsकेवल पकड़ config सामान जो मुख्य config ओवरराइड करता है:

// dev.js
const devConfig = {
  apiEndPoint: 'http://localhost:4000'
}

module.exports = devConfig;

महत्वपूर्ण हिस्सा वह है webpack.config.jsजो कॉन्फिगरेशन को कंपोज़ करता है और डेफिनप्लगिन का उपयोग कर एक पर्यावरण वैरिएबल उत्पन्न करता है जो कंपोज़्ड कॉन्फिडेंट__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 आयात निर्यात सिंटैक्स का उपयोग करना क्योंकि इसकी वेबपैक के तहत):

const config = __APP_CONFIG__;

export default config;

अपने app.jsआप में अब आप import config from './config';विन्यास वस्तु प्राप्त करने के लिए उपयोग कर सकते हैं ।


2
यहाँ वास्तव में सबसे अच्छा जवाब
गेब्रियल

18

एक अन्य तरीका एक जेएस फाइल का उपयोग कर रहा है 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"

19
इफ़ / और आवश्यकता के साथ एकमात्र समस्या यह है कि दोनों आवश्यक फाइलें जनरेट की गई फ़ाइल में बंडल की जाएंगी। मुझे वर्कअराउंड नहीं मिला है। अनिवार्य रूप से बंडलिंग पहले होता है, फिर मैनबलिंग।
एलेक्स

2
यह गलत नहीं है, यदि आप अपने वेबपैक फ़ाइल में प्लग इन का उपयोग करते हैं, तो वेबपैक webpack.optimize.UglifyJsPlugin()का अनुकूलन मॉड्यूल लोड नहीं करेगा, क्योंकि सशर्त के अंदर लाइन कोड हमेशा गलत होता है, इसलिए वेबपैक इसे उत्पन्न बंडल से हटा देता है
एलेजांद्रो साइलेंट

@AlejandroSilva क्या आपके पास इसका रेपो उदाहरण है?
Thevangelist

1
@Thevangelist yep: github.com/AlejandroSilva/mototracker/blob/master/… यह एक नोड है + प्रतिक्रिया + redux pet proyect: P
एलेजांद्रो सिल्वा

4

ओपी के रूप में एक ही समस्या का सामना करना पड़ा और लाइसेंस के कारण, कुछ बिल्ड में कुछ कोड को शामिल नहीं करने के कारण, मैंने वेबपैक-सशर्त-लोडर को अपनाया निम्नानुसार को :

अपनी बिल्ड कमांड में मैंने अपने बिल्ड के लिए उचित रूप से एक पर्यावरण चर निर्धारित किया है। उदाहरण के लिए package.json में 'डेमो':

...
  "scripts": {
    ...
    "buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
...

मेरे द्वारा पढ़े गए दस्तावेज़ों से जो भ्रामक बिट गायब है, वह यह है कि मुझे यह सुनिश्चित करते हुए पूरे निर्माण प्रसंस्करण में दृश्यमान बनाना होगा कि मेरे env वेरिएबल को प्रक्रिया में वैश्विक रूप से इंजेक्ट किया जाए, इस प्रकार मेरे webpack.config / Demo.js:

/* The demo includes project/reports action to access placeholder graphs.
This is achieved by using the webpack-conditional-loader process.env.demo === true
 */

const config = require('./production.js');
config.optimization = {...(config.optimization || {}), minimize: false};

module.exports = env => {
  process.env = {...(process.env || {}), ...env};
  return config};

इसके स्थान पर, मैं सशर्त रूप से किसी भी चीज को बाहर कर सकता हूं, यह सुनिश्चित करता है कि किसी भी संबंधित कोड को परिणामी जावास्क्रिप्ट से ठीक से हिला दिया जाए। मेरे मार्गों में उदाहरण के लिए .js इस प्रकार डेमो बिल्ड अन्य बिल्ड से बाहर रखा गया है:

...
// #if process.env.demo
import Reports from 'components/model/project/reports';
// #endif
...
const routeMap = [
  ...
  // #if process.env.demo
  {path: "/project/reports/:id", component: Reports},
  // #endif
...

यह वेबपैक 4.29.6 के साथ काम करता है।


1
वहाँ भी है github.com/dearrrfish/preprocess-loader जिसकी अधिक विशेषताएं हैं
user9385381

1

मैं अपने वेबपैक कॉन्फिग में env को सेट करने के लिए संघर्ष कर रहा हूँ। मैं आमतौर पर एनवी सेट करना चाहता हूं ताकि इसे अंदर तक पहुंचाया जा सके webpack.config.js, postcss.config.jsऔर एंट्री प्वाइंट एप्लीकेशन के अंदर ही (index.js आमतौर पर) हो सके। मुझे उम्मीद है कि मेरे निष्कर्ष किसी की मदद कर सकते हैं।

मैं जिस समाधान के साथ आया हूं वह अंदर --env productionया --env developmentउसके बाद मोड सेट करना है webpack.config.js। हालाँकि, यह मुझे envसुलभ बनाने में मदद नहीं करता है जहाँ मैं यह चाहता हूँ (ऊपर देखें), इसलिए मुझे भी process.env.NODE_ENVस्पष्ट रूप से सेट करने की आवश्यकता है , जैसा कि यहाँ सुझाया गया है । सबसे अधिक प्रासंगिक हिस्सा जिसका मुझे webpack.config.jsनीचे अनुसरण करना है।

...
module.exports = mode => {
  process.env.NODE_ENV = mode;

  if (mode === "production") {
    return merge(commonConfig, productionConfig, { mode });
  }
  return merge(commonConfig, developmentConfig, { mode });
};

0

देव और ठेस की तैनाती बनाने के लिए प्रवर्तक चर का उपयोग करें:

https://webpack.js.org/guides/environment-variables/


2
यह वह नहीं है जो मैं पूछ रहा था
डोमिनिक

समस्या यह है कि बंडल बनाते समय वेबपैक स्थिति को नजरअंदाज कर देगा और इसमें विकास के लिए लोड कोड भी शामिल होगा ... इसलिए यह मुद्दे को हल नहीं करता है
sergioviniciuss

-1

जबकि यह सबसे अच्छा समाधान नहीं है, यह आपकी कुछ जरूरतों के लिए काम कर सकता है। यदि आप मेरे लिए काम करने वाले नोड और ब्राउज़र में अलग कोड चलाना चाहते हैं:

if (typeof window !== 'undefined') 
    return
}
//run node only code now

1
ओपी एक संकलन समय निर्णय के बारे में पूछ रहा है, आपका उत्तर रन समय के बारे में है।
माइकल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.