vue.config.js 优化

75 阅读7分钟

路由懒加载

SPA 项目,一个路由对应一个页面,如果不做处理,项目打包后,会把所有页面打包成一个文件,当用户打开首页时,会一次性加载所有的资源,造成首页加载很慢,降低用户体验

列一个实际项目的打包详情:

  • app.js 初始体积: 1175 KB

  • app.css 初始体积: 274 KB

将路由全部改成懒加载

js
 体验AI代码助手
 代码解读
复制代码
// 通过webpackChunkName设置分割后代码块的名字
const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue");
const MetricGroup = () => import(/* webpackChunkName: "metricGroup" */ "@/views/metricGroup/index.vue");
…………
const routes = [
    {
       path: "/",
       name: "home",
       component: Home
    },
    {
       path: "/metricGroup",
       name: "metricGroup",
       component: MetricGroup
    },
    …………
 ]

重新打包后,首页资源拆分为 app.js 和 home.js,以及对应的 css 文件

  • app.js:244 KB、 home.js: 35KB

  • app.css:67 KB、home.css: 15KB

通过路由懒加载,该项目的首页资源压缩约 52%

路由懒加载的原理

懒加载前提的实现:ES6的动态地加载模块——import()

调用 import() 之处,被作为分离的模块起点,意思是,被请求的模块和它引用的所有子模块,会分离到一个单独的 chunk 中
——摘自《webpack——模块方法》的import()小节

要实现懒加载,就得先将进行懒加载的子模块分离出来,打包成一个单独的文件

webpackChunkName 作用是 webpack 在打包的时候,对异步引入的库代码(lodash)进行代码分割时,设置代码块的名字。webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中

externals 提取项目依赖

externals 来提取这些依赖包,告诉 webpack 这些依赖是外部环境提供的,在打包时可以忽略它们,就不会再打到 chunk-vendors.js 中

1、vue.config.js 中配置:

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

2)在 index.html 中使用 CDN 引入依赖

xml
 体验AI代码助手
 代码解读
复制代码
  <body>
    <script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
    <script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>
    <script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>
    <script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>
  </body>

验证 externals 的有效性:

重新打包,最新数据如下:

打包体积:1.12M

image.png 打包速度:18879ms

image.png

使用 externals 后,包体积压缩50%、打包速度提升26%

2、组件库的按需引入

为什么没有使用 externals 的方式处理组件库呢?

externals缺点:直接在html内引入的,失去了按需引入的功能,只能引入组件库完整的js和css

组件库按需引入的原理:最终只引入指定组件和对应的样式

elementUI 需要借助 babel-plugin-component 插件实现,插件的作用如下:

如按需引入 Button 组件:

import { Button } from 'element-ui'

Vue.component(Button.name, Button)

编译后的文件(自动引入 button.css):

javascript
 体验AI代码助手
 代码解读
复制代码
import _Button from "element-ui/lib/button";
import _Button2 from "element-ui/lib/theme-chalk/button.css";
// base.css是公共的样式
import "element-ui/lib/theme-chalk/base.css";

Vue.component(_Button.name, _Button);

通过该插件,最终只引入指定组件和样式,来实现减少组件库体积大小

1)安装 babel-plugin-component

 体验AI代码助手
 代码解读
复制代码
npm install babel-plugin-component -D

2)babel.config.js中引入

css
 体验AI代码助手
 代码解读
复制代码
module.exports = {
  presets: ['@vue/app'],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ]
  ]
};

验证组件库按需引入的有效性:

重新打包,最新数据如下:

打包体积:648KB

image.png 打包速度:15135ms

image.png 组件库按需引入后,包体积压缩72%、打包速度提升40%

同时 chunk-vendors.css 的体积也有了明显的减少,从206KB降到了82KB

原始体积:

image.png 按需引入后:

image.png

3、减小三方依赖的体积

具体参考文章 juejin.cn/post/718631…

在 Vue 项目中,通过配置 externals 并结合按需引入策略来优化第三方包,可以有效减小打包体积,提升应用加载速度。下面我将为你梳理这两种方法的实现步骤和注意事项。

为了让你能快速了解这两种策略的核心配置,这里有一个简单的对比表格:

优化策略 主要手段 适用场景 配置 externals 在 vue.config.js 中声明外部依赖,并通过 CDN 引入 适用于 Vue、Vue-Router、Vuex、Axios 等稳定、通过 CDN 分发的大型库 按需引入 使用 Babel 插件或基于 ES6 模块的 Tree Shaking,或 unplugin-vue-components 等自动导入工具 适用于 Element UI、Ant Design Vue 等提供ES 模块的组件库

🔧 配置 externals

这种方法的核心是让 Webpack 在打包时排除指定的依赖,转而通过 CDN 链接在运行时引入。

  1. 修改 Vue 配置 在项目根目录下的 vue.config.js 文件中,配置 externals 字段。这里需要指定包名及其对应的全局变量。
    // vue.config.js
    module.exports = {
      configureWebpack: {
        externals: {
          'vue': 'Vue',
          'vue-router': 'VueRouter',
          'vuex': 'Vuex',
          'axios': 'axios'
          // 其他需要排除的库...
        }
      }
    }
    
  2. 引入 CDN 资源 在 public/index.html 中,通过
  3. (可选)调整代码中的引入方式 配置 externals 后,你通常可以继续使用 import 语句。但有时可能需要改为 require 方式,请根据构建结果调整。

🌿 实现按需引入

对于大型组件库,全量引入会显著增加包体积,按需引入只导入你实际用到的组件。

  1. 使用 Babel 插件(传统方式) 这种方式适用于很多 UI 库,例如 Element UI。 · 安装插件:例如,对于 Element UI,需要安装 babel-plugin-component。

    npm install babel-plugin-component --save-dev
    

    · 配置 Babel:在 babel.config.js 或 .babelrc 文件中配置插件。

    // babel.config.js
    module.exports = {
      plugins: [
        [
          'component',
          {
            libraryName: 'element-ui',
            styleLibraryName: 'theme-chalk'
          }
        ]
      ]
    }
    

    · 在代码中按需引入:

    import { Button, Select } from 'element-ui'
    import 'element-ui/lib/theme-chalk/button.css'
    import 'element-ui/lib/theme-chalk/select.css'
    
    Vue.component(Button.name, Button)
    Vue.component(Select.name, Select)
    
  2. 使用现代自动导入工具(推荐) 社区提供的 unplugin-vue-components 等插件可以自动按需引入组件,甚至包括样式,大大简化了开发。 · 以 Vite 项目为例: · 安装插件:例如,为 Element Plus 配置自动导入。 bash npm install unplugin-vue-components unplugin-auto-import -D · 配置插件:在 vite.config.js 中配置。 ```javascript // vite.config.js import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default {
      plugins: [
        // ...其他插件
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],
    }
    ```
    

    配置完成后,你在模板中直接使用 时,插件会自动引入 Button 组件及其样式。

💡 组合使用与进阶优化

· 结合使用:你可以在一个项目中同时使用这两种策略。例如,将 Vue、Vue Router 等核心库通过 externals 和 CDN 引入,同时将 Element UI 这类大型 UI 库通过按需引入的方式处理。 · 路由懒加载:使用 Vue Router 的懒加载功能,将不同路由对应的组件分割成不同的代码块,当路由被访问时才按需加载。

const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [{ path: '/foo', component: Foo }]
})

· 注意函数式组件:一些以函数形式调用的组件(如 Message),自动导入工具可能无法自动处理其样式,需要你手动引入样式文件。

import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'

⚠️ 注意事项

· CDN 的可靠性:使用 externals 方案依赖于 CDN 服务的稳定性。为规避风险,可以考虑使用多个 CDN 提供商备份,或将这些资源部署到自己的静态资源服务器。 · 版本一致性:确保 externals 配置的版本与 CDN 引入的版本一致,避免因版本差异导致运行时错误。 · 优化效果验证:使用 npm run build 并观察打包后文件体积的变化,或使用 webpack-bundle-analyzer 分析打包结果,验证优化效果。

希望这些详细的步骤和说明能帮助你成功优化 Vue 项目的打包体积!如果你能告诉我你项目中主要使用了哪些第三方库,或许我可以给出更具体的配置建议。