📦 Uni-app 项目分包提取与构建自动化脚本集
✨ 背景介绍
在 Uni-app 项目中,合理使用 subPackages
(分包)不仅能提升 App 首屏加载速度,还能增强模块化管理,特别适用于大型项目或多人协作开发场景。
为了简化分包配置的维护,本文提供了一套完整的 Node.js 脚本方案,支持以下功能:
- 自动从
pages.json
提取subPackages
并生成独立配置文件(按需使用); - 将独立配置文件合并回
pages.json
,避免手动修改; - 集成到 Vite 构建流程中,实现构建时自动更新配置,提升开发与发布效率。
⚠️ 使用前需确保本地已安装 Node.js。
📁 项目结构概览
建议目录结构如下:
arduino
arduino
复制编辑
your-project/
├─ pages.json // 页面配置主文件
├─ createSubPackageDirs.js // 提取并生成分包 JSON 的脚本
├─ build-pages.js // 根据分包 JSON 写入 pages.json 的脚本
├─ vite.config.js // Vite 构建配置,集成自动更新脚本
├─ subPackages_pages/ // 存放分包 JSON 的目录
🛠 脚本一:提取分包配置并生成 JSON 文件
✅ 脚本功能
- 读取
pages.json
中的subPackages
配置; - 为每个分包生成一个以
root
最后路径片段命名的.json
文件; - 输出目录为
subPackages_pages/
,便于模块管理与版本控制。
🔧 使用方法
⚠️ 该脚本是为了将就旧项目中pages.json里面的分包进行提取以便管理,该脚本也可以不执行
bash
复制编辑
node createSubPackageDirs.js
执行后将自动生成对应的 JSON 文件。
📄 脚本源码
javascript
js
复制编辑
// createSubPackageDirs.js
const fs = require('fs');
const path = require('path');
const pagesJsonPath = path.resolve(__dirname, 'pages.json');
const targetBaseDir = path.resolve(__dirname, 'subPackages_pages');
function readPagesJson() {
try {
const data = fs.readFileSync(pagesJsonPath, 'utf-8');
return JSON.parse(data);
} catch (err) {
console.error('❌ 无法读取 pages.json:', err);
process.exit(1);
}
}
function createDirIfNotExists(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
console.log(`✅ 已创建目录: ${dirPath}`);
}
}
function writeJsonFile(filePath, data) {
try {
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
console.log(`✅ 写入成功: ${filePath}`);
} catch (err) {
console.error(`❌ 写入失败: ${filePath}`, err);
}
}
function main() {
createDirIfNotExists(targetBaseDir);
const config = readPagesJson();
const subPackages = config.subPackages || [];
if (!subPackages.length) {
console.log('⚠️ 未发现 subPackages 配置');
return;
}
subPackages.forEach((pkg) => {
if (pkg.root) {
const fileName = path.basename(pkg.root) + '.json';
const targetPath = path.join(targetBaseDir, fileName);
writeJsonFile(targetPath, pkg);
}
});
console.log('🎉 分包 JSON 提取完成!');
}
main();
🛠 脚本二:合并 JSON 文件回 pages.json
⚠️ 如果 pages.json
中已存在 subPackages
配置并包含部分分包内容,建议先执行 createSubPackageDirs.js
脚本,将现有分包配置导出为独立的 JSON 文件。
若未执行导出脚本 ,在后续执行合并脚本时,subPackages_pages/
目录中的 JSON 文件如果与现有 pages.json
中的某个 root
路径一致,将直接覆盖对应分包的配置内容,请谨慎操作以避免意外数据丢失。
✅ 脚本功能
- 扫描
subPackages_pages/
中的所有.json
文件; - 校验
root
与pages
字段; - 自动与已有
subPackages
做哈希比对,避免重复写入; - 更新并写入新的
pages.json
文件。
🔧 使用方法
bash
复制编辑
node build-pages.js
📄 脚本源码
ini
js
复制编辑
// build-pages.js
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
function getObjectHash(obj) {
return crypto.createHash('md5').update(JSON.stringify(obj)).digest('hex');
}
const rootDir = path.resolve(__dirname);
const mainPagesPath = path.join(rootDir, 'pages.json');
const subPackagesDir = path.join(rootDir, 'subPackages_pages');
if (!fs.existsSync(mainPagesPath)) {
console.error(`❌ pages.json 不存在: ${mainPagesPath}`);
process.exit(1);
}
let mainConfig = {};
try {
mainConfig = JSON.parse(fs.readFileSync(mainPagesPath, 'utf-8'));
} catch (e) {
console.error('❌ 解析 pages.json 出错', e);
process.exit(1);
}
const existingMap = new Map();
(mainConfig.subPackages || []).forEach(pkg => {
if (pkg.root) {
existingMap.set(pkg.root, {
pkg,
hash: getObjectHash(pkg)
});
}
});
const newSubPackages = [];
if (fs.existsSync(subPackagesDir)) {
fs.readdirSync(subPackagesDir).forEach(file => {
const fullPath = path.join(subPackagesDir, file);
if (file.endsWith('.json')) {
try {
const pkg = JSON.parse(fs.readFileSync(fullPath, 'utf8'));
if (pkg.root && Array.isArray(pkg.pages)) {
newSubPackages.push(pkg);
}
} catch (e) {
console.warn(`⚠️ 解析失败: ${file}`, e);
}
}
});
}
let changed = false;
newSubPackages.forEach(pkg => {
const old = existingMap.get(pkg.root);
const newHash = getObjectHash(pkg);
if (!old || old.hash !== newHash) {
existingMap.set(pkg.root, { pkg, hash: newHash });
changed = true;
}
});
if (changed) {
const merged = Array.from(existingMap.values()).map(v => v.pkg);
const updated = { ...mainConfig, subPackages: merged };
try {
fs.writeFileSync(mainPagesPath, JSON.stringify(updated, null, 2), 'utf8');
console.log(`✅ 已更新 pages.json`);
} catch (e) {
console.error(`❌ 写入 pages.json 失败`, e);
}
} else {
console.log('✅ 分包未变化,无需写入');
}
⚙️ 集成 Vite 自动构建流程
将以下插件集成到你的 vite.config.js
中,可在打包时自动执行分包构建逻辑。
javascript
js
复制编辑
// vite.config.js
import { defineConfig } from 'vite';
import { execSync } from 'child_process';
import uni from '@dcloudio/vite-plugin-uni';
import path from 'path';
export default defineConfig({
plugins: [
uni(),
autoBuildPagesPlugin()
]
});
function autoBuildPagesPlugin() {
return {
name: 'auto-build-pages',
apply: 'build',
buildStart() {
try {
const scriptPath = path.resolve(__dirname, 'build-pages.js');
execSync(`node "${scriptPath}"`, { stdio: 'inherit' });
console.log('📦 pages.json 构建完成');
} catch (error) {
console.error('❌ 构建 pages.json 出错', error);
throw error;
}
}
};
}