前端性能优化 - CDN引入分析及实践

在前端项目里引入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  

你可能感兴趣的:(前端性能优化 - CDN引入分析及实践)