505 lines
14 KiB
JavaScript
505 lines
14 KiB
JavaScript
/**
|
||
* 切换 pages.json 到不同端的专属编译模式。
|
||
*
|
||
* 用法:
|
||
* npm run pages:consumer → 仅编译 consumer 相关页面
|
||
* npm run pages:merchant → 仅编译 merchant 相关页面
|
||
* npm run pages:admin → 仅编译 admin 相关页面
|
||
* npm run pages:full → 恢复完整 pages.json
|
||
*/
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
|
||
const root = path.resolve(__dirname, "..");
|
||
const pagesJson = path.join(root, "pages.json");
|
||
const pagesFull = path.join(root, "pages.full.json");
|
||
const backupDir = path.join(root, ".pages-backup");
|
||
const pagesModeFile = path.join(root, "utils", "pagesMode.uts");
|
||
const currentClientFile = path.join(root, "config", "current-client.uts");
|
||
const pageExtensions = [".uvue", ".vue", ".nvue"];
|
||
|
||
const consumerUserPages = [
|
||
"pages/user/boot",
|
||
"pages/user/login",
|
||
"pages/user/register",
|
||
"pages/user/forgot-password",
|
||
"pages/user/terms",
|
||
"pages/user/center",
|
||
"pages/user/profile",
|
||
"pages/user/change-password",
|
||
"pages/user/bind-phone",
|
||
"pages/user/bind-email",
|
||
];
|
||
|
||
const merchantUserPages = [
|
||
"pages/user/login",
|
||
"pages/user/boot",
|
||
"pages/user/register",
|
||
"pages/user/forgot-password",
|
||
"pages/user/terms",
|
||
"pages/user/change-password",
|
||
];
|
||
|
||
const adminUserPages = [
|
||
"pages/user/login",
|
||
"pages/user/boot",
|
||
"pages/user/forgot-password",
|
||
"pages/user/terms",
|
||
"pages/user/change-password",
|
||
];
|
||
|
||
const targetConfigs = {
|
||
consumer: {
|
||
fileName: "pages.consumer.json",
|
||
label: "消费者端",
|
||
entryPath: "pages/main/index",
|
||
homeRedirect: "/pages/main/index",
|
||
tabBarPath: "/pages/main/index",
|
||
orderedTopLevelPaths: [
|
||
"pages/main/index",
|
||
...consumerUserPages,
|
||
"pages/main/messages",
|
||
"pages/main/cart",
|
||
"pages/main/profile",
|
||
],
|
||
topLevelMatcher(pagePath) {
|
||
return (
|
||
pagePath.startsWith("pages/main/") ||
|
||
consumerUserPages.includes(pagePath)
|
||
);
|
||
},
|
||
subPackageMatcher(rootPath) {
|
||
return rootPath === "pages/mall/consumer";
|
||
},
|
||
tabBarMatcher(pagePath) {
|
||
return pagePath.startsWith("pages/main/");
|
||
},
|
||
defaultCondition() {
|
||
return {
|
||
current: 0,
|
||
list: [
|
||
{
|
||
name: "consumer端",
|
||
path: "pages/main/index",
|
||
query: "role=consumer",
|
||
},
|
||
],
|
||
};
|
||
},
|
||
},
|
||
merchant: {
|
||
fileName: "pages.merchant.json",
|
||
label: "商家端",
|
||
entryPath: "pages/user/login",
|
||
homeRedirect: "/pages/mall/merchant/index",
|
||
tabBarPath: "",
|
||
orderedTopLevelPaths: [
|
||
"pages/user/login",
|
||
"pages/user/boot",
|
||
"pages/user/register",
|
||
"pages/user/forgot-password",
|
||
"pages/user/terms",
|
||
"pages/user/change-password",
|
||
"pages/mall/merchant/index",
|
||
"pages/mall/merchant/messages",
|
||
"pages/mall/merchant/orders",
|
||
"pages/mall/merchant/growth",
|
||
"pages/mall/merchant/profile",
|
||
],
|
||
topLevelMatcher(pagePath) {
|
||
return (
|
||
merchantUserPages.includes(pagePath) ||
|
||
pagePath.startsWith("pages/mall/merchant/")
|
||
);
|
||
},
|
||
subPackageMatcher() {
|
||
return false;
|
||
},
|
||
defaultCondition() {
|
||
return {
|
||
current: 0,
|
||
list: [
|
||
{
|
||
name: "merchant端",
|
||
path: "pages/mall/merchant/index",
|
||
query: "role=merchant",
|
||
},
|
||
],
|
||
};
|
||
},
|
||
},
|
||
admin: {
|
||
fileName: "pages.admin.json",
|
||
label: "管理后台",
|
||
entryPath: "pages/user/login",
|
||
homeRedirect: "/pages/mall/admin/homePage/index",
|
||
tabBarPath: "",
|
||
orderedTopLevelPaths: [
|
||
"pages/user/login",
|
||
"pages/user/boot",
|
||
"pages/user/forgot-password",
|
||
"pages/user/terms",
|
||
"pages/user/change-password",
|
||
"pages/mall/admin/homePage/index",
|
||
"pages/mall/admin/userCenter/index",
|
||
],
|
||
topLevelMatcher(pagePath) {
|
||
return (
|
||
adminUserPages.includes(pagePath) ||
|
||
pagePath === "pages/mall/admin/homePage/index" ||
|
||
pagePath === "pages/mall/admin/userCenter/index"
|
||
);
|
||
},
|
||
subPackageMatcher(rootPath) {
|
||
return rootPath.startsWith("pages/mall/admin/");
|
||
},
|
||
defaultCondition() {
|
||
return {
|
||
current: 0,
|
||
list: [
|
||
{
|
||
name: "admin端",
|
||
path: "pages/mall/admin/homePage/index",
|
||
query: "role=admin",
|
||
},
|
||
],
|
||
};
|
||
},
|
||
},
|
||
delivery: {
|
||
fileName: "pages.delivery.json",
|
||
label: "服务人员端/上门服务端",
|
||
entryPath: "pages/user/login",
|
||
homeRedirect: "/pages/mall/delivery/home/index",
|
||
tabBarPath: "/pages/mall/delivery/home/index",
|
||
standalone: true,
|
||
},
|
||
};
|
||
|
||
const fullModeConfig = {
|
||
homeRedirect: "/pages/main/index",
|
||
tabBarPath: "/pages/main/index",
|
||
};
|
||
|
||
const mode = process.argv[2]; // 'consumer' | 'merchant' | 'admin' | 'full'
|
||
|
||
function readJson(filePath) {
|
||
const rawContent = fs.readFileSync(filePath, "utf8").replace(/^\uFEFF/, "");
|
||
return JSON.parse(rawContent);
|
||
}
|
||
|
||
function writeJson(filePath, content) {
|
||
fs.writeFileSync(filePath, `${JSON.stringify(content, null, 2)}\n`, "utf8");
|
||
}
|
||
|
||
function writePagesMode(modeName) {
|
||
fs.writeFileSync(
|
||
pagesModeFile,
|
||
`export const CURRENT_PAGES_MODE = '${modeName}'\n`,
|
||
"utf8",
|
||
);
|
||
}
|
||
|
||
function writeCurrentClient(modeName) {
|
||
fs.mkdirSync(path.dirname(currentClientFile), { recursive: true });
|
||
fs.writeFileSync(
|
||
currentClientFile,
|
||
`export const CURRENT_CLIENT: string = '${modeName}'\n`,
|
||
"utf8",
|
||
);
|
||
console.log(`🔁 已同步当前端标识 → ${modeName}`);
|
||
}
|
||
|
||
function ensureFullBackup() {
|
||
if (fs.existsSync(pagesFull)) {
|
||
return;
|
||
}
|
||
fs.copyFileSync(pagesJson, pagesFull);
|
||
console.log("📦 已备份 pages.json → pages.full.json");
|
||
}
|
||
|
||
function backupCurrentPages(targetName) {
|
||
if (!fs.existsSync(pagesJson)) {
|
||
return;
|
||
}
|
||
|
||
fs.mkdirSync(backupDir, { recursive: true });
|
||
const timestamp = new Date().toISOString().replace(/[.:]/g, "-");
|
||
const backupPath = path.join(
|
||
backupDir,
|
||
`pages.${targetName}.${timestamp}.json`,
|
||
);
|
||
fs.copyFileSync(pagesJson, backupPath);
|
||
console.log(`📦 已备份当前 pages.json → ${path.relative(root, backupPath)}`);
|
||
}
|
||
|
||
function getPageMap(fullConfig) {
|
||
return new Map(fullConfig.pages.map((page) => [page.path, page]));
|
||
}
|
||
|
||
function findMatchingPageFile(routePath) {
|
||
for (const extension of pageExtensions) {
|
||
const candidate = path.join(root, `${routePath}${extension}`);
|
||
if (fs.existsSync(candidate)) {
|
||
return candidate;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function clonePage(page) {
|
||
return JSON.parse(JSON.stringify(page));
|
||
}
|
||
|
||
function flattenSubPackagePages(fullConfig, rootPath) {
|
||
const targetPackage = fullConfig.subPackages.find(
|
||
(item) => item.root === rootPath,
|
||
);
|
||
if (!targetPackage) {
|
||
return [];
|
||
}
|
||
|
||
return targetPackage.pages.map((page) => ({
|
||
path: `${rootPath}/${page.path}`,
|
||
style: page.style ? JSON.parse(JSON.stringify(page.style)) : {},
|
||
}));
|
||
}
|
||
|
||
function getTopLevelPages(fullConfig, targetConfig) {
|
||
const pageMap = getPageMap(fullConfig);
|
||
const matchedFromTopLevel = fullConfig.pages
|
||
.filter((page) => targetConfig.topLevelMatcher(page.path))
|
||
.map((page) => clonePage(page));
|
||
|
||
const flattenedPages = (targetConfig.flattenRoots || []).flatMap((rootPath) =>
|
||
flattenSubPackagePages(fullConfig, rootPath),
|
||
);
|
||
|
||
const mergedMap = new Map();
|
||
for (const page of [...matchedFromTopLevel, ...flattenedPages]) {
|
||
mergedMap.set(page.path, page);
|
||
}
|
||
|
||
const orderedPages = [];
|
||
for (const pagePath of targetConfig.orderedTopLevelPaths) {
|
||
if (mergedMap.has(pagePath)) {
|
||
orderedPages.push(mergedMap.get(pagePath));
|
||
mergedMap.delete(pagePath);
|
||
} else if (pageMap.has(pagePath)) {
|
||
orderedPages.push(clonePage(pageMap.get(pagePath)));
|
||
}
|
||
}
|
||
|
||
for (const page of [...matchedFromTopLevel, ...flattenedPages]) {
|
||
if (mergedMap.has(page.path)) {
|
||
orderedPages.push(mergedMap.get(page.path));
|
||
mergedMap.delete(page.path);
|
||
}
|
||
}
|
||
|
||
return dedupePages(orderedPages);
|
||
}
|
||
|
||
function getSubPackages(fullConfig, targetConfig) {
|
||
return fullConfig.subPackages
|
||
.filter((item) => targetConfig.subPackageMatcher(item.root))
|
||
.map((item) => JSON.parse(JSON.stringify(item)));
|
||
}
|
||
|
||
function dedupePages(pages) {
|
||
const seen = new Set();
|
||
return pages.filter((page) => {
|
||
if (seen.has(page.path)) {
|
||
return false;
|
||
}
|
||
seen.add(page.path);
|
||
return true;
|
||
});
|
||
}
|
||
|
||
function getCondition(targetConfig, sourceCondition) {
|
||
if (sourceCondition && Array.isArray(sourceCondition.list)) {
|
||
const filteredList = sourceCondition.list.filter(
|
||
(item) => item.path === targetConfig.entryPath,
|
||
);
|
||
if (filteredList.length > 0) {
|
||
return {
|
||
current: 0,
|
||
list: filteredList,
|
||
};
|
||
}
|
||
}
|
||
|
||
return targetConfig.defaultCondition();
|
||
}
|
||
|
||
function validateGeneratedConfig(targetName, config) {
|
||
const missingRoutes = [];
|
||
const routeSet = new Set();
|
||
|
||
for (const page of config.pages || []) {
|
||
routeSet.add(page.path);
|
||
if (!findMatchingPageFile(page.path)) {
|
||
missingRoutes.push(page.path);
|
||
}
|
||
}
|
||
|
||
for (const subPackage of config.subPackages || []) {
|
||
for (const page of subPackage.pages || []) {
|
||
const fullPath = `${subPackage.root}/${page.path}`;
|
||
routeSet.add(fullPath);
|
||
if (!findMatchingPageFile(fullPath)) {
|
||
missingRoutes.push(fullPath);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (const tabItem of config.tabBar?.list || []) {
|
||
if (!routeSet.has(tabItem.pagePath)) {
|
||
missingRoutes.push(`tabBar -> ${tabItem.pagePath}`);
|
||
}
|
||
}
|
||
|
||
for (const conditionItem of config.condition?.list || []) {
|
||
if (!routeSet.has(conditionItem.path)) {
|
||
missingRoutes.push(`condition -> ${conditionItem.path}`);
|
||
}
|
||
}
|
||
|
||
if (missingRoutes.length > 0) {
|
||
console.error(`❌ ${targetName} 配置存在无效页面引用:`);
|
||
for (const routePath of missingRoutes) {
|
||
console.error(` - ${routePath}`);
|
||
}
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
function buildTargetConfig(fullConfig, targetName, sourceCondition) {
|
||
const targetConfig = targetConfigs[targetName];
|
||
const nextConfig = {};
|
||
|
||
nextConfig.pages = getTopLevelPages(fullConfig, targetConfig);
|
||
nextConfig.subPackages = getSubPackages(fullConfig, targetConfig);
|
||
|
||
if (targetConfig.tabBarMatcher) {
|
||
const filteredTabBarList = (fullConfig.tabBar?.list || []).filter((item) =>
|
||
targetConfig.tabBarMatcher(item.pagePath),
|
||
);
|
||
if (filteredTabBarList.length > 0 && fullConfig.tabBar) {
|
||
nextConfig.tabBar = {
|
||
...JSON.parse(JSON.stringify(fullConfig.tabBar)),
|
||
list: filteredTabBarList,
|
||
};
|
||
}
|
||
}
|
||
|
||
for (const key of Object.keys(fullConfig)) {
|
||
if (["pages", "subPackages", "tabBar", "condition"].includes(key)) {
|
||
continue;
|
||
}
|
||
nextConfig[key] = JSON.parse(JSON.stringify(fullConfig[key]));
|
||
}
|
||
|
||
nextConfig.condition = getCondition(targetConfig, sourceCondition);
|
||
|
||
validateGeneratedConfig(targetName, nextConfig);
|
||
return nextConfig;
|
||
}
|
||
|
||
function writeTargetConfig(targetName, config) {
|
||
const targetPath = path.join(root, targetConfigs[targetName].fileName);
|
||
writeJson(targetPath, config);
|
||
fs.copyFileSync(targetPath, pagesJson);
|
||
writePagesMode(targetName);
|
||
writeCurrentClient(targetName);
|
||
|
||
const pageCount = config.pages.length;
|
||
const subPackageCount = config.subPackages.length;
|
||
const tabBarCount = config.tabBar?.list?.length || 0;
|
||
|
||
console.log(`✅ 已切换为【${targetConfigs[targetName].label}专属编译模式】`);
|
||
console.log(` 目标配置:${targetConfigs[targetName].fileName}`);
|
||
console.log(` pages:${pageCount} 个`);
|
||
console.log(` subPackages:${subPackageCount} 个`);
|
||
console.log(` tabBar:${tabBarCount} 个`);
|
||
console.log(" 恢复完整版本:npm run pages:full");
|
||
}
|
||
|
||
function switchStandaloneConfig(targetName) {
|
||
const targetPath = path.join(root, targetConfigs[targetName].fileName);
|
||
if (!fs.existsSync(targetPath)) {
|
||
console.error(`❌ ${targetConfigs[targetName].fileName} 不存在。`);
|
||
process.exit(1);
|
||
}
|
||
|
||
const config = readJson(targetPath);
|
||
validateGeneratedConfig(targetName, config);
|
||
fs.copyFileSync(targetPath, pagesJson);
|
||
writePagesMode(targetName);
|
||
writeCurrentClient(targetName);
|
||
|
||
const pageCount = config.pages != null ? config.pages.length : 0;
|
||
const subPackageCount =
|
||
config.subPackages != null ? config.subPackages.length : 0;
|
||
const tabBarCount =
|
||
config.tabBar != null && Array.isArray(config.tabBar.list)
|
||
? config.tabBar.list.length
|
||
: 0;
|
||
|
||
console.log(`✅ 已切换为【${targetConfigs[targetName].label}专属编译模式】`);
|
||
console.log(` 目标配置:${targetConfigs[targetName].fileName}`);
|
||
console.log(` pages:${pageCount} 个`);
|
||
console.log(` subPackages:${subPackageCount} 个`);
|
||
console.log(` tabBar:${tabBarCount} 个`);
|
||
console.log(" 恢复完整版本:npm run pages:full");
|
||
}
|
||
|
||
function restoreFullPages() {
|
||
if (!fs.existsSync(pagesFull)) {
|
||
console.error("❌ pages.full.json 不存在。");
|
||
console.error(" 可能当前已经是完整模式,或备份文件已被删除。");
|
||
process.exit(1);
|
||
}
|
||
|
||
backupCurrentPages("full");
|
||
fs.copyFileSync(pagesFull, pagesJson);
|
||
writePagesMode("full");
|
||
writeCurrentClient("full");
|
||
console.log("✅ 已恢复【完整 pages.json】");
|
||
console.log(" 包含 consumer + merchant + admin 全部页面。");
|
||
}
|
||
|
||
if (mode === "full") {
|
||
restoreFullPages();
|
||
} else if (Object.prototype.hasOwnProperty.call(targetConfigs, mode)) {
|
||
ensureFullBackup();
|
||
backupCurrentPages(mode);
|
||
|
||
if (targetConfigs[mode].standalone === true) {
|
||
switchStandaloneConfig(mode);
|
||
process.exit(0);
|
||
}
|
||
|
||
const fullConfig = readJson(pagesFull);
|
||
const sourceCondition = fs.existsSync(pagesJson)
|
||
? (() => {
|
||
try {
|
||
return readJson(pagesJson).condition;
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
})()
|
||
: null;
|
||
|
||
const nextConfig = buildTargetConfig(fullConfig, mode, sourceCondition);
|
||
writeTargetConfig(mode, nextConfig);
|
||
} else {
|
||
console.log("用法:");
|
||
console.log(" npm run pages:consumer 切换到消费者端专属编译模式");
|
||
console.log(" npm run pages:delivery 切换到服务人员端专属编译模式");
|
||
console.log(" npm run pages:merchant 切换到商家端专属编译模式");
|
||
console.log(" npm run pages:admin 切换到管理后台专属编译模式");
|
||
console.log(" npm run pages:full 恢复完整编译模式");
|
||
}
|