前言
webpack作為現代前端技術的基石,相信絕大部分的前端開發者都聽說或是在專案中使用過。但是由於現在各種各樣cli工具的出現,能夠掌握webpack基本配置和使用的人,可能就不那麼多了。
最開始接觸webpack還是在以前的angular.js專案中,之後從angular.js轉到react後一直使用的create-react-app進行專案初始化。需要改動webpack配置時也是在使用eject命令暴露出webpack config進行修改,一直沒有自己從零開始配置過。在這期間angular.js升級成為Angular,jQuery逐漸被歷史淘汰,Vue也從一個後期之秀成為現在的當紅前端框架。不得不說,前端技術的更新迭代速度真的可以用飛速來形容了。在如此快速的更新速度下,作為一個前端開發人員,一定要緊跟技術的步伐,時刻保持著學習狀態,才能保證自己在大潮流中不掉隊。這也是我寫這篇文章的初衷,用來記錄自己的學習成果。
要注意的是,本文不會贅述現代前端開發中的一些基礎知識,如 npm依賴管理、模組化等基礎知識。所以,若你並沒有聽說過webpack,或不知道它是什麼,那麼建議你還是先了解一下基礎知識。若對webpack已經瞭如指掌,那麼也大可不必看這篇文章。不過大佬若是願意指導一番,我也是非常開心的!!^_^
正文
簡介
webpack是什麼?
本質上,webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(static module bundler)。在 webpack 處理應用程式時,它會在內部建立一個依賴圖(dependency graph),用於對映到專案需要的每個模組,然後將所有這些依賴生成到一個或多個bundle。—— 來自 webpack 官方文件
簡單的說,webpack就是一個現代前端開發的打包機。現代前端非常流行使用模組化的方式開發,webpack所做的就是將各個js模組合理的打包成bundle或者chunk。在打包的過程中,可以通過loader的方式,將新的js語法、CSS預處理語言等轉換成更容易被瀏覽器支援的形式。
webpack是基於nodejs的,在絕大部分時,在使用時需要為它寫一個配置檔案。這個配置檔案的主要結構如下:
module.exports = {
mode: 'development' // 模式配置
entry: '', // 入口檔案
output: {}, // 出口檔案
module: {}, // 處理對應模組
plugins: [], // 對應的外掛
devServer: {}, // 開發伺服器配置(僅在開發中使用)
}
複製程式碼
接下來,我們就來一步步的完成這些配置。
準備
初始化和安裝
在指定資料夾下執行 npm init
進行初始化。
mkdir webpackDemo&&npm init
因為專案並不是一個要釋出到npm的專案,所以執行npm init後只用一路回車即可。
安裝webpack和react的依賴:
npm install --save-dev webpack react react-dom
在webpack4之後的版本中,還需要安裝webpack-cli,具體方法同上。
建立初始目錄結構和檔案
在專案根目錄建立config資料夾,並在內建立webpack.config.js。
開啟根目錄下的package.json 配置scripts
:
"scripts": {
"build": "webpack --mode production --config ./config/webpack.config.js",
}
複製程式碼
配置scripts指令碼是為了後期在執行過程中只用在命令列中輸入 npm '指令碼中指定配置' 就能夠完成命令列的輸入操作。比如輸入 npm build,就會自動執行 "webpack --mode production --config ./config/webpack.config.js" 這一長串的操作。
建立程式碼資料夾和react的入口檔案:
在專案根目錄中建立src資料夾,並在內建立index.js、App.js、index.css。
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css'
ReactDOM.render(
<App />,
document.getElementById('root')
);
複製程式碼
App.js
import React from 'react';
export default class App extends React.Component {
render() {
return <div>
<p className="text">動手搭建一個基於webpack4的react開發環境</p>
</div>
}
}
複製程式碼
index.css
.text{
color:'red'
}
複製程式碼
完成上述操作後,專案目錄結構應該像下面這樣
webpackDemo
│ node_modules
└───config
│ webpack.config.js
└───src
│ index.js
│ index.css
│ App.js
package.json
複製程式碼
現在,我們完成了簡單的初始化工作,下面開始瞭解webpack吧。
模式 (mode)
mode是webpack4中新增的概念,它有三個選項:development
、production
、none
,用來設定webpack的優化方式。
development
開發模式,該模式優化了開發速度,提供了詳細的錯誤機制和瀏覽器除錯工具。並且關閉了程式碼壓縮,使程式碼能夠更快的構建。
production
生產模式,該模式能夠提供更小的程式碼包,去除了只在開發階段執行的程式碼。自動開啟了程式碼混淆壓縮。
配置
module.export = {
mode:'production' // 'development'||'production'||'none'
}
複製程式碼
程式入口 (entry)
在這裡,可以宣告一個應用的起點。入口可以有一個或者多個。在單頁應用中,入口一般只有一個。不過也可以將公共依賴配置成為單頁應用的入口,這樣單頁應用也可以有多個入口。而在多頁應用中,一般會有多個入口檔案。
一個簡單的單頁應用入口如下:
module.export = {
mode:'production' // 'development'||'production'||'none',
entry:'./src/index.js',
}
複製程式碼
輸出 (output)
output用來配置專案打包後的檔名稱、路徑。用來告訴webpack怎麼輸出、輸出到哪、叫什麼名字。
const path = require('path');
module.export = {
mode:'production' // 'development'||'production'||'none',
entry:'./src/index.js',
output: {
// 在bundle中引入註釋 注意:該選項不應該在生產模式中啟用
pathinfo:true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "[name].[hash].js"
}
}
複製程式碼
這裡的filename並沒有給它一個實際的名稱,而是使用模板字串去設定webpack生成後的檔名稱。這個設定中的[name]代表模組名稱,在單入口檔案中預設為main。而[hash]則會生成一個模組識別符號的hash,預設是20位,可以通過[hash:16]的方式指定它的位數。打包後的檔名稱就像這樣main.f236aaeca342dfb1f8dd.js
。在生成檔名稱後跟上hash有助於我們在專案重新部署後由於引用的檔名稱變了,瀏覽器會去下載新的檔案,不再繼續使用本地的快取。
loader
webpack的作用就是將前端開發中的各個模組進行處理以及打包。而loader的作用就是處理webpack中的這些模組。
webpack中模組有很多種,常見的有:
-
模組化的js檔案
-
css/less/sass檔案
-
圖片以及靜態檔案
loader在module中配置:
// 示例
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = {
mode: 'development',
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/, // 用來指定針對的檔案型別 支援正則
exclude: /node_modules/, // 用來指定需要排除的資料夾,優化打包速度
include: appSrc, // 指定所包含的資料夾 ,優化打包速度
loader: "babel-loader", // 針對指定檔案使用的loader
}
]
}
};
複製程式碼
要對這些模組進行處理,就要使用到不同的loader。在此之前,先簡單的介紹一下需要使用到的loader。
babel-loader
babel是一個語法轉換器,能夠讓你自由的使用JavaScript的最新語法。它能夠將我們所寫的新語法、jsx等轉換成瀏覽器能夠友好支援的形式。
要使用babel-loader需要下列依賴,可以通過執行npm install --save-dev babel-loader @babel/core @babel/preset-react @babel/preset-env
安裝它們。
-
babel-loader
-
@babel/core
babel的核心元件,裡面包含著babel的api。
-
@babel/preset-env
用來轉義JavaScript語法。
-
@babel/preset-react
用來轉義react。
配置babel-loader:
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = {
mode: 'development',
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
// 指定babel預處理轉義
presets: ["@babel/preset-env", "@babel/preset-react"]
}
}
]
}
}
複製程式碼
完成上述配置後,還需配置一下babel,讓它能夠轉換react和js的新語法。可以像上面使用webpack配置中的option選項中的presets欄位指定babel預處理的方式。
也可以在專案的根目錄建立babel的配置檔案.babelrc
。.babelrc
字尾rc來自linux中,使用過linux就知道linux中很多rc結尾的檔案,比如.bashrc,rc是run command的縮寫,翻譯成中文就是執行時的命令,表示程式執行時就會來呼叫這個檔案。
babel所有的操作基本都會來讀取這個配置檔案,除了一些在回撥函式中設定options引數的,如果沒有這個配置檔案,會從package.json檔案的babel屬性中讀取配置。
在.babelrc
中新增下列語句:
{
"presets": ["@babel/preset-env","@babel/preset-react"]
}
複製程式碼
url-loader
url-loader和file-loader的作用類似,都是使webpack能夠打包靜態檔案。url-loader相較於file-loader的功能更強大,它能夠使用兩種方式進行打包。
url-loader有一個重要的引數 limit
,這個引數用來設定打包檔案大小的限制。當檔案小於指定引數時,它能夠返回一個DataURL(base64)形勢的檔案。當檔案大於指定引數時,它將通過file-loader進行打包。
配置url-loader:
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = {
mode: 'development',
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
// 指定babel預處理轉義
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
// url-loader的配置
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
// 設定url-loader轉DataURL的檔案大小上限
limit: 10000
}
}
]
}
}
複製程式碼
url-loader還有兩個引數mimetype
和fallback
,這兩個引數使用的並不多,就不在這裡贅述了。
style-loader和css-loader
style-loader和css-loader都是用來處理css檔案的,不過它們的作用並不相同。
css-loader:用來讀取css檔案的內容,並進行處理 如:minimize。
style-loader:將通過import形式匯入到js中的css檔案插入到<style></style>
標籤內。
在webpack中的配置如下:
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = {
mode: 'development',
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
// 指定babel預處理轉義
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
// 設定url-loader轉DataURL的檔案大小上限
limit: 10000
}
},
// 針對css檔案配置style-loader和css-loader
{
test: /\.css$/,
include: appSrc,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// 可以包含一些配置
modules:true|false, // 是否開啟css模組化,開啟後引入的css檔案僅針對當前頁面有效,不會作用到全域性
minimize: true // 開發模式下應該設為false,優化打包速度
}
}
]
}
]
}
}
複製程式碼
如上所示,當我們在針對同一型別的檔案配置多個loader時。可以將loader宣告在一個陣列內,陣列項可以是一個物件,也可以僅僅是一個字串,這取決於你針對某個loader還有沒有特殊的設定。比如在配置css-loader時,還宣告瞭option選項,並在option選項內開啟了minimize選項。但是在配置style-loader時,僅僅寫了一個字串。
需要注意的是,陣列內loader的執行順序是從陣列的最後一項依次向前執行。所有我們將css-loader配置在了後面,它是先執行的。這更符合處理邏輯,先對css進行處理,再插入到html中。
外掛
外掛是webpack的一個極其重要的功能,webpack提供了豐富的外掛介面,使開發者能夠自由的開發外掛來擴充webpack的功能。
這裡我們拿大名鼎鼎的 HtmlWebpackPlugin
來舉例。
設想一個場景,在打包時,需要手動的去建立一個html檔案,然後在其中引入打包好的各種檔案。即使建立好html檔案後,由於在config中設定了hash形式的打包檔名稱。我們在每次打包後還需要根據hash名稱的變動去改變html內引入的檔名稱,這是非常低階的重複勞作。
HtmlWebpackPlugin
為我們解決了這個問題。HtmlWebpackPlugin
能夠根據我們提供的模板自動生成html檔案,並引入打包後的內容。
下面介紹一下HtmlWebpackPlugin
的使用過程。
安裝:npm install --save-dev html-webpack-plugin
安裝完成後,先在專案的根目錄建立一個資料夾public
,在其中建立一個模板檔案index.html
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製程式碼
然後在webpack中配置外掛:
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
// 引入html-webpack-plugin外掛
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
// 指定babel預處理轉義
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
// 設定url-loader轉DataURL的檔案大小上限
limit: 10000
}
},
// 針對css檔案配置style-loader和css-loader
{
test: /\.css$/,
include: appSrc,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// 可以包含一些配置
minimize: true // 開發模式下應該設為false,優化打包速度
}
}
]
}
]
},
plugins: [
// HTML模板檔案處理外掛
new HtmlWebpackPlugin({
file: 'index.html', // 生成的檔名稱
template: 'public/index.html' // 指定模板檔案
})
],
}
複製程式碼
現在在命令列中執行npm build
,webpack將打包src目錄內的檔案。並將在根目錄生成一個build檔案,將打包的內容輸出在裡面。
這時候,我們其實已經完成了webpack的基本配置。但是現在的配置是基於development模式進行打包的,沒有進行壓縮,很顯然這並不能做為一個可釋出的版本。要修改為生產模式其實也很簡單,可以通過兩種方式去實現。
-
修改配置檔案中的mode選項,將development修改為production。
-
刪除配置中的mode選項,修改package.json scripts中的build項為
webpack --mode production --config ./config/webpack.config.js
。
在配置2中,使用--mode 能夠為webpack-cli設定打包模式。修改後再次打包,這時候程式碼經過webpack production模式的優化,進行了混淆壓縮,變成了釋出版本。
devServer
在日常的開發過程中,肯定不能每修改一點東西就重新build一次,這樣開發效率會受到很大的影響。這時需要啟動一個服務,來監聽檔案的變動。當檔案儲存時就重新打包,同時幫我們自動重新整理瀏覽器,方便我們及時觀察到更新。
要完成上述操作有幾種方式,這裡只介紹其中的一種,使用 webpack-dev-server
外掛。
執行 npm install --save-dev webpack-dev-server
安裝外掛,在module.explot中新增配置項 devServer
。
devServer的配置項有很多,這裡大概的介紹其中幾種常用的配置:
-
contentBase: '',告訴伺服器從哪個目錄中提供內容
-
https: true|false, 是否啟用https
-
compress: true|false, 是否啟用壓縮
-
host: '127.0.0.1', 指定host地址
-
port: 23333, 指定埠
-
overlay: true|false, 當出現編譯器錯誤或警告時,在瀏覽器中顯示全屏覆蓋層。
-
progress: true|false, 將執行進度輸出到控制檯。
將devServer新增到配置中:
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
// 引入html-webpack-plugin外掛
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 入口
entry: './src/index.js',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
// 指定babel預處理轉義
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
// 設定url-loader轉DataURL的檔案大小上限
limit: 10000
}
},
// 針對css檔案配置style-loader和css-loader
{
test: /\.css$/,
include: appSrc,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// 可以包含一些配置
minimize: true // 開發模式下應該設為false,優化打包速度
}
}
]
}
]
},
devServer: {
// HOST
host: '127.0.0.1',
// 埠
port: 23333,
// 報錯提示在網頁遮罩層
overlay: true,
// 顯示執行進度
progress: true,
},
plugins: [
// HTML模板檔案處理外掛
new HtmlWebpackPlugin({
file: 'index.html', // 生成的檔名稱
template: 'public/index.html' // 指定模板檔案
})
]
}
複製程式碼
需要注意的時,devServer應當用在開發環境中,所以現在需要將之前的配置進行修改。
-
在配置中刪除mode項。
-
為package.json的scripts中新增另一個啟動命令
"start": "webpack-dev-server --open --mode development --config ./config/webpack.config.js"
-
將之前的build項改為
webpack --mode production --config ./config/webpack.config.js
。
現在,執行npm build,webpack將使用production模式進行打包。執行npm start時,將使用development模式進行打包,並且webpack-dev-server將啟動一個服務,監聽檔案變更。
現在執行npm start,就可以開始進行開發了!
進階
在上面的配置中,我們已經實現了一個react專案開發環境的基本配置。但這遠遠不夠,在實際的專案中,可能會用到很多的工具來優化開發速度。同時也需要針對不同的環境寫不同的配置,做不同的優化等。並且,可能還涉及到程式碼分割、壓縮等配置。
下面,我們來一步步完善webpack的配置。
devtool
webpack中devtool選項用來控制是否生成,以及如何生成 source map。
想要了解source map,可以看一下這篇文章。簡單的說,source map就是幫助我們定位到錯誤資訊位置的檔案。正確的配置source map,能夠提高開發效率,更快的定位到錯誤位置。
webpack中devtool有很多種配置,我們可以在 這裡 瞭解它。
在開發環境中,更推薦使用cheap-module-eval-source-map
,它能幫助我們準確的定位到錯誤原始碼位置的同時,也能提供更快的構建速度和構建效能。
而在生產環境中,可以不啟動任何source map(不配置devtool項),也可以使用source-map
。需要注意的是,不要將source map部署到生產伺服器中。
為svg檔案配置loader
一般情況下,專案都會需要用到圖示。常見的圖示使用方式有很多種,如雪碧圖、字型圖示、svg等。雪碧圖和iconfont的使用方式不需要進行特殊的處理,這裡我們就不再贅述。下面介紹一個使用svg圖示的方法。
通過 svgr ,能夠直接將svg圖示以react元件的形式引入專案中。
就像這樣:
import React from 'react';
import { ReactComponent as Icon } from './icon.svg';
export default class App extends React.Component {
render() {
return <div>
<Icon width={10} height={10} />
</div>
}
}
複製程式碼
在react最新版本的cli create-react-app
,已近預設整合了svgr。在我們自己的專案中使用也很簡單,只需要針對 .svg
新增loader即可。
{
test: /\.svg$/,
use: ['@svgr/webpack'],
}
複製程式碼
svgr同時也支援node、react-native等處理方式,可以通過 svgr文件來了解。
構建不同環境下的配置
在生產環境和開發環境的構建目標差異很大。比如在開發環境中,需要更快的構建速度和更強的錯誤提示。但是在生產環境中,則希望構建的程式碼能更小,更輕,更側重於效能。所以,針對不同的環境,需要不同的配置檔案。但是如果將配置完全拆分開,兩個配置檔案中可能會包含很多重複的程式碼。這時我們需要提出公共的配置,為了將這些配置合併在一起,可以使用webpack-merge。
下面,我們開始使用 webpack-merge 進行配置優化。
首先,使用npm安裝依賴 npm install --save-dev webpack-merge
然後,在config資料夾下建立 webpack.config.common.js 、 webpack.config.dev.js 、webpack.config.prod.js。顧名思義,這三個配置代表了通用、開發、生產模式的配置檔案。
將之前配置中用到的公共配置提出到 webpack.config.common.js 內:
// webpack.config.common.js
// 打包HTML檔案
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = {
// 入口
entry: './src/index.js',
module: {
rules: [
{
// 配置svg圖示loader,可以在專案中通過元件的形式直接引入svg圖示
test: /\.svg$/,
include: appSrc,
use: ['@svgr/webpack']
}
]
},
plugins: [
// HTML模板檔案處理外掛
new HtmlWebpackPlugin({
file: 'index.html',
template: 'public/index.html'
})
]
}
複製程式碼
開發環境下的配置:
const merge = require('webpack-merge');
// 引入公共配置檔案
const common = require('./webpack.config.common.js');
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')
module.exports = merge(common, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
// 出口
output: {
pathinfo: true,
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
// chunk名稱配置
chunkFilename: '[name].chunk.js',
// 輸出的檔名配置
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
// exclude: /node_modules/,
include: appSrc,
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
// 針對靜態檔案
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
limit: 8192,
name: 'static/[name].[hash:8].[ext]',
}
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
minimize: false
}
}
]
}
]
},
devServer: {
// HOST
host: '127.0.0.1',
// 埠
port: 23333,
// 報錯提示在網頁遮罩層
overlay: true,
// 顯示執行進度
progress: true,
}
})
複製程式碼
生產環境配置檔案:
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.config.common.js');
// 每次執行打包 先清除之前的打包檔案
const CleanWebpackPlugin = require('clean-webpack-plugin');
const appSrc = path.resolve(__dirname,'../src')
module.exports = merge(common, {
mode: 'production',
// 出口
output: {
pathinfo: false,
chunkFilename: 'js/[name].chunk.js',
// 所有輸出檔案的目標路徑
// 必須是絕對路徑(使用 Node.js 的 path 模組)
path: path.resolve(__dirname, './../build'),
filename: "js/[name].[chunkhash:8].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: appSrc,
// exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
// 針對靜態檔案
{
test: /\.(png|jpg|gif)$/,
loader: "url-loader",
options: {
limit: 10000,
name: 'static/[name].[hash:8].[ext]',
}
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
minimize: true
}
}
]
}
]
},
plugins: [
// 打包前清除之前的build目錄
new CleanWebpackPlugin(['build'], path.resolve(__dirname, '../'))
]
});
複製程式碼
現在配置已經修改完成,我們還需要修改一下package.json,讓啟動命令去引用不同的配置檔案。
將開發模式的啟動配置修改為 "start": "webpack-dev-server --open --mode development --config ./config/webpack.config.dev.js"
。
生產模式的啟動配置修改為 "build": "webpack --mode production --config ./config/webpack.config.prod.js",
現在我們使用npm start
命令啟動專案,執行的是webpack.config.dev.js檔案,這是開發配置檔案,我們可以在裡面做一些針對開發模式的優化。
使用npm build
命令啟動專案,執行的是webpack.config.prod.js檔案,這是生產配置檔案,我們可以在裡面做一些針對生產模式的優化。
防止打包檔案的重複
執行build命令打包檔案時,會在專案的根目錄下生成build目錄,並在其中生成打包檔案。當執行多次build後,會發現由於專案名稱的hash值不同,build目錄下可能存在多個版本打包後的檔案。要解決這個問題,可以使用外掛 clean-webpack-plugin
。
首先安裝外掛 npm i clean-webpack-plugin --save-dev
配置如下:
const CleanWebpackPlugin = require('clean-webpack-plugin')
// webpack config
{
plugins: [
new CleanWebpackPlugin(['build'], path.resolve(__dirname, '../'))
]
}
複製程式碼
配置完外掛後,再執行npm build命令。會發現每次打包前,build目錄都會被刪除,然後重新建立。
注意,該外掛只用於生產環境配置。
總結
到這裡,我們實現了webpack的基礎的配置,以及各種概念的掃盲。其實這隻能算是基礎用法,要實現一個真正完善的webpack配置肯定遠遠不止這些。這篇文章的物件導向為初學者,所有在這裡就不過多的介紹那些比較複雜的概念。
在掌握了上述基礎配置後,大家可以嘗試著進行一些更深入的學習,如optimization、tree shaking、生產環境下的構建速度優化等。