Production

이 가이드에서 프로덕션 사이트나 애플리케이션을 구축하기 위한 유틸리티와 좋은 사례들에 대해서 자세히 알아보겠습니다.

Setup

development와 production의 빌드 목표는 매우 다릅니다. development 에서는 강력한 소스 매핑, localhost 서버에서는 라이브 리로딩이나 hot module replacement 기능을 원합니다. production에서의 목표는 로드 시간을 줄이기 위해 번들 최소화, 가벼운 소스맵 및 애셋 최적화에 초점을 맞추는 것으로 변경됩니다. 논리적으로 분리를 해야 하면 일반적으로 환경마다 webpack 설정을 분리하여 작성하는 것이 좋습니다.

production과 development에 관련된 부분을 분리하더라도, 중복을 제거하기 위해 "공통"의 설정은 계속 유지해야 합니다. 이러한 설정을 합치기 위해 webpack-merge 유틸리티를 사용합니다. "공통"의 설정을 사용하면 환경별 설정에서 코드를 복사하지 않아도 됩니다.

webpack-merge를 설치하고 이전 가이드에서 이미 작업 한 부분을 분리하겠습니다.

npm install --save-dev webpack-merge

project

  webpack-demo
  |- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
  |- /dist
  |- /src
    |- index.js
    |- math.js
  |- /node_modules

webpack.common.js

+ const path = require('path');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+ module.exports = {
+   entry: {
+     app: './src/index.js',
+   },
+   plugins: [
+     new HtmlWebpackPlugin({
+       title: 'Production',
+     }),
+   ],
+   output: {
+     filename: '[name].bundle.js',
+     path: path.resolve(__dirname, 'dist'),
+     clean: true,
+   },
+ };

webpack.dev.js

+ const { merge } = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+   mode: 'development',
+   devtool: 'inline-source-map',
+   devServer: {
+     contentBase: './dist',
+   },
+ });

webpack.prod.js

+ const { merge } = require('webpack-merge');
+ const common = require('./webpack.common.js');
+
+ module.exports = merge(common, {
+   mode: 'production',
+ });

webpack.common.js에서 entryoutput을 설정했으며, 두 환경에서 필요한 플러그인들을 포함했습니다. webpack.dev.js에서 modedevelopment으로 설정했습니다. 또한, 해당 환경에 권장(강력한 소스 매핑)되는 devtool과 간단한 devServer 설정을 추가했습니다. 마지막으로 webpack.prod.jsmodeTree shaking 가이드에서 처음 언급했던 TerserPlugin을 로드하기 위해 production으로 설정 합니다.

환경별 설정에서 merge()를 사용하여 호출하면 webpack.dev.jswebpack.prod.js에 공통 설정을 포함합니다. webpack-merge 툴은 병합을 위한 다양한 고급 기능을 제공하지만, 지금 사례에서는 이런 기능이 필요하지 않습니다.

NPM Scripts

지금부터 새로운 설정 파일을 사용하기 위해 npm 스크립트를 수정해 보겠습니다. webpack-dev-server를 실행하는 start 스크립트의 경우 webpack.dev.js를 사용하고, 프로덕션 빌드를 만들기 위해 webpack을 실행하는 build 스크립트의 경우 webpack.prod.js를 사용합니다.

package.json

  {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "src/index.js",
    "scripts": {
-     "start": "webpack serve --open",
+     "start": "webpack serve --open --config webpack.dev.js",
-     "build": "webpack"
+     "build": "webpack --config webpack.prod.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "css-loader": "^0.28.4",
      "csv-loader": "^2.1.1",
      "express": "^4.15.3",
      "file-loader": "^0.11.2",
      "html-webpack-plugin": "^2.29.0",
      "style-loader": "^0.18.2",
      "webpack": "^4.30.0",
      "webpack-dev-middleware": "^1.12.0",
      "webpack-dev-server": "^2.9.1",
      "webpack-merge": "^4.1.0",
      "xml-loader": "^1.2.1"
    }
  }

production 설정을 계속 추가하는대로 출력이 어떻게 변경되는지 위 스크립트를 자유롭게 실행하여 확인해보세요.

Specify the Mode

많은 라이브러리는 process.env.NODE_ENV 변수를 이용하여 어떤 라이브러리를 포함해야 하는지 결정합니다. 예를 들어 process.env.NODE_ENV'production'으로 설정되지 않으면 몇몇 라이브러리는 디버깅의 편의성을 위해 로그 및 테스트를 추가할 수도 있습니다. 그러나 process.env.NODE_ENV'production'으로 설정되어 있으면 실제 사용자의 작업 실행 방식을 최적화 하기 위해 코드의 중요한 부분을 추가하거나 삭제 할 수 있습니다. webpack v4부터 mode를 지정하면 DefinePlugin이 자동으로 설정됩니다.

webpack.prod.js

  const { merge } = require('webpack-merge');
  const common = require('./webpack.common.js');

  module.exports = merge(common, {
    mode: 'production',
  });

react와 같은 라이브러리를 사용한다면 DefinePlugin을 추가한 후에 명확하게 번들 크기가 줄어야 합니다. 또한 로컬 /src의 코드 역시 제어 할 수 있습니다. 따라서 다음 검사는 유효합니다.

src/index.js

  import { cube } from './math.js';
+
+ if (process.env.NODE_ENV !== 'production') {
+   console.log('Looks like we are in development mode!');
+ }

  function component() {
    const element = document.createElement('pre');

    element.innerHTML = [
      'Hello webpack!',
      '5 cubed is equal to ' + cube(5)
    ].join('\n\n');

    return element;
  }

  document.body.appendChild(component());

Minification

webpack v4+의 production mode에서는 기본으로 코드를 최소화합니다.

TerserPlugin은 최소화를 시작하고 기본으로 사용하기에 좋지만 다른 옵션도 있습니다.

만약 다른 최소화 플러그인을 사용하기로 결정했다면, 다른 플러그인이 Tree shaking 가이드에 설명 된 대로 사용하지 않는 코드를 제거하고 optimization.minimizer를 제공하는지 확인해야 합니다.

Source Mapping

소스맵은 디버깅뿐만 아니라 벤치마크 테스트에도 유용하므로 프로덕션에도 활성화하는 것이 좋습니다. 즉, 프로덕션용으로 추천되는 빌드 속도가 가장 빠른 것을 선택해야 합니다. (devtool 참조) 이 가이드에서는 development에서 사용한 inline-source-map이 아닌 production의 source-map을 사용합니다.

webpack.prod.js

  const { merge } = require('webpack-merge');
  const common = require('./webpack.common.js');

  module.exports = merge(common, {
    mode: 'production',
+   devtool: 'source-map',
  });

Minimize CSS

프로덕션을 위해 CSS를 최소화하는 것이 중요합니다. Minimizing for Production을 참고하세요.

CLI Alternatives

위에서 설명한 대부분의 옵션은 커맨드 라인 인자로 설정할 수 있습니다. 예를 들어 optimization.minimize은 --optimization-minimize, 그리고 mode는 --mode로 설정할 수 있습니다. CLI 인자의 전체 목록을 보려면 npx webpack --help=verbose를 실행하세요.

이런 간단한 방식은 편리하지만, 좀 더 알맞은 설정을 위해 webpack 설정 파일에서 이런 옵션을 설정하는 것이 좋습니다.


Translators