[javascript] Webpack을 사용하는 환경 기반 조건부 빌드

개발을위한 몇 가지 사항이 있습니다. 예를 들어 배포 된 빌드 파일을 부 풀리지 않게하고 싶은 모의 작업이 있습니다.

RequireJS에서는 플러그인 파일에 구성을 전달할 수 있으며이를 기반으로 조건부로 요구할 수 있습니다.

웹팩의 경우이 작업을 수행하는 방법이없는 것 같습니다. 먼저 환경에 대한 런타임 구성을 만들기 위해 resolve.alias 를 사용 하여 환경에 따라 요구 사항 을 다시 지정했습니다. 예 :

// 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.alias를 다시 사용하여 필요한 모든 것을 스텁 파일로 수동으로 다시 지정할 수 있지만 덜 해키라고 느끼는 방법이 있습니까?

어떻게 할 수 있는지 아이디어가 있습니까? 감사.



답변

define 플러그인을 사용할 수 있습니다 .

env설정 개체를 내보내는 파일의 경로 인 webpack 빌드 파일에서 다음과 같이 간단한 작업을 수행하여 사용합니다 .

// 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 빌드 예제를 볼 수 있습니다 .


답변

“webpack.DefinePlugin”답변이 환경 기반 가져 오기 / 요구 사항을 정의하는 모든 곳에서 가장 높은 이유를 잘 모르겠습니다.

이 접근 방식 의 문제점 은 여전히 ​​모든 모듈을 클라이언트에 제공하고 있다는 것 입니다. 예를 들어 webpack-bundle-analyezer 로 확인하십시오 . 그리고 bundle.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}`,
        },
      },
    ],
  },
  // ...
};


답변

나는 Matt Derrick ‘Answer 와 비슷한 것을 사용 했지만 두 가지 점에 대해 걱정했습니다.

  1. 전체 구성은 내가 사용할 때마다 주입됩니다 ENV(대규모 구성에는 좋지 않음).
  2. require(env)다른 파일을 가리 키기 때문에 여러 진입 점을 정의해야 합니다.

내가 생각 해낸 것은 구성 개체를 만들고 구성 모듈에 주입하는 간단한 작곡가입니다.
파일 구조는 다음과 같습니다.

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

main.js모든 기본 설정 물건을 원하는 분야

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

module.exports = mainConfig;

dev.jsproduction.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이며 다음과 같습니다 (webpack 아래에 있으므로 여기에서 es6 가져 오기 내보내기 구문 사용).

const config = __APP_CONFIG__;

export default config;

당신에 app.js당신은 지금 사용할 수 import config from './config';는 config 객체를 얻을 수 있습니다.


답변

또 다른 방법은 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"


답변

OP와 동일한 문제에 직면하고 라이센스 때문에 특정 빌드에 특정 코드를 포함하지 않도록 요구 했으며 다음과 같이 webpack-conditional-loader 를 채택했습니다 .

내 빌드 명령에서 내 빌드에 맞게 환경 변수를 설정했습니다. 예를 들어 package.json의 ‘demo’:

...
  "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};

이를 통해 조건부로 모든 것을 제외하여 관련 코드가 결과 자바 스크립트에서 적절하게 제거되도록 할 수 있습니다. 예를 들어, 내 routes.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에서 작동합니다.


답변

내 webpack 구성에서 env를 설정하는 데 어려움을 겪었습니다. 내가 일반적으로 원하는 것은 내부에 도달 할 수 있도록 설정 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 });
};