眾所周知,webpack進入第4個大版本已經有2個月的時間了,而且webpack團隊升級更新的速度也是非常的驚人
在寫下如下內容的時候webpack已經出到了4.6的版本了,劍指5.0應該是指日可待了,當然這些都是個人的臆想,並不代表任何意見
既然我們已經迎接了webpack4的到來了,那麼就一起來使用一下,即使你沒用過之前的版本,沒關係,我們重新出發,將工作中常用到的配置寫給大家來看
非友情提示:由於webpack使用起來並不能僅看程式碼就方便理解,所以有圖有真相的才是正解,於是乎本文配圖很多,真的是很多
首先,既來之,則安之
安裝webpack
- 需要先在專案中npm init初始化一下,生成package.json
- 建議node版本安裝到8.2以上
// webpack4中除了正常安裝webpack之外,需要再單獨安一個webpack-cli
npm i webpack webpack-cli -D
複製程式碼
★ npm i -D 是 npm install --save-dev 的簡寫,是指安裝模組並儲存到 package.json 的 devDependencies中,主要在開發環境中的依賴包
0配置了什麼
webpack4可以支援0配置打包,這裡所說的0配置又是什麼呢?當然在開發者眼中0配置的東西,那根本是無法用的,因為不夠智慧,那麼我們就來看看做到了哪些0配置
在使用webpack進行打包的時候,預設情況下會將src下的入口檔案(index.js)進行打包
// node v8.2版本以後都會有一個npx
// npx會執行bin裡的檔案
npx webpack // 不設定mode的情況下 打包出來的檔案自動壓縮
npx webpack --mode development // 設定mode為開發模式,打包後的檔案不被壓縮
複製程式碼
當執行npx webpack命令的時候,webpack會自動查詢專案中src目錄下的index.js檔案,然後進行打包,生成一個dist目錄並存在一個打包好的main.js檔案
這些算是0配置的操作了,名字都是定義好的,不能變,想想也很雞肋
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/fb3234b43a2e1a68308a671ec6082e914067e7bd67d04bd1b08b2e6a070cc2c8.png)
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/8b0a9116c1e7008e8ea5f8eed4d35e9da83ad90810fe92606729c7260ddf99b2.png)
webpack是基於Node的
在專案下建立一個webpack.config.js(預設,可修改)檔案來配置webpack
module.exports = {
entry: '', // 入口檔案
output: {}, // 出口檔案
module: {}, // 處理對應模組
plugins: [], // 對應的外掛
devServer: {}, // 開發伺服器配置
mode: 'development' // 模式配置
}
複製程式碼
以上就是webpack的正常配置模組
★ 啟動devServer需要安裝一下webpack-dev-server
npm i webpack-dev-server -D
複製程式碼
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/0ec2e0771761c95ff2c283c3a6a61804c2a7a8f5daa7169e360610c9c4b2293c.png)
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js', // 入口檔案
output: {
filename: 'bundle.js', // 打包後的檔名稱
path: path.resolve('dist') // 打包後的目錄,必須是絕對路徑
}
}
複製程式碼
上面就可以說是實現了最簡單的webpack配置了,那接下來就打包一下看看
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/a611b7bfd54708c834b6ab67041f7af631434056bb4b976a5ab43b11077454aa.png)
配置執行檔案
工作當中我們打包編譯的時候一般都執行npm run dev這樣的命令,既然是通過npm執行的命令,我們就應該找到package.json裡的執行指令碼去配置一下命令,這裡如下圖所示
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/a4612b48962582c4b178a0fa5072700a252e97ff806f0d3cb0e1f7168949a86d.png)
npm run dev是我們開發環境下打包的檔案,當然由於devServer幫我們把檔案放到記憶體中了,所以並不會輸出打包後的dist資料夾
通過npm run build之後會生成一個dist目錄資料夾,就和上面打包後的樣子一樣了
多入口檔案
多個入口可以有兩種實現方式進行打包
- 一種是沒有關係的但是要打包到一起去的,可以寫一個陣列,實現多個檔案打包
- 另一種就是每一個檔案都單獨打包成一個檔案的
- 下面就來看看這兩種方式的寫法
let path = require('path');
module.exports = {
// 1.寫成陣列的方式就可以打出多入口檔案,不過這裡打包後的檔案都合成了一個
// entry: ['./src/index.js', './src/login.js'],
// 2.真正實現多入口和多出口需要寫成物件的方式
entry: {
index: './src/index.js',
login: './src/login.js'
},
output: {
// 1. filename: 'bundle.js',
// 2. [name]就可以將出口檔名和入口檔名一一對應
filename: '[name].js', // 打包後會生成index.js和login.js檔案
path: path.resolve('dist')
}
}
複製程式碼
這時候執行npm run build後,會生成打包好的兩個js檔案,如圖所示
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/29a3ee4c794bb0c613680812624ab012d1373800e006e3deebf9d52f8a5ba493.png)
配置Html模板
檔案都打包好了,但是我們在使用的時候不能在dist目錄下去建立一個html檔案,然後去引用打包後的js吧,這不合理,實際開發中也不會這樣
我們需要實現html打包功能,可以通過一個模板實現打包出引用好路徑的html來
這就需要用到一個常用的外掛了,html-webpack-plugin,用之前我們來安一下它
npm i html-webpack-plugin -D
複製程式碼
因為是個外掛,所以需要在config.js裡引用一下的
let path = require('path');
// 外掛都是一個類,所以我們命名的時候儘量用大寫開頭
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
// 新增hash可以防止檔案快取,每次都會生成4位的hash串
filename: 'bundle.[hash:4].js',
path: path.resolve('dist')
},
plugins: [
// 通過new一下這個類來使用外掛
new HtmlWebpackPlugin({
// 用哪個html作為模板
// 在src目錄下建立一個index.html頁面當做模板來用
template: './src/index.html',
hash: true, // 會在打包好的bundle.js後面加上hash串
})
]
}
複製程式碼
通過上面的配置後,我們再npm run build打包看一下現在是個什麼樣子了
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/0daf037f70b18617c7189ce040c8de5fba7b030d7c0bb549d3b2d569286b568a.png)
多頁面開發,怎麼配置多頁面
如果開發的時候不只一個頁面,我們需要配置多頁面,那麼需要怎麼來搞呢?不用擔心,html-webpack-plugin外掛自有辦法,我們來觀望一下
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 多頁面開發,怎麼配置多頁面
entry: {
index: './src/index.js',
login: './src/login.js'
},
// 出口檔案
output: {
filename: '[name].js',
path: path.resolve('dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index'] // 對應關係,index.js對應的是index.html
}),
new HtmlWebpackPlugin({
template: './src/login.html',
filename: 'login.html',
chunks: ['login'] // 對應關係,login.js對應的是login.html
})
]
}
複製程式碼
繼續npm run build看打包後的樣子
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/1d527f01de842caf41897a02caa3099236f664a1cf5bdaad9db8b5e5edc85b9d.png)
引用CSS檔案
可以在src/index.js裡引入css檔案,到時候直接打包到生產目錄下
需要下載一些解析css樣式的loader
npm i style-loader css-loader -D
// 引入less檔案的話,也需要安裝對應的loader
npm i less less-loader -D
複製程式碼
下面我們來看一下如何配置css檔案的解析
// index.js
import './css/style.css'; // 引入css
import './less/style.less'; // 引入less
console.log('這裡是打包檔案入口-index.js');
// webpack.config.js
module.exports = {
entry: {
index: './src/index.js'
},
output: {
filename: 'bundle.js',
path: path.resolve('dist')
},
module: {
rules: [
{
test: /\.css$/, // 解析css
use: ['style-loader', 'css-loader'] // 從右向左解析
/*
也可以這樣寫,這種方式方便寫一些配置引數
use: [
{loader: 'style-loader'},
{loader: 'css-loader'}
]
*/
}
]
}
}
複製程式碼
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/717c3ddec29eefe3d24f03e3856e50a9febcef8a947eb68462abaa91e226053e.png)
- 此時打包後的css檔案是以行內樣式style的標籤寫進打包後的html頁面中,如果樣式很多的話,我們更希望直接用link的方式引入進去,這時候需要把css拆分出來
- extract-text-webpack-plugin外掛相信用過的人都知道它是幹什麼的,它的功效就在於會將打包到js裡的css檔案進行一個拆分
拆分CSS
// @next表示可以支援webpack4版本的外掛
npm i extract-text-webpack-plugin@next -D
複製程式碼
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
// 拆分css樣式的外掛
let ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filaneme: 'bundle.js',
path: path.resolve('dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextWebpackPlugin.extract({
// 將css用link的方式引入就不再需要style-loader了
use: 'css-loader'
})
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
// 拆分後會把css檔案放到dist目錄下的css/style.css
new ExtractTextWebpackPlugin('css/style.css')
]
}
複製程式碼
此時拆分完css後,打包的html頁面就以link的方式去引入css了,這樣很好
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/20680791aacf1798244be6db6d9243ca204e557abe28d0f836e93ed6531837a6.png)
不過既然大家都知道它,那就順便也提一下吧
npm i mini-css-extract-plugin -D
複製程式碼
使用起來和上面的外掛是差不多的
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/a.css' // 指定打包後的css
})
]
}
複製程式碼
拆分成多個css
這裡要著重說一下上面兩個外掛的區別了,我個人還是建議用extract-text-webpack-plugin的,畢竟從之前的版本承接下來的,雖然在安包的時候需要@next,但是還是值得信賴的
而且現在的extract-text-webpack-plugin也支援了拆分成多個css,而目前mini-css-extract-plugin還不支援此功能
// 正常寫入的less
let styleLess = new ExtractTextWebpackPlugin('css/style.css');
// reset
let resetCss = new ExtractTextWebpackPlugin('css/reset.css');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: resetCss.extract({
use: 'css-loader'
})
},
{
test: /\.less$/,
use: styleLess.extract({
use: 'css-loader'
})
}
]
},
plugins: [
styleLess,
resetCss
]
}
複製程式碼
通過這樣操作後可以打包成兩個不同的css檔案,如下圖
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/1f7f8fecd35afb9002b7a33595553bc8fc512d7705b95bb25ea21ebf8bb941d2.png)
引用圖片
- 處理圖片方面,也需要loader
npm i file-loader url-loader -D
複製程式碼
如果是在css檔案裡引入的如背景圖之類的圖片,就需要指定一下相對路徑
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextWebpackPlugin.extract({
use: 'css-loader',
publicPath: '../'
})
},
{
test: /\.(jpe?g|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, // 小於8k的圖片自動轉成base64格式,並且不會存在實體圖片
outputPath: 'images/' // 圖片打包後存放的目錄
}
}
]
}
]
}
}
複製程式碼
在css中指定了publicPath路徑這樣就可以根據相對路徑引用到圖片資源了,如下圖所示
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/aa4c94f6112b0e9f1fa9d7d8e9c8ebf512f136fcb0e269e8a132ed711b2b61ee.png)
頁面img引用圖片
頁面中經常會用到img標籤,img引用的圖片地址也需要一個loader來幫我們處理好
npm i html-withimg-loader -D
複製程式碼
module.exports = {
module: {
rules: [
{
test: /\.(htm|html)$/,
use: 'html-withimg-loader'
}
]
}
}
複製程式碼
這樣再打包後的html檔案下img就可以正常引用圖片路徑了
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/52114de419fa26fbf4da5d2b69cdcdea39004df55af36cbfc0c5aa9ae67ac3f2.png)
引用字型圖片和svg圖片
字型圖示和svg圖片都可以通過file-loader來解析
module.exports = {
module: {
rules: [
{
test: /\.(eot|ttf|woff|svg)$/,
use: 'file-loader'
}
]
}
}
複製程式碼
這樣即使樣式中引入了這類格式的圖示或者圖片都沒有問題了,img如果也引用svg格式的話,配合上面寫好的html-withimg-loader就都沒有問題了
新增CSS3字首
通過postcss中的autoprefixer可以實現將CSS3中的一些需要相容寫法的屬性新增響應的字首,這樣省去我們不少的時間
由於也是一個loader載入器,我們也需要先安裝一下
npm i postcss-loader autoprefixer -D
複製程式碼
安裝後,我們還需要像webpack一樣寫一個config的配置檔案,在專案根目錄下建立一個postcss.config.js檔案,配置如下:
module.exports = {
plugins: [require('autoprefixer')] // 引用該外掛即可了
}
複製程式碼
然後在webpack裡配置postcss-loader
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
}
複製程式碼
轉義ES6
在實際開發中,我們在大量的使用著ES6及之後的api去寫程式碼,這樣會提高我們寫程式碼的速度,不過由於低版本瀏覽器的存在,不得不需要轉換成相容的程式碼,於是就有了常用的Babel了
Babel會將ES6的程式碼轉成ES5的程式碼
那麼不再多說,既然要使用它,就先來安一下
npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 -D
複製程式碼
當把這些都安好後,我們就開始配置,由於要相容的程式碼不僅僅包含ES6還有之後的版本和那些僅僅是草案的內容,所以我們可以通過一個.babelrc檔案來配置一下,對這些版本的支援
// .babelrc
{
"presets": ["env", "stage-0"] // 從右向左解析
}
複製程式碼
我們再在webpack裡配置一下babel-loader既可以做到程式碼轉成ES5了
module.exports = {
module: {
rules: [
{
test:/\.js$/,
use: 'babel-loader',
include: /src/, // 只轉化src目錄下的js
exclude: /node_modules/ // 排除掉node_modules,優化打包速度
}
]
}
}
複製程式碼
在我們每次npm run build的時候都會在dist目錄下建立很多打好的包,如果積累過多可能也會混亂
所以應該在每次打包之前將dist目錄下的檔案都清空,然後再把打好包的檔案放進去
這裡提供一個clean-webpack-plugin外掛
npm i clean-webpack-plugin -D
複製程式碼
let CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
// 打包前先清空
new CleanWebpackPlugin('dist')
]
}
複製程式碼
啟動靜態伺服器
啟動一個靜態伺服器,預設會自動重新整理,就是說你對html,css,js檔案做了修改並儲存後,瀏覽器會預設重新整理一次展現修改後的效果
正常情況下我們都是在開發環境中開發專案,所以之前配置的指令碼"dev"可以派上用場了,在執行npm run dev命令後,會啟動靜態伺服器,我們訪問localhost:3000埠就可以看到開發的頁面內容了
如果devServer裡open設為true後,會自動開啟瀏覽器
module.exports = {
devServer: {
contentBase: './dist',
host: 'localhost', // 預設是localhost
port: 3000, // 埠
open: true, // 自動開啟瀏覽器
hot: true // 開啟熱更新
}
}
複製程式碼
當然在npm run dev命令下,打包的檔案存在於記憶體中,並不會產生在dist目錄下
熱更新和自動重新整理的區別
在配置devServer的時候,如果hot為true,就代表開啟了熱更新
But這並沒那麼簡單,因為熱更新還需要配置一個webpack自帶的外掛並且還要在主要js檔案裡檢查是否有module.hot
下面就讓我們直接看下程式碼是如何實現的
// webpack.config.js
let webpack = require('webpack');
module.exports = {
plugins: [
// 熱更新,熱更新不是重新整理
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true,
port: 3000
}
}
// 此時還沒完雖然配置了外掛和開啟了熱更新,但實際上並不會生效
// index.js
let a = 'hello world';
document.body.innerHTML = a;
console.log('這是webpack打包的入口檔案');
// 還需要在主要的js檔案裡寫入下面這段程式碼
if (module.hot) {
// 實現熱更新
module.hot.accept();
}
複製程式碼
以上index.js中的內容,如果將變數a的值進行修改儲存後,會在不重新整理頁面的情況下直接修改掉,這樣就實現了熱更新
那麼熱更新從現在看來和自動重新整理瀏覽器的區別也不是太大嘛!自動重新整理也是可以接受的啊
其實不然,熱更新的好處可能在vue或者react中有更大的發揮,其中某一個元件被修改的時候就會針對這個元件進行熱更新了,這裡用到vue或react的同學去實際體驗一下吧
resolve解析
在webpack的配置中,resolve我們常用來配置別名和省略字尾名
module.exports = {
resolve: {
// 別名
alias: {
$: './src/jquery.js'
},
// 省略字尾
extensions: ['.js', '.json', '.css']
},
}
複製程式碼
這個配置在webpack中比較簡單,我們也就不再敘述了,下面來看點乾貨
提取公共程式碼
在webpack4之前,提取公共程式碼都是通過一個叫CommonsChunkPlugin的外掛來辦到的。到了4以後,內建了一個一模一樣的功能,而且起了一個好聽的名字叫“優化”
下面我們就來看看如何提取公共程式碼
// 假設a.js和b.js都同時引入了jquery.js和一個寫好的utils.js
// a.js和b.js
import $ from 'jquery';
import {sum} from 'utils';
複製程式碼
那麼他們兩個js中其中公共部分的程式碼就是jquery和utils裡的程式碼了
可以針對第三方外掛和寫好的公共檔案
module.exports = {
entry: {
a: './src/a.js',
b: './src/b.js'
},
output: {
filename: '[name].js',
path: path.resolve('dust')
},
// 提取公共程式碼
+ optimization: {
splitChunks: {
cacheGroups: {
vendor: { // 抽離第三方外掛
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包後的檔名,任意命名
// 設定優先順序,防止和自定義的公共程式碼提取時被覆蓋,不進行打包
priority: 10
},
utils: { // 抽離自己寫的公共程式碼,utils這個名字可以隨意起
chunks: 'initial',
name: 'utils', // 任意命名
minSize: 0 // 只要超出0位元組就生成一個新包
}
}
}
+ },
plugins: [
new HtmlWebpackPlugin({
filename: 'a.html',
template: './src/index.html', // 以index.html為模板
+ chunks: ['vendor', 'a']
}),
new HtmlWebpackPlugin({
filename: 'b.html',
template: './src/index.html', // 以index.html為模板
+ chunks: ['vendor', 'b']
})
]
}
複製程式碼
通過以上配置,可以把引入到a.js和b.js中的這部分公共程式碼提取出來,如下圖所示
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/5a7a9b3b2f454b35fb3b3cbbd8ef8234041a7b3fc229e743986ab2fe757aca80.png)
指定webpack配置檔案
在package.json的腳步裡,我們可以配置呼叫不同的webpack配置檔案進行打包,舉個栗子
![webpack4-用之初體驗,一起敲它十一遍](https://i.iter01.com/images/f897c9f8bc6a3060cd3b3bead9ce32d21604b3ae88e8730610d32ccf7f6ef611.png)
就到這裡吧
關於webpack4的一些常規操作就說到這裡了,其實在工作當中更多時候,也並不需要我們去配置這些內容
不過我們要爭做優秀的前端兒,所以就必須掌握這些必備的技能,必須會,沒有之一!
好了,就寫到這裡吧,想必大家也看累了吧,辛苦大家了,哈哈。