---
# System prepended metadata

title: Webpack Basic
tags: [JavaScript, Tools]

---

# Webpack Basic
###### tags: `Tools` `JavaScript`

## 1. Webpack入門
### 簡介
* webpack是一個前端資源建構工具。
* 一个靜態模組打包器(modulebundler)。
* 在webpack中,前端的所有資源(js/json/css/img/less/...)都會作為模組處理。
* 根據依賴關係生成的樹狀結構將相關依賴導入，形成塊(chunk)，再根據塊來打包轉換生成對應的靜態資源(bundle)給瀏覽器解析。

### 5個核心概念
#### Entry
入口(Entry)指示webpack以哪個檔案為入口作為起點開始打包，分析構建内部依賴圖。
#### Output
輸出(Output)指示webpack打包後的資源bundles輸出到哪裡去，以及如何命名。
#### Loader
Loader讓webpack能夠去處理那些非JavaScript文件(webpack自身只理解JavaScript)
#### Plugins
插件(Plugins)可以用於執行範圍更廣的任務。插件的範圍包括，從打包優化和壓缩，一直到重新定義環境中的變數等。
#### Mode
模式(Mode)指定webpack使用對應模式的設定。


| 選項 | 描述 | 特點 |
| -------- | -------- | -------- |
| development     | 會將DefinePlugin中process.env.NODE_ENV的值設定為development。啟用NamedChunksPlugin和NamedModulesPlugin。     | 能讓程式碼本機調適運行的環境     |
| production     | 會將DefinePlugin中process.env.NODE_ENV的值設定為production。啟用FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin,SideEffectsFlagPlugin和TerserPlugin。     | 能讓程式碼優化上線運行的環境     |

## 2.webpack的初體驗
### 初始化設定
* 初始化package.json：npm init
* 下載並安裝webpack：
    * npm install webpack webpack-cli-D

### 編譯打包應用
必須先透過npm init指令來初始化設定

![](https://i.imgur.com/95kne7C.png)

## 3.webpack開發環境的基本設定
### 打包樣式資源
1. 建立檔案webpack.config.js
```javascript=
/*
    webpack.config.js是webpack的設定檔案
        作用：指示webpack幹那些活(當你運行webpack指令時，會加載裡面的設定)

        所有建構工具都是基於nodejs平台運行的~模組化預設採用commonjs

*/

//用來拼接絕對路徑的方法
const {resolve} = require('path')

module.exports = {
    //webpack設定
    //入口起點
    entry: './src/index.js',
    //輸出
    output:{
        //輸出文件名
        filename: 'built.js',
        //輸出路徑
        //__dirname是nodejs的變數，代表當前文件的目錄絕對路徑
        path: resolve(__dirname, 'build')
    },
    //loader的設定
    module:{
        rules:[
            //詳細loader設定
            //不同文件必須配置不同loader處理
            {
                //匹配那些檔案
                test: /\.css$/,
                //使用哪些loader進行處理
                use:[
                    //use陣列中loader執行順序：從右到左，從上到下依次執行
                    //創建style標籤，將js中的樣式資源插入進行，添加到head中生效
                    'style-loader',
                    //將css檔案變成commonjs模組加載js中，裡面內容是樣式字串
                    'css-loader'
                ]
            },
            {
                test:/\.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            }
        ]
    },
    //plugins的設定
    // Plugins:[
    //     //詳細plugins的設定
    // ],
    //模式
    mode:'development'
}
```

2. 安裝各種loader包：
    * npm i css-loader style-loader less-loader less -D

3. 指令：webpack

### 打包HTML資源

1. 安裝plugin包：
npm install html-webpack-plugin -D

2. 建立webpack設定檔案![](https://i.imgur.com/kTEWMcV.png)

### 打包圖片資源

![](https://i.imgur.com/yxHjE8b.png)


```javascript=
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: './src/index.js',
    output:{
        filename: 'built.js',
        path : resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test: /\.less$/,
                //要使用多個loader處理用use
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                //問題：預設處理不了html中的img圖片
                //處理圖片資源
                test: /\.(jpg|png|gif)$/,
                //使用一個loader
                //下載 url-loader file-loader
                loader: 'url-loader',
                options:{
                    //圖片大小小於8kb，就會被base64處理
                    //優點：減少請求數量(減輕伺服器壓力)
                    //缺點：圖片大小會更大(檔案請求速度更慢)
                    limit: 8 * 1024,
                    //問題：因為url-loader預設使用es6模組化解析，而html-loader導入圖片是commonjs
                    //解析時會出問題： [object Module]
                    //解決：關閉url-loader的es6模組化，使用commonjs解析
                    esModule: false,
                    //給圖片進行重新命名
                    //[hash:10]取圖片的hash的前10位
                    //[ext]取檔案原來的副檔名
                    name: '[hash:10].[ext]'
                }
            },
            {
                test: /\.html$/,
                //處理html檔案的img圖片(負責導入img，從而能被url-loader進行處理)
                loader: 'html-loader'
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ],
    mode: 'development'
}
```

### 打包其他資源

![](https://i.imgur.com/fUzmRlw.png)


```javascript=
const HtmlWebpackPlugin = require('html-webpack-plugin')
const{resolve} = require('path')

module.exports = {
    entry: './src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            //打包其他資源(除了html/js/css資源以外的資源)
            {
                //排除
                exclude:/\.(css|js|html)$/,
                loader:'file-loader'
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development'
}
```

### devServer
```javascript=
const HtmlWebpackPlugin = require('html-webpack-plugin')
const{resolve} = require('path')

module.exports = {
    entry: './src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            //打包其他資源(除了html/js/css資源以外的資源)
            {
                //排除
                exclude:/\.(css|js|html)$/,
                loader:'file-loader'
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development',


    //開發伺服器devServer：用來自動化(自動編譯，自動打開瀏覽器，自動重新整理)
    //特點：只會在記憶體中編譯打包，不會有任何輸出
    //啟動devServer指令為：npx webopack-dev-server
    devServer:{
        //項目構建後路徑
        contentBase:resolve(__dirname, 'build'),
        //啟動gzip壓縮
        compress:true,
        //port number
        port:3000,
        //自動打開瀏覽器
        open:true
    }
}
```

## 4.webpack生產環境的基本設定
### 提取css成單獨檔案
插件安裝：npm install mini-css-extract-plugin

![](https://i.imgur.com/fDIiBCP.png)

```javascript=
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const MiniCssExtractPlugin = require('mini-css-extract-plugin')


module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test: /\.css$/,
                use:[
                    //'style-loader',
                    //這個loader取代style-loader，作用：提取js中的css成單獨檔案
                    MiniCssExtractPlugin.loader,
                    //將css檔案整合到js檔案中
                    'css-loader'
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin({
            //對輸出的檔案改名
            filename: 'css/built.css'
        })
    ],
    mode: 'development'
}
```

### css兼容性處理

安裝loader：npm install postcss-loader postcss-preset-env

```javascript=
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

//設定nodejs環境變數
//process.env.NODE_ENV = 'development'

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test: /\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    /*
                        css兼容性處理：postcss --> postcss-loader postcss-preset-env

                        幫postcss找到package.json中browerslist裡面的設定，透過設定加載指定的css兼容性樣式

                          "browserslist":{
                                //開發環境 --> 設定node環境變數：process.env.NODE_ENV = development
                                "development":[
                                "last 1 chrome version",
                                "last 1 firefox version",
                                "last 1 safari version"
                                ],
                                //生產環境：預設是看生產環境
                                "production":[
                                ">0.2%",
                                "not dead",
                                "not op_mini all"
                                ]
                            }
                    */
                    //使用loader的預設設定
                    //'postcss-loader',
                    {
                        loader: 'postcss-loader',
                        options:{
                            ident:'postcss',
                            plugins:() => [
                                //postcss的插件
                                require('postcss-preset-env')()
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin({
            //對輸出的檔案改名
            filename: 'css/built.css'
        })
    ],
    mode: 'development'
}
```

### 壓縮css檔案

安裝插件：npm install optimize-css-assets-webpack-plugin

```javascript=
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

//設定nodejs環境變數
//process.env.NODE_ENV = 'development'

// optimize-css-assets-webpack-plugin

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test: /\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options:{
                            ident:'postcss',
                            plugins:() => [
                                //postcss的插件
                                require('postcss-preset-env')()
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin({
            //對輸出的檔案改名
            filename: 'css/built.css'
        }),
        //壓縮css
        new OptimizeCssAssetsWebpackPlugin()
    ],
    mode: 'development'
}
```

### js語法檢查eslint
下載安裝包：npm install eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import

```javascript=
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");


module.exports = {
    entry: './src/js/index.js',
    output:{
        filename:'js/built.js',
        path: resolve(__dirname,'build')
    },
    module:{
        rules:[
            /*
                語法檢查：eslint-loader eslint
                    注意：只檢查自己寫的原程式碼，第三方的lib是不用檢查的
                    設定檢查規則：
                        package.json中eslintConfig中設定~
                          "eslintConfig": {
                                "extends": "airbnb-base"
                            }

                        airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
            */
           {
            test:/\.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            options:{
                //自動修復eslint的錯誤
                fix: true
            }
           }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode: 'development'
}
```

### js兼容性處理

下載安裝包：npm install babel-loader @babel/core @babel/preset-env @babel/polyfill core-js

```javascript=
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");


module.exports = {
    entry: './src/js/index.js',
    output:{
        filename:'js/built.js',
        path: resolve(__dirname,'build')
    },
    module:{
        rules:[
            /*
                js兼容性處理：babel-loader @babel/preset-env
                    1.基本js兼容性處理 --> @babel/preset-env
                        問題：只能轉換基本語法，如promise高級語法不能轉換
                    2.全部js兼容性處理 --> @babel/polyfill
                        問題：我只要解決部分兼容性問題，但是將所有兼容性程式碼全都導入，體積太大了~
                    3.需要做兼容性處理的就做：按需加載 --> corejs

            */
           {
            test:/\.js$/,
            exclude: /node_modules/,
            loader:'babel-loader',
            options:{
                //預設：指定babel做怎麼樣的兼容性處理
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            //按需加載
                            useBuiltIns:'usage',
                            //指定core-js版本
                            corejs:{
                                version: 3
                            },
                            //指定兼容性做到哪個版本瀏覽器
                            targets:{
                                chrome: '60',
                                firefox: '60',
                                ie: '9',
                                safari: '10',
                                edge: '17'
                            }
                        }
                    ]
                ]
            }
           }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode: 'development'
}
```

### 壓縮html與js
js：
```javascript=
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");


module.exports = {
    entry: './src/js/index.js',
    output:{
        filename:'js/built.js',
        path: resolve(__dirname,'build')
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    //生產環境下會自動壓縮js程式碼
    mode: 'production'
}
```

html：
```htmlembedded=
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");


module.exports = {
    entry: './src/js/index.js',
    output:{
        filename:'js/built.js',
        path: resolve(__dirname,'build')
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html',
            //壓縮html程式碼
            minify:{
                //移除空格
                collapseWhitespace: true,
                //移除註釋
                removeComments: true
            }
        })
    ],
    mode: 'production'
}
```

## 5.webpack優化設定
* 開發環境性能優化
    * 優化打包建構速度
    * 優化程式碼調適
* 生產環境性能優化
    * 優化打包建構速度
    * 優化程式碼執行的性能