核心概念
webpack是一個應用程式的靜態模組打包工具,當webpack處理應用程式時,它會在內部構建一個依賴圖:
任何時候,一個檔案依賴於另一個檔案,webpack 就把此視為檔案之間有 依賴關係。這使得 webpack 可以接收非程式碼資源(non-code asset)(例如 images 或 web fonts),並且可以把它們作為 依賴 提供給你的應用程式。
此依賴圖會對映專案所需的每一個模組,並生成一個或多個bundle。
特點
- 程式碼轉換: TypeScript 編譯成 JavaScript、SCSS,LESS 編譯成 CSS.
- 檔案優化:壓縮 JavaScript、CSS、HTML 程式碼,壓縮合並圖片。
- 程式碼分割:提取多個頁面的公共程式碼、提取首屏不需要執行部分的程式碼讓其非同步載入。
- 模組合併:在採用模組化的專案裡會有很多個模組和檔案,需要構建功能把模組分類合併成一個檔案。
- 自動重新整理:監聽本地原始碼的變化,自動重新構建、重新整理瀏覽器。
- 自動化流程
入口(entry)
入口起點指示 webpack 應該使用哪個模組,來作為構建其內部 依賴圖的開始。進入入口起點後,webpack 會找出有哪些模組和庫是入口起點(直接和間接)依賴的。
預設值是 ./src/index.js,可以通過在 webpack configuration 中配置 entry 屬性,來指定一個(或多個)不同的入口起點。例如:
webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js'
}
複製程式碼
輸出(output)
output 屬性告訴 webpack 在哪裡輸出它所建立的 bundle,以及如何命名這些檔案。
主要輸出檔案的預設值是 ./dist/main.js,其他生成檔案預設放置在 ./dist 資料夾中。可以通過在配置中指定一個 output 欄位,來配置這些處理過程:
webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
複製程式碼
在上面的示例中,通過 output.filename 和 output.path 屬性,來告訴 webpack bundle 的名稱,以及想要 bundle 生成(emit)到哪裡。最上面匯入的 path 模組是一個 Node.js 核心模組,用於操作檔案路徑。
loader
webpack 只能理解 JavaScript 和 JSON 檔案。loader 讓 webpack 能夠去處理其他型別的檔案,並將它們轉換為有效 模組,以供應用程式使用,以及被新增到依賴圖中。
注意,loader 能夠 import 匯入任何型別的模組(例如 .css 檔案),這是 webpack特有的功能 其他打包程式或任務執行器的可能並不支援,官方團隊認為這種語言擴充套件是很有必要的, 因為這可以使開發人員建立出更準確的依賴關係圖。
webpack 的配置中 loader 有兩個屬性:
- test 屬性,用於標識出應該被對應的 loader 進行轉換的某個或某些檔案。
- use 屬性,表示進行轉換時,應該使用哪個 loader。
webpack.config.js
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};
複製程式碼
在 webpack 配置中定義 rules 時,要定義在 module.rules 而不是 rules 中。如果沒有按照正確方式去做,webpack 會給出警告。
請記住,使用正規表示式匹配檔案時,不要為它新增引號。也就是說,/\.txt$/ 與 '/\.txt$/'/ "/\.txt$/" 不一樣。前者指示 webpack 匹配任何以 .txt 結尾的檔案,後者指示 webpack 匹配具有絕對路徑 '.txt' 的單個檔案; 這可能不符合預期的想法。
外掛(plugin)
loader 用於轉換某些型別的模組,而外掛則可以用於執行範圍更廣的任務。包括:打包優化,資源管理,注入環境變數。
外掛介面(plugin interface) 功能極其強大,可以用來處理各種各樣的任務。
想要使用一個外掛,只需要 require() 它,然後把它新增到 plugins 陣列中。多數外掛可以通過選項(option)自定義。也可以在一個配置檔案中因為不同目的而多次使用同一個外掛,這時需要通過使用 new 操作符來建立它的一個例項。
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝
const webpack = require('webpack'); // 用於訪問內建外掛
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
複製程式碼
在上面的示例中,html-webpack-plugin 為應用程式生成 HTML 一個檔案,並自動注入所有生成的 bundle。
模式(mode)
通過選擇 development, production 或 none 之中的一個,來設定 mode 引數,你可以啟用 webpack 內建在相應環境下的優化。其預設值為 production。
module.exports = {
mode: 'production'
};
複製程式碼
構建專案
1、新建
新建一個空資料夾,用於建立專案,使用 npm init 命令建立一個 package.json 檔案。
輸入這個命令後,終端會問你一系列諸如專案名稱,專案描述,作者等資訊,也可以使用 npm init -y
這個命令來一次生成 package.json 檔案。
如下圖:
2、安裝 webpack
安裝 webapck 時需要把 webpack-cli 也裝上是因為在 webpack4.x 版本後 webpack 模組把一些功能分到了 webpack-cli 模組,所以兩者都需要安裝,安裝方法如下:
npm install webpack webpack-cli --global //這是安裝全域性webpack及webpack-cli模組
複製程式碼
3、新建檔案目錄
在根目錄件夾中新建兩個資料夾,分別為 src 資料夾和 dist 資料夾,接下來再建立三個檔案:此時,專案結構如下
- index.html --放在 dist 資料夾中;
- hello.js --放在 src 資料夾中;
- index.js --放在 src 資料夾中;
a、index.html 中寫下 html 程式碼,它的作用是為引入打包後的 js 檔案:
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Webpack Project</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
<!--這是打包之後的js檔案,我們暫時命名為bundle.js-->
</body>
</html>
複製程式碼
b、在 hello.js 中匯出模組:
// hello.js
module.exports = function() {
let hello = document.createElement('div')
hello.innerHTML = 'Hello world!'
return hello
}
複製程式碼
c、在 index.js 中引入這個模組(hello.js):
//index.js
const hello = require('./hello.js')
document.querySelector('#root').appendChild(hello())
複製程式碼
開啟 index.html 就可以看到我們的頁面了
4、配置 webpack.config.js
可以在當前專案的根目錄下新建一個配置檔案 webpack.config.js 用來配置打包方式。 webpack.config.js 配置如下
const path = require('path') // 處理絕對路徑
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口檔案
output: {
path: path.join(__dirname, '/dist'), //打包後的檔案存放的地方
filename: 'bundle.js' //打包後輸出檔案的檔名
}
}
複製程式碼
有了這個配置檔案,只需在終端中執行 webpack 命令就可進行打包,這條命令會自動引用 webpack.config.js 檔案中的配置選項。
5、構建本地伺服器
a、webpack-dev-server 配置本地伺服器
Webpack 提供了一個可選的本地開發伺服器,這個本地伺服器基於 node.js 構建,它是一個單獨的元件,在 webpack 中進行配置之前需要單獨安裝它作為專案依賴:
npm i webpack-dev-server -D
複製程式碼
devServer 的一些配置選項:
- contentBase :設定伺服器所讀取檔案的目錄,當前我們設定為"./dist"
- port :設定埠號,如果省略,預設為 8080
- inline :設定為 true,當原始檔改變時會自動重新整理頁面
- historyApiFallback :設定為 true,所有的跳轉將指向 index.html
// webpack.config.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口檔案
output: {
path: path.join(__dirname, '/dist'), //打包後的檔案存放的地方
filename: 'bundle.js' //打包後輸出檔案的檔名
},
devServer: {
contentBase: './dist', // 本地伺服器所載入檔案的目錄
port: '8088', // 設定埠號為8088
inline: true, // 檔案修改後實時重新整理
historyApiFallback: true
}
}
複製程式碼
b、package.json 檔案中新增啟動和打包命令
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open"
},
複製程式碼
這樣就可以用以下命令進行本地執行或者打包檔案:
- npm run dev 啟動本地伺服器,webpack-dev-server 就是啟動伺服器的命令,--open 是用於啟動完伺服器後自動開啟瀏覽器。
- npm run build 執行打包命令
此時,只要輸入 npm run dev 就可以在http://localhost:8088/ 中檢視頁面。
6、配置常用 loader
loader 可以讓 webpack 能夠去處理那些非 JavaScript 檔案(webpack 自身只理解 JavaScript)。loader 可以將所有型別的檔案轉換為 webpack 能夠處理的有效模組,然後你就可以利用 webpack 的打包能力,對它們進行處理。
a、配置 css-loader 和 sass-loader
要載入一個 css 檔案,需要安裝配置 style-loader 和 css-loader。
- css-loader:載入.css 檔案
- style-loader:使用 style 標籤將 css-loader 內部樣式注入到我們的 HTML 頁面
const path = require('path')
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口檔案
output: {
path: path.join(__dirname, '/dist'), //打包後的檔案存放的地方
filename: 'bundle.js' //打包後輸出檔案的檔名
},
devServer: {
contentBase: './dist', // 本地伺服器所載入檔案的目錄
port: '8088', // 設定埠號為8088
inline: true, // 檔案修改後實時重新整理
historyApiFallback: true //不跳轉
},
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的檔案
use: ['style-loader', 'css-loader']
{
test: /\.(scss|sass)$/, // 正則匹配以.scss和.sass結尾的檔案
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
}
}
複製程式碼
b、配置 Babel-loader
Babel 其實是一個編譯 JavaScript 的平臺,它可以編譯程式碼達到以下目的:
- 能使用最新的 JavaScript 程式碼(ES6,ES7...)
- 能使用基於 JavaScript 進行了擴充的語言,比如 React 的 JSX;
module: {
...
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src')]
}
]
}
複製程式碼
c、理圖片
處理圖片資源時,我們常用的兩種 loader 是 file-loader 或者 url-loader。 當使用 url-loader 載入圖片,圖片小於上限值,則將圖片轉 base64 字串,否則使用 file-loader 載入圖片。
module: {
...
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
複製程式碼
7、配置常用外掛
a、自動生成 html 檔案(HtmlWebpackPlugin)
1、安裝外掛:
npm i html-webpack-plugin -D
複製程式碼
2、把 dist 資料夾清空
3、在根目錄新建 index.html,內容和原來的 html 一致,只是不引入 js 檔案。
4、webpack.config.js 中引入 HtmlWebpackPlugin 外掛
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
})
]
複製程式碼
b、增加 css 字首
寫 css 時,一些屬性需要手動加上字首,在 webpack 中可以自動加上:
1、安裝
npm i postcss-loader autoprefixer -D
複製程式碼
2、在專案根目錄下新建 postcss.config.js 檔案
在專案根目錄下新建 postcss.config.js 檔案
module.exports = {
plugins: [
require('autoprefixer') // 引用autoprefixer模組
]
}
module.exports = {
...
module: {
rules: [
{
test: /\.css$/, // 正則匹配以.css結尾的檔案
use: [
{ loader: 'style-loader' }, // 這裡採用的是物件配置loader的寫法
{ loader: 'css-loader' },
{ loader: 'postcss-loader' } // 使用postcss-loader
]
}
...
]
}
...
}
複製程式碼
c、css分離
將CSS提取為獨立的檔案的外掛,對每個包含css的js檔案都會建立一個CSS檔案,支援按需載入css和sourceMap
安裝
npm install --save-dev mini-css-extract-plugin
複製程式碼
使用:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// 類似 webpackOptions.output裡面的配置 可以忽略
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// 這裡可以指定一個 publicPath
// 預設使用 webpackOptions.output中的publicPath
publicPath: '../'
},
},
'css-loader',
],
}
]
}
}
複製程式碼
參考文章
1、www.webpackjs.com/concepts/ 【官方文件】
2、 juejin.im/post/5db0fd… 【掘金】