@module-federation/rspress-plugin 0.0.0-next-20250723062542 → 0.0.0-next-20250724024905
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +64 -13
- package/dist/esm/packages/rspress-plugin/src/findPath.d.ts +3 -0
- package/dist/esm/packages/rspress-plugin/src/plugin.d.ts +1 -0
- package/dist/esm/packages/rspress-plugin/src/rebuild.d.ts +20 -0
- package/package.json +8 -6
- package/dist/esm/packages/rspress-plugin/src/findSearchIndexPath.d.ts +0 -1
- package/dist/esm/packages/rspress-plugin/src/rebuildSearchIndexByHtml.d.ts +0 -10
package/dist/esm/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import external_node_path_default from "node:path";
|
|
|
8
8
|
import { load } from "cheerio";
|
|
9
9
|
import { htmlToText } from "html-to-text";
|
|
10
10
|
import { groupBy } from "lodash-es";
|
|
11
|
+
import external_turndown_default from "turndown";
|
|
11
12
|
import external_fs_default from "fs";
|
|
12
13
|
const logger = createLogger('[ Module Federation Rspress Plugin ]');
|
|
13
14
|
const src_logger = logger;
|
|
@@ -19,6 +20,10 @@ function findSearchIndexPaths(outputDir) {
|
|
|
19
20
|
const searchIndexFiles = files.filter((file)=>file.startsWith(SEARCH_INDEX_NAME) && file.endsWith('.json') && external_fs_default.statSync(external_path_default.join(staticDir, file)).isFile());
|
|
20
21
|
if (searchIndexFiles) return searchIndexFiles.map((searchIndexFile)=>external_path_default.join(staticDir, searchIndexFile));
|
|
21
22
|
}
|
|
23
|
+
function findMarkdownFilePath(outputDir, defaultLang, route) {
|
|
24
|
+
const filepath = external_path_default.join(outputDir, route.relativePath.replace(new RegExp(`^${defaultLang}/`), ''));
|
|
25
|
+
return filepath.replace(external_path_default.extname(filepath), '.md');
|
|
26
|
+
}
|
|
22
27
|
function generateTocFromHtml(html) {
|
|
23
28
|
const $ = load(html);
|
|
24
29
|
const headings = $('h1, h2, h3, h4, h5, h6');
|
|
@@ -42,8 +47,22 @@ function generateTocFromHtml(html) {
|
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
const replaceHtmlExt = (filepath)=>filepath.replace(external_node_path_default.extname(filepath), '.html');
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
const getRouteId = (route)=>route.absolutePath;
|
|
51
|
+
async function getRouteHtmlMap(routesMap, options) {
|
|
52
|
+
const routeHtmlMap = {};
|
|
53
|
+
await Promise.all(Object.entries(routesMap).map(async ([routeId, route])=>{
|
|
54
|
+
const { outputDir, defaultLang } = options;
|
|
55
|
+
const htmlPath = replaceHtmlExt(external_node_path_default.join(outputDir, route.lang === defaultLang ? route.relativePath.replace(route.lang, '') : route.relativePath));
|
|
56
|
+
const content = await promises_default.readFile(htmlPath, 'utf-8');
|
|
57
|
+
routeHtmlMap[routeId] = {
|
|
58
|
+
filepath: htmlPath,
|
|
59
|
+
content
|
|
60
|
+
};
|
|
61
|
+
}));
|
|
62
|
+
return routeHtmlMap;
|
|
63
|
+
}
|
|
64
|
+
async function extractPageDataFromHtml(routesMap, routeHtmlMap, options) {
|
|
65
|
+
return Promise.all(Object.entries(routesMap).map(async ([routeId, route])=>{
|
|
47
66
|
const { domain, searchCodeBlocks, outputDir, defaultLang } = options;
|
|
48
67
|
const defaultIndexInfo = {
|
|
49
68
|
title: '',
|
|
@@ -59,8 +78,8 @@ async function extractPageDataFromHtml(routes, options) {
|
|
|
59
78
|
_filepath: route.absolutePath,
|
|
60
79
|
_relativePath: ''
|
|
61
80
|
};
|
|
62
|
-
const
|
|
63
|
-
|
|
81
|
+
const html = routeHtmlMap[routeId].content;
|
|
82
|
+
if (!html) throw new Error(`html not found for route "${routeId}"`);
|
|
64
83
|
let { toc: rawToc, title } = generateTocFromHtml(html);
|
|
65
84
|
let content = html;
|
|
66
85
|
content = htmlToText(html, {
|
|
@@ -129,14 +148,14 @@ function deletePrivateField(obj) {
|
|
|
129
148
|
for(const key in newObj)if (key.startsWith('_')) delete newObj[key];
|
|
130
149
|
return newObj;
|
|
131
150
|
}
|
|
132
|
-
async function rebuildSearchIndexByHtml(
|
|
151
|
+
async function rebuildSearchIndexByHtml(routesMap, routeHtmlMap, options) {
|
|
133
152
|
const { versioned, outputDir } = options;
|
|
134
153
|
const searchFilePaths = findSearchIndexPaths(outputDir);
|
|
135
154
|
if (!searchFilePaths) {
|
|
136
155
|
src_logger.error('Cannot find search index files!');
|
|
137
156
|
process.exit(1);
|
|
138
157
|
}
|
|
139
|
-
const pages = await extractPageDataFromHtml(
|
|
158
|
+
const pages = await extractPageDataFromHtml(routesMap, routeHtmlMap, options);
|
|
140
159
|
const groupedPages = groupBy(pages, (page)=>{
|
|
141
160
|
if (page.frontmatter?.pageType === 'home') return 'noindex';
|
|
142
161
|
const version = versioned ? page.version : '';
|
|
@@ -157,6 +176,20 @@ async function rebuildSearchIndexByHtml(routes, options) {
|
|
|
157
176
|
await promises_default.writeFile(searchFilePath, stringifiedIndex);
|
|
158
177
|
}));
|
|
159
178
|
}
|
|
179
|
+
async function rebuildLLMsMDFilesByHtml(routesMap, routeHtmlMap, options) {
|
|
180
|
+
const { outputDir, defaultLang } = options;
|
|
181
|
+
const turndownService = new external_turndown_default();
|
|
182
|
+
await Promise.all(Object.entries(routeHtmlMap).map(async ([routeId, routeHtml])=>{
|
|
183
|
+
try {
|
|
184
|
+
const { content } = routeHtml;
|
|
185
|
+
const markdown = turndownService.turndown(content);
|
|
186
|
+
const mdFilePath = findMarkdownFilePath(outputDir, defaultLang, routesMap[routeId]);
|
|
187
|
+
await promises_default.writeFile(mdFilePath, markdown);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
src_logger.error(`rebuildLLMsMDFilesByHtml ${routeId} error:${e}`);
|
|
190
|
+
}
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
160
193
|
const isDev = ()=>'development' === process.env.NODE_ENV;
|
|
161
194
|
function replaceEntryWithBootstrapEntry(bundlerConfig) {
|
|
162
195
|
const { entry } = bundlerConfig;
|
|
@@ -201,7 +234,7 @@ function replaceEntryWithBootstrapEntry(bundlerConfig) {
|
|
|
201
234
|
bundlerConfig.entry = replaceWithAsyncEntry(entry, bundlerConfig.name || 'index');
|
|
202
235
|
}
|
|
203
236
|
function plugin_pluginModuleFederation(mfConfig, rspressOptions) {
|
|
204
|
-
const { autoShared = true, rebuildSearchIndex = true } = rspressOptions || {};
|
|
237
|
+
const { autoShared = true, rebuildSearchIndex = true, rebuildLLMsMDFiles = true } = rspressOptions || {};
|
|
205
238
|
if (autoShared) mfConfig.shared = {
|
|
206
239
|
react: {
|
|
207
240
|
singleton: true,
|
|
@@ -231,7 +264,7 @@ function plugin_pluginModuleFederation(mfConfig, rspressOptions) {
|
|
|
231
264
|
};
|
|
232
265
|
let enableSSG = false;
|
|
233
266
|
let outputDir = '';
|
|
234
|
-
let
|
|
267
|
+
let routesMap = {};
|
|
235
268
|
return {
|
|
236
269
|
name: 'plugin-module-federation',
|
|
237
270
|
async config (config) {
|
|
@@ -268,12 +301,15 @@ function plugin_pluginModuleFederation(mfConfig, rspressOptions) {
|
|
|
268
301
|
}
|
|
269
302
|
},
|
|
270
303
|
routeGenerated (routeMetaArr) {
|
|
271
|
-
|
|
304
|
+
routesMap = routeMetaArr.reduce((prev, cur)=>{
|
|
305
|
+
prev[getRouteId(cur)] = cur;
|
|
306
|
+
return prev;
|
|
307
|
+
}, {});
|
|
272
308
|
},
|
|
273
309
|
async afterBuild (config) {
|
|
274
|
-
if (!mfConfig.remotes || isDev() || !rebuildSearchIndex) return;
|
|
310
|
+
if (!mfConfig.remotes || isDev() || !rebuildSearchIndex || !rebuildLLMsMDFiles) return;
|
|
275
311
|
if (!enableSSG) {
|
|
276
|
-
src_logger.error('rebuildSearchIndex
|
|
312
|
+
src_logger.error('rebuildSearchIndex and rebuildLLMsMDFiles are only supported for ssg');
|
|
277
313
|
process.exit(1);
|
|
278
314
|
}
|
|
279
315
|
const searchConfig = config?.search || {};
|
|
@@ -281,7 +317,7 @@ function plugin_pluginModuleFederation(mfConfig, rspressOptions) {
|
|
|
281
317
|
const domain = searchConfig?.mode === 'remote' ? searchConfig.domain ?? '' : '';
|
|
282
318
|
const versioned = searchConfig && 'remote' !== searchConfig.mode && searchConfig.versioned;
|
|
283
319
|
const searchCodeBlocks = 'codeBlocks' in searchConfig ? Boolean(searchConfig.codeBlocks) : true;
|
|
284
|
-
await
|
|
320
|
+
const routeHtmlMap = await getRouteHtmlMap(routesMap, {
|
|
285
321
|
outputDir,
|
|
286
322
|
versioned,
|
|
287
323
|
replaceRules,
|
|
@@ -289,7 +325,22 @@ function plugin_pluginModuleFederation(mfConfig, rspressOptions) {
|
|
|
289
325
|
searchCodeBlocks,
|
|
290
326
|
defaultLang: config.lang || 'en'
|
|
291
327
|
});
|
|
292
|
-
|
|
328
|
+
const rebuildOptions = {
|
|
329
|
+
outputDir,
|
|
330
|
+
versioned,
|
|
331
|
+
replaceRules,
|
|
332
|
+
domain,
|
|
333
|
+
searchCodeBlocks,
|
|
334
|
+
defaultLang: config.lang || 'en'
|
|
335
|
+
};
|
|
336
|
+
if (rebuildSearchIndex) {
|
|
337
|
+
await rebuildSearchIndexByHtml(routesMap, routeHtmlMap, rebuildOptions);
|
|
338
|
+
src_logger.info('rebuildSearchIndex success!');
|
|
339
|
+
}
|
|
340
|
+
if (rebuildLLMsMDFiles && config.plugins?.find((p)=>'@rspress/plugin-llms' === p.name)) {
|
|
341
|
+
await rebuildLLMsMDFilesByHtml(routesMap, routeHtmlMap, rebuildOptions);
|
|
342
|
+
src_logger.info('rebuildLLMsMDFiles success!');
|
|
343
|
+
}
|
|
293
344
|
}
|
|
294
345
|
};
|
|
295
346
|
}
|
|
@@ -3,6 +3,7 @@ import type { RspressPlugin } from '@rspress/shared';
|
|
|
3
3
|
type RspressPluginOptions = {
|
|
4
4
|
autoShared?: boolean;
|
|
5
5
|
rebuildSearchIndex?: boolean;
|
|
6
|
+
rebuildLLMsMDFiles?: boolean;
|
|
6
7
|
};
|
|
7
8
|
export declare function pluginModuleFederation(mfConfig: moduleFederationPlugin.ModuleFederationPluginOptions, rspressOptions?: RspressPluginOptions): RspressPlugin;
|
|
8
9
|
export { createModuleFederationConfig } from '@module-federation/sdk';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RouteMeta, ReplaceRule } from '@rspress/shared';
|
|
2
|
+
interface RouteHtmlMap {
|
|
3
|
+
[routeId: string]: {
|
|
4
|
+
filepath: string;
|
|
5
|
+
content: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export type RebuildOptions = {
|
|
9
|
+
domain: string;
|
|
10
|
+
searchCodeBlocks: boolean;
|
|
11
|
+
replaceRules: ReplaceRule[];
|
|
12
|
+
versioned?: boolean;
|
|
13
|
+
outputDir: string;
|
|
14
|
+
defaultLang: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const getRouteId: (route: RouteMeta) => string;
|
|
17
|
+
export declare function getRouteHtmlMap(routesMap: Record<string, RouteMeta>, options: RebuildOptions): Promise<RouteHtmlMap>;
|
|
18
|
+
export declare function rebuildSearchIndexByHtml(routesMap: Record<string, RouteMeta>, routeHtmlMap: RouteHtmlMap, options: RebuildOptions): Promise<void>;
|
|
19
|
+
export declare function rebuildLLMsMDFilesByHtml(routesMap: Record<string, RouteMeta>, routeHtmlMap: RouteHtmlMap, options: RebuildOptions): Promise<void>;
|
|
20
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/rspress-plugin",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250724024905",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Module Federation plugin for Rspress",
|
|
6
6
|
"keywords": [
|
|
@@ -34,17 +34,19 @@
|
|
|
34
34
|
"@rspress/shared": "2.0.0-beta.16",
|
|
35
35
|
"@types/html-to-text": "^9.0.4",
|
|
36
36
|
"@types/lodash-es": "^4.17.12",
|
|
37
|
-
"@types/react": "^18.3.11"
|
|
37
|
+
"@types/react": "^18.3.11",
|
|
38
|
+
"@types/turndown": "5.0.5 "
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
41
|
"cheerio": "1.0.0-rc.12",
|
|
41
42
|
"fs-extra": "11.3.0",
|
|
42
43
|
"html-to-text": "^9.0.5",
|
|
43
44
|
"lodash-es": "^4.17.21",
|
|
44
|
-
"
|
|
45
|
-
"@module-federation/sdk": "0.0.0-next-
|
|
46
|
-
"@module-federation/
|
|
47
|
-
"@module-federation/
|
|
45
|
+
"turndown": "7.2.0",
|
|
46
|
+
"@module-federation/sdk": "0.0.0-next-20250724024905",
|
|
47
|
+
"@module-federation/enhanced": "0.0.0-next-20250724024905",
|
|
48
|
+
"@module-federation/rsbuild-plugin": "0.0.0-next-20250724024905",
|
|
49
|
+
"@module-federation/error-codes": "0.0.0-next-20250724024905"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
52
|
"build": "rslib build",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function findSearchIndexPaths(outputDir: string): string[] | undefined;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { RouteMeta, ReplaceRule } from '@rspress/shared';
|
|
2
|
-
export type RebuildSearchIndexByHtmlOptions = {
|
|
3
|
-
domain: string;
|
|
4
|
-
searchCodeBlocks: boolean;
|
|
5
|
-
replaceRules: ReplaceRule[];
|
|
6
|
-
versioned?: boolean;
|
|
7
|
-
outputDir: string;
|
|
8
|
-
defaultLang: string;
|
|
9
|
-
};
|
|
10
|
-
export declare function rebuildSearchIndexByHtml(routes: RouteMeta[], options: RebuildSearchIndexByHtmlOptions): Promise<void>;
|