第九章:Vue3 项目优化与部署(从能跑到能上线)

一、入门:项目优化的核心目标与基础认知

项目优化不是“锦上添花”,而是上线前的“必备步骤”——核心目标是减小打包体积(让用户更快下载资源)、提升页面性能(让页面加载/交互更流畅)、增强稳定性(减少线上报错),最终提升用户体验和搜索引擎排名(SEO)。

Vue3 项目的优化主要围绕两大方向:

  • 开发阶段优化:编码时规避性能问题(如合理使用v-if/v-show、避免不必要的响应式);
  • 构建与部署阶段优化:通过工具链(Vite/Webpack)减小打包体积,通过服务器配置(Nginx)优化资源加载。

二、精通:全方位优化实战(从代码到构建)

1. 代码层面优化(开发时直接落地)

(1)响应式优化:避免不必要的响应式数据
  • 问题:用ref/reactive包裹不需要响应式的数据(如静态配置、临时变量),会增加 Vue 响应式系统的计算开销;
  • 解决方案
    • 静态数据直接定义为普通变量(无需ref):
      // 错误:静态配置不需要响应式
      const staticConfig = ref({ pageSize: 10, title: '列表' })
      // 正确:普通变量,不触发响应式追踪
      const staticConfig = { pageSize: 10, title: '列表' }
      
    • 临时变量(如函数内的中间值)不定义为响应式:
      const handleCalculate = () => {
        // 临时变量,无需响应式
        const tempNum = 10 
        return tempNum * count.value // 仅 count 是响应式数据
      }
      
(2)模板渲染优化:减少不必要的 DOM 操作
  • v-show替代v-if(频繁切换场景)

    • v-if:条件不满足时会销毁 DOM,满足时重新创建,适合“一次判断、很少切换”(如权限控制的按钮);
    • v-show:通过display: none隐藏 DOM,DOM 始终存在,适合“频繁切换”(如 Tab 切换、弹窗显示隐藏),避免频繁创建/销毁 DOM 的开销。
  • v-for必须加key且避免用index作为key

    • key的作用是帮助 Vue 识别 DOM 节点的唯一性,避免复用错误;
    • index作为key(如列表排序/删除时),会导致 Vue 误判节点身份,引发渲染错乱,推荐用数据的唯一 ID 作为key
      <!-- 错误:index 会随列表排序变化 -->
      <div v-for="(item, index) in list" :key="index">{{ item.name }}</div>
      <!-- 正确:用数据唯一 ID 作为 key -->
      <div v-for="item in list" :key="item.id">{{ item.name }}</div>
      
  • 避免在模板中写复杂表达式:复杂逻辑提取到computed或方法中,提升可读性且computed会缓存结果:

    <!-- 错误:模板中逻辑复杂,且无缓存 -->
    <p>{{ item.price > 100 ? `¥${item.price.toFixed(2)}` : `¥${item.price}` }}</p>
    <!-- 正确:用 computed 缓存结果 -->
    <p>{{ formatPrice(item.price) }}</p>
    
    <script setup>
    const formatPrice = computed(() => (price) => {
      return price > 100 ? `¥${price.toFixed(2)}` : `¥${price}`
    })
    </script>
    
(3)组件优化:拆分与缓存结合
  • 拆分大型组件:将超过 300 行代码的组件拆分为“基础组件”(如InputItemButtonGroup)和“业务组件”,提升复用性和维护性,同时减少单个组件的渲染压力;
  • 合理使用KeepAlive缓存组件:对“切换后不需要重新渲染”的组件(如列表页、表单页)用KeepAlive缓存,避免重复请求数据和 DOM 渲染(详见第七章),但不要缓存所有组件(如实时更新的仪表盘),避免内存占用过高。

2. 构建层面优化(Vite 配置为主)

Vue3 项目推荐用 Vite 构建(比 Webpack 更快),通过修改vite.config.js实现打包优化。

(1)减小打包体积:Tree Shaking 与按需引入
  • Tree Shaking:Vite 默认支持 Tree Shaking(摇树优化),会自动移除代码中“未被使用的部分”(如未调用的函数、未引入的组件),但需确保代码符合 ES 模块规范(避免用CommonJSrequire);
  • UI 库按需引入:如 Element Plus、Ant Design Vue 等 UI 库,全量引入会增加 100KB+ 体积,需配置按需引入:
    1. 安装插件:npm install unplugin-vue-components unplugin-auto-import -D
    2. 修改vite.config.js
    // vite.config.js
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    // 按需引入 UI 库的插件
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
    
    export default defineConfig({
      plugins: [
        vue(),
        // 自动导入 Element Plus 的 API(如 ElMessage)
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        // 自动导入 Element Plus 的组件(无需手动 import)
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],
    })
    
    1. 使用组件:直接在模板中用<el-button>,无需手动import ElButton from 'element-plus/es/components/button/index',插件会自动按需引入。
(2)资源优化:图片、字体处理
  • 图片压缩与格式优化

    1. 安装图片压缩插件:npm install vite-plugin-imagemin -D
    2. 配置插件(自动压缩 png/jpg/svg 等格式):
    // vite.config.js
    import Imagemin from 'vite-plugin-imagemin'
    
    export default defineConfig({
      plugins: [
        // ...其他插件
        Imagemin({
          gifsicle: { optimizationLevel: 7 }, // gif 压缩
          optipng: { optimizationLevel: 7 }, // png 压缩
          jpegtran: { quality: 80 }, // jpg 压缩(质量 80,肉眼无明显差异)
          svgo: { plugins: [{ removeViewBox: false }] }, // svg 压缩
        }
      ]
    })
    
    1. 优先使用 WebP 格式:WebP 比 JPG 小 30%+,可通过<picture>标签兼容旧浏览器:
    <picture>
      <source srcset="image.webp" type="image/webp"> <!-- 支持 WebP 的浏览器加载 -->
      <img src="image.jpg" alt="示例图片"> <!-- 不支持的浏览器加载 JPG -->
    </picture>
    
  • 字体文件优化

    • 字体文件(如中文字体)体积大(常超过 1MB),需用“字体子集化”工具(如 FontSpider)提取项目中实际使用的字符,删除无用字符,体积可减小 80%+;
    • 配置 Vite 加载字体文件:
      // vite.config.js
      export default defineConfig({
        resolve: {
          alias: {
            '@fonts': path.resolve(__dirname, 'src/assets/fonts'), // 字体文件路径别名
          }
        }
      })
      
(3)构建产物分析:定位大文件

通过rollup-plugin-visualizer插件生成打包体积分析图,直观看到哪些文件体积过大,针对性优化:

  1. 安装插件:npm install rollup-plugin-visualizer -D
  2. 配置插件:
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    // ...其他插件
    visualizer({
      open: true, // 构建完成后自动打开分析图
      gzipSize: true, // 显示 gzip 压缩后的体积
      brotliSize: true, // 显示 brotli 压缩后的体积
    })
  ]
})
  1. 执行打包:npm run build,会在项目根目录生成stats.html,打开后可看到:
    • node_modules/lodash/lodash.js体积大,可替换为lodash-es(支持 Tree Shaking),或只引入需要的函数(如import debounce from 'lodash/debounce');
    • 如自定义组件体积大,检查是否包含未使用的代码或大型资源。

3. 性能优化:提升加载与交互速度

(1)首屏加载优化:预加载与懒加载
  • 预加载(Preload):对“首屏必需的资源”(如核心 JS、CSS、字体)用<link rel="preload">提前加载,避免渲染阻塞:

    <!-- index.html 中 -->
    <link rel="preload" href="/src/assets/fonts/main-font.woff2" as="font" type="font/woff2" crossorigin>
    <link rel="preload" href="/src/main.js" as="script">
    
  • 懒加载(Lazy Load)

    • 路由懒加载:已在第六章讲解,通过动态import实现“访问路由时才加载组件”;
    • 图片懒加载:用vue-lazyload插件实现“图片进入视口时才加载”:
      1. 安装插件:npm install vue-lazyload -S
      2. 全局注册:
      // main.js
      import { createApp } from 'vue'
      import VueLazyload from 'vue-lazyload'
      const app = createApp(App)
      app.use(VueLazyload, {
        loading: '/src/assets/loading.png', // 加载中占位图
        error: '/src/assets/error.png' // 加载失败占位图
      })
      
      1. 使用:将<img src>改为<img v-lazy>
      <img v-lazy="item.imageUrl" alt="商品图片">
      
(2)缓存策略:减少重复下载
  • HTTP 缓存:通过 Nginx 配置Cache-Control,让浏览器缓存静态资源(如 JS、CSS、图片),下次访问无需重新下载:
    # Nginx 配置
    location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2)$ {
      expires 7d; # 缓存 7 天
      add_header Cache-Control "public, max-age=604800"; # 604800 秒 = 7 天
    }
    
  • 内容哈希(Content Hash):Vite 打包时会自动为静态资源添加“内容哈希”(如main.[hash].js),当文件内容变化时,哈希值会变,浏览器会重新下载;内容不变时,哈希值不变,浏览器继续使用缓存,避免“缓存过期”问题。

三、实战:项目部署(Nginx 上线流程)

Vue3 项目是单页应用(SPA),部署时需解决“路由刷新404”“资源访问路径”两个核心问题,推荐用 Nginx 作为服务器。

1. 打包项目:生成部署文件

  1. 配置vite.config.jsbase(资源基础路径):
    • 若项目部署在域名根路径(如https://example.com/),base: '/'(默认);
    • 若部署在子路径(如https://example.com/vue-project/),base: '/vue-project/'
      // vite.config.js
      export default defineConfig({
        base: '/vue-project/', // 根据实际部署路径修改
        // ...其他配置
      })
      
  2. 执行打包命令:npm run build,会在项目根目录生成dist文件夹(部署的核心文件)。

2. Nginx 配置:解决 SPA 问题

  1. 安装 Nginx:根据操作系统(Windows/Linux/Mac)下载安装,Linux 可通过yum install nginx(CentOS)或apt install nginx(Ubuntu)安装。
  2. 上传dist文件夹:将dist文件夹上传到 Nginx 的html目录(如 Linux 路径/usr/share/nginx/html/vue-project)。
  3. 修改 Nginx 配置文件(核心步骤):
    • 找到配置文件路径:Linux 通常在/etc/nginx/nginx.conf/etc/nginx/conf.d/default.conf
    • 编辑配置:
      server {
        listen 80; # 监听 80 端口(HTTP)
        server_name example.com; # 你的域名(如无域名,填服务器 IP)
      
        # 配置项目路径
        location /vue-project/ { # 与 vite.config.js 的 base 一致
          root /usr/share/nginx/html; # Nginx 静态文件根目录
          index index.html; # 默认首页
          try_files $uri $uri/ /vue-project/index.html; # 解决 SPA 路由刷新404
          # 解释:当访问 /vue-project/goods/1 时,Nginx 先找对应文件,找不到则返回 index.html,由 Vue Router 处理路由
        }
      
        # 静态资源缓存配置(优化加载速度)
        location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2)$ {
          root /usr/share/nginx/html;
          expires 7d;
          add_header Cache-Control "public, max-age=604800";
        }
      }
      
  4. 重启 Nginx:
    • Linux:systemctl restart nginx
    • Windows:打开 Nginx 安装目录,执行nginx -s reload
  5. 验证部署:在浏览器输入https://example.com/vue-project/(或服务器 IP + 路径),能正常访问项目且路由刷新不报错,说明部署成功。

3. 进阶:HTTPS 配置(提升安全性)

现在主流网站都用 HTTPS,需申请 SSL 证书(免费证书可在阿里云、腾讯云申请),并修改 Nginx 配置:

server {
  listen 443 ssl; # 监听 443 端口(HTTPS)
  server_name example.com;

  # SSL 证书配置(替换为你的证书路径)
  ssl_certificate /etc/nginx/ssl/example.com.pem; # 证书公钥
  ssl_certificate_key /etc/nginx/ssl/example.com.key; # 证书私钥

  # SSL 优化配置
  ssl_protocols TLSv1.2 TLSv1.3; # 支持的 TLS 版本
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;

  # 项目路径配置(与 HTTP 一致)
  location /vue-project/ {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /vue-project/index.html;
  }
}

# HTTP 重定向到 HTTPS(强制使用 HTTPS)
server {
  listen 80;
  server_name example.com;
  return 301 https://$host$request_uri; # 将 HTTP 请求重定向到 HTTPS
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐