webpack 4 - 初探

What is Webpack ?

  • 前端程式碼模組化後的打包工具
    • 讓我們可將前端的JS, CSS模組化, 透過Webpack打包成一個(或多個)檔案後輸出

Quick Start

  • 首先在專案根目錄下建立 webpack.config.js
1
2
$ node install --save-dev webpack
$ webpack // 會在當前目錄尋找webpack.config.js這個設定檔去執行 .

Content in webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
module.exports = {
context: path.resolve(__dirname, "./src"),
entry: {
main: "./main.js",
module: "./module.js"
},
output: {
filename: [name].bundle.js
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};
  • context:
    • 要打包的檔案們所在的目錄
    • 當有設定這個Property時, 之後所有要打包的檔案只需使用’./[檔案+附檔名]’即可
  • entry:
    • 設定JS的程式進入點
    • Default為: ‘index.js’
      • 當為物件時
        • Key: 提供 output 的property參考, Value: 檔案Path
        • 可以有多個進入點, 各自包成一個file
  • output:
    • 設定打包完後檔案放的路徑, 以及名稱
      • 打包後檔案放的路徑
        • path: [欲放置的路徑]
        • default為 ./dist
      • 打包後檔案名稱
        • filename: [檔案的名稱]
        • 可以動態設定檔案名稱, 依據 entry 中的key值
          • e.g. filename: [name].bundle.js
  • module:
    • 設定所使用到的Loader
    • Loader
      • Pre processor of our code
        • 由於Webpack只看得懂 JS, 因此對於一些其他資源(e.g. html, css, image … etc.), 再進入webpack core之前需要做一些preprocessing
      • 一個物件, 主要有兩個屬性
        • test:
          • 以正規表達式說明目標副檔名
        • use:
          • 使用哪個Loader
          • style-loader: Transform CSS into modules
          • css-loader: Then add \<style> in DOM
          • 常用的loader
            • babel-loader
            • css-loader/style-loader
            • image-loader
          • value為一個陣列, 且有順序性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 先執行css-loader後, 才執行style-loader
...
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
...
  • plugins:
    • Post processor of our code
    • e.g.
      • Uglify … etc.

Some Tips

  • Vendor bundling
    • 使用情境
      • 當某一個module使用多次(被多個我們自己寫的file reference到)時, 我們希望只pack一份就好(而不是我們的每個file都pack一次這個module) .
      • 在watch mode下, 我們不需要一直去build我們用到的外部module(e.g. lodash), 我們只需重新build「我們自己寫」的部分
    • Vendor bundling
      • 將那些「我們多次使用」或是「完全不會再更動的外部module」獨立打包「一次」,之後就不會再更動它了
    • 優點
      • Speed up loading
      • Speed up bundling(在包第一次之後)
    • Usage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// In webpack.config.js
...
var webpack = require('webpack');
module.exports = {
entry: {
main: './main.js',
vendor: ['loadash',...] // 手動指定哪些pkg要包成vendor
},
...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js',
minChunks: 2 // 重複使用到幾次即判別成vendor
}),
...
]
}
  • Aliasing the path
    • 把路徑Alias成一個變數
    • 當資料夾結構改變時, 只要到config更改一次, 不用到每個用到該路徑source code更動
1
2
3
4
5
6
7
8
9
10
11
12
13
// in webpack.config.js
...
module.exports = {
...
resolve: {
alias: {
// 當webpack在src code中parse到'components'時, 自動化把它轉換成'[srcPath]/components'這個路徑
components: path.resolve(srcPath, 'components')
},
...
},
...
}
1
2
3
// in index.js
import ... from 'components/componentA.js';
...
  • webpack-dev-server
    • 一個webpack提供開發時使用的server
      • Live Reload
      • Hot Module Replacement(HMR)
      • 只重新load我們有修改的部分, 也就是不重新load「整個」頁面 .
    • Usage
1
$ npm install --save-dev webpack-dev-server
1
2
3
4
5
6
// in package.json
...
"scripts": {
"start": "webpack-dev-server --mode development --open",
}
...
  • Webpack 4 - Dev mode / production mode setting in CLI

    • 可以透過CLI指令來設定development mode或production mode
    • development mode

      • Usage

        1
        $ webpack --mode development
      • 可以搭配 webpack-dev-server 使用

      • Development mode on the other hand is optimized for speed and does nothing more than providing an un-minified bundle.
    • production mode

      • Usage

        1
        $ webpack --mode development
      • Production mode enables all sorts of optimizations out of the box. Including minification, scope hoisting, tree-shaking and more.

  • HTML / CSS with webpack

Sample set up for webpack

1
2
3
4
$ npm install --save-dev webpack webpack-cli webpack-dev-server
$ npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
$ npm install --save-dev css-loader mini-css-extract-plugin
$ npm install --save-dev html-loader html-webpack-plugin
1
2
3
4
5
6
7
\\ in package.json
...
"scripts": {
"start": "webpack-dev-server --mode development --open",
"build": "rm -r ./dist && webpack --mode production"
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');

module.exports = {
context: path.resolve(__dirname,'./src'),
entry: {
main: './main.js',
},
output: {
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /(\.js || \.jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};

參考文獻