項(xiàng)目的線上版本我們一般都會(huì)結(jié)合構(gòu)建工具(webpack
)插件和服務(wù)端配置(nginx
)來實(shí)現(xiàn) http 傳輸 的 gzip 壓縮盲厌,目的就是把服務(wù)端響應(yīng)的文件的體積盡量減小坚俗,優(yōu)化返回速度。那這件事具體是怎么實(shí)現(xiàn)的呢尸昧?
http 傳輸中 gzip 壓縮的原理
客戶端(瀏覽器)在請求靜態(tài)資源(js揩页、css等)的時(shí)候,在請求頭 Request Header 里帶上 accept-encoding
字段來表明接受哪些壓縮方法烹俗, 如accept-encoding: gzip, deflate
爆侣;服務(wù)端在接收到請求時(shí)如果發(fā)現(xiàn)有這個(gè)配置,則發(fā)送gzip壓縮版本的文件幢妄,并在響應(yīng)頭 Response Headers 配置一個(gè) content-encoding
字段兔仰,用于說明服務(wù)端數(shù)據(jù)的壓縮方法(可選值是gzip、compress蕉鸳、deflate
)乎赴,否則(沒有accept-encoding
)就發(fā)送源文件;客戶端再根據(jù)返回響應(yīng)頭里 content-encoding
對應(yīng)的格式去做相應(yīng)的解碼/解壓縮潮尝;沒有content-encoding
項(xiàng)則不進(jìn)行解壓縮榕吼。
accept-encoding
和content-encoding
字段都非常語義化,就是傳輸?shù)奈募栽鯓拥母袷骄幋a/解碼勉失,所以當(dāng)響應(yīng)頭有content-encoding: gzip
出現(xiàn)友题,就能說明我們服務(wù)端的gzip壓縮成功開啟了。如下:
同時(shí)我們還能看到壓縮后的文件 size戴质,記得先在Chrome瀏覽器的 Network 下勾選 ??Use large request rows
誰來壓縮文件度宦?
(1) 服務(wù)端響應(yīng)請求時(shí)壓縮
如果我們在服務(wù)器用Nginx代理部署項(xiàng)目,就直接讓 nginx 來處理壓縮告匠,它有專門為此構(gòu)建的內(nèi)容戈抄,可以更好地利用緩存并減少開銷。我們要做的只是在服務(wù)端的 nginx.conf
做好配置后专,其他就不需要我們操心了划鸽。
配置參數(shù)可參考:Nginx的gzip配置文檔
# 開啟gzip壓縮
gzip on;
gzip_buffers 4 16k; # 置用于壓縮響應(yīng)的緩沖區(qū)的數(shù)量和大小
gzip_comp_level 9; # 對響應(yīng)壓縮的級別,可選范圍:1到9戚哎,數(shù)字越大壓縮得越好裸诽,但也越占用CPU時(shí)間
gzip_http_version 1.1; # 默認(rèn) 1.1,請求壓縮響應(yīng)所需的最小HTTP版本
gzip_min_length 1k; # 設(shè)置被gzip的響應(yīng)的最小長度型凳,小于該值的文件不會(huì)被壓縮
# 追加啟用gzip壓縮的MIME類型丈冬,默認(rèn)已有text/html
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on; # 默認(rèn)off,如果指令gzip甘畅、gzip_static或gunzip是active的埂蕊,啟用插入" Vary: Accept-Encoding "響應(yīng)報(bào)頭字段
具體配置位置展示
(2) 項(xiàng)目打包構(gòu)建生產(chǎn)版本時(shí)壓縮
既然服務(wù)端都可以做壓縮往弓,為什么在 webpack 打包應(yīng)用時(shí)還要多此一舉呢?我們可以看上面 nginx 配置中 gzip_comp_level
這個(gè)配置項(xiàng)蓄氧,數(shù)字越大壓縮效果越好函似,但是會(huì)耗費(fèi)更多的CPU和時(shí)間,我們壓縮文件主要是為了減少傳輸時(shí)間喉童,如果每次請求靜態(tài)資源服務(wù)端都要壓縮很久才會(huì)返回信息撇寞,不僅本末倒置嗎?況且服務(wù)器開銷也會(huì)增大很多堂氯。既然現(xiàn)在的 spa 應(yīng)用文件都是打包生成的重抖,我們在打包的時(shí)候就直接生成高壓縮等級的文件,作為靜態(tài)資源放在服務(wù)器上祖灰,接收到請求后直接把這些壓縮版文件返回回去不就好了?
webpack 的 compression-webpack-plugin 就是專門做這件事情的:
tip:我bulid的時(shí)候報(bào)了Cannot read property 'tapPromise' of undefined
的錯(cuò)畔规,其實(shí)就是版本和vue-cli的某些包不兼容局扶,把 compression-webpack-plugin 的版本降低到6.1.1
就可以了。
先安裝npm install compression-webpack-plugin -D
叁扫,然后到vue.config.js配置:
const CompressionPlugin = require("compression-webpack-plugin");
configureWebpack: config => {
config.name = name
const plugins = []
if (IS_PROD) { // 生產(chǎn)環(huán)境
plugins.push(
// 為靜態(tài)資源準(zhǔn)備壓縮版本三妈,在服務(wù)器也要開啟相應(yīng)配置
new CompressionWebpackPlugin({
test: /\.(js|css|json|ico|svg)$/,// 匹配文件格式
algorithm: 'gzip',
threshold: 10240, // 對超過10k的數(shù)據(jù)壓縮
minRatio: 0.8, // 壓縮比
// filename: "[path][base].gz", // 壓縮后的文件名,默認(rèn)值是 [path][base].gz
filename(pathData) {
// `pathData` 參數(shù)包含很多可以獲取到文件路徑相關(guān)數(shù)據(jù)的屬性 - `path`/`name`/`ext`/等等
// 如果路徑中包含svg莫绣,則放到svg/目錄下
// 只是演示畴蒲,一般都用字符串默認(rèn)值就好
if (/\.svg$/.test(pathData.ext)) {
return 'static/svg/[base].gz'
}
return '[path][base].gz'
},
deleteOriginalAssets: false, // 不刪除源文件,true 則只保留壓縮后的文件
})
)
} else {
// 為開發(fā)環(huán)境修改配置
}
config.plugins = [...config.plugins, ...plugins]
},
其中 filename
參數(shù)就是定義文件編碼壓縮后的路徑和文件名对室,格式除了字符串也可以是Function
(基本沒啥必要)模燥。
默認(rèn)值是"[path][base].gz"
,一般保持默認(rèn)值就好掩宜。
gz是文件后綴蔫骂,那[path]
和 [base]
是啥呢
比如我們有這么個(gè)靜態(tài)資源:static/images/image.png?foo=bar#hash
(static
是我打包目錄下自定義的靜態(tài)資源目錄),然后若我們給插件 filename 的值里配置如下參數(shù)牺汤,完成壓縮后輸出的文件名中:
-
[path]
會(huì)被替換為源靜態(tài)資源的目錄, 包括末尾的/
(static/images/
) -
[file]
為源靜態(tài)資源的路徑 (static/images/image.png
) -
[name]
為源文件的文件名 (image
) -
[ext]
為源文件(包含.
)的擴(kuò)展名 (.png
) -
[base]
會(huì)被替換為 ([name]
+[ext]
) 的內(nèi)容 (image.png
) -
[query]
為源文件的查詢參數(shù)辽旋,包括?
(?foo=bar
) -
[fragment]
為源文件的 fragment (在URL的概念里叫做hash
)(#hash
)
參考文章:探索HTTP傳輸中g(shù)zip壓縮