地球可视化的项目制作完毕后,使用 chrome 的 lighthouse 检测性能后,结果如下。还有不少改进的地方。

image-20240404144359636

# 一、图片压缩转格式

图片可以使用 tinyPNG 压缩,然后转为 webp 格式。能缩小体积。地球可视化用到了地球,太阳和星空的贴图原先加起来 1540kb 的图片,压缩后为 358kb,效果显著。

# 二、按需引入

  1. 路由懒加载。;路由中的组件可以动态引入,等要加载的时候再加载。
1
2
3
component: function(){
return import('../watchEarth.vue')
}
  1. 动态引入子组件,有一些子组件首屏加载的时候没有展示,可以等到需要的时候再加载。子组件引入的方式为动态引入,打包的时候还会分别给每一个组件打包。

动态引入

1
2
countryMap:()=>import('./components/countryMap.vue'),
earthText:()=>import('./components/earthText.vue')

给子组件标签一个 v-if 标签,需要用到再去请求并渲染

1
2
<countryMap v-if="showCountryMap" :earthTextureURL="earthTextureURL"></countryMap>
<earth-text v-if="showEarthText"></earth-text>
  1. 项目中使用到了 json 数据用于绘制地图,文件较大为 900kb,经过打包压缩后为 280kb 的 js 文件,仍然很大,而且这个地图不是首屏优先展示的数据可以晚一些获取,所以在使用到这些数据的组件中动态引入,这时首屏就不会马上引入这个大体积的 js 文件了。

    1
    import('./world.json').then((mapData)=>{}))

最终结果如下,效果显著,不过性能从 77 分提升至 95 分,就 lcp 差一些。lcp 是指用户看到最大内容所需要的时间,地球可视化最先看到的应该是地球而不是底下的地图,可以 lighthouse 却将底下的地图当做最大内容,统计底下地图渲染出来的时间,这个明显有误,最佳的用户体验应该是最先看到地球而不是地图。实际上上面三个步骤优化体验最明显的应该是图片压缩转格式,因为项目不大,引入的子组件体积不大,一般就 100kb,动态引入子组件少加载的 200 多 kb,相比三张图片压缩减少的 1.2mb 来说还是太少了。

# 三、减少打包体积

​ 原先的项目中有 threejs,Echarts 等等第三方库,这些第三方库打包进去后文件的体积过大有 2283kb,经过打包压缩后仍然有 674kb,使用 cdn 引入这些第三方库,然后打包的时候就可以不用将这些库引入进去,从而减少打包的体积。

检测打包体积工具 webpack-bundle-analyzer

1
2
3
4
5
6
7
npm install --save-dev webpack-bundle-analyzer
chainWebpack: config => {
// 配置包分析器
config.plugins.delete('prefetch')
config.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}

在 index.html 中将这些第三方库使用 cdn 的方法引入,然后再项目中就可以不使用 import 引入,而是全局引用。

然后再 vue.config.js 中配置一下,webpack 便不会将其打包进去。

1
2
3
4
5
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1"></script>
<script src="https://cdn.jsdelivr.net/npm/three/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js" integrity="sha256-QvgynZibb2U53SsVu98NggJXYqwRL7tg3FeyfXvPOUY=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-gl@2.0.9/dist/echarts-gl.min.js" integrity="sha256-v7obh7jDwG5cftd0EAJYbHR7AOTv2qkgd9FcLcchvaA=" crossorigin="anonymous"></script>
1
2
3
4
5
6
7
8
configureWebpack:{
externals:{
'vue':'Vue',
'vue-router':'VueRouter',
'THREE':'three',
'echarts':'echarts',
},
},

原先打包体积为 2283kb,压缩后为 674kb。将第三方库使用 cdn 引入,不将其打包进去后,体积为 68kb,压缩后为 26kb。看起来效果显著。不过在使用 lighthouse 测试后却发现与想象中的不一样,实际运行速度反而慢了。

结果如下,除了 tbt 快了之外,其他反而慢了。大概可能有两个原因,一个是项目中使用 cdn 加速的服务器为 jsdelivr,而我项目部署的服务器为 cloudflare,可能 jsdelivr 相比 cloudflare 的速度要慢一些。第二个原因可能是将大的文件拆分成多个小的文件后,请求次数变多,加重请求负担从而降低速度。对于多个小的文件是可以采用一次请求获取,比如精灵图,将多个小图片拼接成大的图片,然后请求大的图片即可,这样能减少请求次数。具体是哪个原因,个人认为大概率是因为 jsdelivr 的服务器速度不如 cloudflare 的服务器速度。

​ 此外,还可以在 package.json 中 "build": “vue-cli-service build --modern”,在后面再 modern。这样就能打两份包,一份给高版本的浏览器使用,无需兼容低版本浏览器,体积更小,运行速度更快,一份给低版本浏览器使用用于兼容低版本浏览器。

参考资料:

https://www.bilibili.com/video/BV1hA4m137xw