欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:前端 Webpack學(xué)習(xí)記錄

柚子快報激活碼778899分享:前端 Webpack學(xué)習(xí)記錄

http://yzkb.51969.com/

記錄學(xué)習(xí)筆記,歡迎指正

1.大型項(xiàng)目為什么需要打包

1.1 使用打包工具原因

編譯或轉(zhuǎn)譯文件:

項(xiàng)目中可能用到ES6語法,可能有瀏覽器不支持。需要打包工具將代碼編譯輸出為ES5語法的代碼。項(xiàng)目中可能使用Sass,Less等預(yù)處理器,瀏覽器本身并不支持。需要打包工具將代碼編譯輸出為CSS代碼。同編譯器的特點(diǎn),打包工具具有編譯器可以優(yōu)化代碼。

處理模塊:

大型項(xiàng)目可以劃分為若干模塊,模塊的開發(fā)需要依賴規(guī)范。例如UMD,AMD,CMD,ESM規(guī)范。瀏覽器默認(rèn)不支持除了ESM的規(guī)范,需要打包工具將項(xiàng)目打包成js文件,css文件后通過入口文件引入。

注意:編譯和轉(zhuǎn)譯的區(qū)別?

編譯是將高級程序語言的代碼轉(zhuǎn)為低級程序語言的代碼,例如匯編代碼,或者適合于某種虛擬機(jī)上運(yùn)行的代碼。轉(zhuǎn)譯是將高級程序語言的代碼轉(zhuǎn)為另一種高級程序語言的代碼。嚴(yán)格來說babel應(yīng)該稱之為轉(zhuǎn)譯器。

注意:webpack的能力包含編譯CSS,Typescript等文件嗎?

webpack本身功能比較局限只能編譯JavaScript和Json文件,將模塊進(jìn)行處理。編譯ES6,Sass,Less等需要webpack安裝其它的loader加載器。

注意:為什么使用ESM規(guī)范還需要打包?

避免頻繁網(wǎng)絡(luò)請求:

如果使用ESM規(guī)范但不打包,那么每使用一個模塊都要重新請求,頻繁請求會影響瀏覽器緩存效率,導(dǎo)致緩存命中率低。 如果使用ESM規(guī)范但打包,那么可以把模塊聚集在一個或屈指可數(shù)的幾個文件中,不會讓瀏覽器頻繁請求文件 提升兼容性:

大部分瀏覽器都支持ESM規(guī)范,但是考慮可能有低版本瀏覽器不支持,或支持度低。

2.包管理工具常識

2.1 開發(fā)環(huán)境和生產(chǎn)環(huán)境

開發(fā)環(huán)境:

項(xiàng)目未打包時運(yùn)行的環(huán)境。依賴于開發(fā)時依賴和生產(chǎn)時依賴的包。

生產(chǎn)時依賴的包可以流向開發(fā)時依賴,可以通過集合的包含關(guān)系來理解。如果想移動生產(chǎn)時依賴的包到開發(fā)時依賴,直接執(zhí)行 npm i sylvester -D類似的命令即可。 通常webpack配置全局變量process.env.NODE_ENV為development。

生產(chǎn)環(huán)境:

項(xiàng)目打包后運(yùn)行的環(huán)境。依賴于生產(chǎn)時依賴的包。

開發(fā)時依賴的包不能流向生產(chǎn)時依賴,可以通過集合的包含關(guān)系來理解。如果想移動包,那么只能刪除開發(fā)時依賴的指定包,之后再在生產(chǎn)時依賴中重新安裝。 通常webpack配置全局變量process.env.NODE_ENV為production。

舉例:

例如用于代理前綴的修改。通常為了便于做反向代理,會把所有JavaScript發(fā)起的請求的URL添加前綴做統(tǒng)一代理。如果不使用項(xiàng)目中統(tǒng)一封裝的網(wǎng)絡(luò)請求,例如使用window.location.href下載文件,并且生產(chǎn)環(huán)境下前后端都塞入tomcat,不存在跨域,那么可以通過process.env.NODE_ENV來判斷環(huán)境來決定是否添加前綴。

2.2 包的常用指令

npm install/add/i/ins…

空: 安裝開發(fā)時依賴和生產(chǎn)時依賴的所有包。 某個包: 默認(rèn)使用–save命令安裝這個包。 –save或-S + 某個包: 安裝生產(chǎn)時依賴,記錄到package.json的dependencies中。

舉例: react,ahooks,styled-components注意: 安裝包時默認(rèn)是–save指令是為了保證項(xiàng)目的正常運(yùn)行。如果默認(rèn)安裝到開發(fā)時環(huán)境或全局環(huán)境,那么如果交付遠(yuǎn)程服務(wù)器打包時,可能導(dǎo)致缺少必要的包。 –save-dev或-D + 某個包: 安裝開發(fā)時依賴,記錄到package.json的devDependencies中。

舉例: webpack,typescript,jest,eslint注意: 生產(chǎn)時依賴和開發(fā)時依賴不存在交集,因此無法同時將某個包安裝到兩個環(huán)境中,即 npm install sylvester -D -S不會同時安裝到兩個環(huán)境。 –global或-g + 某個包: 安裝到全局環(huán)境。

注意:

項(xiàng)目之間的依賴最好是獨(dú)立管控的,不推薦全局安裝。如果項(xiàng)目要使用遠(yuǎn)程服務(wù)器打包(打包后交付測試或部署上線)走自動化流程,那么遠(yuǎn)程服務(wù)器打包時找不到你在本地全局安裝的包,因?yàn)槟悴粫阉涗浀絧ackage.json中 –no-save + 某個包: 安裝依賴。但不記錄到開發(fā)時依賴和生產(chǎn)時依賴。

注意: 這通常用于測試某個第三方依賴,并且你的同事暫時不會安裝它。不過這并不是妥當(dāng)?shù)姆椒?,因?yàn)槟憧赡芫帉懸蕾囉谶@個第三方依賴的代碼,如果你提交代碼,會導(dǎo)致其他人報錯。推薦的方法是應(yīng)該新拉一個分支,或者新建一個項(xiàng)目來進(jìn)行測試。 –force或-f (+ 某個包): 強(qiáng)制安裝。 –production: 只安裝生產(chǎn)時依賴。

注意:

只是依據(jù)package.json安裝生產(chǎn)時依賴,安裝新依賴時使用該命令將被忽視。因此這個命令的表現(xiàn)和 npm update的表現(xiàn)類似,可以用來更新依賴。不論在什么環(huán)境下webpack打包都會依賴開發(fā)時依賴和生產(chǎn)時依賴,因此交付遠(yuǎn)程服務(wù)器打包時應(yīng)該使用 npm install而不是 npm install --production目前沒有只安裝開發(fā)時依賴的指令,因?yàn)殚_發(fā)環(huán)境依賴于開發(fā)時依賴和生產(chǎn)時依賴,只安裝開發(fā)時依賴沒有任何意義。

**npm update **

空: 忽略開發(fā)時依賴的更新,只更新生產(chǎn)時的依賴。其它與安裝時指令類似,如果想指定也更新開發(fā)時依賴,可以添加特殊指令。

npm uninstall/rm

與安裝時指令類似

2.3 包版本計算器

版本命名規(guī)范:

2.3.5-beta.3

..-.

major: 大版本minor: 小版本(可選)patch: 補(bǔ)丁版本(可選)prerelease_tag: 預(yù)發(fā)布標(biāo)簽(可選)

alpha: 內(nèi)測版本beta: 公測版本rc: 候選版本pre: 前面的三個數(shù)字類型的版本不足以標(biāo)識修改時使用pre prerelease_version: 預(yù)發(fā)布版本(可選)

版本前綴含義:

*: 允許升級到任何版本。^: 不超過左邊非零數(shù)字

舉例:

^2.3.1表示 2.3.1 <= version < 3.0.0^0.3.1表示 0.3.1 <= version < 0.4.0^0.0.1表示 0.0.1 <= version < 0.0.2 ~: 允許補(bǔ)丁版本升級到任意發(fā)布的版本。

舉例:

~2.3.1表示 2.3.1 <= version < 2.4.0~2.3表示 2.3.0 <= version < 2.4.0~2表示 2.0.0 <= version < 2.1.0 >,<,>=,<=: 按符號字面意思表示版本允許升級的范圍。

模糊版本更新機(jī)制:

npm install忽略模糊版本

npm update更新到最新模糊版本

2.4 包執(zhí)行者

npx + 包 + 包對應(yīng)的指令

npx是包執(zhí)行者,在項(xiàng)目里npx會去node_modules/.bin中尋找包的執(zhí)行程序執(zhí)行。例如我沒有全局安裝webpack,只是在項(xiàng)目中用npm安裝,并且我想執(zhí)行webpack的指令,那么我可以使用npx。

舉例:

無webpack.config.js:npx webpack ./src/main.js --mode=development 有webpack.config.js:npx webpack

3.Webpack核心配置點(diǎn)

3.1 概述

entry(入口): 打包入口,從一個或多個入口打包

output(輸出): 打包文件輸出位置

loader(加載器): webpack本身只能編譯JavaScript處理模塊化。編譯CSS等其它資源需要借助loader。

plugins(插件): 擴(kuò)展webpack的功能。

devServer(服務(wù)器): 開發(fā)模式下運(yùn)行項(xiàng)目并熱更新。

mode(模式): 開發(fā)模式development和生產(chǎn)模式production。

3.2 Output

3.2.1 配置入口文件輸出位置

Node全局變量和方法:

__dirname:__dirname返回當(dāng)前文件所在文件夾的絕對路徑 __filename: __filename返回當(dāng)前文件的絕對路徑 path.resolve: 負(fù)責(zé)解析路徑。

將若干個表示相對路徑的參數(shù)拼接到當(dāng)前文件所在的文件夾的絕對路徑上如果有參數(shù)是絕對路徑,那么忽略最后一個絕對路徑前的參數(shù)

module.exports = {

output: {

path: path.resovle(__dirname, "dist")

filename: "static/js/main.js"

}

}

3.2.2 配置自動清空上次打包效果

module.exports = {

output: {

clean: true

}

}

3.3 loader

3.3.1 配置樣式loader

解析順序: loader可以通過配置use屬性進(jìn)行鏈?zhǔn)秸{(diào)用,默認(rèn)規(guī)定鏈表頭是數(shù)組尾部,因此loader是從右向左解析。

module.exports = {

module: {

rules: [

{

test: /\.css$/,

use: ["style-loader", "css-loader"]

},

{

test: /\.less$/,

use: ["style-loader", "css-loader", "less-loader"],

},

{

test: /\.s[ac]ss$/,

use: ["style-loader", "css-loader", "sass-loader"],

},

{

test: /\.styl$/,

use: ["style-loader", "css-loader", "stylus-loader"],

},

]

}

}

3.3.2 配置樣式兼容性loader

在package.json中配置需要兼容的瀏覽器,否則兼容性loader不會生效

// package.json中配置需要兼容的瀏覽器

{

"browserslist": {

"last 2 version" // 匹配的瀏覽器的最近的兩個版本

"> 1%" // 全球用戶使用率超過1%的瀏覽器

"not dead" // 不考慮官方聲明已經(jīng)不再維護(hù)的瀏覽器

}

}

配置css兼容性loader

樣式兼容性loader的位置: 在css-loader后面,在css預(yù)解析器loader的前面配置loader的方式: 在use中直接寫loader名稱表示使用默認(rèn)配置,使用對象方式寫loader和options可以自定義配置

const getStyleLoader = (pre) => {

return [

MiniCssExtractPlugin.loader,

"css-loader",

// 在use中直接寫loader的名稱表示使用默認(rèn)配置,下面是通過options自定義配置,配置依據(jù)來源于官網(wǎng)

{

loader: "postcss-loader",

options: {

postcssOptions: {

plugins: ["postcss-preset-env"],

},

},

},

pre,

].filter(Boolean);

}

module.exports = {

module: {

rules: [

{

test: /\.css$/,

use: getStyleLoader()

},

{

test: /\.less$/,

use: getStyleLoader("less-loader")

},

{

test: /\.s[ac]ss$/,

use: getStyleLoader("sass-loader")

},

{

test: /\.styl$/,

use: getStyleLoader("stylus-loader")

},

]

}

}

3.3.3 配置腳本兼容性loader

配置babel-loader??梢院蜆邮郊嫒菪詌oader類比:

都是處理兼容性的loader都用到了自定義配置自定義配置都可以提出來形成獨(dú)立的配置文件

{

test: /\.js$/,

// 不處理的文件

exclude: /node_modules|bower_components/,

use: {

loader: "babel-loader",

// 也可以寫?yīng)毩⑽募abel.config.js來配置下述內(nèi)容

options: {

presets: ["@babel/preset-env"],

},

},

}

3.3.4 配置資源loader

配置資源輸出路徑: generator中的filename指定了輸出的文件名或路徑。

有效配置: 只有設(shè)置了type為資源類型 asset, asset/resource, ...的文件配置輸出路徑才有效。無效配置: 如果給css或者css預(yù)解析文件配置輸出路徑是無效的,這些loader的行為是把css輸出到j(luò)s文件中,因此不會輸出css文件,因此不會有文件在期望的輸出路徑生成。但是你可以借助plugin擴(kuò)展loader的能力來完成這個行為。 資源打包成DataUrl形式: 資源打包成DataUrl可以避免發(fā)請求。

DataUrl形式: [編碼類型]<編碼數(shù)據(jù)>文件轉(zhuǎn)為DataUrl體積會變大,但是文件較小時轉(zhuǎn)成DataUrl的增長率較小,比較適合。如果文件較大,不適合轉(zhuǎn)DataUrl,會導(dǎo)致體積大幅度上升。其中編碼類型可以base64編碼,未編碼等編碼形式可轉(zhuǎn)化類型: 設(shè)置 type: asset會編碼成base64,需要配置一下DataUrl,什么大小才轉(zhuǎn)base64編碼的DataUrl。type: asset/resource不會進(jìn)行轉(zhuǎn)DataUrl形式。

module.exports = {

modules: {

rules: [

// 圖片文件

{

test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,

type: 'asset',

parser: {

// 小于100KB的圖片解析為內(nèi)置資源dataUrl形式

dataUrlCondition: {

maxSize: 100 * 1024,

},

},

generator: {

// name: 文件名

// hash: 生成文件的唯一標(biāo)識

// 10: 限制hash長度最多為10

// ext: 擴(kuò)展名

// query: 查詢參數(shù)

filename: 'images/[name][hash:10][ext][query]',

},

},

// 字體文件

{

test: /\.(woff|woff2|eot|ttf|otf)$/i,

type: 'asset',

generator: {

filename: 'fonts/[name][hash][ext]',

},

},

]

}

}

3.4 plugin

3.4.1 配置開發(fā)規(guī)范plugin

webpack配置

const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = {

plugins: [

new ESLintPlugin({

// eslint檢測的文件夾

context: path.resolve(__dirname, "../src"),

})

]

}

.eslintrc配置

注意: eslint配置文件.eslintrc.js一般放在根目錄下。配置完后立即生效,在開發(fā)代碼時會自動調(diào)用解析器檢查是否符合配置的規(guī)范。

配置說明:

extends: 配置要繼承的eslint配置文件。

舉例: 下面的配置繼承于 eslint:recommended,之后又添加了部分自定義配置。也可以安裝 eslint-config-react-app來繼承于 react-app。 env: 配置代碼運(yùn)行的環(huán)境。

舉例: 下面配置node環(huán)境和browser環(huán)境,那么代碼可能會運(yùn)行在這兩個環(huán)境上,那么eslint在做檢查時要支持對應(yīng)環(huán)境上的全局變量。 parser: 配置eslint調(diào)用的解析器。默認(rèn)解析器是Espree。

舉例: 即使配置parserOptions,Espree也會判定在函數(shù)中使用import動態(tài)加載模塊是錯誤的。那么這時可以更換parser,例如babel-eslint或@typescript-eslint/parser parserOptions: 修改parse的配置。

舉例: Espree默認(rèn)檢查es5語法,項(xiàng)目如果用es6規(guī)范的代碼,那么需要指定ecmaVersion支持對應(yīng)版本的語法。sourceType指定文件的模塊系統(tǒng),是module模塊還是單獨(dú)的script腳本。 rules: 修改eslint的檢查規(guī)則。核心配置內(nèi)容。

舉例:

每個配置項(xiàng)都對應(yīng)著值 0, 1, 2和off, warn, error。表示命中該規(guī)則時“在文件中的表現(xiàn)”和“本地服務(wù)器上的表現(xiàn)”,例如文件中顯示黃色波浪線,紅色波浪線,不阻塞服務(wù)器運(yùn)行,但是輸出提示,阻塞服務(wù)器運(yùn)行。下面的配置表示使用var聲明變量時會報警告。聲明變量后未使用會報警告。 plugins: 擴(kuò)展eslint能力。

舉例: 配置插件使eslint可以檢查JSX。這樣擴(kuò)展了rules內(nèi)容,eslint本身的所有rules可以在官網(wǎng)上查到配置,安裝插件可以提供新的校驗(yàn)?zāi)芰托r?yàn)選項(xiàng)。例如安裝eslint-plugin-react,提供JSX和react框架風(fēng)格的相關(guān)檢查。

module.exports = {

extends: ["eslint:recommended"],

env: {

node: true,

browser: true,

},

parser: "@typescript-eslint/parser",

parserOptions: {

ecmaVersion: 2020,

sourceType: "module"

},

plugins: ["@typescript-eslint"],

rules: {

// 使用var做警告

"no-var": "warn",

// 未使用的變量做警告

"no-unused-vars": "warn",

},

};

3.4.2 配置文檔輸出plugin

配置輸出HTML的原因: 沒有配置前打包輸出沒有html文件,只是在public文件夾中的入口html文件中配置引入腳本的位置。如果打包后的腳本名稱發(fā)生變化的話又需要重新配置引入比較麻煩。

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {

plugins: [new HtmlWebpackPlugin({

// 不使用默認(rèn)位置,自定義輸出位置

template: path.resolve(__dirname, "../public/index.html")

})]

}

3.4.3 配置提取樣式plugin

提取CSS文件的原因: 如果使用style-loader來實(shí)現(xiàn)CSS-In-JS的方式,進(jìn)入頁面時會有閃動效果。先解析js,解析完成后再通過style標(biāo)簽插入樣式,由無樣式的效果到有樣式的效果導(dǎo)致了頁面閃動。注意事項(xiàng): 用插件的loader代替style-loader

const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = {

modules: {

// 用MiniCssExtractPlugin.loader代替style-loader避免把CSS輸出到JS中

rules: [

{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] },

{

test: /\.less$/,

use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],

},

{

test: /\.s[ac]ss$/,

use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],

},

{

test: /\.styl$/,

use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],

},

]

}

plugins: [

new MiniCssExtractPlugin({

// 不用默認(rèn)輸出位置,指定輸出位置

filename: "static/css/main.css",

})

]

}

3.4.4 配置壓縮樣式plugin

是否要安裝壓縮其它資源的plugin: js壓縮在生產(chǎn)模式下打包webpack會默認(rèn)輸出壓縮后的js (使用的Terser),配置輸出html的插件并且在生產(chǎn)模式下打包webpack也會默認(rèn)輸出壓縮后的html,但是css不會默認(rèn)壓縮,需要安裝壓縮樣式的plugin

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {

plugins: [new CssMinimizerPlugin()]

}

3.5 devServer

3.5.1 配置熱更新服務(wù)器

// 開發(fā)服務(wù)器:不會輸出打包內(nèi)容到dist

devServer: {

host: "localhost",

port: "3000",

// 是否自動打開瀏覽器

open: true,

// 是否只局部重新構(gòu)建修改的文件,如果為false,那么已修改就會重新打包所有內(nèi)容(默認(rèn)值就是true)

hot: true

}

3.6 mode

3.6.1 開發(fā)模式和生產(chǎn)模式

需要配置mode為development或production,這會影響打包結(jié)果是否壓縮

舉例: 網(wǎng)上說可以在根目錄新建一個config文件夾來保存生產(chǎn)和開發(fā)環(huán)境的webpack配置文件。個人覺得使用一份webpack配置文件即可,在內(nèi)部進(jìn)行環(huán)境判斷即可。 開發(fā)模式不需要指定output的輸出目錄,開發(fā)模式下一般采用webpack-dev-server服務(wù)器運(yùn)行,會將打包結(jié)果輸入內(nèi)存。

注意: 熱更新會導(dǎo)致頻繁打包來更新打包后的文件,webpack-dev-server將文件輸出到內(nèi)存可以提高IO讀寫效率

3.7 內(nèi)部過程

3.7.1 Module

Module是模塊,指的是文件,不是webpack運(yùn)行時內(nèi)部過程的概念。

模塊支持性: webpack支持多種模塊系統(tǒng),例如ESM,AMD,CommonJS等。

模塊類型:

模塊一定是文件。如果通過import從某個js文件中導(dǎo)入了一個函數(shù),那么函數(shù)不會被視為webpack模塊,函數(shù)所在的js文件將被視為模塊。 模塊不一定是js文件,在ESM系統(tǒng)中import可以導(dǎo)入各種資源,css文件,圖片等都可以被視為webpack模塊。

3.7.2 Chunk

Chunk定義:

Chunk是webpack打包的內(nèi)部過程中的概念,Chunk表示塊,是一種文件,產(chǎn)生在webpack的輸入到輸出過程中。

Chunk產(chǎn)生方式:

根據(jù)入口產(chǎn)生的依賴圖: 將文件系統(tǒng)看做圖,那么默認(rèn)情況下每個打包入口的所有可達(dá)節(jié)點(diǎn)的集合都會被裝載到一個chunk中。根據(jù)按需加載: 例如在ESM系統(tǒng)中每個 import()導(dǎo)入的模塊都會被裝載到一個新chunk中。這么做的意圖是將按需加載的模塊放到不同chunk中,然后輸出不同的bundle,最后在使用某個按需加載的模塊時就會發(fā)請求新的bundle文件,以此實(shí)現(xiàn)按需加載。

注意: 這是一個理想情況,chunk和bundle不一定是一一對應(yīng)的,默認(rèn)情況下它們是一對一,如果有特殊配置,例如code split,那么會有不同的對應(yīng)關(guān)系。因此真正按需加載時你想請求模塊A,可能也會同時請求到模塊B和模塊C,因?yàn)槟憧赡軐ε渲昧薱hunk組,使部分模塊打包到一個chunk中,最后使得按需加載的模塊都在一個bundle中。

舉例: chunk和bundle不一定是一一對應(yīng)的。下圖描述了一個chunk可以對應(yīng)多個最終輸出的bundle。如果使用了上文提到的提取樣式的插件就會有改效果。![外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳 根據(jù)代碼分割: 如果使用了下文提到的代碼分割來做優(yōu)化,那么將會按照配置規(guī)則來將模塊轉(zhuǎn)載到chunk中,可能導(dǎo)致一個模塊被裝到多個chunk的情況。

產(chǎn)生Chunk的時機(jī):

產(chǎn)生的chunk并不只是對代碼塊進(jìn)行組裝或拆分。產(chǎn)生chunk時,loader和plugin的大部分工作已經(jīng)完成了。chunk到bundle的過程主要是optimization配置和部分plugin配置在發(fā)揮作用,例如MiniCssExtractPlugin將css提取成單獨(dú)文件。

注意: code split只是控制生成chunk的規(guī)則,并不控制chunk到bundle的生成規(guī)則。

3.7.3 Bundle

bundle是文件,表示webpack最終輸出的文件。bundle不是webpack運(yùn)行時的內(nèi)部概念。

3.7.4 Chunk和Bundle的對應(yīng)關(guān)系

參考Chunk中的描述

4.Webpack優(yōu)化

4.1 開發(fā)體驗(yàn)優(yōu)化

使用 devtool中不同 source-map報錯信息和源代碼進(jìn)行對應(yīng),否則報錯信息會直接指向打包后的代碼。不同的 source-map記錄的報錯信息精度不同,因此打包時編譯的速度會受到影響。

開發(fā)模式: cheap-module-source-map

錯誤信息精確到行打包速度快 生產(chǎn)模式: source-map

錯誤信息精確到行和列打包速度比上面的慢

4.1.1 cheap-module-source-map

報錯信息精確到行

下圖中顯然是args.reduce調(diào)用時出錯,但是波浪線從第二行開頭開始。不能精確到從args開始。

報錯信息精確到行不代表不會顯示列信息,下圖顯示了錯誤在源代碼第二行第一列。只是這個列不夠精確,默認(rèn)就是第一列。

映射建立方式

打包后文件片段

對應(yīng)的源文件片段

打包后會生成json格式的.map映射文件描述映射關(guān)系。其中mappings描述了映射關(guān)系。指的是打包后文件到源文件的映射。

這里翻譯成js形式可以解讀為:

return args.reduce(function (sum, item) {映射到 args.reduce((sum, item) => (isNaN(item) ? sum : sum + item), 0)(); return isNaN(item) ? sum : sum + item;映射到 args.reduce((sum, item) => (isNaN(item) ? sum : sum + item), 0)(); }, 0)();映射到 args.reduce((sum, item) => (isNaN(item) ? sum : sum + item), 0)();

從編譯原理的角度理解:

詞法分析階段只記錄源代碼的行信息到詞素(token)上。行信息傳遞到語法分析階段生成的抽象語法樹上。依據(jù)抽象語法樹生成中間代碼時,中間代碼的每個詞素都能記憶源代碼的行信息。并且保證中間代碼某一行的詞素都對應(yīng)源代碼的同一行,否則換行。編譯完成后根據(jù)輸出代碼每行詞素記憶的行信息,建立.map映射文件,方便代碼出錯時快速定位到源文件。

4.1.2 source-map

報錯信息精確到行和列

與source-map相比,波浪線可以精確到調(diào)用語句??刂婆_報錯信息可以精確到調(diào)用語句所在的列。

映射建立方式

和cheap-module-source-map一樣都會建立.map映射文件,效果和上面一樣。

翻譯一下就是建立了詞素到詞素的映射關(guān)系,詞素到詞素的映射細(xì)粒度比行到行的映射細(xì)粒度小很多,所以生成的map文件也會大一些。

為什么生產(chǎn)模式下不能用cheap-module-source-map?

如果生成模式下使用cheap-module-source-map會導(dǎo)致無法精確定位錯誤信息到源文件,并且也不會生成.map映射文件。生產(chǎn)模式下js代碼是壓縮的,只有一行。從編譯原理的角度來講,即使代碼只有一行那也不影響我做映射,因?yàn)樵~法分析階段記錄的映射是精確到詞素(token)級別的。但是問題出在cheap-module-source-map工具上,它只會根據(jù)詞素記錄的行信息來建立行到行映射,即建立細(xì)粒度更大更模糊的映射。壓縮后的代碼可能只有一行,所以映射只會有一條,所以無法精確定位。并且不論詞法分析階段記錄再多信息也沒用,因?yàn)樽詈笾粫∫恍〔糠中畔⒆瞿:挠成洹?/p>

4.2 提升打包構(gòu)建速度

4.2.1 模塊熱更新—HotModuleReplacement

配置devServer

設(shè)置hot屬性為true,當(dāng)文件修改時只局部重新構(gòu)建。設(shè)置為false時,文件一旦修改就會對整個項(xiàng)目重新構(gòu)建。

hot屬性無法針對js文件。如果修改js可以局部重新構(gòu)建,那么可以考慮安裝vue-hot-loader或react-hot-laoder。

4.2.2 匹配唯一Loader一oneOf

配置loader

生產(chǎn)環(huán)境和開發(fā)環(huán)境都適用。如果不配置oneOf,那么處理css文件時能命中第一個loader,但是命中完成后還會向后遍歷看是否能命中其它loader。如果文件很多時,打包的時間復(fù)雜度的常數(shù)會很大。oneOf是一種優(yōu)化常數(shù)的方法。

rules: [

{

oneOf: [

{

test: /\.css$/,

use: getStyleLoader(),

},

{

test: /\.less$/,

// 類比上述過程,那就是先把less轉(zhuǎn)為css-loader,然后重復(fù)上述過程

use: getStyleLoader("less-loader"),

},

{

test: /\.s[ac]ss$/,

use: getStyleLoader("sass-loader"),

},

{

test: /\.styl$/,

use: getStyleLoader("stylus-loader"),

},

// 激活內(nèi)置的loader(見文檔外部資源模塊)

{

test: /\.(png|jpe?g|gif|webp)$/,

// 大圖盡量不轉(zhuǎn)base64,base64增長率太大。小圖片轉(zhuǎn)base64,base64增長率比較小,可以接受。

type: "asset",

parser: {

dataUrlCondition: {

// 小于300KB的圖片會轉(zhuǎn)base64以節(jié)省請求數(shù)量。(300KB有點(diǎn)大,是因?yàn)楸镜貨]有小圖)。

// 并且重新打包不會刪除之前資源,所以刪除dist后重新打包即可。

maxSize: 10 * 1024,

},

},

generator: {

// 輸出圖片名稱(也可以是路徑)

// hash: 圖片名稱(唯一的)。下面的是10表示只取前十位

// ext: 文件擴(kuò)展名

// query: url查詢參數(shù)

filename: "static/images/[hash:10][ext][query]",

},

},

{

test: /\.(woff|woff2|eot|ttf|otf)$/i,

type: "asset/resource",

generator: {

filename: "static/media/[hash:10][ext][query]",

},

},

// babel

{

test: /\.js$/,

// 不處理的文件

exclude: /node_modules|bower_components/,

use: {

loader: "babel-loader",

// 也可以寫?yīng)毩⑽募abel.config.js

// options: {

// presets: ["@babel/preset-env"],

// },

},

},

],

},

],

4.2.3 包含和排除—Include/Exclude

一般只針對js文件做處理,例如babel和eslint。并且要注意include和exclude只能存在一個。

// babel

module.exports = {

module: {

rules: [

{

test: /\.js$/,

// 不處理的文件

exclude: /node_modules|bower_components/,

// 處理的文件(exclude和include只能使用一種)

// include: path.resolve(__dirname, '../src')

use: ["babel-loader"],

}

]

}

}

// eslint

module.exports = {

plugins: [

new ESLintPlugin({

// 檢測的文件夾

context: path.resolve(__dirname, "../src"),

// 不處理的文件

exclude: 'node_modules'

})

]

}

4.2.4 緩存—Cache

使用緩存原因

打包文件中往往都是js占比最大,并且每個js都會經(jīng)過Eslint插件和Babel加載器編譯。因此在重新構(gòu)建時可以緩存上次編譯結(jié)果,為重復(fù)構(gòu)建提速。

module.exports = {

module: {

rules: [

{

oneOf: [

// babel

{

test: /\.js$/,

exclude: /node_modules|bower_components/,

use: {

loader: "babel-loader",

options: {

// 開啟babel緩存

cacheDirectory: true,

// 不壓縮緩存文件(壓縮會影響速度,壓縮只會減少緩存占用的存儲空間)

cacheCompression: false,

},

},

}

]

}

]

},

plugins: [

// eslint

new ESLintPlugin({

context: path.resolve(__dirname, "../src"),

exclude: "node_modules",

// 開啟緩存

cache: true,

// 緩存位置

cacheLocation: path.resolve(__dirname, "../node__modules/.cache/eslintcache")

})

]

}

4.2.5 多進(jìn)程—Thread

對JS處理的loader或plugin進(jìn)行多線程優(yōu)化

下面對:(1)babel(2)eslint(3)terser(4)cssMinimizer做了多進(jìn)程優(yōu)化

注意: 關(guān)于優(yōu)化的插件可以放到optimization屬性的配置中。例如代碼壓縮,代碼分割,tree shaking等等。

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

const TerserWebpackPlugin = require("terser-webpack-plugin");

const threads = 4

module.exports = {

// babel

module: {

oneOf: [

{

test: /\.js$/,

exclude: /node_modules|bower_components/,

use: [

{

// 安裝thread-loaders,開啟多進(jìn)程對babel做處理

loader: "thread-loader",

options: {

// 進(jìn)程數(shù)量

works: threads,

},

},

{

loader: "babel-loader",

options: {

cacheDirectory: true,

cacheCompression: false,

},

},

],

},

]

},

plugins: [

new ESLintPlugin({

context: path.resolve(__dirname, "../src"),

exclude: "node_modules",

cache: true,

cacheLocation: path.resolve(

__dirname,

"../node_modules/.cache/eslintcache"

),

// 開啟多進(jìn)程

threads,

}),

],

optimization: {

minimizer: [

// 壓縮css

new CssMinimizerPlugin(),

// 壓縮js

new TerserWebpackPlugin({

// 開啟多進(jìn)程對JavaScript壓縮優(yōu)化

parallel: threads,

}),

]

}

}

4.3 減少代碼體積

4.3.1 移除未使用代碼—Tree Shaking

tree shaking是webpack的默認(rèn)行為。如果一個模塊導(dǎo)出了若干內(nèi)容,但是其中有某些內(nèi)容沒有被其余模塊使用,那么不會被打包最后的文件。

舉例: 假設(shè)main.js是項(xiàng)目的入口文件,在其中引用了add函數(shù),但是從main開始打包,沒有任何其余文件引用util中的mul函數(shù),那么最后只會有add函數(shù)被打進(jìn)包。

util.js

export const add = (a, b) => a + b

export const mul = (a, b) => a * b

main.js

import { add } from './util'

console.log(add(1, 2))

4.3.2 禁止引入的方法直接注入—babel

普通babel導(dǎo)致的問題: 正常情況下,假設(shè)項(xiàng)目中多個文件引入了lodash的debounce做防抖,按之前的打包配置,babel會把debounce方法實(shí)現(xiàn)的代碼直接注入到每個引用它的模塊中,這導(dǎo)致了debounce的代碼重復(fù)出現(xiàn)了很多次。解決方案: 安裝插件@babel/plugin-transform-runtime在babel-loader中使用,可以把注入的行為轉(zhuǎn)為引用,實(shí)際上公共代碼就出現(xiàn)一次。注意(代碼復(fù)用針對對象問題):這個babel插件只是針對輔助函數(shù),例如Object.assign,Promise等等。并不能處理我們自定義的函數(shù)或組件,復(fù)用這些自定義代碼塊需要通過配置splitchunk實(shí)現(xiàn)。

module.exports = {

module: {

oneOf: [

// babel

{

test: /\.js$/,

exclude: /node_modules|bower_components/,

use: [

{

loader: "thread-loader",

options: {

works: threads,

},

},

{

loader: "babel-loader",

options: {

cacheDirectory: true,

cacheCompression: false,

// 減少代碼體積

plugins: ["@babel/plugin-transform-runtime"],

},

},

],

}

]

}

}

4.3.3 壓縮圖片—Image Minimizer

可以配置Image Minimizer在打包時對圖片進(jìn)行壓縮。這個優(yōu)化操作配置比較麻煩。需要安裝該插件,image-minimizer-webpack-plugin,可以在webpack官網(wǎng)上查看相關(guān)配置。

4.4 優(yōu)化代碼運(yùn)行性能

4.4.1 代碼分割—Code Split

Code Split定義:

回顧一下上文提到的Chunk的概念,而Code Split主要用于控制生成Chunk,那么Code Split主要應(yīng)用于

多入口: 打包設(shè)置多個入口分割插件: 根據(jù)Code Split配置分割代碼生成新Chunk按需加載: 遇到按需加載直接分割代碼生成新Chunk。注(產(chǎn)生過多小chunk問題):大型項(xiàng)目中路由很多,動態(tài)加載的代碼很多,可能導(dǎo)致分割出很多小chunk,這通過splitchunk插件無法控制,需要使用webpack內(nèi)置的limitchunk插件控制數(shù)量

Code Split通信:

背景:

瀏覽器不能直接支持AMD,CMD等模塊系統(tǒng)。假如代碼分割導(dǎo)致打包后產(chǎn)生了A和B兩個js文件,并且A文件需要引用B文件的某些代碼塊,這會怎么實(shí)現(xiàn)?

原理:

查看打包后文件(例如要求輸出UMD格式)發(fā)現(xiàn)每個文件都是一個封閉的作用域,無法直接通信。那么A要引用B中代碼時,先請求B的資源,請求完后放入頁面執(zhí)行B的腳本,B會把自己導(dǎo)出的內(nèi)容掛載到全局對象上。不同模塊引用代碼塊通過全局對象進(jìn)行通信。

Code Split默認(rèn)配置:

需要注意,在生產(chǎn)模式和開發(fā)模式下默認(rèn)值會有些出入

字段取值默認(rèn)值含義chunks‘a(chǎn)sync’|‘a(chǎn)ll’| ‘initial’async代碼分割應(yīng)用的場景: 表示代碼分割默認(rèn)應(yīng)用場景。默認(rèn)為async,只對按需加載生效。all表示對所有模塊生效。initial表示對入口和按需加載生效。minSizenumber20000分割時,chunk的最小大?。?表示當(dāng)前chunk超過該大小后會自動分割出新chunk。單位是byte,默認(rèn)在20kb左右。minRemainingSizenumber0分割后,chunk的最小大?。?表示分割后不能生成過小的chunk。默認(rèn)為0,表示分割后的chunk大小不做限制。minChunksnumber1分割后,chunk的最小引用次數(shù): 表示分割后的chunk被其它c(diǎn)hunk引用的最小次數(shù)。默認(rèn)是1,該條件默認(rèn)生效,表示默認(rèn)可分割。注(無法復(fù)用問題):如果SPA應(yīng)用只打出一個chunk,chunk中有很多復(fù)用代碼塊,如果設(shè)置minChunks大于1不會觸發(fā)公共代碼塊分割maxAsyncRequestsnumber30分割后,產(chǎn)生的chunk的最大數(shù)量: 指的是按需加載文件生成的chunk過大,需要進(jìn)一步拆分成多個chunk,限制進(jìn)一步拆分chunk的數(shù)量。maxInitialRequestsnumber30分割后,產(chǎn)生的chunk的最大數(shù)量: 指的是入口文件生成的chunk過大,需要進(jìn)一步拆分成多個chunk。顯然這對異步加載模塊無效,因?yàn)楫惒郊虞d模塊已經(jīng)分到另一個chunk里面了,使用的是maxAsyncRequests配置。enforceSizeThresholdnumber50000cacheGroups配置哪些代碼可以打包到一個組里

module.exports = {

optimization: {

splitChunks: {

chunks: 'async',

minSize: 20000,

minRemainingSize: 0,

minChunks: 1,

maxAsyncRequests: 30,

maxInitialRequests: 30,

enforceSizeThreshold: 50000,

cacheGroups: {

defaultVendors: {

test: /[\\/]node_modules[\\/]/,

priority: -10,

reuseExistingChunk: true,

},

default: {

minChunks: 2,

priority: -20,

reuseExistingChunk: true,

},

},

},

}

}

4.4.2 提取公共模塊—代碼分割—Code Split

回顧一下上文提到的Chunk的概念,Code Split主要用于控制生成Chunk,那么Code Split主要方式是

多入口: 打包設(shè)置多個入口分割插件: 根據(jù)Code Split配置分割代碼生成新Chunk按需加載: 遇到按需加載直接分割代碼生成新Chunk。

除此之外Code Split可以用于指定哪些代碼需要打包到一個Chunk中,可以借助這個能力來復(fù)用代碼塊(4.3.2中提到)。

module.exports = {

splitChunks: {

cacheGroups: {

// node_modules中代碼都打包到vendors塊中

vendors: {

test: /[\\/]node_modules[\\/]/,

priority: -10,

chunks: 'all',

name: 'vendors'

},

// common中代碼都打包到common塊中

common: {

test: /[\\/]packages\/common[\\/]/,

priority: -10,

chunks: 'all',

name: 'common'

},

// sfa中代碼都打包到sfa塊中

sfa: {

test: /[\\/]packages\/sfa[\\/]/,

priority: -10,

chunks: 'all',

name: 'sfa'

},

// 其它代碼打包規(guī)則

// reuseExistingChunk: true 表示開啟打包時代碼復(fù)用

default: {

// minChunks為1表示SPA中只要存在代碼復(fù)用就可以分割出去

minChunks: 1,

priority: -20,

reuseExistingChunk: true

}

}

},

},

}

4.4.3 緩存優(yōu)化—runtimeChunk

背景:

在代碼分割后,我們某次迭代可能只修改部分文件,這樣導(dǎo)致打包后的對應(yīng)chunk發(fā)生變化,并且文件hash值變化。但是實(shí)際不是這樣,這會導(dǎo)致入口chunk的緩存失效。

運(yùn)行時:

導(dǎo)致這個問題的原因是每個入口chunk中都會保存webpack運(yùn)行時的配置,比如模塊加載邏輯。如果代碼觸發(fā)了Code Split,那么這部分代碼將描述每個模塊對應(yīng)的hash值文件名。如果其中某個模塊的hash值改變就會導(dǎo)致這部分代碼刷新,從而導(dǎo)致入口chunk被修改,最后導(dǎo)致緩存無法復(fù)用。

解決方案:

配置runtimeChunk,指定從入口chunk提取出運(yùn)行時文件。

module.exports = {

optimization: {

runtimeChunk: {

name: (entryPoint) => `runtime~${entryPoint.name}.js`

}

}

}

代碼中有app和main兩個打包入口,配置runtimeChunk后生成了兩個runtime文件。這樣修改52,743,847這幾個chunk時就不會導(dǎo)致main或app的chunk緩存失效了。

優(yōu)點(diǎn):

多入口: 多入口時可以設(shè)置值runtimeChunk為single,把所有運(yùn)行時代碼提取到一個runtime文件中。如果多個入口中的依賴圖中存在相同節(jié)點(diǎn),那么將會復(fù)用運(yùn)行時配置,不需要在每個入口chunk中指明依賴圖中的chunk名稱,減少代碼量。緩存值: 不論是多入口還是單入口,抽取運(yùn)行時配置都可以避免修改chunk時使入口chunk的緩存失效。

柚子快報激活碼778899分享:前端 Webpack學(xué)習(xí)記錄

http://yzkb.51969.com/

推薦鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18945438.html

發(fā)布評論

您暫未設(shè)置收款碼

請?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄