# 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指令來初始化設定

## 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設定檔案
### 打包圖片資源

```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'
}
```
### 打包其他資源

```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

```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優化設定
* 開發環境性能優化
* 優化打包建構速度
* 優化程式碼調適
* 生產環境性能優化
* 優化打包建構速度
* 優化程式碼執行的性能