vue2打包优化之cdn

1,487 阅读3分钟

前言

项目完成,我们会将项目进行上线,同时为了提升性能,我们往往会进行一些优化处理。由于项目打包之后,会将之前所使用到的部署依赖包和项目中使用到的外部资源都打包,如果之前引入的包很多,或者引入的不必需的包,那么会增大项目的体积,从而造成用户访问的时候需要请求更多的数据才能正常的访问,不利于用户体验,所以需要对打包过程进行优化。

webpack-bundle-analyzer:查看资源树

优化cdn之前,我们需要知道自己优化的目标是啥,哪些值得我们去优化的,因此我们需要借助webpack-bundle-analyzer这样的工具帮我们分析代码

先安装插件webpack-bundle-analyzer:

npm i webpack-bundle-analyzer -D

在vue.config.js中配置使用:

// 使用webpack-bundle-analyzer分析打包
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [new BundleAnalyzerPlugin()],
};
https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7eb190a96d224f45bbebcd3123d12589~tplv-k3u1fbpfcp-zoom-1.image

配置完毕后打开package.json,在scripts中配置如下命令:

"analyz""NODE_ENV=production npm_config_report=true npm run build"

这样在你npm run build的时候就会自动打开http://127.0.0.1:8888/看到生产包的文件情况了,这里我一个vue-cli创建的基础项目组成是这样的

开始优化

从刚才的打包结果可以看出,vue全家桶占据了我们生产包的大头,此时我们如果使用cdn移除这些依赖,是否就可以只保留src中的业务代码了呢?

下面我们开始尝试,思路是以下两点

添加包的排除:

这步操作的关键点是configureWebpack.externals

其形式是这样的:

module.exports = {
    configureWebpack: {
        externals: {
          vue'Vue',
          'vue-router''VueRouter',
          vuex'Vuex'
        },
    },
}

这就是在告诉Webpack:请不要将这个模块注入编译后的JS文件里,对于我源代码里出现的任何import/require这个模块的语句,请将它保留。

怎么使用,根据webpack给出的标准动作(点击查看webpack/externals)。根据文档这里直接上结论:

请查看上面的例子。属性名称是vue,表示应该排除import Vue from 'vue' 中的vue模块。为了替换这个模块,Vue 的值将被用来检索一个全局的 Vue变量。换句话说,当设置为一个字符串时,它将被视为全局的(定义在上面和下面)。

这时我们重新打包操作,再看看打包分析,发现刚才的三兄弟已经没了。

但现在程序是不可运行的,因为我们已经排除了部分依赖,因此接下来我们开始下一步

添加cdn地址到index.html:

查找依赖的cdn

最常用的地址有:

jsdelivr
cdnjs

通过查询我们查到了对应的cdn地址,并配置如下:

const cdn = {
  css: [],
  js: [
    'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
    'https://cdn.jsdelivr.net/npm/vue-router@3.2.0/dist/vue-router.min.js',
    'https://cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js'
  ]
};

这里暂时没用UI组件,所以css没有配置

将cdn参数添加到页面

chainWebpack (config) {
    config.plugin('html').tap(args => {
      args[0].cdn = cdn
      return args
    })
  }

改造index.html

<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>" preload></script>
    <% } %>
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="stylesheet" preload></link>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="stylesheet"></link>
    <% } %>

这样打包后就可以正常使用啦

附:

vue.config.js完整版:

const path = require('path');

const externals = {
  vue'Vue',
  'vue-router''VueRouter',
  vuex'Vuex'
};

const cdn = {
  css: [],
  js: [
    'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
    'https://cdn.jsdelivr.net/npm/vue-router@3.2.0/dist/vue-router.min.js',
    'https://cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js'
  ]
};

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src')
      }
    },
    externals,
    plugins: [
      // 开启 BundleAnalyzerPlugin
      new BundleAnalyzerPlugin()
    ]
  },
  chainWebpack(config) {
    config.plugin('html').tap((args) => {
      args[0].cdn = cdn;
      return args;
    });
  }
};

index.html完整版

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="stylesheet" preload></link>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="stylesheet"></link>
    <% } %>
    <title><%= htmlWebpackPlugin.options.title %></title>
    <!-- built files will be auto injected -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>" preload></script>
    <% } %>
  </head>
  <body>
    <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>
    <!-- built files will be auto injected -->
  </body>
</html>