优化打包加速首屏打开-npm和cdn引入优缺点

1,123 阅读3分钟

问题:使用cdn引入库是不是真的比npm引入的好?好在哪里?

场景:首屏加速,页面打开时更快。

原理:

页面里面有多少外链接资源文件,比如说链接引入的图片、css文件、js文件等。默认编译时会将所有的第三方的包打成一个chunk-vendors.js,浏览器的并发会限制同域资源的请求数的(一般是10个),如果第三方的包很多的话就会导致包很大网页首页加载的很慢很慢 所以可以将一些通用的,较大的包单独拎出来,从第三方的服务器加载,打破浏览器的并发限制,提高下载速度(浏览器引入网络资源的多线程的,js才是单线程的),防止自己的服务器带宽不够下载文件慢的问题。 如果没有多少资源文件的话,强行并发下载,会产生多线程小文件的I/O瓶颈。

按需引入的问题:如果只是按需引入了很少的依赖包也是没有必要用CDN引入的,因为根本问题是依赖包太大才需要用CDN的高带宽去解决。

cdn优势:

  • 带宽更大引入时更快,加快首屏速度

  • 不同地区用户访问可以就近加载。(如果自己的web站点带宽够大,全国甚至全球多低部署的话就没有必要用cdn了)

  • 国内

  • 国外

总结:

在本地按需引入组件,然后使用cdn代理服务器将整个项目放上cdn代理服务器,这才是最优解。技能使用npm按需引入的优势,又可以享受CDN的优势。(这里还没有深入研究)

具体优化过程:

  1. 查看打包工具🔧
  • 在终端运行vue ui,会自动弹出浏览器,运行相应的项目命令即可
  • 看每个包都占了多少可以使用webpack-bundle-analyzer ,命令:npm install webpack-bundle-analyzer 打包构建后自动弹出
//在vue.config.js中设置
module.exports = defineConfig({
  ...
  configureWebpack: config => {...},
  devServer: {...},
  css: {...},
  chainWebpack: (config) => {
    config.when(process.env.NODE_ENV === 'production', config => {
      config.plugin('webpack-bundle-analyzer').use(
        require('webpack-bundle-analyzer').BundleAnalyzerPlugin
      )
    })
  }
})
  1. 主要修改三个文件public/ndex.html,vue.config.js,src/main.js(涉及全局引入的时候需要修改)
  • public/index.html:主要是引入cdn的script
<!DOCTYPE html>
<html lang="">

<head>
  ...
  <link href="https://cdn.bootcdn.net/ajax/libs/element-plus/2.2.26/index.css" rel="stylesheet">
  ...
</head>
<body>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.13/vue.global.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-plus/2.2.28/index.full.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-plus-icons-vue/2.0.5/index.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/4.0.3/vue-router.global.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vuex/4.0.0/vuex.global.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.0/echarts.common.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue-i18n/9.2.2/vue-i18n.global.min.js"></script>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app">
  </div>
</body>
</html>
  • vue.config.js:主要是配置webpack的externals,分离打包第三方资源包,这样打包后这些文件就不会打包到vendor.js 和app.js中,会大大减少打包体积

    优点:声明文件被外部引用不用打包,不参与打包流程,由于直接写死在html里,可以使用cdn等加速

//定义需要cdn引入的变量,key是依赖包的名称,value是源码抛出来的全局变量
const objExternals = {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  vuex: 'Vuex',
  axios: 'axios',
  echarts: 'echarts',
  'element-plus': 'ElementPlus',
  'vue-i18n': 'VueI18n'
}
module.exports = defineConfig({
  ...
  configureWebpack: config => {
    // ⚠️按需引入失效,直接删除?不知道理解的对不对
    // config.plugins.push(AutoImport({
    //   resolvers: [ElementPlusResolver()]
    // }))
    // config.plugins.push(Components({
    //   resolvers: [ElementPlusResolver()]
    // }))
    //配置externals
    config.externals = objExternals
  },
` })``
  1. Gzip打包压缩需要后端配合,
  • 首先安装npm i -D compression-webpack-plugin
  • 在 vue.config.js中加入:
module.exports = defineConfig({
  ...
  configureWebpack: config => {
    config.plugins.push(new CompressionPlugin({
      test: /.js$|.html$|.css/, // 指定压缩文件
      threshold: 10240, // 超过10kb的文件进行压缩
      deleteOriginalAssets: false// true // 是否删除原文件
    }))
  },
 })    
    

遇到问题:

  • 在打包后发现element-plus还是被打包进了依赖项目,原因:没有删除之前设置的按需引入

  • 可能会有的样式问题:cdn引入ElementPlus table显示不正常→cdn引入 不支持自结束标签的写法,要写完整标签

效果对比:2.1M→523kb