webpack基础学习,各个loader和plugin的具体配置
一、邂逅Webpack
Webpack是什么
webpack是一個靜態(tài)的模塊化打包工具,為現(xiàn)代的JavaScript應(yīng)用程序;
-
打包bundler:webpack可以將幫助我們進(jìn)行打包,所以它是一個打包工具
-
靜態(tài)的static:這樣表述的原因是我們最終可以將代碼打包成最終的靜態(tài)資源(部署到靜態(tài)服務(wù)器);
-
模塊化module:webpack默認(rèn)支持各種模塊化開發(fā),ES Module、CommonJS、AMD等;
-
現(xiàn)代的modern:我們前端說過,正是因為現(xiàn)代前端開發(fā)面臨各種各樣的問題,才催生了webpack的出現(xiàn)和發(fā)展;
二、webpack配置和css處理
webpack配置文件
1、出口、入口的配置
我們可以在根目錄下創(chuàng)建一個webpack.config.js文件,來作為webpack的配置文件:
module.exports = {entry: " 指定入口路徑",output: {filename:"bundle.js", // 出口名字path: '出口路徑'} }2、css-loader的使用
loader是什么
-
loader 可以用于對模塊的源代碼進(jìn)行轉(zhuǎn)換;
-
我們可以將css文件也看成是一個模塊,我們是通過import來加載這個模塊的;
-
在加載這個模塊時,webpack其實并不知道如何對其進(jìn)行加載,我們必須制定對應(yīng)的loader來完成這個功能;
module.rules的配置如下:
-
test屬性:用于對resource(資源)進(jìn)行匹配的,通常會設(shè)置成正則表達(dá)式;
-
use屬性:對應(yīng)的值時一個數(shù)組:[UseEntry]
-
UseEntry是一個對象,可以通過對象的屬性來設(shè)置一些其他屬性
-
loader:必須有一個loader屬性,對應(yīng)的值是一個字符串;
-
options:可選的屬性,值是一個字符串或者對象,值會被傳入到loader中;
-
query:目前已經(jīng)使用options來替代;
-
-
傳遞字符串(如:use: [ 'style-loader' ])是loader 屬性的簡寫方式(如:use: [ { loader: 'style-loader'} ])
-
-
loader屬性:Rule.use: [ { loader } ] 的簡寫。
3、style-loader
當(dāng)我們通過css-loader來加載css文件時,代碼沒有生效。這是因為css-loader只是將.css文件進(jìn)行解析,并不會將解析之后的css插入到頁面中,而style-loader將完成插入style的操作
注意:因為loader的執(zhí)行順序是從右向左(或者說從下到上,或者說從后到前的),所以我們需要將styleloader寫到css-loader的前面;
? ? ? ?use:[{loader:"style-loader"},{loader:"css-loader"}]4、less-loader
? ? ? use:[{loader:"style-loader"},{loader:"css-loader"}{loader:"less-loader"}]5、瀏覽器的兼容性
認(rèn)識browserslist工具
-
Browserslist編寫規(guī)則一:
-
defaults:Browserslist的默認(rèn)瀏覽器(> 0.5%, last 2 versions, Firefox ESR, not dead)。
-
5%:通過全局使用情況統(tǒng)計信息選擇的瀏覽器版本。>=,<和<=工作過。
-
dead:24個月內(nèi)沒有官方支持或更新的瀏覽器。現(xiàn)在是IE 10,IE_Mob11,BlackBerry 10,BlackBerry 7,Samsung 4和OperaMobile12.1。
-
last 2 versions:每個瀏覽器的最后2個版本。
-
配置browserslist
-
方案一:在package.json中配置;
"browserslist": ["last 2 version","not dead","> 0.2%" ] -
方案二:單獨的一個配置文件.browserslistrc文件;
last 2 versionnot dead> 0.2%
6、認(rèn)識postCss工具
PostCSS是一個通過JavaScript來轉(zhuǎn)換樣式的工具,這個工具可以幫助我們進(jìn)行一些CSS的轉(zhuǎn)換和適配,比如自動添加瀏覽器前綴、css樣式的重置;
如何使用
安裝工具:postcss、postcss-cli
npm install postcss postcss-cli -D插件autoprefixer
添加瀏覽器前綴需要安裝autoprefixer
npm install autoprefixer -D直接使用使用postcss工具,并且制定使用autoprefixer
npx postcss --use autoprefixer -o end.css ./src/css/style.csspostcss-loader
-
借助構(gòu)建工具進(jìn)行css處理
-
單獨的postcss配置
在跟目錄下創(chuàng)建postcss.config.js
module.exports = {plugins: [require('autoprefixer')] }-
postcss-preset-env
在項目中配置postcss-loader時,我們一般不使用autoprefixer。而是使用另一插件postcss-preset-env
-
postcss-preset-env也是一個postcss的插件;
-
它可以幫助我們將一些現(xiàn)代的CSS特性,轉(zhuǎn)成大多數(shù)瀏覽器認(rèn)識的CSS,并且會根據(jù)目標(biāo)瀏覽器或者運行時環(huán)境添加所需的polyfill;
-
也包括會自動幫助我們添加autoprefixer(所以相當(dāng)于已經(jīng)內(nèi)置了autoprefixer);
安裝
npm install postcss-preset-env -D使用
module.exports = {plugins: [require('postcss-preset-env')] }三、加載和處理其他資源
1、file-loader
用來處理jpg、png等格式的圖片
-
file-loader的作用就是幫助我們處理import/require()方式引入的一個文件資源,并且會將它放到我們輸出的文件夾中;
安裝
npm install file-loader -D配置:
{test:/\.(png|jpe?g|svg|gif)$/i,use: {loader: "file-loader"} ?}1、文件名稱規(guī)則
對處理后的文件名稱按照一定的規(guī)則進(jìn)行顯示,一般使用PlaceHolders來完成,webpack給我們提供了大量的PlaceHolders來顯示不同的內(nèi)容:
介紹幾個最常用的placeholder:
-
[ext]:處理文件的擴(kuò)展名;
-
[name]:處理文件的名稱;
-
[hash]:文件的內(nèi)容,使用MD4的散列函數(shù)處理,生成的一個128位的hash值(32個十六進(jìn)制);
-
[contentHash]:在file-loader中和[hash]結(jié)果是一致的(在webpack的一些其他地方不一樣,后面會講到);
-
[hash:<length>]:截圖hash的長度,默認(rèn)32個字符太長了;
-
[path]:文件相對于webpack配置文件的路徑;
2、設(shè)置文件名稱和存放路徑
{test:/\.(png|jpe?g|svg|gif)$/i,use: {loader: "file-loader"options: {name: "img/[name].[hash:8].[ext]",outputPath: "img"}} ?}2、url-loader
將較小的文件轉(zhuǎn)換為base64的URI
安裝:
npm install url-loader -D配置:
{test:/\.(png|jpe?g|svg|gif)$/i,use: {loader: "url-loader"options: {name: "img/[name].[hash:8].[ext]",outputPath: "img"}} ?}打包之后的顯示結(jié)果跟file-loader一樣,但是在打包好的dist文件夾中,看不到圖片文件,而是轉(zhuǎn)換為base64格式存儲。
limit屬性
限制轉(zhuǎn)換base64格式的圖片大小(比如小于100kb)
{test:/\.(png|jpe?g|svg|gif)$/i,use: {loader: "url-loader"options: {limit:100 * 1024,name: "img/[name].[hash:8].[ext]",outputPath: "img"}} ?}3、asset module type
1、介紹
-
webpack5之前,加載這些資源我們需要使用一些loader,比如raw-loader 、url-loader、file-loader
-
webpack5之后,我們可以直接使用資源模塊類型(asset module type),來替代上面的這些loader;
資源模塊類型(asset module type),通過添加4 種新的模塊類型,來替換所有這些loader
-
asset/resource發(fā)送一個單獨的文件并導(dǎo)出URL。之前通過使用file-loader 實現(xiàn)
-
asset/inline導(dǎo)出一個資源的data URI。之前通過使用url-loader 實現(xiàn);
-
asset/source導(dǎo)出資源的源代碼。之前通過使用raw-loader 實現(xiàn);
-
asset在導(dǎo)出一個data URI 和發(fā)送一個單獨的文件之間自動選擇。之前通過使用url-loader,并且配置資源體積限制實現(xiàn);
2、使用
? ? {test: /\.(png|jpe?g|svg|gif)$/i,type: "asset/resource",},-
如何自定義文件的輸出路徑和文件名
-
url-loader中的limit限制圖片大小效果
4、加載字體文件
處理特殊字體或者字體圖標(biāo)的使用
我們可以選擇使用file-loader來處理,也可以選擇直接使用webpack5的資源模塊類型來處理;
{test: /\.(woff2?|eot|ttf)$/,type: "asset/resource",generator: {filename: "img/[name].[hash:6][ext]",},},四、認(rèn)識plugin
-
Loader是用于特定的模塊類型進(jìn)行轉(zhuǎn)換;
-
Plugin可以用于執(zhí)行更加廣泛的任務(wù),比如打包優(yōu)化、資源管理、環(huán)境變量注入等;
1、CleanWebpackPlugin
每次修改了一些配置,重新打包時,都需要手動刪除dist文件夾,CleanWebpackPlugin可以幫助我們完成這個功能。
安裝:
npm install clean-webpack-plugin -D配置:
const { CleanWebpackPlugin } = require("clean-webpack-plugin");module.exports = {plugins : [new CleanWebpackPlugin()]};2、HtmlWebpackPlugin
HtmlWebpackPlugin用來對HTML進(jìn)行打包處理
安裝:
npm install html-webpack-plugin -D配置:
const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = {plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({titile: "webpack案例",}),], };3、自定義HTML模板
如果我們想在自己的模塊中加入一些比較特別的內(nèi)容:
-
添加一個noscript標(biāo)簽,在用戶的JavaScript被關(guān)閉時,給予響應(yīng)的提示;
-
比如在開發(fā)vue或者react項目時,我們需要一個可以掛載后續(xù)組件的根標(biāo)簽<div id="app"></div>;
自定義模板數(shù)據(jù)填充
上面的代碼中,會有一些類似這樣的語法<%變量%>,這個是EJS模塊填充數(shù)據(jù)的方式。
在配置HtmlWebpackPlugin時,我們可以添加如下配置:
-
template:指定我們要使用的模塊所在的路徑;
-
title:在進(jìn)行htmlWebpackPlugin.options.title讀取時,就會讀到該信息;
4、DefinePlugin的介紹
當(dāng)在我們的模塊中還使用到一個BASE_URL的常量,我們需要設(shè)置這個常量,這個時候我們可以使用DefinePlugin插件;
使用:
DefinePlugin允許在編譯時創(chuàng)建配置的全局常量,是一個webpack內(nèi)置的插件(不需要單獨安裝):
const { DefinePlugin } = require("webpack"); module.exports = {plugins: [new DefinePlugin({BASE_URL:'"./"' ?// 注意需要多一層包裹})], };5、CopyWebpackPlugin
vue的打包過程中,如果我們將一些文件放到public的目錄下,那么這個目錄會被復(fù)制到dist文件夾中。這個復(fù)制的功能,我們可以使用CopyWebpackPlugin來完成;
安裝:
npm install copy-webpack-plugin -D配置:
-
from:設(shè)置從哪一個源中開始復(fù)制;
-
to:復(fù)制到的位置,可以省略,會默認(rèn)復(fù)制到打包的目錄下;
-
globOptions:設(shè)置一些額外的選項,其中可以編寫需要忽略的文件:
-
.DS_Store:mac目錄下回自動生成的一個文件;
-
index.html:也不需要復(fù)制,因為我們已經(jīng)通過HtmlWebpackPlugin完成了index.html的生成;
-
五、source-map
source-map是從已轉(zhuǎn)換的代碼,映射到原始的源文件。使瀏覽器可以重構(gòu)原始源并在調(diào)試器中顯示重建的原始源
使用:
第一步:根據(jù)源文件,生成source-map文件,webpack在打包時,可以通過配置生成source-map;
第二步:在轉(zhuǎn)換后的代碼,最后添加一個注釋,它指向sourcemap;
//# sourceMappingURL=common.bundle.js.map瀏覽器會根據(jù)我們的注釋,查找響應(yīng)的source-map,并且根據(jù)source-map還原我們的代碼,方便進(jìn)行調(diào)試。
分析source-map
-
version:當(dāng)前使用的版本,也就是最新的第三版;
-
sources:從哪些文件轉(zhuǎn)換過來的source-map和打包的代碼(最初始的文件);
-
names:轉(zhuǎn)換前的變量和屬性名稱(因為我目前使用的是development模式,所以不需要保留轉(zhuǎn)換前的名稱);
-
mappings:source-map用來和源文件映射的信息(比如位置信息等),一串base64VLQ(veriablelengthquantity可變長度值)編碼;
-
file:打包后的文件(瀏覽器加載的文件);
-
sourceContent:轉(zhuǎn)換前的具體代碼信息(和sources是對應(yīng)的關(guān)系);
-
sourceRoot:所有的sources相對的根目錄;
生成source-map
webpack為我們提供了非常多的選項,目前為止是26個,來處理source-map,選擇不同的值,打包形成的代碼會有性能的差異,可以根據(jù)不同情況進(jìn)行選擇
-
不會生成source-map的配置項
-
false:不使用source-map,也就是沒有任何和source-map相關(guān)的內(nèi)容。
-
nnone:production模式下的默認(rèn)值,不生成source-map。
-
eval:development模式下的默認(rèn)值,不生成source-map
-
但是它會在eval執(zhí)行的代碼中,添加//#sourceURL=;
-
它會被瀏覽器在執(zhí)行時解析,并且在調(diào)試面板中生成對應(yīng)的一些文件目錄,方便我們調(diào)試代碼;
-
-
source-map值
生成一個獨立的source-map文件,并且在bundle文件中有一個注釋,指向source-map文件;
bundle文件中有如下的注釋:
//# sourceMappingURL=bundle.js.mapeval-source-map值
eval-source-map:會生成sourcemap,但是source-map是以DataUrl添加到eval函數(shù)的后面
inline-source-map值
inline-source-map:會生成sourcemap,但是source-map是以DataUrl添加到bundle文件的后面
cheap-source-map
cheap-source-map:
-
會生成sourcemap,但是會更加高效一些(cheap低開銷),因為它沒有生成列映射(Column Mapping)
cheap-module-source-map值
會生成sourcemap,類似于cheap-source-map,但是對源自loader的sourcemap處理會更好。
hidden-source-map值
-
會生成sourcemap,但是不會對source-map文件進(jìn)行引用;
-
相當(dāng)于刪除了打包文件中對sourcemap的引用注釋;
nosources-source-map值
會生成sourcemap,但是生成的sourcemap只有錯誤信息的提示,不會生成源代碼文件;
多個值的組合(重要)
事實上,webpack提供給我們的26個值,是可以進(jìn)行多組合的。
組合的規(guī)則如下:
-
inline-|hidden-|eval:三個值時三選一;
-
nosources:可選值;
-
cheap可選值,并且可以跟隨module的值;
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
在開發(fā)中,最佳的實踐是什么呢?
-
開發(fā)階段:推薦使用source-map或者cheap-module-source-map
-
測試階段:推薦使用source-map或者cheap-module-source-map
-
發(fā)布階段:false、缺省值(不寫)
六、Babel深入理解
1、babel是什么東西,用來做什么的
-
Babel是一個工具鏈,主要用于舊瀏覽器或者緩解中將ECMAScript 2015+代碼轉(zhuǎn)換為向后兼容版本的JavaScript;
-
語法轉(zhuǎn)換、源代碼轉(zhuǎn)換、Polyfill實現(xiàn)目標(biāo)緩解缺少的功能等;
Babel命令行使用
-
@babel/core:babel的核心代碼,必須安裝;
-
@babel/cli:可以讓我們在命令行使用babel;
使用babel來處理我們的源代碼:
-
src:是源文件的目錄;
-
--out-dir:指定要輸出的文件夾dist;
插件的使用
比如我們需要轉(zhuǎn)換箭頭函數(shù),那么我們就可以使用箭頭函數(shù)轉(zhuǎn)換相關(guān)的插件:
npm install @babel/plugin-transform-arrow-functions -D npx babel src--out-dirdist--plugins=@babel/plugin-transform-arrow-functions查看轉(zhuǎn)換后的結(jié)果,我們會發(fā)現(xiàn)const 并沒有轉(zhuǎn)成var,這是因為plugin-transform-arrow-functions,并沒有提供這樣的功能,我們需要使用plugin-transform-block-scoping 來完成這樣的功能。
npm install @babel/plugin-transform-block-scoping -D npx babel src--out-dirdist--plugins=@babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functionsBabel的預(yù)設(shè)preset
如果要轉(zhuǎn)換的內(nèi)容過多,一個個設(shè)置是比較麻煩的,我們可以使用預(yù)設(shè)(preset)
安裝 :
npm install @babel/preset-env -D執(zhí)行:
npx babel src--out-dirdist--presets=@babel/preset-env2、Babel的底層原理
工作流程:
-
解析階段(Parsing)
-
轉(zhuǎn)換階段(Transformation)
-
生成階段(CodeGeneration)
流程圖:
3、babel-loader
安裝:
npm install babel-loader @babel/core使用:
module.exports = {module: {rules: [{test:/\.js$/,use: {loader: "babel-loader"}}]} }指定使用的插件
我們必須指定使用的插件才會生效
module: {rules: [{test:/\.js$/,use: {loader: "babel-loader",options: {plugins: ["@babel/plugin-transform-block-scoping","@babel/plugin-transform-arrow-functions"]}}}]}babel-preset
如果我們一個個去安裝使用插件,那么需要手動來管理大量的babel插件,我們可以直接給webpack提供一個preset,webpack會根據(jù)我們的預(yù)設(shè)來加載對應(yīng)的插件列表,并且將其傳遞給babel。
常見的預(yù)設(shè):
-
env
-
react
-
TypeScript
安裝preset-env:
npm install @babel/preset-env {test:/\.js$/,use: {loader: "babel-loader",options: {plugins: ["@babel/plugin-transform-block-scoping","@babel/plugin-transform-arrow-functions"]}} }Babel的Stage-X設(shè)置
在babel7之前(比如babel6中),我們會經(jīng)常看到這種設(shè)置方式:
-
它表達(dá)的含義是使用對應(yīng)的babel-preset-stage-x預(yù)設(shè);
-
從babel7開始,已經(jīng)不建議使用了,建議使用preset-env來設(shè)置;
4、Babel的配置文件
我們可以將babel的配置信息放到一個獨立的文件中,babel給我們提供了兩種配置文件的編寫:
-
babel.config.json(或者.js,.cjs,.mjs)文件;
-
.babelrc.json(或者.babelrc,.js,.cjs,.mjs)文件;
區(qū)別:
-
.babelrc.json:早期使用較多的配置方式,但是對于配置Monorepos項目是比較麻煩的;
-
babel.config.json(babel7):可以直接作用于Monorepos項目的子包,更加推薦;
5、認(rèn)識polyfill
更像是應(yīng)該填充物(墊片),一個補(bǔ)丁,可以幫助我們更好的使用JavaScript;
使用場景:
比如我們使用了一些語法特性(例如:Promise,Generator,Symbol等以及實例方法例如Array.prototype.includes等),但是某些瀏覽器壓根不認(rèn)識這些特性,必然會報錯,我們可以使用polyfill來填充或者說打一個補(bǔ)丁,那么就會包含該特性了;
可以通過單獨引入core-js和regenerator-runtime來完成polyfill的使用:
npm install core-js regenerator-runtime --save {test:/\.m?js$/,exclude:/node_modules/,use:"babel-loader" }配置babel.config.js
我們需要在babel.config.js文件中進(jìn)行配置,給preset-env配置一些屬性:
-
useBuiltIns:設(shè)置以什么樣的方式來使用polyfill;
-
corejs:設(shè)置corejs的版本
-
另外corejs可以設(shè)置是否對提議階段的特性進(jìn)行支持;
-
設(shè)置proposals屬性為true即可;
-
useBuiltIns屬性設(shè)置
-
useBuiltIns屬性有三個常見的值
第一個值:false
-
打包后的文件不使用polyfill來進(jìn)行適配;
-
并且這個時候是不需要設(shè)置corejs屬性的;
第二個值:usage
-
會根據(jù)源代碼中出現(xiàn)的語言特性,自動檢測所需要的polyfill;
-
這樣可以確保最終包里的polyfill數(shù)量的最小化,打包的包相對會小一些;
-
可以設(shè)置corejs屬性來確定使用的corejs的版本;
第三個值:entry
-
如果我們依賴的某一個庫本身使用了某些polyfill的特性,但是因為我們使用的是usage,所以之后用戶瀏覽器可能會報錯,果你擔(dān)心出現(xiàn)這種情況,可以使用entry;
-
需要在入口文件中添加`import 'core-js/stable'; import 'regenerator-runtime/runtime';
-
這樣做會根據(jù)browserslist目標(biāo)導(dǎo)入所有的polyfill,但是對應(yīng)的包也會變大;
-
6、認(rèn)識Plugin-transform-runtime(了解)
在前面我們使用的polyfill,默認(rèn)情況是添加的所有特性都是全局的,如果我們正在編寫一個工具庫,這個工具庫需要使用polyfill,別人在使用我們工具時,工具庫通過polyfill添加的特性,可能會污染它們的代碼,所以,當(dāng)編寫工具時,babel更推薦我們使用一個插件:@babel/plugin-transform-runtime來完成polyfill的功能;
7、React的jsx支持
安裝:
npm install @babel/preset-react -D使用:
presets: [["@babel/preset-env", {useBuiltIns:"usage",corejs: 3.8}],["@babel/preset-react"] ]8、TypeScript的編譯
TypeScript通過compiler來轉(zhuǎn)換成JavaScript
安裝:
npm install typescript -DTypeScript的編譯配置信息我們通常會編寫一個tsconfig.json文件:
tsc --init之后我們可以運行npxtsc來編譯自己的ts代碼:
npx tsc1、使用ts-loader編譯TS
安裝:
npm install ts-loader -D配置:
{test:'/\.ts$/',exclude: /node_modules/,use: ["ts-loader"] }2、使用babel-loader編譯TS
Babel是有對TypeScript進(jìn)行支持
-
我們可以使用插件:@babel/tranform-typescript;
-
但是更推薦直接使用preset:@babel/preset-typescript;
安裝:
npm install @babel/preset-typescript -D配置:
{test:'/\.ts$/',exclude: /node_modules/,use: ["babel-loader"] }七、大數(shù)據(jù)中關(guān)于代碼格式校驗(Eslint和prettierrc )
大數(shù)據(jù)中關(guān)于eslint的配置
/** @Description: eslint 配置* @ 規(guī)則依賴于 @umijs/fabric,在此基礎(chǔ)上,可自行添加自己的規(guī)則進(jìn)行配置* @Author: 賈永昌* @Date: 2022-05-01 13:55:14* @LastEditTime: 2022-05-02 17:35:45*/ module.exports = {extends: [require.resolve('@umijs/fabric/dist/eslint')], ?// in antd-design-proglobals: {ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,page: true,}, ?rules: {// 強(qiáng)制語句有分號結(jié)尾semi: [2, 'always'],// ? 操作符前后必須有空格 bad: 1||2 good: 1 || 2'space-infix-ops': 2,// ? 對象字面量中冒號前面禁止有空格,后面必須有空格 bad: {a :'a'} good:{a: 'a'}'key-spacing': 2,// ? 花括號首尾必須有空格'object-curly-spacing': [2, 'always'],// ? 語句塊(if、function、class、try...catch等的大括號) 的前面必須要有空格'space-before-blocks': 2,// ? 箭頭函數(shù)的箭頭與后面的{}之間需要空格'arrow-spacing': 2,// ? 禁止多余的空格'no-multi-spaces': 2,// ? 禁止代碼行結(jié)束后面有多余空格'no-trailing-spaces': 2,// ? 禁止多余空行'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 1, maxEOF: 1 }],// ? 允許標(biāo)識符中使用懸空下劃線(標(biāo)識符的開頭或末尾的下劃線)'no-underscore-dangle': 0,// ? 允許邏輯短路、三元運算符等表達(dá)式求值'no-unused-expressions': 0,// ? 禁止使用嵌套的三元表達(dá)式'no-nested-ternary': 2,// ? 禁止對函數(shù)參數(shù)再賦值(保證react函數(shù)式編程純函數(shù)的概念)'no-param-reassign': 2,// ? 禁止使用 var 定義變量'no-var': 2,// ? 禁止修改const聲明的變量'no-const-assign': 2,// ? 函數(shù)調(diào)用時 函數(shù)名與()之間不能有空格'no-spaced-func': 2, ?// ? jsx 屬性中強(qiáng)制使用雙引號'jsx-quotes': [2, 'prefer-double'],// ? 禁止 jsx 屬性對象的引用括號里 兩邊加空格'react/jsx-curly-spacing': [2, 'never'],// ? JSX 中前標(biāo)簽傳有屬性換行展示的話,其后面的 > 也需換行對齊展示'react/jsx-closing-bracket-location': 2,// ? 校驗 jsx 中所有換行屬性值縮進(jìn)'react/jsx-indent-props': [2, 2],// ? jsx 中傳入屬性值是Boolean值且為true時,省略傳入'react/jsx-boolean-value': 2,// ? 在 JSX 屬性中禁止等號前后存在空格'react/jsx-equals-spacing': 2, ?// ? 關(guān)閉此規(guī)則,允許 useEffect 的依賴為空數(shù)組'react-hooks/exhaustive-deps': 0, ?// ? 未使用的變量警告提醒'@typescript-eslint/no-unused-vars': ['warn'],// ? 禁用使用在前,保證 useEffct 使用在最前面,這時候里面如果使用了外部的函數(shù)就會報這錯'@typescript-eslint/no-use-before-define': 0,// ? 允許空的 ts 接口定義 eg: interface IProps {}'@typescript-eslint/no-empty-interface': 0,}, }; 大數(shù)據(jù)中 .prettierrc 配置 {"printWidth": 80,"tabWidth": 2,"singleQuote": true,"useTabs": false,"semi": true,"jsxSingleQuote": false,"trailingComma": "all","bracketSpacing": true,"jsxBracketSameLine": false,"arrowParens": "always","requirePragma": false,"insertPragma": false,"proseWrap": "preserve", "htmlWhitespaceSensitivity": "css","overrides": [{"files": ".prettierrc","options": { "parser": "json" }}] }八、DevServer
為什么需要搭建本地服務(wù)器?
我們希望可以做到,當(dāng)文件發(fā)生變化時,可以自動完成編譯和展示
-
webpack watch mode
-
webpack-dev-server
-
webpack-dev-middleware
1、Webpack watch(基本不用)
webpack給我們提供了watch模式:
-
在該模式下,webpack依賴圖中的所有文件,只要有一個發(fā)生了更新,那么代碼將被重新編譯(損耗性能)
開啟watch的兩種方式
-
方式一:在導(dǎo)出的配置中,添加watch: true;
-
方式二:在啟動webpack的命令中,添加--watch的標(biāo)識;
2、webpack-dev-server(必會,常用)
除了可以監(jiān)聽到文件的變化,還可以具備實時重新加載的功能
安裝:
npm install --save-dev webpack-dev-server配置:
"scripts" : {"watch":"webpack --watch""serve":"webpack serve --config wk.config.js" }webpack-dev-server 在編譯之后不會寫入到任何輸出文件。而是將bundle 文件保留在內(nèi)存中:
-
事實上webpack-dev-server使用了一個庫叫memfs(memory-fswebpack自己寫的)
3、webpack-dev-middleware(基本不用)
如果我們想要有更好的自由度,可以使用webpack-dev-middleware;
定義:
webpack-dev-middleware 是一個封裝器(wrapper),它可以把webpack處理過的文件發(fā)送到一個server,webpack-dev-server 在內(nèi)部使用了它,然而它也可以作為一個單獨的package 來使用,以便根據(jù)需求進(jìn)行更多自定義設(shè)置;
4、output的publicPath(outPut中的配置)
output中還有一個publicPath屬性,該屬性是指定index.html文件打包引用的一個基本路徑
-
它的默認(rèn)值是一個空字符串,所以我們打包后引入js文件時,路徑是bundle.js;
-
在開發(fā)中,我們也將其設(shè)置為/,路徑是/bundle.js,那么瀏覽器會根據(jù)所在的域名+路徑去請求對應(yīng)的資源;
-
如果我們希望在本地直接打開html文件來運行,會將其設(shè)置為./,路徑時./bundle.js,可以根據(jù)相對路徑去查找資源;
module.exports = {entry: " 指定入口路徑",output: {filename:"bundle.js", // 出口名字path: '出口路徑'publicPath:'./'} }
5、devServer的publicPath
devServer中也有一個publicPath的屬性,該屬性是指定本地服務(wù)所在的文件夾
-
它的默認(rèn)值是/,也就是我們直接訪問端口即可訪問其中的資源http://localhost:8080
-
如果我們將其設(shè)置為了/abc,那么我們需要通過http://localhost:8080/abc才能訪問到對應(yīng)的打包后的資源
-
并且這個時候,我們其中的bundle.js通過http://localhost:8080/bundle.js也是無法訪問的:
-
所以必須將output.publicPath也設(shè)置為/abc;
-
官方其實有提到,建議devServer.publicPath與output.publicPath相同;
-
6、devServer的contentBase(不常用)
主要作用是如果我們打包后的資源,又依賴于其他的一些資源,那么就需要指定從哪里來查找這個內(nèi)容
-
比如在index.html中,我們需要依賴一個abc.js文件,這個文件我們存放在public文件中
-
在index.html中,我們應(yīng)該如何去引入這個文件
-
比如代碼是這樣的:<script src="./public/abc.js"></script>
-
但是這樣打包后瀏覽器是無法通過相對路徑去找到這個文件夾的;
-
所以代碼是這樣的:<script src="/abc.js"></script>;
-
但是我們?nèi)绾巫屗ゲ檎业竭@個文件的存在呢?設(shè)置contentBase即可
-
7、hotOnly、hos、port、open、compress配置
-
hotOnly是當(dāng)代碼編譯失敗時,是否刷新整個頁面
-
port設(shè)置監(jiān)聽的端口,默認(rèn)情況下是8080
-
host設(shè)置主機(jī)地址
-
open是否打開瀏覽器
-
compress是否為靜態(tài)文件開啟gzip compression
8、Proxy代理(解決跨域問題)注意:在開發(fā)環(huán)境中使用
我們可以將請求先發(fā)送到一個代理服務(wù)器,代理服務(wù)器和API服務(wù)器沒有跨域的問題,就可以解決我們的跨域問題了
配置:
-
target:表示的是代理到的目標(biāo)地址,比如/api-hy/moment會被代理到http://localhost:8888/api-hy/moment;
-
pathRewrite:默認(rèn)情況下,我們的/api-hy也會被寫入到URL中,如果希望刪除,可以使用pathRewrite;
-
secure:默認(rèn)情況下不接收轉(zhuǎn)發(fā)到https的服務(wù)器上,如果希望支持,可以設(shè)置為false;
-
changeOrigin:它表示是否更新代理后請求的headers中host地址;
9、historyApiFallback
-
historyApiFallback是開發(fā)中一個非常常見的屬性,它主要的作用是解決SPA頁面在路由跳轉(zhuǎn)之后,進(jìn)行頁面刷新時,返回404的錯誤。
-
boolean值:默認(rèn)是false
-
如果設(shè)置為true,那么在刷新時,返回404錯誤時,會自動返回index.html的內(nèi)容;
-
-
object類型的值,可以配置rewrites屬性:
-
可以配置from來匹配路徑,決定要跳轉(zhuǎn)到哪一個頁面;
-
九、模塊熱替換(HMR)
什么是HMR
-
HMR的全稱是Hot Module Replacement,翻譯為模塊熱替換;
-
模塊熱替換是指在應(yīng)用程序運行過程中,替換、添加、刪除模塊,而無需重新刷新整個頁面;
如何使用HMR
-
默認(rèn)情況下,webpack-dev-server已經(jīng)支持HMR,我們只需要開啟即可;
-
在不開啟HMR的情況下,當(dāng)我們修改了源代碼之后,整個頁面會自動刷新,使用的是live reloading;
1、開啟HMR
// 在webpack.config.js 中添加以下配置 devserver: {hot:true }同時還需要指定發(fā)生更新的模塊
if(module.hot) {module.hot.accept("./*文件路徑",() => {console.log()}) }2、框架中的HMR
項目中已經(jīng)有非常成熟的方案,別操心了
-
vue開發(fā)中,我們使用vue-loader,此loader支持vue組件的HMR,提供開箱即用的體驗
-
react開發(fā)中,有React HotLoader,實時調(diào)整react組件(目前React官方已經(jīng)棄用了,改成使用reactrefresh);
3、HMR的原理
HMR的原理是什么
-
webpack-dev-server會創(chuàng)建兩個服務(wù):提供靜態(tài)資源的服務(wù)(express)和Socket服務(wù)(net.Socket)
-
express server負(fù)責(zé)直接提供靜態(tài)資源的服務(wù)(打包后的資源直接被瀏覽器請求和解析);
HMR Socket Server,是一個socket的長連接:(想想webSocket,需要及時通信)
-
長連接有一個最好的好處是建立連接后雙方可以通信(服務(wù)器可以直接發(fā)送文件到客戶端)
-
當(dāng)服務(wù)器監(jiān)聽到對應(yīng)的模塊發(fā)生變化時,會生成兩個文件.json(manifest文件)和.js文件(update chunk);
-
通過長連接,可以直接將這兩個文件主動發(fā)送給客戶端(瀏覽器)
-
瀏覽器拿到兩個新的文件后,通過HMR runtime機(jī)制,加載這兩個文件,并且針對修改的模塊進(jìn)行更新;
十、resolve模塊解析
resolve用于設(shè)置模塊如何被解析:
-
resolve可以幫助webpack從每個require/import 語句中,找到需要引入到合適的模塊代碼;
-
webpack 使用enhanced-resolve來解析文件路徑;
webpack能解析三種文件路徑:
-
絕對路徑
-
相對路徑
-
模塊路徑:在resolve.modules中指定的所有目錄檢索模塊,默認(rèn)值是['node_modules'],所以默認(rèn)會從node_modules中查找文件;
1、extensions和alias配置
extensions是解析到文件時自動添加擴(kuò)展名:
-
默認(rèn)值是['.wasm','.mjs','.js','.json'];
配置:
module.exports = {entry: " 指定入口路徑",output: {filename:"bundle.js", // 出口名字path: '出口路徑'},resolve:{extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'],} }
我們可以使用alias給某些常見的路徑起一個別名;
resolve:{extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'],alias: {"@":resolveApp('./src'),pages:resolveApp('./src/pages')}}十一、環(huán)境分離和代碼分離
1、入口文件解析
context的作用是用于解析入口(entry point)和加載器(loader)
默認(rèn)是webpack的啟動目錄
module.exports = {context:path.resolve(__dirname,'./')entry:"../src/index.js" }2、配置文件的分離
-
將原來的webpack.config.js劃分為webpack.comm.conf.js(通用配置)、webpack.dev.conf.js(開發(fā)環(huán)境)、webpack.prod.conf.js(生產(chǎn)環(huán)境)三部分
-
利用mode配置項,區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境。用利用merge將用到的環(huán)境配置和通用配置合并
3、認(rèn)識代碼分離
代碼分離(CodeSplitting)主要的目的是將代碼分離到不同的bundle中,之后我們可以按需加載,或者并行加載這些文件;
Webpack中常用的代碼分離有三種
-
入口起點:使用entry配置手動分離代碼;
-
防止重復(fù):使用EntryDependencies或者SplitChunksPlugin去重和分離代碼;
-
動態(tài)導(dǎo)入:通過模塊的內(nèi)聯(lián)函數(shù)調(diào)用來分離代碼;
1、多入口起點
entry: {index:"./src/index.js",main:"./src/main.js" } output: {filename:"[name].bundle.js",path:resolveApp("./build") }2、EntryDependencies(入口依賴)
假如我們的index.js和main.js都依賴兩個庫:lodash、dayjs
-
如果我們單純的進(jìn)行入口分離,那么打包后的兩個bunlde都有會有一份lodash和dayjs;
entry: {index: {import:"./src/index.js",dependOn:"shared"},main:{import:"./src/main.js",dependOn:"shared"},shared:['lodash','axios'] } output: {filename:"[name].bundle.js",path:resolveApp("./build"),publicPath: "" }
3、SplitChunks
另外一種分包的模式是splitChunk,它是使用SplitChunksPlugin來實現(xiàn)的:
Webpack提供了SplitChunksPlugin默認(rèn)的配置,我們也可以手動來修改它的配置:
-
比如默認(rèn)配置中,chunks僅僅針對于異步(async)請求,我們可以設(shè)置為initial或者all;
4、SplitChunks自定義配置
SplitChunks: {chunks:'all',// 拆分包的大小,至少為minsize// 如果一個包拆分出來不到minsize,那么將不會被拆分minsize:100,// 將大于maxMize的包,拆分成不小于minSize 的包maxsize:1000,// 至少包被引入的次數(shù)minChunks:2,// 最大異步請求數(shù)量maxAsyncRequests:30,// 最大的初始化請求數(shù)量cacheGroups: {venders: {test:/[\\/]node_modules[\\/]/,priority: -10,filename: "[id]_[hash:6]_vendor.js"},foo: {test:/foo/,priority: -20,filename: "foo_[id]_[name]_.js"}} }配置解析:
-
Chunks
-
默認(rèn)值是async
-
另一個值是initial,表示對通過的代碼進(jìn)行處理
-
all表示對同步和異步代碼都進(jìn)行處理
-
-
minSize
-
拆分包的大小, 至少為minSize;
-
如果一個包拆分出來達(dá)不到minSize,那么這個包就不會拆分;
-
-
maxSize
-
將大于maxSize的包,拆分為不小于minSize的包;
-
-
minChunks
-
至少被引入的次數(shù),默認(rèn)是1;
-
如果我們寫一個2,但是引入了一次,那么不會被單獨拆分;
-
-
name:設(shè)置拆包的名稱
-
可以設(shè)置一個名稱,也可以設(shè)置為false;
-
設(shè)置為false后,需要在cacheGroups中設(shè)置名稱;
-
-
cacheGroups
-
用于對拆分的包就行分組,比如一個lodash在拆分之后,并不會立即打包,而是會等到有沒有其他符合規(guī)則的包一起來打包;
-
test屬性:匹配符合規(guī)則的包;
-
name屬性:拆分包的name屬性;
-
filename屬性:拆分包的名稱,可以自己使用placeholder屬性;
-
5、動態(tài)導(dǎo)入(dynamic import)
使用ECMAScript中的import()語法來完成,也是目前推薦的方式;
注意:
-
在webpack中,通過動態(tài)導(dǎo)入獲取到一個對象;
-
真正導(dǎo)出的內(nèi)容,在改對象的default屬性中,所以我們需要做一個簡單的解構(gòu);
動態(tài)導(dǎo)入的文件命名
它的命名我們通常會在output中,通過chunkFilename屬性來命名
output: {filename: "[name].bundle.js",path:resolveApp("./build"),chunkFilename: "chunk_[id]_[name].js" }默認(rèn)情況下我們獲取到的[name]是和id的名稱保持一致的
-
我們希望修改name的值,可以通過magic comments(魔法注釋)的方式
6、optimization.chunkIds配置
optimization.chunkIds配置用于告知webpack模塊的id采用什么算法生成。
-
natural:按照數(shù)字的順序使用id;
-
named:development下的默認(rèn)值,一個可讀的名稱的id;
-
deterministic:確定性的,在不同的編譯中不變的短數(shù)字id
最佳實踐:
-
開發(fā)過程中,我們推薦使用named;
-
打包過程中,我們推薦使用deterministic;
7、optimization. runtimeChunk配置
配置runtime相關(guān)的代碼是否抽取到一個單獨的chunk中:
-
抽離出來后,有利于瀏覽器緩存的策略:
-
設(shè)置的值
-
true/multiple:針對每個入口打包一個runtime文件;
-
single:打包一個runtime文件;
-
對象:name屬性決定runtimeChunk的名稱;
-
8、Prefetch和Preload
-
webpack v4.6.0+增加了對預(yù)獲取和預(yù)加載的支持。
-
prefetch(預(yù)獲取):將來某些導(dǎo)航下可能需要的資源
-
preload(預(yù)加載):當(dāng)前導(dǎo)航下可能需要資源
-
-
區(qū)別
-
preload chunk 會在父chunk 加載時,以并行方式開始加載。prefetch chunk 會在父chunk 加載結(jié)束后開始加載。
-
preload chunk 具有中等優(yōu)先級,并立即下載。prefetch chunk 在瀏覽器閑置時下載。
-
preload chunk 會在父chunk 中立即請求,用于當(dāng)下時刻。prefetch chunk 會用于未來的某個時刻。
-
9、CDN
CDN稱之為內(nèi)容分發(fā)網(wǎng)絡(luò)(ContentDeliveryNetwork或ContentDistributionNetwork,縮寫:CDN)
開發(fā)中的應(yīng)用方式:
-
方式一:打包的所有靜態(tài)資源,放到CDN服務(wù)器,用戶所有資源都是通過CDN服務(wù)器加載的;
-
方式二:一些第三方資源放到CDN服務(wù)器上;
方式一花錢,直接說方式二
一些比較出名的開源框架都會將打包后的源碼放到一些比較出名的、免費的CDN服務(wù)器上
使用方法:
-
第一步,我們可以通過webpack配置,來排除一些庫的打包:
externals: {lodash: "_",dayjs: "dayjs" } -
第二步,在html模塊中,加入CDN服務(wù)器地址:
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.core.js"></script>
10、認(rèn)識shimming
-
shimming是一個概念,是某一類功能的統(tǒng)稱:
-
比如我們現(xiàn)在依賴一個第三方的庫,這個第三方的庫本身依賴lodash,但是默認(rèn)沒有對lodash進(jìn)行導(dǎo)入(認(rèn)為全局存在lodash),那么我們就可以通過ProvidePlugin來實現(xiàn)shimming的效果;
-
-
注意:webpack并不推薦隨意的使用shimming
-
Webpack背后的整個理念是使前端開發(fā)更加模塊化;
-
也就是說,需要編寫具有封閉性的、不存在隱含依賴(比如全局變量)的彼此隔離的模塊;
-
11、MiniCssExtractPlugin
MiniCssExtractPlugin可以幫助我們將css提取到一個獨立的css文件中,該插件需要在webpack4+才可以使用。
安裝:
npm install mini-css-extract-plugin -D配置:
plugins: [new MiniCssExtractPlugin({filename:"css/[name].[contenthash:8].css",chunkfilename: "css/[name].[contenthash:8].css"}) ], module:{rules: [{test:/\.css$/i,use:[MiniCssExtractPlugin.loader,'css-loader']}] }12、Hash、ContentHash、ChunkHash
-
hash值的生成和整個項目有關(guān)系:
-
比如我們現(xiàn)在有兩個入口index.js和main.js;
-
它們分別會輸出到不同的bundle文件中,并且在文件名稱中我們有使用hash;
-
這個時候,如果修改了index.js文件中的內(nèi)容,那么hash會發(fā)生變化;
-
那就意味著兩個文件的名稱都會發(fā)生變化;
-
-
chunkhash可以有效的解決上面的問題,它會根據(jù)不同的入口進(jìn)行借來解析來生成hash值:
比如我們修改了index.js,那么main.js的chunkhash是不會發(fā)生改變的;
-
contenthash表示生成的文件hash名稱,只和內(nèi)容有關(guān)系:
-
比如我們的index.js,引入了一個style.css,style.css有被抽取到一個獨立的css文件中;
-
這個css文件在命名時,如果我們使用的是chunkhash;
-
那么當(dāng)index.js文件的內(nèi)容發(fā)生變化時,css文件的命名也會發(fā)生變化;
-
這個時候我們可以使用contenthash;
-
十二、DLL_Tree Shaking
認(rèn)識DLL庫(了解一下)
-
DLL全程是動態(tài)鏈接庫(Dynamic Link Library),是為軟件在Windows中實現(xiàn)共享函數(shù)庫的一種實現(xiàn)方式;
-
webpack中也有內(nèi)置DLL的功能,它指的是我們可以將可以共享,并且不經(jīng)常改變的代碼,抽取成一個共享的庫;
Terser介紹和安裝(一般使用默認(rèn)配置)
-
Terser是一個JavaScript的解釋(Parser)、Mangler(絞肉機(jī))/Compressor(壓縮機(jī))的工具集;
-
早期我們會使用uglify-js來壓縮、丑化我們的JavaScript代碼,但是目前已經(jīng)不再維護(hù),并且不支持ES6+的語法;
-
-
Terser可以幫助我們壓縮、丑化我們的代碼,讓我們的bundle變得更小。
安裝:
npm install terser -g // 可以進(jìn)行局部安裝,也可以全局安裝命令行使用
terser [input files] [options]常見的配置項:
Compress option
-
arrows:class或者object中的函數(shù),轉(zhuǎn)換成箭頭函數(shù);
-
arguments:將函數(shù)中使用arguments[index]轉(zhuǎn)成對應(yīng)的形參名稱;
-
dead_code:移除不可達(dá)的代碼(tree shaking);
-
等等其他屬性,詳情看官方文檔
Mangle option
-
toplevel:默認(rèn)值是false,頂層作用域中的變量名稱,進(jìn)行丑化(轉(zhuǎn)換)
-
keep_classnames:默認(rèn)值是false,是否保持依賴的類名稱;
-
keep_fnames:默認(rèn)值是false,是否保持原來的函數(shù)名稱;
Terser在webpack中配置使用
-
(注意)真實開發(fā)中,我們不需要手動的通過terser來處理我們的代碼,我們可以直接通過webpack來處理:
-
在webpack中有一個minimizer屬性,在production模式下,默認(rèn)就是使用TerserPlugin來處理我們的代碼的;
-
如果我們對默認(rèn)的配置不滿意,也可以自己來創(chuàng)建TerserPlugin的實例,并且覆蓋相關(guān)的配置;(基本不會手動配置)
-
CSS的壓縮
安裝:
npm install css-minimizer-webpack-plugin -D在optimization.minimizer中配置:
minimizer: [new CssMinimizerplugin({parallel: true}) ]提升作用域 Scope Hoisting
-
Scope Hoisting從webpack3開始增加的一個新功能,功能是對作用域進(jìn)行提升,并且讓webpack打包后的代碼更小、運行更快;
-
默認(rèn)情況下webpack打包會有很多的函數(shù)作用域,Scope Hoisting可以將函數(shù)合并到一個模塊中來運行
-
使用:
-
在production模式下,默認(rèn)這個模塊就會啟用;
-
在development模式下,我們需要自己來打開該模塊;
-
Tree Shaking
定義:最早的想法起源于LISP,用于消除未調(diào)用的代碼(純函數(shù)無副作用,可以放心的消除,這也是為什么要求我們在進(jìn)行函數(shù)式編程時,盡量使用純函數(shù)的原因之一)
webpack實現(xiàn)TreeShaking
兩種方法:
-
在optimization中配置usedExports為true,來幫助Terser進(jìn)行優(yōu)化;
-
在package.json中配置sideEffects,直接對模塊進(jìn)行優(yōu)化;
usedExports
在usedExports設(shè)置為true時,會有一段注釋:unused harmony export mul,這段注釋告知Terser在優(yōu)化時,可以刪除掉這段代碼
注意:
-
配置該屬性時,需要將mode設(shè)置為development模式
-
usedExports實現(xiàn)tree Shaking是結(jié)合terse來完成的
sideEffects
sideEffects用于告知webpack compiler哪些模塊時有副作用的(副作用的意思是這里面的代碼有執(zhí)行一些特殊的任務(wù),不能僅僅通過export來判斷這段代碼的意義;)
-
在package.json中設(shè)置sideEffects的值:
-
false:告知webpack可以安全的刪除未用到的exports;
-
如果有一些希望保留,可以設(shè)置數(shù)組
-
CSS實現(xiàn)TreeShaking
我們可以使用一個庫來完成CSS的Tree Shaking:PurgeCSS,幫助我們刪除未使用的CSS的工具
安裝:
npm install purgecss-webpack-plugin -D配置:
-
paths:表示要檢測哪些目錄下的內(nèi)容需要被分析,這里我們可以使用glob;
-
默認(rèn)情況下,Purgecss會將我們的html標(biāo)簽的樣式移除掉,如果我們希望保留,可以添加一個safelist的屬性;
-
purgecss也可以對less文件進(jìn)行處理(所以它是對打包后的css進(jìn)行tree shaking操作)
HTTP壓縮
定義:HTTP壓縮是一種內(nèi)置在服務(wù)器和客戶端之間的,以改進(jìn)傳輸速度和帶寬利用率的方式
流程:
第一步:HTTP數(shù)據(jù)在服務(wù)器發(fā)送前就已經(jīng)被壓縮了
第二步:兼容的瀏覽器在向服務(wù)器發(fā)送請求時,會告知服務(wù)器自己支持哪些壓縮格式
第三步:服務(wù)器在瀏覽器支持的壓縮格式下,直接返回對應(yīng)的壓縮后的文件,并且在響應(yīng)頭中告知瀏覽器;
目前的壓縮格式
-
compress–UNIX的“compress”程序的方法(歷史性原因,不推薦大多數(shù)應(yīng)用使用,應(yīng)該使用gzip或deflate);
-
deflate–基于deflate算法(定義于RFC1951)的壓縮,使用zlib數(shù)據(jù)格式封裝;
-
gzip–GNUzip格式(定義于RFC1952),是目前使用比較廣泛的壓縮算法;
-
br–一種新的開源壓縮算法,專為HTTP內(nèi)容的編碼而設(shè)計;
Webpack對文件壓縮
webpack中相當(dāng)于是實現(xiàn)了HTTP壓縮的第一步操作,我們可以使用CompressionPlugin。
安裝:
npm install compression-webpack-plugin -D配置:
new CompressionPlugin({test:/\.(css|js)$/, ?// 匹配哪些文件需要壓縮threshold:500, // 設(shè)置文件多大開始壓縮minRatio: 0.7, // 至少采用的壓縮比例algorithm: "gzip" // 采用的壓縮算法 })HTML文件中代碼的壓縮
我們之前使用了HtmlWebpackPlugin插件來生成HTML的模板,事實上它還有一些其他的配置:
-
inject:設(shè)置打包的資源插入的位置
-
true、false、body、head
-
-
cache:設(shè)置為true,只有當(dāng)文件改變時,才會生成新的文件(默認(rèn)值也是true)
-
minify:默認(rèn)會使用一個插件html-minifier-terser
InlineChunkHtmlPlugin
可以輔助將一些chunk出來的模塊,內(nèi)聯(lián)到html中
安裝
npm install react-dev-utils -D在production的plugins中進(jìn)行配置:
module.exports = {plugin:[new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/])] }十三、webpack打包分析
分析一:打包的時間分析
speed-measure-webpack-plugin 可以幫助我們看到每一個loader、每一個plugin的打包時間
安裝:
npm install speed-measure-webpack-plugin -D配置:
const smp = new SpeedMeasurePlugin(); cpnst webpackConfig = smp.wrap({plugins: [new MyPlugin(),new MyOtherPlugin()] })分析二:打包后文件分析
使用webpack-bundle-analyzer工具
安裝:
npm install webpack-bundle-analyzer -D配置
module.exports = {plugins: [new BundleAnalyzerPlugin()] }Compiler和Compilation的區(qū)別(面試題)
-
Compiler中webpack構(gòu)建的之初就會創(chuàng)建的一個對象, 并且在webpack的整個生命周期都會存在(before -run -beforeCompiler-compile -make -finishMake-afterCompiler-done)
-
只要是做webpack的編譯, 都會先創(chuàng)建一個Compiler
-
-
Compilation是到準(zhǔn)備編譯模塊(比如main.js), 才會創(chuàng)建Compilation對象
-
watch -> 源代碼發(fā)生改變就需要重新編譯模塊
-
主要是存在于compile -make 階段主要使用的對象
-
-
Compiler可以繼續(xù)使用(如果我修改webpack的配置, 那么需要重新執(zhí)行run run build)
-
Compilation需要創(chuàng)建一個新的Compilation對象
總結(jié)
以上是生活随笔為你收集整理的webpack基础学习,各个loader和plugin的具体配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务器系统清理工具,服务器清理内存工具
- 下一篇: 【BMI指数计算器V4.0】项目实战