목표
webpack4에서 splitChunks을 사용해서 중복된 모듈을 없애보자
초기설정 + webpack install
moment,lodash npm 인스톨
후술할 app/index.js안에서 사용되는 외부 패키지를 설치
npm install moment lodash --save
lodash
유틸리티 라이브러리로 array, collection, date, number, object 등이 있으며, 데이터를 쉽게 다룰 수 있도록 도와준다
moment
날짜관련 작업을 위한 자바스크립트 라이브러리
테스트용 설정파일
1. index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Libraries Code Splitting</title>
  </head>
  <body>
    <header>
      <h3>Libraries Code Splitting</h3>
    </header>
    <div>
      <label for="p1"><strong>Moment JS : </strong></label>
      <p class="p1">
        not yet loaded
      </p>
      <label for="p2"><strong>Lodash JS : </strong></label>
      <p class="p2">
        not yet loaded
      </p>
    </div>
    <script src="dist/vendor.js"></script>
    <script src="dist/main.js"></script>
  </body>
</html>
2. app/index.js
index.html의not yet loaded로 되어있는 부분안에 moment,loadash를 이용한 리턴값을 넣어주는 코드다.
var moment = require("moment");
var _ = require("lodash");
var ele = document.querySelectorAll("p");
document.addEventListener("DOMContentLoaded", function(event) {
  ele[0].innerText = moment().format();
  ele[1].innerText = _.drop([1, 2, 3], 0);
});
3. webpack.config.js
var webpack = require("webpack");
var path = require("path");
module.exports = {
  entry: {
    main: "./app/index.js",
    vendor: ["moment", "lodash"]
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  }
};
entry에 app/index.js 이외에 monet,lodash라는 외부패키지를 vendor.js라는 이름으로 번들링하는 예제이다.
moment,lodash 이 부분은 npm install 해서 node_modules에 해당 패키지가 존재하지 않으면 추가가 불가능
webpack실행(splitChunks 사용하기전)
npx webpack
result
Hash: 8cf75a53511be7a1ec91
Version: webpack 4.29.6
Time: 505ms
Built at: 2019-04-11 15:34:38
    Asset      Size  Chunks             Chunk Names
  main.js  1.12 MiB    main  [emitted]  main
vendor.js  1.12 MiB  vendor  [emitted]  vendor
Entrypoint main = main.js
Entrypoint vendor = vendor.js
[0] multi moment lodash 40 bytes {vendor} [built]
[./app/index.js] 253 bytes {main} [built]
[./node_modules/moment/locale sync recursive ^\.\/.*$] ./node_modules/moment/locale sync ^\.\/.*$ 3 KiB {main} {vendor} [optional] [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} {vendor} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} {vendor} [built]
    + 129 hidden modules
정상적으로 실행되면 dist/ 밑에 main.js 와 vendor.js가 생성되어 있을것이다
여기까지 문제점
dist/ 밑에 main.js 와 vendor.js안에 각각 완벽하게 똑같은 lodash,moment 코드가 중복해서 들어가 있다.
이 부분을 효율적으로 관리해주기 위해 splitChunks 를 사용해 중복되는 부분을 공통영역으로 만들어 줄 수 있다.
이하와 같이 webpack.config.js 변경
optimization 부분을 추가
var path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./app/index.js",
    vendor: ["moment", "lodash"]
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  optimization: {
    splitChunks: {
      name: "vendor",
      chunks: "initial"
    }
  }
};
webpack실행(splitChunks 사용후)
npx webpack
result
Hash: b6b89be7ea558d5f36b5
Version: webpack 4.29.6
Time: 507ms
Built at: 2019-04-11 16:13:28
    Asset      Size  Chunks             Chunk Names
  main.js  21.8 KiB    main  [emitted]  main
vendor.js  1.12 MiB  vendor  [emitted]  vendor
Entrypoint main = vendor.js main.js
[0] multi moment lodash 40 bytes {vendor} [built]
[./app/index.js] 253 bytes {main} [built]
[./node_modules/moment/locale sync recursive ^\.\/.*$] ./node_modules/moment/locale sync ^\.\/.*$ 3 KiB {main} {vendor} [optional] [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {vendor} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {vendor} [built]
    + 129 hidden modules
실행결과만 봐도 splitChunks 사용전에는 main.js가 1.12MiB였는데 21.8KiB로 줄어들은걸 알 수 있다. dist/vendor.js에만 lodash,moment관련 패키지가 있고 dist/main.js에는 존재하지 않는다.
하나더..runtimeChunk나눠주기
웹펙을 초기화할때 사용하는 부분(webpackBootstrap)도 runtimeChunk라는 옵션으로 따로 빼낼 수 있다.
설정을 이하와 같이 변경
var path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./app/index.js",
    vendor: ["moment", "lodash"]
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  optimization: {
    runtimeChunk: {
      //추가 부분
      name: "runtime"
    },
    splitChunks: {
      name: "vendor",
      chunks: "initial"
    }
  }
};
webpack실행(runtimeChunk 적용후)
npx webpack
result
Hash: 6fb2c91d04c5f9bd3863
Version: webpack 4.29.6
Time: 503ms
Built at: 2019-04-11 16:43:18
     Asset      Size   Chunks             Chunk Names
   main.js  15.7 KiB     main  [emitted]  main
runtime.js  6.04 KiB  runtime  [emitted]  runtime
 vendor.js  1.12 MiB   vendor  [emitted]  vendor
Entrypoint main = runtime.js vendor.js main.js
[0] multi moment lodash 40 bytes {vendor} [built]
[./app/index.js] 253 bytes {main} [built]
[./node_modules/moment/locale sync recursive ^\.\/.*$] ./node_modules/moment/locale sync ^\.\/.*$ 3 KiB {main} {vendor} [optional] [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {vendor} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {vendor} [built]
    + 129 hidden modules
runtime.js라는게 추가된걸 확인
etc
1. CommonsChunkPlugin is dead.
webpack 4 이전에는
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor" // Specify the common bundle's name.
  })
];
이런식으로 추가해줬었는데 webpack4부터 CommonsChunkPlugin가 사라져서 위와 같은 방법으로 적어주면 이하와 같은 에러가 발생한다
webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.
The CommonsChunkPlugin has been removed in v4. You better open a new issue, this thread is dead. Read this and tell me if it solves your problem. Link —
2. 당연한 얘기지만 npm install하지않으면 entry에 패키지 추가 안됨
lodash를 일부로 uninstall하고 webpack실행하면 이하와 같은 에러가 발생하게됨
ERROR in multi moment lodash
Module not found: Error: Can't resolve 'lodash' in '/Users/sehwakim/docker/LearnWebpack/example2-1-CommonsChunkPlugin'
 @ multi moment lodash vendor[1]
 runtimeChunk: {
            name: 'vendor'
        },