|
@@ -351,6 +351,8 @@ async function loadExposesConfig(
|
|
|
|
|
|
|
|
// 查找 exposes 变量的定义
|
|
// 查找 exposes 变量的定义
|
|
|
const exposesMatch = content.match(
|
|
const exposesMatch = content.match(
|
|
|
|
|
+ /const\s*\{\s*exposes\s*\}\s*=\s*generateExposesFromRoutes\([^)]+\)\s*;?/,
|
|
|
|
|
+ ) || content.match(
|
|
|
/const\s*\{\s*exposes\s*\}\s*=\s*generateExposesFromRoutes\([^)]+\)\.exposes/,
|
|
/const\s*\{\s*exposes\s*\}\s*=\s*generateExposesFromRoutes\([^)]+\)\.exposes/,
|
|
|
);
|
|
);
|
|
|
if (exposesMatch) {
|
|
if (exposesMatch) {
|
|
@@ -449,105 +451,68 @@ async function getResourceCode(
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 生成 routes-info.json 的 Rsbuild 插件
|
|
* 生成 routes-info.json 的 Rsbuild 插件
|
|
|
- * 自动从路由配置中读取元数据(支持嵌套 children)
|
|
|
|
|
|
|
+ * @param exposes 暴露的组件映射(key: expose路径, value: 组件路径)
|
|
|
|
|
+ * @param routesList 路由配置数组
|
|
|
*/
|
|
*/
|
|
|
-export function generateRoutesInfoPlugin(): RsbuildPlugin {
|
|
|
|
|
|
|
+export function generateRoutesInfoPlugin(
|
|
|
|
|
+ exposes?: Record<string, string>,
|
|
|
|
|
+ routesList?: ParsedRoute[],
|
|
|
|
|
+): RsbuildPlugin {
|
|
|
return {
|
|
return {
|
|
|
name: 'generate-routes-info',
|
|
name: 'generate-routes-info',
|
|
|
setup(api) {
|
|
setup(api) {
|
|
|
api.onAfterBuild(async ({ stats }) => {
|
|
api.onAfterBuild(async ({ stats }) => {
|
|
|
|
|
+ console.log('🔧 generateRoutesInfoPlugin 开始执行...');
|
|
|
if (api.context.mode !== 'production') {
|
|
if (api.context.mode !== 'production') {
|
|
|
|
|
+ console.log('⏭️ 非生产模式,跳过生成');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
const distPath = api.context.distPath;
|
|
const distPath = api.context.distPath;
|
|
|
const manifestPath = path.join(distPath, 'mf-manifest.json');
|
|
const manifestPath = path.join(distPath, 'mf-manifest.json');
|
|
|
const rootPath = api.context.rootPath;
|
|
const rootPath = api.context.rootPath;
|
|
|
-
|
|
|
|
|
- // 获取当前构建模式
|
|
|
|
|
const mode = api.context.mode;
|
|
const mode = api.context.mode;
|
|
|
|
|
|
|
|
// 读取 mf-manifest.json
|
|
// 读取 mf-manifest.json
|
|
|
const manifestContent = await fs.readFile(manifestPath, 'utf-8');
|
|
const manifestContent = await fs.readFile(manifestPath, 'utf-8');
|
|
|
const manifest: Manifest = JSON.parse(manifestContent);
|
|
const manifest: Manifest = JSON.parse(manifestContent);
|
|
|
|
|
+ console.log(`📋 读取 manifest: ${manifest.exposes.length} 个 exposes`);
|
|
|
|
|
|
|
|
- // 读取 rsbuild.config.ts 的 exposes 配置
|
|
|
|
|
- const configPath = path.join(rootPath, 'rsbuild.config.ts');
|
|
|
|
|
- const exposesConfig = await loadExposesConfig(configPath, rootPath);
|
|
|
|
|
-
|
|
|
|
|
- // 如果从配置文件读取失败(因为使用了自动生成),则直接生成
|
|
|
|
|
- if (Object.keys(exposesConfig).length === 0) {
|
|
|
|
|
- console.log('🔄 直接从路由生成 exposes 配置');
|
|
|
|
|
- // 需要动态导入 routes 模块
|
|
|
|
|
- try {
|
|
|
|
|
- const routesModule = await import(
|
|
|
|
|
- path.join(rootPath, 'src/router/routes.ts')
|
|
|
|
|
- );
|
|
|
|
|
- const { exposes: autoExposes } = generateExposesFromRoutes(
|
|
|
|
|
- routesModule.routes,
|
|
|
|
|
- { onlyLeafNodes: true },
|
|
|
|
|
- );
|
|
|
|
|
- Object.assign(exposesConfig, autoExposes);
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('❌ 自动生成 exposes 失败:', error);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 建立组件路径到 expose key 的映射
|
|
|
|
|
- const exposeMap = buildExposeMap(exposesConfig);
|
|
|
|
|
-
|
|
|
|
|
- // 读取路由配置(优先从 routes.ts 读取,如果不存在则从 index.ts 读取)
|
|
|
|
|
- const routesPath = path.join(rootPath, 'src/router/routes.ts');
|
|
|
|
|
- const indexPath = path.join(rootPath, 'src/router/index.ts');
|
|
|
|
|
-
|
|
|
|
|
- let parsedRoutes: ParsedRoute[] = [];
|
|
|
|
|
-
|
|
|
|
|
- // 先尝试读取 routes.ts
|
|
|
|
|
- try {
|
|
|
|
|
- await fs.access(routesPath);
|
|
|
|
|
- parsedRoutes = await parseRoutesFromFile(routesPath);
|
|
|
|
|
- console.log('✅ 从 routes.ts 读取路由配置');
|
|
|
|
|
- } catch {
|
|
|
|
|
- // 如果 routes.ts 不存在,则尝试从 index.ts 读取
|
|
|
|
|
- try {
|
|
|
|
|
- parsedRoutes = await parseRoutesFromFile(indexPath);
|
|
|
|
|
- console.log('✅ 从 index.ts 读取路由配置');
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('❌ 无法读取路由配置文件:', error);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 使用传入的 exposes 或从 manifest 构建
|
|
|
|
|
+ let exposures: Record<string, string> = exposes || {};
|
|
|
|
|
+ if (Object.keys(exposures).length === 0) {
|
|
|
|
|
+ manifest.exposes.forEach((exp) => {
|
|
|
|
|
+ exposures[exp.path] = exp.name;
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 递归构建路由树
|
|
|
|
|
- const pages = buildRouteTree(parsedRoutes, exposeMap, manifest);
|
|
|
|
|
|
|
+ // 从 manifest exposes 直接构建路由信息
|
|
|
|
|
+ const pages: RouteInfoNode[] = manifest.exposes
|
|
|
|
|
+ .filter(exp => !exp.path.includes('/__'))
|
|
|
|
|
+ .map(exp => {
|
|
|
|
|
+ const parts = exp.path.replace(/^\.\//, '').split('/');
|
|
|
|
|
+ const lastPart = parts[parts.length - 1];
|
|
|
|
|
+ return {
|
|
|
|
|
+ path: exp.path,
|
|
|
|
|
+ name: lastPart,
|
|
|
|
|
+ component: exp.path,
|
|
|
|
|
+ meta: {
|
|
|
|
|
+ id: exp.id,
|
|
|
|
|
+ title: lastPart,
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
// 读取 resourceCode
|
|
// 读取 resourceCode
|
|
|
const resourceCode = await getResourceCode(rootPath, mode);
|
|
const resourceCode = await getResourceCode(rootPath, mode);
|
|
|
|
|
|
|
|
- // 包装成新的格式
|
|
|
|
|
- const routesInfo = {
|
|
|
|
|
- resourceCode,
|
|
|
|
|
- pages,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const routesInfo = { resourceCode, pages };
|
|
|
|
|
|
|
|
// 写入 routes-info.json
|
|
// 写入 routes-info.json
|
|
|
const outputPath = path.join(distPath, 'routes-info.json');
|
|
const outputPath = path.join(distPath, 'routes-info.json');
|
|
|
- await fs.writeFile(
|
|
|
|
|
- outputPath,
|
|
|
|
|
- JSON.stringify(routesInfo, null, 2),
|
|
|
|
|
- 'utf-8',
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ await fs.writeFile(outputPath, JSON.stringify(routesInfo, null, 2), 'utf-8');
|
|
|
|
|
|
|
|
- // 统计路由节点数
|
|
|
|
|
- const countRoutes = (routes: RouteInfoNode[]): number => {
|
|
|
|
|
- let count = 0;
|
|
|
|
|
- routes.forEach((route) => {
|
|
|
|
|
- count++;
|
|
|
|
|
- if (route.children) {
|
|
|
|
|
- count += countRoutes(route.children);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- return count;
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ console.log(`✅ routes-info.json 已生成 (resourceCode: ${resourceCode}, 页面: ${pages.length} 个)`);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('❌ 生成 routes-info.json 失败:', error);
|
|
console.error('❌ 生成 routes-info.json 失败:', error);
|
|
|
}
|
|
}
|