在前端項目里引入CDN技術以達到加速網頁加載的目的
以create-react-app
為例,
// config-overrides.js
const addCustomize = () => (config) => {
config.plugins.push(
new HtmlWebpackExternalsPlugin({
externals: [
{
// 引入的模塊
module: "react",
// cdn的地址
entry: "https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"
// 掛載到了window上的名稱
// window.jQuery就可以全局使用
global: "React",
}
],
})
);
return config;
};
module.exports = override(
...
addCustomize(),
)
當然,需要引入BundleAnalyzerPlugin進行編譯打包后體積查看
// config-overrides.js
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const addCustomize = () => (config) => {
...
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: "static", //輸出靜態報告文件report.html,而不是啟動一個web服務
})
);
....
}
筆者莫得私有CDN,于是乎想著試試用ng實現類似的引入方式。
即: ng暴露linux某個文件夾,可以遠程讀取里面的文件,那么CDN的文件放在上面,且設置對應長時間的緩存策略,達到只讀一次之后就不必再次請求獲取資源的目的,原理上除了加速,使用、讀取是跟CDN類似的,在此嘗試讀取本機的資源
搞起
配置ng
location /private_static {
alias /home/private_static/;
expires 180d; ## 長時間的緩存策略
add_header Cache-Control "public";
add_header Access-Control-Allow-Origin *; ## 跨域設置
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
autoindex on; ## 開啟遠程讀取模式
}
然后一個個把umd類型的包放進去即可
drwxr-xr-x 3 root root 4096 Apr 29 10:05 antd
drwxr-xr-x 3 root root 4096 Apr 29 10:04 antd-design-icons
drwxr-xr-x 3 root root 4096 Apr 29 10:04 antd-mobile
drwxr-xr-x 2 root root 4096 Apr 29 09:51 geolocation
drwxr-xr-x 3 root root 4096 Apr 29 10:09 react
drwxr-xr-x 3 root root 4096 Apr 29 11:57 react-activation
drwxr-xr-x 3 root root 4096 Apr 29 10:07 react-dom
drwxr-xr-x 3 root root 4096 Apr 29 10:06 react-is
drwxr-xr-x 3 root root 4096 Apr 29 10:06 react-router-dom
drwxr-xr-x 3 root root 4096 Apr 29 10:06 styled-components
drwxr-xr-x 3 root root 4096 Apr 29 10:03 vconsole
其一例子如下:
// config-overrides.js
config.plugins.push(
new HtmlWebpackExternalsPlugin({
externals: [
{
// 引入的模塊
module: "react",
// cdn的地址
entry: "https://www.yingtai.tech/private_static/react/16.13.1/react.production.min.js",
// 掛載到了window上的名稱
// window.jQuery就可以全局使用
global: "React",
}
],
})
);
筆者嘗試將N多個使用到的依賴包都改為CDN讀取,前后打包對比:
未使用CDN模式:
大部分包使用CDN模式(嚴格來說,ng如此配置,除了加速,其他跟CDN一樣):
打包后體積小了近170+kb,較原先的包小了近23%。頓時有點開心,優化了一大截
但是真的優化了嗎?
于是放上服務器對比前后首次加載速度:
未使用CDN模式:
約在1.9s~2.1s之間
(自己的服務器,帶寬較低,同樣的包在公司測試服務器能有900ms~1.01s的速度,具體優化之前有文章提及如何優化的,在此不做贅述)
大部分包使用CDN模式后:
包是小了,但是首次渲染時間竟然到8s了,excuse me ? 沒優化都比優化快多了好嘛!
即使是ng,沒有CDN加速,也不至于吧
分析原因,發現如果每個依賴包都用CDN模式,會加大網絡request請求數量,時間就損耗在這里了,有些甚至才幾十kb的,加載速度也跟幾百kb相差無幾,這就虧大了。
So接下來的策略應該是:
通過BundleAnalyzerPlugin分析,哪些包特大,才采用CDN模式
那么就單對這個包進行CDN:
也小了100+kb,包體積10%左右的優化
速度也趨近于2s左右
只優化了一個大包,原先的加載速度應該是在2.2s-2.3s之間,快了0.2s,加載速度提升9-10%左右,且如果使用加速后的CDN而非這種ng模擬的形式,應該會更快
但最重要的在這里:
如果是單域名,多個子域名伺服多個應用,那么采用了這種CDN形式,能讓各個應用體積都減少10%,且節省已加載的共用包的加載時間!
這就很可觀了!
比如,https://yingtai.tech/有多個子域名,伺服多個應用:
https://yingtai.tech/first_app/
https://yingtai.tech/second_app/
https://yingtai.tech/third_app/
...
N個應用都用到了對應的react,react-dom包,那么這N個應用各自可以減少10%的打包體積。
同時:如果用戶訪問了first_app,然后訪問second_app,由于設置了對應react,react-dom包的訪問策略,在訪問frist_app時,已經將公用包儲存在本地,當訪問second_app甚至其他類似的app情況下,會讀取共用包本地緩存,那么當首次訪問second_app,只需要加載second_app非共用的資源包即可
即只要訪問過該域名下的某個應用一次,那么其訪問該域名下的應用的首次加載時間將會對應減少
按上面例子來說,假設訪問a、b、c三個應用,三個應用共用一個包E,
a應用首次訪問耗時2.2s,此時去訪問b或者c應用,同等網絡情況下,必然比2.2s耗時小
以另一個項目為例子:
未CDN前:
加載速度:(帶寬大點的服務器,確實快很多!)
CDN后:
加載速度:
之前是900ms ~ 1.1s左右,現在基本可以800ms~900ms,包體積小100kb+
當然最看重的還是,統一域名下的其他應用,單煩用到相關的包,都能用本地緩存,節省首次加載時間
附用到的附帶命令:
linux下載
curl -O <對應的url>
linux移動文件
mv <source file> <target location>