在前端项目里引入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模式:
parsed size大部分包使用CDN模式(严格来说,ng如此配置,除了加速,其他跟CDN一样):
CDN parsed size
打包后体积小了近170+kb,较原先的包小了近23%。顿时有点开心,优化了一大截
但是真的优化了吗?
于是放上服务器对比前后首次加载速度:
未使用CDN模式:
image.png
约在1.9s~2.1s之间
(自己的服务器,带宽较低,同样的包在公司测试服务器能有900ms~1.01s的速度,具体优化之前有文章提及如何优化的,在此不做赘述)
大部分包使用CDN模式后:
image.png
包是小了,但是首次渲染时间竟然到8s了,excuse me ? 没优化都比优化快多了好嘛!
即使是ng,没有CDN加速,也不至于吧
分析原因,发现如果每个依赖包都用CDN模式,会加大网络request请求数量,时间就损耗在这里了,有些甚至才几十kb的,加载速度也跟几百kb相差无几,这就亏大了。
So接下来的策略应该是:
通过BundleAnalyzerPlugin分析,哪些包特大,才采用CDN模式
image.png那么就单对这个包进行CDN:
image.png也小了100+kb,包体积10%左右的优化
image.png速度也趋近于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前:
image.png
加载速度:(带宽大点的服务器,确实快很多!)
image.png
CDN后:
image.png
加载速度:
image.png
之前是900ms ~ 1.1s左右,现在基本可以800ms~900ms,包体积小100kb+
当然最看重的还是,统一域名下的其他应用,单烦用到相关的包,都能用本地缓存,节省首次加载时间
附用到的附带命令:
linux下载
curl -O <对应的url>
linux移动文件
mv <source file> <target location>
网友评论