---
description: >-
  https://viblo.asia/p/webpack-series-ep3-code-splitting-chia-code-trong-webpack-yMnKMyRzK7P
---

# \[WEBPACK] Webpack series (ep3) - code splitting - chia code trong webpack (ok)

## Ví dụ 1: khi chưa sử dụng splitChunks

C:\Users\Administrator\Desktop\demo\package.json

```
{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "html-webpack-plugin": "^4.5.0",
    "lodash": "^4.17.20",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12"
  }
}

```

C:\Users\Administrator\Desktop\demo\webpack.config.js

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ]
};
```

C:\Users\Administrator\Desktop\demo\src\index.js

```
import _ from 'lodash';
console.log(
  _.join(['Index', 'module', 'loaded!'], ' ')
);
```

C:\Users\Administrator\Desktop\demo\src\lib.js

```
import _ from 'lodash';
console.log(
  _.join(['Lib', 'module', 'loaded!'], ' ')
);
```

Kết quả sau khi sinh ra

C:\Users\Administrator\Desktop\demo\dist\index.html

```
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Code Splitting</title>
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <script src="index.bundle.js"></script>
  <script src="lib.bundle.js"></script>
</body>
</html>
```

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbO04PSazK0zsYexU8%2F-MIbTsuDRjN7NHDS3kjk%2FScreenshot_1.png?alt=media\&token=56b60c69-188c-46b0-abd3-0a5edf863175)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbO04PSazK0zsYexU8%2F-MIbTvROEXACxpiwsntk%2FScreenshot_2.png?alt=media\&token=c840e226-ea01-4938-a95e-74cc49643c2e)

## Ví dụ 2: khi đã sử dụng splitChunks

C:\Users\Administrator\Desktop\demo\webpack.config.js

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js',
    another: './src/another.js',
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ],
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

C:\Users\Administrator\Desktop\demo\package.json

```
{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "html-webpack-plugin": "^4.5.0",
    "lodash": "^4.17.20",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12"
  }
}

```

C:\Users\Administrator\Desktop\demo\src\index.js

```
import _ from 'lodash';
console.log(
  _.join(['Index', 'module', 'loaded!'], ' ')
);
```

C:\Users\Administrator\Desktop\demo\src\lib.js

```
import _ from 'lodash';
console.log(
  _.join(['Lib', 'module', 'loaded!'], ' ')
);
```

C:\Users\Administrator\Desktop\demo\src\another.js

```
import _ from 'lodash';
console.log(
  _.join(['Another', 'module', 'loaded!'], ' ')
);
```

Kết quả :)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbVyAakfqnGtqWXW6i%2F-MIbXyRwVQwsZgxjWT81%2FScreenshot_4.png?alt=media\&token=2bd87d89-dd14-4c8e-a624-036ae8a20940)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbVyAakfqnGtqWXW6i%2F-MIbY-zX690fNTsP9EOn%2FScreenshot_5.png?alt=media\&token=603799ed-71f2-41d0-aee9-c75c5e536120)

Xem thêm khi tạo file another như sau :)

C:\Users\Administrator\Desktop\demo\src\another.js

```
import * as $ from 'jquery';
$('body').append($('<span>').text('from another'));
```

C:\Users\Administrator\Desktop\demo\src\lib.js

```
import _ from 'lodash';
console.log(
  _.join(['Lib', 'module', 'loaded!'], ' ')
);
```

C:\Users\Administrator\Desktop\demo\src\index.js

```
import _ from 'lodash';
import * as $ from 'jquery';
console.log(
  _.join(['Index', 'module', 'loaded!'], ' ')
);
$('body').append($('<span>').text('from index'));
```

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbY1QaGeKtRMYReSWX%2F-MIb_24Uqx5mHYYhOByy%2FScreenshot_6.png?alt=media\&token=d827d1ed-9757-4a24-aa8f-6495af826ef8)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbY1QaGeKtRMYReSWX%2F-MIb_4n4c1oSO6TL27E7%2FScreenshot_7.png?alt=media\&token=ddb1f12d-9497-4bbe-8865-2e19341b5395)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbY1QaGeKtRMYReSWX%2F-MIb_77omrnsDzIpksZd%2FScreenshot_8.png?alt=media\&token=a1a28528-b4b4-47d1-bed2-c75fed855543)

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIbY1QaGeKtRMYReSWX%2F-MIb_9FrCyZX68JfUenI%2FScreenshot_9.png?alt=media\&token=f9aa4d06-9e72-44a6-b7f9-729020281440)

Nếu sử dụng C:\Users\Administrator\Desktop\demo\webpack.config.js

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js',
    another: './src/another.js',
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ],
  optimization: {
    splitChunks: {
      name: 'common',
      chunks: 'all'
    }
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

![](https://2726517656-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M1E4Gk2ppVKb4olmnun%2F-MIb_AhAiBybJDZ-Gu-e%2F-MIbb9D8NaZ_pG7-J11E%2FScreenshot_10.png?alt=media\&token=fbe137f2-62b7-4cb7-96df-4fb8e14ff024)

## Webpack series (ep3) - code splitting - chia code trong webpack

[Webpack](https://viblo.asia/tags/webpack)[JavaScript](https://viblo.asia/tags/javascript)

## Code splitting là gì? <a href="#code-splitting-la-gi-0" id="code-splitting-la-gi-0"></a>

**Code splitting** có thể là một trong những feature thuyết phục nhất của Webpack, nó cho phép chúng ta chia nhỏ code ra nhiều bundle nhỏ hơn, những cái mà chúng ta có thể tải khi cần hoặc để tải song song. Nó thường được sử dụng để tạo ra những bundle code nhỏ hơn cũng như quản lý vấn đề ưu tiên tải tài nguyên, caí nào tải trước, cái nào tải sau, cái nào tải sau cái nào. Nếu sử dụng đúng cách nó có thể tác động lớn đến tốc độ và thời gian tải.

Có 3 cách tiếp cận để split code hiện tại:

* **Entry point**: Phân chia thủ công bằng cách cấu hình file `entry`, file để bắt đầu chạy ứng dụng và từ đó webpack hoạt động
* **Prevent duplication** (ở webpack 4.0 là `splitChunks`): Sử dụng `CommonsChunkPlugin` để xóa những bundle trùng lắp và split ra các `chunks`, hiểu nôm na plugin này sẽ giúp loại bỏ việc split ra 2 hoặc nhiều hơn các bundle khác nhau.
* **Dynamic Imports**: Chia code thông qua các function được gọi trong các modules.

### Entry point <a href="#entry-point-1" id="entry-point-1"></a>

Đây là cách đơn giản nhất, trực quan về cách phân chia code. Chúng ta chỉ cần chỉ rõ ra các entries và webpack sẽ dựa vào đó và tạo ra các bundle tương ứng. Mặc dù vậy cách này khá thủ công và cũng tiềm ẩn những rủi ro không hay mà chúng sẽ gặp phải, giờ chúng ta thử cài đặt nào.

Giả sử máy chúng ta chưa hề cái webpack từ trước nhé.

```
    mkdir wp-demo
    cd wp-demo
    npm init -y
    npm install webpack -g
    npm i webpack-cli -g
    npm i lodash
    npm i html-webpack-plugin
```

> `npm i` là short command của `npm install` `-g` là install global

**Project**

```
wp-demo
    |- package.json
    |- webpack.config.js
    |- /dist
    |- /src
        |- index.js
        |- lib.js
    |- /node_modules
```

Chúng ta sẽ implement _**index.js**_ và _**lib.js**_ đều sử dụng hàm của **lodash**

**index.js**

```
import _ from 'lodash';

console.log(
  _.join(['Index', 'module', 'loaded!'], ' ')
);
```

**lib.js**

```
import _ from 'lodash';

console.log(
  _.join(['Lib', 'module', 'loaded!'], ' ')
);
```

**webpack.config.js**

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js'
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

Run `webpack -d`

```
Hash: 4f059d29eff6ead625f4
Version: webpack 4.4.1
Time: 905ms
Built at: 2018-4-4 01:01:03
          Asset       Size  Chunks             Chunk Names
  index.bundle.js   1.36 MiB   index  [emitted]  index
  lib.bundle.js   1.36 MiB     lib  [emitted]  lib
     index.html  251 bytes          [emitted]
```

Như đã nói ở trên cách này có những tiềm ẩn rủi ro là:

* `index.bundle.js` và `lib.bundle.js` đều sử dụng thư viện `lodash` và vì do nó là hai `entry` riêng biệt nên bọn nó không liên quan cũng như không biết thằng còn lại làm gì và cần gì? Nên ai cần cái gì thì import cái đó "chuyện anh anh làm chuyện tui tui làm" do đó 2 bundle đều import thư viện lodash, và đương nhiên cách này là không hề tốt chút nào nếu chúng ta không cẩn thận...
* Nên nếu muốn làm manual như cách này, tốt nhất chỉ nên có một entry nhận import và các entry khác chỉ import từ entry lib này. Ví dụ `lib.js` sẽ export `lodash` và `index.js` sẽ import cái này để xài, nhưng như vậy là không hay tẹo nào, nói chung khá là không thoải mái vì "ta thích gì ở đâu thì ta import vào xài không cần phải phụ thuộc thằng nào đã export expiet gì chưa?".
* Cách này manual nên đương nhiên nó sẽ không linh hoạt để phân chia code một cách tự động.

Và để giải quyết vấn đề của **entry point** chúng ta sẽ áp dụng **Prevent duplication** bằng cách dùng **CommonsChunkPlugin** [https://webpack.js.org/plugins/commons-chunk-plugin/](https://webpack.js.org/plugins/commons-chunk-plugin/)

### Prevent Duplication <a href="#prevent-duplication-2" id="prevent-duplication-2"></a>

`CommonChunkPlugin` cho phép chúng ta extract ra những hàm, thư viện,... chung vào một entry nào đó hoặc đưa ra 1 chunk mới nào đó. Sử dụng nó để hủy sự trùng lắp trong việc sử dụng thư viện `lodash`.

Thêm `CommonChunkPlugin` vào phần `plugins`. **webpack.config.js**

```
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js'
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'common'
    })
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

Run thử nào `webpack -d`

Với `CommonsChunkPlugin` chúng ta thấy sự trùng lặp trong việc gọi thư viện `lodash` trong `index.js` và `lib.js` đã được giải quyết bằng việc tạo ra một bundle mới gọi là `common`, và hai enties của chúng ta đã gọi thư viện `lodash` **trực tiếp** từ module `common` này.

```
Hash: 70a59f8d46ff12575481
Version: webpack 2.6.1
Time: 510ms
            Asset       Size  Chunks                    Chunk Names
  index.bundle.js  665 bytes       0  [emitted]         index
  lib.bundle.js  537 bytes       1  [emitted]         lib
  common.bundle.js     547 kB       2  [emitted]  [big]  common
```

> **Chú ý**: từ `webpack version 4` thì webpack đã remove plugin `CommonsChunkPlugin` thay vào đó là `optimization.splitChunks`, nếu bạn nào bắt đầu sử dụng `Webpack` ngay thời điểm (version 4) này thì follow theo cách này. Theo như tài liệu của webpack thì `optimization.splitChunks` có nhiều điểm cải tiến hơn `CommonsChunkPlugin` là:

1. Ít sinh ra code hơn
2. Cache tốt hơn
3. Chia nhỏ common chunk hơn => download ít và nhẹ hơn

Bấy giờ chúng ta thêm một file mới là `another.js`, sau đó cài đặt `jquery` và sử dụng nó trong cả `index.js` và `another.js`

```
npm i jquery -D
touch src/another.js
```

**another.js**

```
import * as $ from 'jquery';

$('body')
    .append($('<span>').text('from another'));
```

**index.js**

```
import _ from 'lodash';
import * as $ from 'jquery';

console.log(
  _.join(['Index', 'module', 'loaded!'], ' ')
);

$('body')
    .append($('<span>').text('from index'));
```

Update lại **webpack.config.js**

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        index: './src/index.js',
        lib: './src/lib.js',
        another: './src/another.js',
    },
    plugins: [
        new HTMLWebpackPlugin({
            title: 'Code Splitting'
        })
    ],
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
};
```

Run `webpack -p`

```
Hash: e87b2ac1bbf030a2de33
Version: webpack 4.4.1
Time: 7157ms
Built at: 2018-4-4 15:02:42
                          Asset       Size  Chunks             Chunk Names
vendors~another~index.bundle.js   85.2 KiB       0  [emitted]  vendors~another~index
    vendors~index~lib.bundle.js   69.3 KiB       1  [emitted]  vendors~index~lib
              another.bundle.js   1.15 KiB       2  [emitted]  another
                  lib.bundle.js   1.16 KiB       3  [emitted]  lib
                index.bundle.js   1.22 KiB       4  [emitted]  index
                     index.html  467 bytes          [emitted]
```

Chúng ta thấy các nó chia nhỏ các common chunk ra:

1. `vendors~another~index.bundle.js`: `index.js` và `another.js` sẽ dùng chung, nó chứa source của `jquery`
2. `vendors~index~lib.bundle.js`: `index.js` và `lib.js` dùng chung, chứa source của `lodash`

Rõ ràng ở mức này việc chia nhỏ code của dự án chúng ta như thế này tưởng đối có thể sử dụng được, nhưng với những dự án lớn hơn, phức tạp hơn cũng như cần sự linh động của việc chia code hơn chúng ta sẽ đi tới phần cuối cùng.

### Dynamic Imports <a href="#dynamic-imports-3" id="dynamic-imports-3"></a>

Theo như spec của `webpack` thì họ support hai kỹ thuật tương tự nhau để chia code tự động là:

1. `import()` syntax dựa theo [ECMAScript proposal](https://github.com/tc39/proposal-dynamic-import) (hàng ngoại nhập theo xu hướng thị trường) - support từ ver [2.xxx](http://2.xxx/) (xxx ko nhớ)
2. `require.ensure` systax của webpack định nghĩa ra (hàng nội) - support từ ver1

#### sử dụng `import()` <a href="#su-dung-import-4" id="su-dung-import-4"></a>

Cập nhât lại các files

**another.js**

```
import _ from 'lodash';
export const join = function(arr) {
  return _.join(arr, ' ');
}
```

**index.js**

```
import $ from 'jquery';
$('body').append($('<button>')
  .text('Get lodash function')
  .on('click', () => {
    import('./another.js').then(another => {
      const str = another.join(['Used', 'lodash', 'join!']);
      $('body').append($('span').text(str));
    });
  })
);
$('body').append($('<span>').text('jquery from index'));
```

Chúng ta sẽ dùng jquery tạo một button và sau khi click button đó, thì sẽ tải module `another.js` và kèm đó là `lodash`, sau đó sử dụng hàm `join` của `lodash` và execute

State của việc này sẽ là như thế này:

1. load `index.js` và vendor của nó là `vendor~index.js`
2. người dùng click button
3. load `another.bundle.js` và `vendors~another.bundle.js` chứa source của `lodash` và sử dụng hàm `join`, sau đó tạo ra 1 thẻ `<span>` và append vào body.

**webpack.config.js**

```
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    index: './src/index.js',
    lib: './src/lib.js',
    another: './src/another.js',
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ],
  optimization: {
    splitChunks: {
      name: 'common',
      chunks: 'all'
    }
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

Run `webpack -p`

```
Version: webpack 4.4.1
Time: 933ms
Built at: 2018-4-4 17:54:13
                    Asset       Size  Chunks             Chunk Names
vendors~another.bundle.js   69.3 KiB       0  [emitted]  vendors~another
        another.bundle.js  198 bytes       1  [emitted]  another
  vendors~index.bundle.js   85.2 KiB       2  [emitted]  vendors~index
          index.bundle.js   2.14 KiB       3  [emitted]  index
               index.html  261 bytes          [emitted]
```

Các bạn có thể vào `dist/index.html` để chạy thử

![Trước khi click button](https://i.imgur.com/9fbW946.png) ![Sau khi click button](https://i.imgur.com/WfkywdG.png) ![Browser hiển thị](https://i.imgur.com/LJD5rf2.png)

Bài viết gốc: [https://www.jinhduong.com/2018/04/03/webpack-series-code-splitting/](https://www.jinhduong.com/2018/04/03/webpack-series-code-splitting/)

Phần 1: [https://www.jinhduong.com/2017/04/20/2017-04-20-webpack-co-ban/](https://www.jinhduong.com/2017/04/20/2017-04-20-webpack-co-ban/)

Phần 2: [https://www.jinhduong.com/2017/04/21/2017-04-21-webpack-co-ban-2/](https://www.jinhduong.com/2017/04/21/2017-04-21-webpack-co-ban-2/)

Thanks for watching !
