UniApp 多页面编译优化:编译时间从10分钟到1分钟

在开发大型 UniApp 项目时,随着业务功能不断增加,页面数量可能达到上百个。每次保存代码都要重新编译所有页面,编译时间可能长达 10分钟以上,严重影响了开发效率。

解决方案概述

通过动态生成 pages.json 实现按需编译,只编译当前开发所需的页面,大幅提升编译速度。

实现效果

优化前 yarn run dev编译耗时201044ms

优化后 yarn run dev -m mode1编译耗时32399ms

完整目录结构

首先,让我们看一下优化后的项目目录结构:

makefile 复制代码
your-uniapp-project/
├── src/
│   ├── pages.json              # 动态生成的文件(会被覆盖)
│   ├── pages/
│   │   ├── index/
│   │   ├── emp/
│   │   └── ...
│   └── ...
├── config/                     # 新增的配置目录
│   ├── pages.json              # 完整的页面配置(原src/pages.json的备份)
│   ├── pages.core.json         # 核心页面配置
│   ├── pages.include.json      # 模块化页面配置
│   └── pages-generate.js       # 页面生成脚本
├── package.json
└── ...

第一步:创建配置目录和文件

1. 创建 config 目录

在项目根目录下创建 config 文件夹。

2. 备份原始 pages.json

src/pages.json 复制到 config/pages.json

json 复制代码
// config/pages.json
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": { ... }
    },
    // ... 所有页面配置
  ],
  "subPackages": [
    {
      "root": "pages/emp",
      "pages": [
        {
          "path": "my/login",
          "style": { ... }
        },
        // ... 所有分包页面
      ]
    }
  ],
  "preloadRule": { ... },
  // ... 其他配置
}

3. 创建核心页面配置

json 复制代码
// config/pages.core.json
{
  "modules": [
    "pages/index/index",
    "pages/emp/my/login",
    "pages/emp/index", 
    "pages/emp/common",
    "commonComponents/index",
    "pages/emp/dept/resSelect",
    "pages/emp/customerGroup/robotList",
    "pages/emp/employee/edit",
    "pages/emp/customer/index"
  ]
}

说明:这些是应用的基石页面,无论开发哪个模块都必须包含。(针对自己的项目进行配置)

4. 创建模块化页面配置

json 复制代码
// config/pages.include.json
{
  "modules": {
    "mode1": [
      "pages/emp/customer/index",
      "pages/emp/order/index",
      "pages/emp/order/detail"
    ],
    "mode2": [
      "pages/product/index",
      "pages/product/detail"
    ]
  }
}

说明:按业务模块组织页面,方便按需选择。

第二步:创建页面生成脚本

创建 config/pages-generate.js

javascript 复制代码
const fs = require('fs')
require('dotenv').config()

// 1. 获取命令行参数
let moduleStr = ''
if (process.env.npm_config_argv) {
  const args = JSON.parse(process.env.npm_config_argv).original
  const i = args.findIndex(arg => arg.startsWith('-m'))
  moduleStr = args[i + 1]
}
if (process.env.npm_config_message) {
  moduleStr = process.env.npm_config_message
}
const enabledModules = moduleStr.split(/\s|,/g) || []

console.log(`启用的模块: ${enabledModules.join(', ')}`)

// 2. 读取所有配置文件
const pagesConfig = JSON.parse(fs.readFileSync('./config/pages.json', 'utf8'))
const moduleConfig = JSON.parse(fs.readFileSync('./config/pages.include.json', 'utf8'))
const commonConfig = JSON.parse(fs.readFileSync('./config/pages.core.json', 'utf8'))

// 3. 收集需要保留的页面路径
const retainedPaths = new Set()

// 3.1 添加选中的模块页面
enabledModules.forEach(module => {
  const modulePages = moduleConfig.modules[module] || []
  console.log(`模块 ${module} 包含 ${modulePages.length} 个页面`)
  modulePages.forEach(path => retainedPaths.add(path))
})

// 3.2 如果有选中模块,自动加入核心页面
if (retainedPaths.size > 0) {
  console.log(`添加 ${commonConfig.modules.length} 个核心页面`)
  commonConfig.modules.forEach(path => {
    retainedPaths.add(path)
  })
}

console.log(`总共保留 ${retainedPaths.size} 个页面路径`)

// 4. 处理主包页面(pages 数组)
const retainedPages = pagesConfig.pages.filter(page => {
  // 如果没有选中任何模块,保留所有页面
  if (retainedPaths.size === 0) return true
  // 否则只保留在 retainedPaths 中的页面
  return retainedPaths.has(page.path)
})

console.log(`主包页面保留: ${retainedPages.length}/${pagesConfig.pages.length}`)

// 5. 处理分包页面(subPackages 数组)
const retainedSubPackages = pagesConfig.subPackages
  .map(subPackage => {
    // 如果没有选中任何模块,保留所有分包
    if (retainedPaths.size === 0) return subPackage
    
    // 过滤分包的页面
    const filteredPages = subPackage.pages.filter(page => {
      const fullPath = `${subPackage.root}/${page.path}`
      // 检查页面路径是否在保留列表中
      return [...retainedPaths].some(path => fullPath.includes(path))
    })
    
    // 如果分包还有页面,就保留这个分包
    return filteredPages.length > 0 
      ? { ...subPackage, pages: filteredPages } 
      : null
  })
  .filter(Boolean)  // 过滤掉 null

console.log(`分包数量保留: ${retainedSubPackages.length}/${pagesConfig.subPackages.length}`)

// 6. 处理预加载规则(preloadRule)
const retainedSubPackageRoots = new Set(retainedSubPackages.map(sp => sp.root))
const retainedPreloadRule = {}
Object.entries(pagesConfig.preloadRule || {}).forEach(([key, rule]) => {
  const validPackages = rule.packages.filter(pkg => retainedSubPackageRoots.has(pkg))
  if (validPackages.length) {
    retainedPreloadRule[key] = { ...rule, packages: validPackages }
  }
})

// 7. 生成新的 pages.json
const generated = {
  ...pagesConfig,
  pages: retainedPages,
  subPackages: retainedSubPackages,
  preloadRule: retainedPreloadRule
}

// 8. 写入到 src 目录
fs.writeFileSync('./src/pages.json', JSON.stringify(generated, null, 2))
console.log('✅ pages.json 已生成!编译时将只包含选中的页面。')

第三步:修改 package.json

修改 package.json 中的编译脚本:

json 复制代码
{
  "scripts": {
    "dev": "node config/pages-generate.js && cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
  }
}

第四步:使用方式

方式一:传统编译(所有页面)

bash 复制代码
npm run dev

方式二:按模块编译

bash 复制代码
# 编译 mode1 模块(核心页面 + mode1模块页面)
npm run dev -m mode1

# 编译多个模块
npm run dev -m mode1,mode2

效果对比

编译方式 页面数量 编译时间 开发体验
传统编译 100+ 页面 10+ 分钟 ❌ 极其糟糕
按模块编译 1~100+ 页面 0.1~10+ 分钟 ✅ 流畅高效

常见问题解答

Q1:为什么要备份 config/pages.json?

A:因为生成脚本会覆盖 src/pages.json,需要保留完整的配置作为模板。(因此需要注意:生成的脚本仅在本地开发时使用

Q2:如何添加新的模块?

A:需要分别在 config/pages.include.jsonsrc/pages.jsonmodules 对象中添加新的模块配置。

Q3:如何确定页面路径?

A:页面路径就是 pages.json 中配置的 path,分包页面需要加上分包根路径。

Q4:这个方案会影响生产环境吗?

A:不会。生产环境构建时使用完整的 pages.json,这个方案只用于开发环境。

总结

通过这个完整的配置方案,你可以:

  1. 大幅减少编译时间:从10分钟降到1-2分钟
  2. 按需编译:只编译当前开发的模块
  3. 保持灵活性:随时切换编译模式
相关推荐
华洛几秒前
实战指南:企业如何选择AI需求的落地技术方案
前端·产品经理·产品
莫爷1 分钟前
JSON vs XML vs YAML 深度对比:如何选择合适的数据格式?
xml·前端·json
We་ct8 分钟前
LeetCode 33. 搜索旋转排序数组:O(log n)二分查找
前端·算法·leetcode·typescript·个人开发·二分·数组
华仔啊13 分钟前
前端不懂 Java?后端怕 CSS?这套AI全栈方案专治各种偏科
java·前端·后端
木斯佳16 分钟前
前端八股文面经大全:得物AI应用开发一面(2026-03-23)·面经深度解析【加精】
前端·人工智能·ai·markdown·chat·rag
无巧不成书02182 小时前
Windows PowerShell执行策略详解:从npm报错到完美解决
前端·windows·npm·powershell执行策略·执行策略·npm.ps1·脚本报错
Z兽兽9 小时前
React@18+Vite项目配置env文件
前端·react.js·前端框架
SuniaWang9 小时前
《Spring AI + 大模型全栈实战》学习手册系列 · 专题六:《Vue3 前端开发实战:打造企业级 RAG 问答界面》
java·前端·人工智能·spring boot·后端·spring·架构
A_nanda10 小时前
根据AI提示排查vue前端项目
前端·javascript·vue.js
happymaker062610 小时前
web前端学习日记——DAY05(定位、浮动、视频音频播放)
前端·学习·音视频