迎接2026,重新认识Vue CLI (v5.x)

文章目录

  • 概要
  • [1. Vue CLI创建项目](#1. Vue CLI创建项目)
  • [2. 减小打包体积](#2. 减小打包体积)
  • [3. 优化打包速度](#3. 优化打包速度)
  • [4. 优化 FCP/LCP](#4. 优化 FCP/LCP)
  • [5. 完整配置方案](#5. 完整配置方案)
  • 小结

概要

迎接2026,重新认识Webpack5

当技术舞台的聚光灯已聚焦于Vite等新兴工具,Vue CLI似乎成了一位沉默的"老将"。然而,在2026年的门槛前,我们有必要摘下"过时"的滤镜,重新审视它的价值。这种重新认识,并非倡导在新项目中回归传统,而是基于一个朴素的现实:技术的生命力不仅在于创新,也在于对存量世界的深刻理解。

大量运行中的企业级应用仍由Vue CLI构建,它们是业务收入的基石。这意味着,精通Vue CLI不再是选择题,而是成为前端开发者应对复杂维护、增量迁移乃至团队协作的关键素养。理解它的配置逻辑与项目结构,无异于掌握了一把开启"技术遗产"大门的钥匙。这并非怀旧,而是一种务实的专业主义------让我们在拥抱未来的同时,也能稳健地支撑起过去。


1. Vue CLI创建项目

  • 安装 Node.js (v16+),建议先安装 nvm-windows

    bash 复制代码
    node -v  # 应输出 v16.x 或更高
    npm -v   # 应输出 8.x 或更高
    npm config set registry https://registry.npmmirror.com/ # 设置淘宝镜像源
    npm config get registry # 输出 https://registry.npmmirror.com/
  • 安装 Vue CLI 脚手架

    bash 复制代码
    npm install -g @vue/cli
    vue --version  # 应输出 v5.x.x(最新版)
  • Vue CLI 创建项目

    bash 复制代码
    # 命令行创建
    vue create my-vue-app  # 按需选择
    
    # 可视化创建
    vue ui  # 自动打开浏览器界面创建项目
  • Vue 项目结构

    bash 复制代码
    my-vue-app/
    ├── public/            # 静态资源(直接复制到输出目录)
    ├── src/
    │   ├── assets/        # 图片/字体等资源
    │   ├── components/    # 可复用组件
    │   ├── router/        # 路由配置(index.js)
    │   ├── store/         # Vuex 状态管理(index.js)
    │   ├── views/         # 页面级组件
    │   ├── App.vue        # 根组件
    │   └── main.js        # 应用入口(初始化Vue实例)
    ├── .eslintrc.js       # ESLint 代码规范配置
    └── vue.config.js      # Webpack 自定义配置(需手动创建)
  • vue.config.js
    Vue CLI 5 隐藏了复杂配置(如 webpack),可通过 vue.config.js 覆盖。

    js 复制代码
    module.exports = {
      devServer: {
        port: 8080,      // 修改开发服务器端口
        open: true       // 启动后自动打开浏览器
      },
      lintOnSave: false  // 关闭保存时代码检查(根据需求开启)
    }
  • 启动开发服务器

    bash 复制代码
    npm run serve  # 访问 http://localhost:8080
  • 添加新功能插件

    bash 复制代码
    vue add @vue/cli-plugin-eslint    # 添加ESLint插件
    vue add vuetify                   # 添加UI框架
  • 生产环境打包

    bash 复制代码
    npm run build  # 生成 dist/ 目录(部署文件)
  • 安装 Visual Studio Code 插件 Vue (Official)


2. 减小打包体积

Vue CLI 项目中,JS 代码压缩和 CSS 代码压缩 功能已内置 支持且默认开启无需额外配置 。Vue CLI内部使用Webpack,而Webpack在生产模式下(mode: 'production')默认会启用TerserPlugin(用于JS压缩)和CssMinimizerPlugin(用于CSS压缩)。Vue CLI的默认配置已经将mode设置为production,因此压缩是自动开启的,无需额外配置。

Vue CLI 内部默认支持 JS 和 CSS 的代码分割无需额外配置。JS 分割通过 Webpack 的 SplitChunksPlugin 和动态导入实现。CSS 分割通过 mini-css-extract-plugin 实现。代码分割只在生产构建时生效。

  • 代码分割与懒加载

    使用动态导入分割路由组件和第三方库:

    js 复制代码
    // 路由配置
    const UserProfile = () => import('@/views/UserProfile.vue') // 按需加载
  • Tree Shaking

    Vue CLI 已内置了 Tree Shaking 优化机制。需要手动干预的情况:

    • 第三方库不支持 Tree Shaking
    • CSS Tree Shaking
    js 复制代码
    // vue.config.js
    import purgecss from '@fullhuman/postcss-purgecss';
    
    // vue.config.js
    module.exports = {
      // CSS Tree Shaking
      // 通过 @fullhuman/postcss-purgecss 插件移除未使用的 CSS
      // 仅在生产环境中启用
      css: {
        loaderOptions: {
          postcss: {
            plugins: [
              purgecss({
                content: ["./src/**/*.vue", "./public/index.html"],
              }),
            ],
          },
        },
      },
      // 配置 webpack 优化项
      chainWebpack: (config) => {
    	// 添加缓存组以分离特定第三方库
    	// 这里以 lodash 和 moment 为例
        config.plugin("optimize").tap((args) => {
          args[0].option.splitChunks.cacheGroups.vendor = {
            test: /[\\/]node_modules[\\/](lodash|moment)[\\/]/,
            name: "vendor",
            chunks: "all",
          };
          return args;
        });
      },
    };
  • 压缩资源

    启用 Gzip/Brotli 压缩,要安装 compression-webpack-plugin):

    js 复制代码
    import CompressionPlugin from 'compression-webpack-plugin';
    
    module.exports = {
      chainWebpack: config => {
        config.plugin('compression').use(CompressionPlugin, [{
          algorithm: 'gzip',
          threshold: 10240
        }])
      }
    }
  • 按需引入第三方库

    以 echarts 为例:

    js 复制代码
    import * as echarts from 'echarts/core'
    import { BarChart } from 'echarts/charts'
    import { GridComponent } from 'echarts/components'
    echarts.use([BarChart, GridComponent])
  • 图片优化

    自动转 WebP(要安装 image-webpack-loader):

    js 复制代码
    chainWebpack: config => {
      config.module.rule('images')
        .use('image-webpack-loader')
        .loader('image-webpack-loader')
    }

3. 优化打包速度

  • 缓存配置(Webpack 5)

    js 复制代码
    module.exports = {
      configureWebpack: {
        cache: {
          type: 'filesystem',
          allowCollectingMemory: true
        }
      }
    }
  • 多线程构建
    安装 thread-loader

    js 复制代码
    chainWebpack: config => {
      config.module
        .rule('js')
        .use('thread-loader')
        .loader('thread-loader')
    }
  • 缩小文件搜索范围

    js 复制代码
    configureWebpack: {
      resolve: {
        alias: { '@': path.resolve(__dirname, 'src') },
        extensions: ['.js', '.vue'] // 减少扩展名检测
      },
      module: {
        noParse: /lodash|echarts/ // 不解析已预编译库
      }
    }
  • 【传统方案】DLL 预构建

    • 创建 dll.config.js:

      js 复制代码
      import webpack from 'webpack';
      
      module.exports = {
        entry: {
          vendor: ['echarts', 'lodash']
        },
        output: {
          filename: '[name].dll.js',
          library: '[name]'
        },
        plugins: [
          new webpack.DllPlugin({
            name: '[name]',
            path: './dll/[name]-manifest.json'
          })
        ]
      }
    • 在 vue.config.js 中引用:

      js 复制代码
      import { DllReferencePlugin } from 'webpack';
      module.exports = {
        plugins: [
          new DllReferencePlugin({
            manifest: require('./dll/vendor-manifest.json')
          })
        ]
      }
  • 【现代方案】使用Webpack 5的持久化缓存和代码分割来替代传统的DLL方案
    Webpack 5的两个核心特性可以完美替代DLL:

    • 持久化缓存(cache.filesystem):通过文件系统缓存构建结果,二次构建时直接复用。
    • 代码分割(splitChunks):自动分离第三方库,配合长期缓存策略。(特别要注意splitChunks的配置细节。设置chunks: 'all'和minSize: 0能确保所有第三方库都被分离,而cacheGroups可以精细控制分组策略。)
    js 复制代码
    module.exports = {
      configureWebpack: {
        cache: {
          type: 'filesystem',
          buildDependencies: {
            config: [__filename]
          }
        }
      },
      chainWebpack: config => {
        config.optimization.splitChunks({
          cacheGroups: {
            echarts: {
              test: /[\\/]node_modules[\\/]echarts[\\/]/,
              name: 'echarts',
              chunks: 'all'
            },
            lodash: {
              test: /[\\/]node_modules[\\/]lodash[\\/]/,
              name: 'lodash',
              chunks: 'all'
            }
          }
        })
      }
    }

4. 优化 FCP/LCP

  • 关键 CSS 内联
    使用 critters-webpack-plugin:

    js 复制代码
    import Critters from 'critters-webpack-plugin';
    
    module.exports = {
      configureWebpack: {
        plugins: [new Critters()]
      }
    }
  • 预加载关键资源

    • 预加载 (preload): 用于当前页面中优先级高 的资源,这些资源对当前页面非常重要,需要尽快加载 。浏览器会优先加载这些资源。

      js 复制代码
      // vue.config.js
      module.exports = {
        chainWebpack: config => {
          // 预加载关键资源(如首屏CSS/JS)
          config.plugin('preload').tap(options => {
            options[0] = {
              rel: 'preload',  // 预加载指令
              include: 'initial',  // 只预加载初始路由资源
              fileBlacklist: [/\.map$/, /hot-update\.js$/]  // 排除不需要预加载的文件
            }
            return options
          })
        }
      }
    • 预取 (prefetch): 用于未来可能使用 的资源(例如,用户可能访问的下一个页面),浏览器会在空闲时加载 这些资源,不会影响当前页面的加载。

      js 复制代码
      // vue.config.js
      module.exports = {
        chainWebpack: config => {
          // 预取非关键资源(如异步路由组件)
          config.plugin('prefetch').tap(options => {
            options[0] = {
              rel: 'prefetch', // 资源预取指令
              include: 'asyncChunks' // 预取所有异步chunk(自动预取所有异步加载的模块)
            }
            return options
          })
        }
      }
  • 图片懒加载
    安装 vue-lazyload,配置在"5.完整配置方案":

    js 复制代码
    <img v-lazy="imageUrl" alt="description">
  • 服务端渲染(SSR):推荐使用Nuxt.js框架

  • CDN 加速静态资源

    js 复制代码
    // vue.config.js
    module.exports = {
      chainWebpack: config => {
        config.externals({
          echarts: 'echarts',
          lodash: '_'
        })
      }
    }
    html 复制代码
    <!-- public/index.html -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

5. 完整配置方案

  • vue.config.js

    js 复制代码
    import path from 'path';
    import CompressionPlugin from 'compression-webpack-plugin';
    import Critters from 'critters-webpack-plugin';
    import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
    
    module.exports = {
      // 基本路径配置
      publicPath: process.env.NODE_ENV === 'production' ? '/static/' : '/',
      
      // 关闭生产源映射
      productionSourceMap: false,
      
      // webpack优化配置
      configureWebpack: {
        resolve: {
          alias: { '@': path.resolve(__dirname, 'src') },
          extensions: ['.js', '.vue'],
          symlinks: false
        },
        module: {
          noParse: /lodash|echarts/  // 不解析预编译库
        },
        plugins: [
          // 资源压缩
          new CompressionPlugin({
            algorithm: 'gzip',
            threshold: 10240,
            minRatio: 0.8
          }),
          // 关键CSS内联
          new Critters({
            preload: 'swap',
            fonts: false
          }),
          // 打包分析
          new BundleAnalyzerPlugin({ 
            analyzerMode: process.env.ANALYZE ? 'server' : 'disabled' 
          })
        ],
        // Webpack 5持久化缓存
        cache: {
          type: 'filesystem',
          buildDependencies: { config: [__filename] }
        }
      },
    
      // chainWebpack高级配置
      chainWebpack: config => {
        // 图片优化
        config.module.rule('images')
          .use('image-webpack-loader')
          .loader('image-webpack-loader')
          .options({ bypassOnDebug: true })
        
        // 多线程构建
        config.module.rule('js')
          .use('thread-loader')
          .loader('thread-loader')
          .options({ workers: 3 })
        
        // 代码分割
        config.optimization.splitChunks({
          chunks: 'all',
          minSize: 20000,
          maxSize: 250000,
          cacheGroups: {
            echarts: {
              test: /[\\/]node_modules[\\/]echarts[\\/]/,
              name: 'echarts',
              priority: 20
            },
            lodash: {
              test: /[\\/]node_modules[\\/]lodash[\\/]/,
              name: 'lodash',
              priority: 10
            }
          }
        })
        
        // CDN外部化
        config.externals({
          echarts: 'echarts',
          lodash: '_'
        })
      }
    }
  • HTML模板配置

    html 复制代码
    <!DOCTYPE html>
    <html lang="zh-CN">
    <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="preload" href="/static/js/app.1234.js" as="script">
      <!-- CDN引入外部库 -->
      <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
    </head>
    <body>
      <div id="app"></div>
      <!-- 预取非关键资源 -->
      <link rel="prefetch" href="/static/js/chunk-vendors.5678.js">
    </body>
    </html>
  • 代码优化

    • 按需引入

      js 复制代码
      // utils/echarts.js
      import * as echarts from 'echarts/core'
      import { BarChart, LineChart } from 'echarts/charts'
      import { GridComponent, TooltipComponent } from 'echarts/components'
      import { CanvasRenderer } from 'echarts/renderers'
      
      echarts.use([
        BarChart, 
        LineChart,
        GridComponent,
        TooltipComponent,
        CanvasRenderer
      ])
      
      export default echarts
    • 路由懒加载

      js 复制代码
      // router/index.js
      const Home = () => import(/* webpackChunkName: "home" */ '@/views/Home.vue')
      const Dashboard = () => import(/* webpackPrefetch: true */ '@/views/Dashboard.vue')
    • 图片懒加载

      js 复制代码
      // main.js
      import VueLazyload from 'vue-lazyload'
      Vue.use(VueLazyload, {
        preLoad: 1.3,
        attempt: 3
      })

小结

  • Vue CLI 是一个功能完整的项目脚手架系统,而 Webpack 是 Vue CLI 底层的静态模块打包器。Vue CLI 的核心价值在于它将 Webpack 等底层工具的复杂配置封装了起来,提供了一套开箱即用的标准化方案。
    • 预设配置:当你使用 vue create命令创建一个新项目时,Vue CLI 已经为你生成了一套经过优化的完整 Webpack 配置,包括对 .vue单文件组件的处理、开发服务器的热重载、生产环境的代码压缩等。
    • 命令行接口:Vue CLI 提供的 vue-cli-service封装了常用的脚本命令(如 npm run serve和 npm run build)。你在执行这些命令时,实际上是 @vue/cli-service在背后调用并执行配置好的 Webpack 任务。
    • 可配置性:你无需执行 eject操作来暴露所有配置。只需在项目根目录创建 vue.config.js文件,就可以轻松地覆盖或扩展内部的 Webpack 配置,例如设置代理解决跨域问题。
  • Vue CLI的Tree Shaking
    • Vue CLI 通过预置配置简化了 90% 的 Tree Shaking 工作,开发者只需专注按需引入代码和选择支持 Tree Shaking 的依赖库即可【开箱即用】。
  • Vue CLI 代码压缩
    • 开箱即用
      • Vue CLI 的生产构建流程默认包含 JS/CSS 压缩,参考 Webpack 的 production 模式配置
    • 压缩层级
      • JS 压缩:通过 terser-webpack-plugin 实现(UglifyJS 的替代品)
      • CSS 压缩:通过 css-minimizer-webpack-plugin 实现
  • Vue CLI 代码分割
    • 开箱即用
      • Vue CLI 默认启用代码分割:
      • JS 分割:通过 Webpack 的 splitChunks 策略
      • CSS 分割:通过 mini-css-extract-plugin 实现
    • 分割触发条件
      • 路由级动态导入 (import('./Component.vue'))
      • 第三方依赖自动分离
      • 公共模块复用检测
  • 预加载关键资源和预取非关键资源
    • 关键资源选择:仅预加载首屏渲染必需的资源(<500KB)
    • 预取适度:避免过度预取导致带宽浪费
    • HTTP/2支持:确保服务器支持多路复用
相关推荐
Coder-coco44 分钟前
游戏助手|游戏攻略|基于SprinBoot+vue的游戏攻略系统小程序(源码+数据库+文档)
java·vue.js·spring boot·游戏·小程序·论文·游戏助手
c***V3234 小时前
Vue优化
前端·javascript·vue.js
李@十一₂⁰6 小时前
HTML 特殊字体符号
前端·html
小奶包他干奶奶8 小时前
Webpack学习——Loader(文件转换器)
前端·学习·webpack
小奶包他干奶奶8 小时前
Webpack学习——原理理解
学习·webpack·devops
zy happy8 小时前
若依 vue3 报错:找不到模块“@/api/xxxx/xxxxx”或其相应的类型声明。。Vue 3 can not find mod
前端·javascript·vue.js
潘小安8 小时前
Git Worktree + Claude Code:让你的开发效率翻倍的秘密武器
前端
meichaoWen9 小时前
【Vue3】vue3的全面学习(一)
前端·javascript·学习
小猪努力学前端9 小时前
在 React + React Router v7 SSR 项目里做多端适配,我踩的两个坑
前端·react.js