webpack 是代碼編譯工具,有入口、出口、loader 和插件;webpack 是一個用于 JavasScript 應(yīng)用程序的靜態(tài)模塊打包工具;當(dāng) webpack 處理應(yīng)用程序時會遞歸構(gòu)建一個依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序的每一個模塊,然后將這個模塊打包成一個或者多個 bundle。
webpack 的本質(zhì)是模塊化打包工具,前端所有的資源都應(yīng)當(dāng)看成是一個模塊,通過 webpack 的核心機(jī)制 loader 來處理,然后借助插件機(jī)制 plugin 來形成一個繁榮的生態(tài);
學(xué)習(xí)可參考 webpack 中文文檔;webpack 版本:5.73.0
一、為什么使用 webpack
1、解決作用域問題
問題原因:
傳統(tǒng)的 JavaScript 文件引入方式會在 window 對象上面綁定全局的變量,這也會嚴(yán)重的污染 window 對象,使得 window 對象變的臃腫;
解決辦法:
1、我們早期使用管理項(xiàng)目資源的工具 Grunt 和 Gulp ,他們是將所有項(xiàng)目文件拼接在一起,其實(shí)是使用了 JavaScript 的立即執(zhí)行函數(shù)來解決作用域的問題,立即執(zhí)行函數(shù)簡稱 IIFE ;當(dāng)腳本被封裝在 IIFE 內(nèi)部時,我們可以安全的拼接和組合文件而不必?fù)?dān)心作用域問題。
;(function(){
let test = 'xxx'
})()
console.log(test) //is not defined
let res = (function(){
return 'xxx'
})()
console.log(res) //xxx
上面是一個立即執(zhí)行函數(shù),如果在立即執(zhí)行函數(shù)外面調(diào)用 test,test 是 ‘is not defined’ ,說明在立即執(zhí)行函數(shù)中的變量是不能夠在外部訪問的,這樣就不會污染到 window;如果想暴露一些東西給 window,則可以使用一個變量,將自執(zhí)行函數(shù)賦值給這個變量,然后就可以在 window 中訪問自執(zhí)行函數(shù)的返回值;
2、代碼拆分問題
問題原因:
使用立即執(zhí)行函數(shù),將所有代碼整合到同一個文件中,會造成代碼體積過大,構(gòu)建和加載的適合效率很慢,所有不得不對代碼進(jìn)行拆分;
解決辦法:
commonJS 運(yùn)行是基于 node.js 環(huán)境的,commonJS 的問世引入了一個 require 的機(jī)制,它允許我們在當(dāng)前文件中去加載和使用某個模塊,只導(dǎo)入需要的模塊;
const add = (a,b) => {
return a+b
}
const minus = (a,b) => {
return a-b
}
module.exports = {
add,
minus
}
//引入 serve.js
const math = require(./math.js)
console.log(math.add(1,2)) //3
上面代碼我們通過 module.exports
來暴露對象,使用頁面通過 require 來引入整個 module.exports
暴露出來的對象;需要注意的是 node 需要在 node.js 環(huán)境中運(yùn)行,所以想查看這個效果需要開啟 node 服務(wù):打開控制臺,找到需要運(yùn)行的 JavaScript 文件 serve.js,執(zhí)行 node serve.js
就可以在控制臺看到結(jié)果;
3、讓瀏覽器支持模塊
1、借助 require.js (不夠簡潔)
定義 add 方法,通過 define 暴露出來,define 第一個參數(shù)是一個數(shù)組,里面填寫所需要依賴的文件路徑;在 html 頁面引入 require.js 文件,通過 data-main 來綁定入口文件;在入口文件 main 中,使用require 方法,第一個參數(shù)是所需要的依賴文件,第二個參數(shù)是個方法,你可以在方法中使用add方法,并返回,這個返回值在瀏覽器中是可以查看的;
2、借助 ECMAScript 標(biāo)準(zhǔn)(瀏覽器支持不完整)
//add.jsconst add =(a,b)=> {return a+b}export default add;//html <script type="module>import add from './add.js'</script>
或者
//add.jsexport const add =(a,b)=> {return a+b}//html <script type="module">import { add } from './add.js'</script>
這里需要聲明 script 的 type = 'module'
;同時使用 export(輸出多個)和 export default (輸出單個)暴露出來的方法引入時也有一點(diǎn)差別;
上面這些手段雖然都能解決對應(yīng)的問題,但是會比較麻煩,這里我們就引出 了更加強(qiáng)大的工具 webpack ;它可以打包 JavaScript 應(yīng)用程序,支持 ES 模塊化標(biāo)準(zhǔn)和 commonJS,可以擴(kuò)展支持圖片、字體文件、樣式文件等靜態(tài)資源打包;
4、構(gòu)建工具對比
1、Webpack:適合一些復(fù)雜的應(yīng)用,可以集成很多第三方庫,可以拆分代碼,使用靜態(tài)資源文件,支持 commonJS、esmodule 等模塊化模式;
2、Parcel:零配置,用戶無需做其他的配置,開箱即用;適合簡單的應(yīng)用,并且可以快速的運(yùn)行起來;
3、Rollup:用標(biāo)準(zhǔn)化的格式來編寫代碼(ES6)通過減少無用的代碼來縮小包的體積;一般只能用來打包 JavaScript;適合一些類庫并且只需要引入很少的第三方庫;(Vue,React 框架)
4、Vite:基于 esmodule 構(gòu)建,可以按需編譯,熱模塊更新;可以和 Vue3 完美結(jié)合;
二、webpack 學(xué)習(xí)起步
1、安裝
安裝 webpack 之前需要確保已經(jīng)安裝了 node.js 的最新版本(參考:node版本升級);然后使用 npm 包管理工具來安裝 webpack:
1、全局安裝
//全局安裝webpack webpack-clinpm install webpack webpack-cli --global
//查看webpack是否安裝成功webpack -v
不建議使用全局安裝 webpack,那樣不利于不同項(xiàng)目中使用不同版本的 webpack,也不利于項(xiàng)目的協(xié)調(diào)開發(fā);
2、本地項(xiàng)目安裝
//安裝npm包管理配置文件package.jsonnpm init -y//局部安裝webpack webpack-clinpm install webpack webpack-cli --save-dev
本地項(xiàng)目安裝之前需要閑創(chuàng)建一個 npm 包管理配置文件;安裝好 webpack 之后本地目錄中會生成 node_modules 文件夾,里面就我們引入的依賴包;(切記,文件名不可以是webpack)
webpack-cli 不是必須的,只是用來處理命令行參數(shù)的工具;
2、運(yùn)行打包
1、如果是在全局安裝的 webpack 直接在控制臺執(zhí)行 webpack
就可以開始打包了;
webpack
2、如果是局部安裝的 webpack,上面的運(yùn)行命令就不行了,因?yàn)榫植堪惭b的并沒有加入到系統(tǒng)環(huán)境變量中,所以控制臺找不到 webpack
指令;這個時候我們需要使用下面的命令來運(yùn)行;
npx webpack
npx 依托于 npm ,有了 npm 就可以直接使用 npx;npx 的作用是表示我們可以觀察當(dāng)前文件夾里面是否有我們想要去運(yùn)行的命令,如果沒有就會在這個目錄的上一層目錄中查找;
注意:運(yùn)行打包可以在任意文件夾下面運(yùn)行,運(yùn)行之后生成的 dist 文件夾會在運(yùn)行打包的文件夾下面;
3、自定義 webpack 配置
在根目錄下創(chuàng)建 webpack.config.js 文件,用來配置 webpack 的配置項(xiàng);
const path = require('path')module.exports = {
entry:'./src/index.js', //入口文件路徑
output:{
filename:'bundle.js',//打包后的文件名
path: path.resolve(__dirname,'./dist'),//打包后文件放置的位置
clean:true //每次打包前清空dist文件夾}}
為了獲取絕對路徑,我們需要引入 node.js 的 path 模塊;通過 resolve 來解析路徑,_dirname (兩個下劃線)表示當(dāng)前文件的物理路徑,也就是 webpack.config.js 文件的上一級文件夾;第二個參數(shù)是指定打包文件保存的文件夾;
打包之后的 bundle.js 在 html 文件中通過標(biāo)簽引入就可以正常使用了;
4、自動引入資源
我們可以使用 webpack 插件 HtmlWebpackPlugin
來自動引入打包后的文件,這也就可以避免手動修改文件的路徑; HtmlWebpackPlugin
插件會為你生成一個新的 HTML 文件在 dist 文件夾下,并且自動引入打包后的入口文件(script 標(biāo)簽),以及 CSS( head中的標(biāo)簽內(nèi));
1、安裝插件
npm install --save-dev html-webpack-plugin
2、配置
在 webpack.config.js 文件中加新的配置:
const path = require('path')var HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {
entry:'./src/index.js',
output:{
filename:'bundle.js',//打包后的文件名
path: path.resolve(__dirname,'./dist'),//打包后文件放置的位置
clean:true //每次打包前清空dist文件夾},
plugins:[new HtmlWebpackPlugin({
tempalte:'./index.html',// 模板,根據(jù)指定模板生成新的html
filename:'app.html',//生成文件的名稱
inject:'body'//指定script標(biāo)簽位置})]}
這樣 dist 文件夾中就會生成 bundle.js 的同時還會生成一個 app.html 文件,這個 app.html 文件就是根據(jù) index.html 文件為模板生成的,并且文件自動引入 bundle.js ;
5、mode 選項(xiàng)
為了能在每次修改之后能夠自動編譯,并且讓瀏覽器自動刷新,我們可以搭建一個開發(fā)環(huán)境來實(shí)現(xiàn);
1、source map 實(shí)現(xiàn)代碼調(diào)試
在 webpack.config.js 添加下面配置項(xiàng),實(shí)現(xiàn)精準(zhǔn)定位 bug 行數(shù);
devtool:'inline-source-map'
2、自動編譯
在初次編譯的時候在命令行后面加一個 watch,這也內(nèi)容修改后控制臺就會自動編譯了;
npx webpack --watch
3、webpack-dev-server
webpack-dev-server
提供了一個基本的 web server 并且具有實(shí)時重新加載的功能;
安裝
npm install webpack-dev-server -D
配置
devServer:{
statis:"./dist" //server根目錄}
啟動
npx webpack server//或者npx webpack-dev-server//自動打開瀏覽器npx webpack-dev-server --open
這里可以啟動一個服務(wù),一般是 http://localhost:8080/,然后在瀏覽器訪問這個地址就可以實(shí)現(xiàn)自動更新瀏覽器了;
webpack-dev-server 實(shí)際上并沒有輸出任何的物理文件,它把打包后的 bundle 文件保存在內(nèi)存里面,這也我們的開發(fā)效率提高了,webpack 的編譯效率也提高了;
6、資源模塊 module
在 webpack 出現(xiàn)之前,前端人員會使用 Grunt 、Gulp 等工具來處理資源,將 src 文件夾的文件移動到 dist 或者 build 目錄中;然而 webpack 最出色的功能除了引入 js 還可以使用內(nèi)置的資源模塊;asset modules 來引入任何的其他類型資源,它允許 webpack 打包其他的文件(字體、圖標(biāo));
資源模塊有四種類型:asset modules type
asset/resource:發(fā)送一個單獨(dú)的文件并導(dǎo)出URL;
asset/inline:導(dǎo)出一個資源的 Data URL;
asset/source:導(dǎo)出資源的源代碼;
asset:導(dǎo)出一個資源的 Data URL 和發(fā)送一個單獨(dú)文件之間自動選擇;
6.1、resource 資源
在 webpack.config.js 新增 module 配置項(xiàng);添加 rules 規(guī)則,通過 test 加上正則匹配指定類型的文件;
module:{
rules:[{//規(guī)則
test:/\.png$/, //正則定義加載文件的類型
type:'asset/resource'}]}//頁面使用import imgSrc from './assets/test.png'
這個時候在頁面上引用的時候就會獲取到圖片的路徑;并且在 dist 文件夾下面可以看到我們導(dǎo)出的圖片資源;
如果想修改圖片存放位置和文件名可以進(jìn)行如下操作:
output:{
filename:'bundle.js',//打包后的文件名
path: path.resolve(__dirname,'./dist'),//打包后文件放置的位置
clean:true, //每次打包前清空dist文件夾
assetModuleFilename:'images/[contenthash][ext]' //contenthash 根據(jù)文件的內(nèi)容生成一個hash字符串,ext表示擴(kuò)展名},
或者在 module 中加一個 generator
module:{
rules:[{//規(guī)則
test:/\.png$/, //正則定義加載文件的類型
type:'asset/resource',
generator:{
filename:'images/[contenthash][ext]'}}]}
注意:如果兩處同時設(shè)置了,那么 generator 的優(yōu)先級會更高;
6.2、inline 資源
在 dist 文件夾下面是看不到圖片資源的,因?yàn)檫@種模式只導(dǎo)出了資源的 URL;這個 URL 是 base64 格式的資源路徑;
6.3、source 資源
可以獲取文本的內(nèi)容,常用來獲取 txt 文件的內(nèi)容;
6.4、通用資源類型 asset
在 inline 和 resource 之間自由選擇,默認(rèn)情況下小于 8kb 的文件將會視為 inline 模塊類型,否則視為 resource 模塊類型;也可以通過設(shè)置 parser.dataUrlCondition.maxSize
來修改默認(rèn)文件大?。?/p>
module:{
rules:[{//規(guī)則
test:/\.png$/, //正則定義加載文件的類型
type:'asset',
parser:{//自定義解析器里面的時間
dataUrlCondition:{
maxSize:4*1024*1024}},
generator:{
filename:'images/[contenthash][ext]'}}]}
7、loader
webpack 除了可以使用資源模塊來引入外部資源,還可以使用 loader 來引入其他類型的文件;webpack 只能理解 js 和 json 類型的文件,這是 webpack 自帶的能力, loader 可以讓 webpack 去解析其他類型的文件并且將這些文件轉(zhuǎn)化為有效的模塊,供應(yīng)用程序使用;
loader 的定義在 module rules 下面定義一個 test 來識別那些文件被轉(zhuǎn)換,use 屬性定義在轉(zhuǎn)化的時候使用那個 loader 來進(jìn)行轉(zhuǎn)化;
module:{
rules:[{
test:/\.text/,
use:'raw-loader'}]}
上面這段配置的意思是:webpack 在通過 import、require 去解析一個 .test 文件的時候,在對文件進(jìn)行打包之前先使用 row-loader 轉(zhuǎn)化一下;
7.1、加載 css
1、處理 css
安裝 css-loader style-loader
//將css識別轉(zhuǎn)化,讓webpack可識別npm i css-loader -D//把css放置到頁面 header 標(biāo)簽里面npm i style-loader -D
安裝成功之后在 webpack.config.js 文件的 module 下新增 rules :
rules:[{
test:/\.css$/,
use:['style-loader','css-loader']}]
多個 loader 可以在 use 里面以數(shù)組的形成傳入,loader 執(zhí)行順序從 use 數(shù)組的后面往前面執(zhí)行,先執(zhí)行的 loader 會將結(jié)果返回傳遞給下一個 loader;并且這個先后執(zhí)行順序必須正確,否則不生效;需要先轉(zhuǎn)化 css ,然后將 css 放到頁面上面;
2、處理 less
安裝 less-loader
npm i less-loader less -D
安裝成功之后在 webpack.config.js 文件的 module 下新增 rules :
rules:[{
test:/\.(css|less)$/,
use:['style-loader','css-loader','less-loader']}]
7.2、抽離和壓縮 css
1、抽離
上面我們通過 loader 將 css 放到了 HTML 中,下面我們看一下將 css 單獨(dú)放在一個文件中,然后通過 link 標(biāo)簽去加載;
安裝插件 mini-css-extract-plugin
//webpack5 下才有這個插件npm i mini-css-extract-plugin -D
在 webpack.config.js 引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')//插件使用plugins:{new MiniCssExtractPlugin({
filename:'styles/[contenthash].css' //制定打包后的css存放位置})},module:{
rules:[{
test:/\.(css|less)$/,
use:['MiniCssExtractPlugin.loader','css-loader','less-loader']}]}
使用插件的 loader MiniCssExtractPlugin.loader
替換掉 style-loader
,這也 dist 文件夾會新增一個 styles 文件夾 ,打包后的 css 就會放在這個文件夾內(nèi),并且在 dist/index.html
文件內(nèi)自動引入;
2、壓縮
安裝插件 css-minimizer-webpack-plugin
npm i css-minimizer-webpack-plugin -D
在 webpack.config.js 引入插件:
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')//這個插件不是在plugins中,而是在優(yōu)化配置中做設(shè)置mode:'production',optimization:{
minimizer:[new CssMinimizerPlugin()]}
注意:這個時候的 mode 必須是 production;
7.3、加載 fonts 字體
可以直接借助 asset module 來接收和載入任何類型的資源;
module:{
rules:[{
test:/\.(woff|woff2|eot|ttf|otf)$/i,
type:'asset/resource'}]}
7.4、加載數(shù)據(jù)
json 是默認(rèn)可以正常導(dǎo)入的,但是要導(dǎo)入 CSV、TSV 和 XML 類型的文件數(shù)據(jù)則需要 loader 來幫忙;
安裝 csv-loader xml-loader
npm i csv-loader xml-loader
安裝成功之后在 webpack.config.js 文件的 module 下新增 rules :
module:{
rules:[{
test:/\.(csv|tsv)$/i,
use:['csv-loader']},{
test:/\.xml$/i,
use:['xml-loader']}]}
然后頁面引入這些類型的文件,就可以正常訪問了,XML文件會轉(zhuǎn)化成 js 對象,CSV 文件會轉(zhuǎn)化成一個數(shù)組;
7.5、自定義 JSON 模塊 parser
通過使用自定義 parser 替換特定的 webpack loader ,將 toml、yaml、json5 文件作為 json 模塊導(dǎo)入;
安裝 toml yaml json5
npm i toml yaml json5 -D
安裝成功之后在 webpack.config.js 文件的 module 下新增 rules :
const toml = require('toml')const yaml= require('yaml')const json5 = require('json5')module:{
rules:[{
test:/\.toml$/i,
type:'json',
parser:{
parse: toml.parse }},{
test:/\.yaml$/i,
type:'json',
parser:{
parse: yaml.parse }},{
test:/\.json5$/i,
type:'json',
parser:{
parse: json5.parse }}]}
8、babel-loader
webpack 只能做 js 打包,但是無法轉(zhuǎn)化 js 代碼; babel-loader 的主要任務(wù)是將 ES6 轉(zhuǎn)化成低版本瀏覽器可以使用的代碼;這里需要先安裝三個包:
babel-loader:在 webpack 里面使用 babel 解析 ES6 的橋梁
@babel/core:babel 的核心模塊
@babel/parset-env:babel 預(yù)設(shè),一組 babel 插件的集合(將很多插件安裝到一個插件里)
npm i babel-loader @babel/core @babel/parset-env -D
安裝成功之后還需要安裝 regeneratorRuntime
插件,這個是 webpack 打包生成的全局輔助函數(shù),由 babel 生成,用于兼容 async/await 語法;
//包含regeneratorRuntime 插件運(yùn)行的時候需要的內(nèi)容npm i @babel/runtime -D//需要regeneratorRuntime 的地方自動require導(dǎo)包,然后編譯的時候需要它npm i @babel/plugin-transform-runtime -D
在 webpack.config.js 文件的 module 下新增 rules :
module:{
rules:[{
test:/\.js$/i,
exclude:/node_module/,//不打包node_module里面的js
use:{
loader: 'babel-loader',
options:{//參數(shù)
presets:['@babel/preset-env'],
plugins:[['@babel/plugin-transform-runtime']]}}}]}
9、代碼分離
代碼分離是 webpack 最主要的特性之一,可以將代碼分離到不同的 bundle 中;分離后的文件我們可以按需加載、并行加載;代碼分離可以獲取最小的 bundle ,可以控制資源加載的優(yōu)先級,如果使用合理可以極大的節(jié)省加載時間;常用分離方式有三種:
9.1、配置入口節(jié)點(diǎn)
使用 entry 配置手動的分離代碼;這種方法的問題是如果有多個入口,那么這些多個入口共享的文件會分別在每個包里重復(fù)打包;
const path = require('path')entry:{
index:'./src/index.js',
other:'./src/other.js'},output:{
filename:'[name].bundle.js', //name可以獲取到entry里面入口的key
path:path.resolve(__dirname,'./dist'),}
多個入口,對應(yīng)打包就會打包出多個出口,但是如果 index 和 other 同時使用了 lodash 包,那么在打包的時候會分別將 lodash 包加到 index 和 other 文件中;
9.2、防止重復(fù)
使用 Entry dependencies 或者 SplitChunkPlugin
去重和分離代碼,配置 dependOn option 選項(xiàng),這也可以在多個模塊之間直接共享模塊;
1、 Entry dependencies
const path = require('path')entry:{
index:{import:'./src/index.js',
dependOn:'shared'},
other:{import:'./src/other.js',
dependOn:'shared'},
shared:'lodash' //配置需要共享的模塊},output:{
filename:'[name].bundle.js', //name可以獲取到entry里面入口的key
path:path.resolve(__dirname,'./dist'),}
將 lodash 模塊單獨(dú)打包在 shared 包中,讓 index 和 other 共享;
2、SplitChunkPlugin
const path = require('path')entry:{
index:'./src/index.js',
other:'./src/other.js'},output:{
filename:'[name].bundle.js', //name可以獲取到entry里面入口的key
path:path.resolve(__dirname,'./dist'),},optimization:{
splitChunks:{
chunks:'all'}}
這種方法會自動幫們做代碼分割處理;
9.3、動態(tài)導(dǎo)入
當(dāng)涉及到動態(tài)代碼拆分時,webpack 提供了兩種方法:import()
語法實(shí)現(xiàn)動態(tài)導(dǎo)入、webpack 遺留功能 require.ensure
;這里推薦使用第一種,所以也只介紹第一種方法;
1、import
function get(){return import('lodash').then((default:_)=>{return _.join(['hello','webpack'],' ')})}get.then(res=>{
console.log(res)})
import 函數(shù)調(diào)用完成之后返回的是一個 Promise,所以可以直接使用 then 來鏈?zhǔn)秸{(diào)用;靜態(tài)導(dǎo)入和動態(tài)導(dǎo)入是可以同時工作的;
下面是動態(tài)導(dǎo)入的兩個比較好的應(yīng)用:
9.3.1、懶加載
懶加載也叫按需加載,是優(yōu)化網(wǎng)頁的一種方式;它主要是將代碼在一些邏輯斷點(diǎn)處分離開,在完成某些操作之后立即引入需要的代碼模塊;這也能加快應(yīng)用程序初始加載速度,也能減輕代碼的體積;
//math.jsexport add(a,b){return a+b}//頁面使用const button = document.createElement('button')button.textContent = '+'button.addEventListener('click',()=>{import(/*webpackChunkName:'math'*/'./math.js').then({add}=>{ //注釋這一段是修改打包后文件的名稱
console.log(add(1,2))})})document.body.appendChild(button)
上面這個例子,webpack 會將 math.js 打包成一個公共文件 math.bundle.js,但是在頁面初始化的時候這個文件不回被加載,當(dāng)點(diǎn)擊按鈕的時候才會被加載出來;
注意:我們可以在 import 引入資源的時候添加注釋來為這個文件打包的時候命名:webpackChunkName:'math'
9.3.2、預(yù)加載模塊
webpack4.6.0 以上版本增加了對預(yù)獲取和預(yù)加載的支持;在聲明 import 時,使用下面指令可以讓 webpack 輸出資源提示,來告訴瀏覽器:
prefetch:預(yù)獲取,將來某些導(dǎo)航下可能需要的資源
preload: 預(yù)加載,當(dāng)前導(dǎo)航下可能需要的資源
//math.jsexport add(a,b){return a+b}//頁面使用const button = document.createElement('button')button.textContent = '+'button.addEventListener('click',()=>{import(/*webpackChunkName:'math', webpackPrefetch:true*/'./math.js').then({add}=>{ //注釋這一段是修改打包后文件的名稱
console.log(add(1,2))})})document.body.appendChild(button)
在引入注釋處加上webpackPrefetch:true
,這也在打包的時候就會將 math.bundle.js 文件放到頁面的 link 標(biāo)簽里面,并且標(biāo)明是 prefetch 類型的引入文件;這也瀏覽器就會在首頁內(nèi)容都加載完畢之后網(wǎng)絡(luò)空閑的時候去加載 math.bundle.js;
preload 方法加載的效果和懶加載的差不多,都是在操作之后需要的時候才會下載對應(yīng)資源;
prefetch 方法是在瀏覽器空閑的時候預(yù)先加載好可能需要的資源,與操作無關(guān);
10、緩存
由于獲取資源比較耗費(fèi)時間,瀏覽器會使用一個緩存機(jī)制,通過命中緩存以降低網(wǎng)絡(luò)流量,是網(wǎng)站加載速度更快;然而在部署新版本的時候不改變資源文件名瀏覽器可能會認(rèn)為你沒有更新,就會使用緩存版本;
10.1、配置輸出文件名
output:{
filename:'[name].[contenthash].js'}
在打包時輸出文件名增加一個動態(tài) hash 字符串,這也每次打包的文件名就不回重復(fù)了;
10.2、緩存第三方庫
將第三方庫(lodash)單獨(dú)提取到一個固定名稱的文件中,因?yàn)檫@些庫一般不回做修改,所以可以利用緩存機(jī)制消除請求,減少向 server 獲取資源;(目標(biāo)是第三方共享文件)
optimization:{
splitChunks:{
cacheGroups:{
vendor:{
test:/[\\/]node_module[\\/]/,
name:'vendors',
chunks:'all'}}}}
這樣所有第三方的包就都被放到 vindors.bundle.js 中了;
10.3、將所有的 js 文件放到一個文件夾中
output:{
filename:'scripts/[name].[contenthash].js'}
11、拆分開發(fā)環(huán)境和生產(chǎn)環(huán)境的配置
11.1、公共路徑(publicPath)
我們可以使用公共路徑來指定應(yīng)用程序中所有資源的基礎(chǔ)路徑;默認(rèn)值是空字符串:“” ,webpack-dev-server 也會默認(rèn)從 publicPath 為基準(zhǔn),使用它來決定在哪個目錄下啟用服務(wù),來訪問 webpack 輸出的文件。
output:{
publishPath:'/' //也可以是其他路徑}
11.2、環(huán)境變量
環(huán)境變量可以消除 webpack.config.js 在開發(fā)環(huán)境和生產(chǎn)環(huán)境之間的差異;webpack 的命令行 npx webpack --env 參數(shù)
允許你傳入任意數(shù)量的環(huán)境變量,在 webpack.config.js 文件中可以訪問到這個變量;想要訪問環(huán)境變量 env 必須將 module.exports 轉(zhuǎn)換成一個函數(shù);
將當(dāng)前打包環(huán)境變量設(shè)置為 production:
npx webpack --env production//也可以攜帶一個 key 、valuenpx webpack --env production --env global=local
在 webpack.config.js 文件中獲取環(huán)境變量:
module.exports = (env) =>{
console.log(env)return {
mode: env.production ? 'production' : 'development'}}
結(jié)果:
{ WEBPACK_BUNDLE: true, WEBPACK_BUILD: true, production: true }//攜帶參數(shù){
WEBPACK_BUNDLE: true,
WEBPACK_BUILD: true,
production: true,
global: 'local'}
js 壓縮
webpack 本身可以對 js 文件進(jìn)行壓縮,但是如果我們配置了 css 壓縮,那么原有的 js 壓縮就會失效,這里我們看一下怎么配置 js 壓縮:
安裝插件 terser-weboack-plugin
npm i terser-weboack-plugin -D
在 webpack.config.js 文件中引入使用:
//壓縮const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')const TerserPlugin = require('terser-weboack-plugin')optimization:{
minimizer:{new CssMinimizerPlugin()new TerserPlugin()}}
上面這倆壓縮插件只會在生產(chǎn)環(huán)境中生效,開發(fā)環(huán)境中不會壓縮;
11.3、拆分配置文件
拆分配置文件的目的就是將生產(chǎn)環(huán)境和開發(fā)環(huán)境的配置文件分開,單獨(dú)配置:webpack.config.dev.js、webpack.config.prod.js ;然后統(tǒng)一放到配置文件夾中;
1、開發(fā)環(huán)境
//webpack.config.dev.jsmodule.exports = {
ebtry:{
index:'./src/index.js'},
output:{
filename:'scripys/[name].js',
path:path.resolve(__dirname,'../dist'),
clean:true,
assetModuleFilename:'images/[contenthash][ext]'},
mode:'development',
devtool:'inline-source-map',
devServer:{static:'./dist'},
optimization:{
splitChunks:{
cacheGroups:{
vendor:{
test:/[\\/]node_module[\\/]/,
name:'vendors',
chunks:'all'}}}}}12345678910111213141516171819202122232425262728
開發(fā)環(huán)境不需要清理服務(wù)器緩存,不需要 publicPath,mode 可以直接設(shè)置為 development,需要 devtool,不需要壓縮相關(guān)配置;
我們可以在控制臺運(yùn)行這個配置:
npx webpack -c ./config/webpack.config.dev.js
由于提前設(shè)置的 output.path = path.resolve(__dirname,'../dist')
這個時候打包的 dist 文件夾會替換 config 同級的 dist 文件夾;這個 dist 就可以用于開發(fā)環(huán)境代碼的部署;
2、生產(chǎn)環(huán)境
//webpack.config.prod.jsconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin')const TerserPlugin = require('terser-weboack-plugin')module.exports = {
ebtry:{
index:'./src/index.js'},
output:{
filename:'scripys/[name].js',
path:path.resolve(__dirname,'../dist'),
clean:true,
assetModuleFilename:'images/[contenthash][ext]',
publicPath:'/'},
mode:'production',
optimization:{
minimizer:{new CssMinimizerPlugin()new TerserPlugin()},
splitChunks:{
cacheGroups:{
vendor:{
test:/[\\/]node_module[\\/]/,
name:'vendors',
chunks:'all'}}}},
performance:{//關(guān)閉提示信息
hints:false}}12345678910111213141516171819202122232425262728293031323334
11.4、合并配置文件
由于配置文件開發(fā)環(huán)境和生產(chǎn)環(huán)境中有很多相同的配置,我們可以把相同配置提取到 webpack.config.common.js 文件中;然后再將配置合并:
安裝包 webpack-merge
npx i webpack-merge -D
在 config 文件夾下新增 webpack.config.js 文件:
const { merge } = require('webpack-merge')const common = require('./webpack.config.common.js')const prod= require('./webpack.config.prod.js')const dev= require('./webpack.config.dev.js')module.exports = (env) => {switch(true){case env.development:return merge(common,dev);case env.production:return merge(common,prod);}}
11.5、npm 腳本
每次打包或者啟動服務(wù)時,都需要在命令行輸入一長串的命令,這里我們配置 npm 來簡化命令行;
1、在項(xiàng)目中的 package.json 文件中
"scripts":{"start": "npx webpack serve -c ./config/webpak.config.js --env development"}
在配置 npm 的時候,我們可以省略 npm 或者 npx
"scripts":{"start": "webpack serve -c ./config/webpak.config.js --env development"}
2、在命令行運(yùn)行
npm run start
由于改寫命令行的時候在后面?zhèn)魅肓谁h(huán)境變量,所以這個時候 start 就代表執(zhí)行 development 環(huán)境的打包;
入門部分就到這里了,后面會繼續(xù)深入學(xué)習(xí) webpack!
該文章在 2024/4/3 14:25:59 編輯過