- packages/core: @aidir/core 底座库(src/pages 页面组件体 1:1 镜像路由树 / kit 站点外壳工厂 / content/blog / scripts) - sites/: 5 个独立 Next.js 网站(ai-stack / launchai / the-ai-ledger / devai-tools / findai) - 每站独立 package.json / next.config / tailwind / messages / .env / 构建 - src/app 约 56 个薄路由文件(re-export 底座页面 + 内联路由段配置 revalidate/dynamic) - src/site/brand.tsx 站点配置 + src/site/home.tsx 站点首页(createMarketingLayout / createHomePage 工厂) - generate-site.mjs: 站点生成器(新增网站 = SITES 加条目,零 Core 修改) - start-all-sites.sh: 一键启动 3001-3005 - next-config.mjs: 底座统一 Next 配置工厂(next-intl + MDX + standalone) - 五站共享同一套 PostgreSQL / Better Auth / Admin(设计文档 §42) - 验证: 5 站 build OK / typecheck OK / 55 路由冒烟 200 / 品牌-内容-截图 差异确认 / 登录-投票-重复检测 e2e PASS
75 lines
1.8 KiB
JavaScript
75 lines
1.8 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import glob from "fast-glob";
|
|
|
|
async function main() {
|
|
const blogRoot = path.join(process.cwd(), "src/content/blog");
|
|
const entries = await glob("**/*.mdx", { cwd: blogRoot });
|
|
const manifest = new Map();
|
|
|
|
for (const entry of entries) {
|
|
const segments = entry.split("/");
|
|
|
|
if (segments.length < 2) {
|
|
continue;
|
|
}
|
|
|
|
const [slug, filename] = segments;
|
|
|
|
if (!slug || slug.startsWith("[")) {
|
|
continue;
|
|
}
|
|
|
|
const locale = filename.replace(/\.mdx$/, "");
|
|
|
|
if (!locale) {
|
|
continue;
|
|
}
|
|
|
|
if (!manifest.has(slug)) {
|
|
manifest.set(slug, new Set());
|
|
}
|
|
|
|
manifest.get(slug).add(locale);
|
|
}
|
|
|
|
const sortedManifest = Array.from(manifest.entries()).sort(([a], [b]) =>
|
|
a.localeCompare(b)
|
|
);
|
|
|
|
const lines = [];
|
|
lines.push("// This file is auto-generated by scripts/generate-blog-manifest.mjs");
|
|
lines.push("// Do not edit manually.\n");
|
|
lines.push("export const blogModuleLoaders = {");
|
|
|
|
for (const [slug, locales] of sortedManifest) {
|
|
lines.push(` "${slug}": {`);
|
|
|
|
const sortedLocales = Array.from(locales).sort((a, b) => a.localeCompare(b));
|
|
|
|
for (const locale of sortedLocales) {
|
|
// 使用 path.posix 确保导入路径始终使用 / (跨平台兼容)
|
|
const importPath = path.posix.join(
|
|
"..",
|
|
"content",
|
|
"blog",
|
|
slug,
|
|
`${locale}.mdx`
|
|
);
|
|
lines.push(` "${locale}": () => import("${importPath}"),`);
|
|
}
|
|
|
|
lines.push(" },");
|
|
}
|
|
|
|
lines.push("} as const;\n");
|
|
|
|
const targetPath = path.join(process.cwd(), "src/lib/blog-manifest.generated.ts");
|
|
fs.writeFileSync(targetPath, lines.join("\n"), "utf-8");
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|