@rspress/plugin-preview 2.0.0-rc.1 → 2.0.0-rc.3
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/index.d.ts +7 -24
- package/dist/index.js +242 -241
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +1 -5
- package/package.json +8 -11
- package/static/global-components/{Device.css → FixedDevice.css} +31 -23
- package/static/global-components/FixedDevice.tsx +68 -0
- package/static/global-components/Preview.css +133 -0
- package/static/global-components/Preview.tsx +130 -0
- package/static/global-components/common/PreviewOperations.css +61 -0
- package/static/global-components/common/{mobile-operation.tsx → PreviewOperations.tsx} +20 -7
- package/static/{global-styles → iframe}/entry.css +3 -4
- package/static/iframe/entry.js +25 -0
- package/static/global-components/Container.tsx +0 -92
- package/static/global-components/DemoBlock.css +0 -23
- package/static/global-components/DemoBlock.tsx +0 -16
- package/static/global-components/Device.tsx +0 -76
- package/static/global-components/common/index.css +0 -103
- package/static/global-styles/iframe.css +0 -31
- package/static/global-styles/internal.css +0 -5
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { RsbuildConfig } from '@rsbuild/core';
|
|
|
2
2
|
import { RspressPlugin } from '@rspress/core';
|
|
3
3
|
|
|
4
4
|
declare interface CustomEntry {
|
|
5
|
-
entryCssPath: string;
|
|
6
5
|
demoPath: string;
|
|
7
6
|
}
|
|
8
7
|
|
|
@@ -10,13 +9,9 @@ declare type IframeOptions = {
|
|
|
10
9
|
/**
|
|
11
10
|
* framework in the iframe
|
|
12
11
|
* @default 'react'
|
|
12
|
+
* @deprecated
|
|
13
13
|
*/
|
|
14
|
-
framework?: 'react'
|
|
15
|
-
/**
|
|
16
|
-
* position of the iframe
|
|
17
|
-
* @default 'follow'
|
|
18
|
-
*/
|
|
19
|
-
position?: 'fixed' | 'follow';
|
|
14
|
+
framework?: 'react';
|
|
20
15
|
/**
|
|
21
16
|
* dev server port for the iframe
|
|
22
17
|
* @default 7890
|
|
@@ -31,31 +26,19 @@ declare type IframeOptions = {
|
|
|
31
26
|
|
|
32
27
|
export declare type Options = {
|
|
33
28
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* false = 'internal'
|
|
37
|
-
*/
|
|
38
|
-
isMobile?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* @deprecated Use iframeOptions.position instead.
|
|
29
|
+
* determine how to handle a internal code block without meta like \`\`\`tsx
|
|
30
|
+
* @default 'preview'
|
|
41
31
|
*/
|
|
42
|
-
|
|
32
|
+
defaultRenderMode?: 'pure' | 'preview';
|
|
43
33
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* iframe mode: component will be rendered in iframe, note that aside will hide.
|
|
34
|
+
* determine how to preview \`\`\`tsx preview code block
|
|
47
35
|
* @default 'internal'
|
|
48
36
|
*/
|
|
49
|
-
|
|
37
|
+
defaultPreviewMode?: 'internal' | 'iframe-fixed' | 'iframe-follow';
|
|
50
38
|
/**
|
|
51
39
|
* enable when preview mode is iframe.
|
|
52
40
|
*/
|
|
53
41
|
iframeOptions?: IframeOptions;
|
|
54
|
-
/**
|
|
55
|
-
* determine how to handle a internal code block without meta
|
|
56
|
-
* @default 'preview'
|
|
57
|
-
*/
|
|
58
|
-
defaultRenderMode?: 'pure' | 'preview';
|
|
59
42
|
/**
|
|
60
43
|
* Supported languages to be previewed
|
|
61
44
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import node_net from "node:net";
|
|
2
|
-
import node_path, {
|
|
3
|
-
import { createRsbuild, mergeRsbuildConfig } from "@rsbuild/core";
|
|
4
|
-
import { pluginBabel } from "@rsbuild/plugin-babel";
|
|
2
|
+
import node_path, { join } from "node:path";
|
|
3
|
+
import { createRsbuild, logger, mergeRsbuildConfig } from "@rsbuild/core";
|
|
5
4
|
import { pluginReact } from "@rsbuild/plugin-react";
|
|
6
|
-
import { pluginSolid } from "@rsbuild/plugin-solid";
|
|
7
5
|
import { RSPRESS_TEMP_DIR, normalizePosixPath, removeTrailingSlash } from "@rspress/core";
|
|
8
|
-
import { cloneDeep, isEqual } from "lodash";
|
|
9
6
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
10
7
|
import node_fs from "node:fs";
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
8
|
+
import { isDeepStrictEqual } from "node:util";
|
|
9
|
+
const entryraw_namespaceObject = "const storageKey = 'rspress-plugin-preview-theme-appearance';\n\nfunction setDocumentTheme(isDark) {\n if (isDark) {\n document.documentElement.classList.add('dark');\n document.documentElement.style.colorScheme = 'dark';\n } else {\n document.documentElement.classList.remove('dark');\n document.documentElement.style.colorScheme = 'light';\n }\n localStorage.setItem(\n 'rspress-plugin-preview-theme-appearance',\n isDark ? 'dark' : 'light',\n );\n}\n\nconst saved = localStorage.getItem(storageKey) || 'light';\nsetDocumentTheme(saved === 'dark');\n\nwindow.addEventListener('message', event => {\n if (event.data.type === 'theme-change') {\n const isDark = event.data.dark;\n setDocumentTheme(isDark);\n }\n});\n";
|
|
10
|
+
const STATIC_DIR = node_path.join(__dirname, '..', 'static');
|
|
11
|
+
const VIRTUAL_DEMO_DIR = node_path.join(process.cwd(), 'node_modules', RSPRESS_TEMP_DIR, 'virtual-demo');
|
|
14
12
|
const toValidVarName = (str)=>{
|
|
15
13
|
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(str)) return str;
|
|
16
14
|
return str.replace(/[^0-9a-zA-Z_$]/g, '_').replace(/^([0-9])/, '_$1');
|
|
17
15
|
};
|
|
18
16
|
const generateId = (pageName, index)=>`_${toValidVarName(pageName)}_${index}`;
|
|
19
|
-
const injectDemoBlockImport = (str, path)=>`
|
|
20
|
-
import DemoBlock from ${JSON.stringify(path)};
|
|
21
|
-
${str}
|
|
22
|
-
`;
|
|
23
17
|
const getLangFileExt = (lang)=>{
|
|
24
18
|
switch(lang){
|
|
25
19
|
case 'jsx':
|
|
@@ -31,72 +25,66 @@ const getLangFileExt = (lang)=>{
|
|
|
31
25
|
return lang;
|
|
32
26
|
}
|
|
33
27
|
};
|
|
34
|
-
|
|
28
|
+
function reactEntry({ demoPath }) {
|
|
29
|
+
return `
|
|
30
|
+
import { createRoot } from 'react-dom/client';
|
|
31
|
+
import Demo from ${JSON.stringify(demoPath)};
|
|
32
|
+
const container = document.getElementById('root');
|
|
33
|
+
createRoot(container).render(<Demo />);
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
36
|
+
async function generateEntry_generateEntry(globalDemos, framework, customEntry) {
|
|
35
37
|
const sourceEntry = {};
|
|
36
|
-
const
|
|
37
|
-
await mkdir(
|
|
38
|
+
const generateEntry = (meta)=>customEntry ? customEntry(meta) : 'react' === framework ? reactEntry(meta) : '';
|
|
39
|
+
await mkdir(VIRTUAL_DEMO_DIR, {
|
|
38
40
|
recursive: true
|
|
39
41
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
import Demo from ${JSON.stringify(demoPath)};
|
|
47
|
-
render(() => <Demo />, document.getElementById('root'));
|
|
48
|
-
`;
|
|
49
|
-
const reactEntry = `
|
|
50
|
-
import { createRoot } from 'react-dom/client';
|
|
51
|
-
import ${JSON.stringify(entryCssPath)};
|
|
52
|
-
import Demo from ${JSON.stringify(demoPath)};
|
|
53
|
-
const container = document.getElementById('root');
|
|
54
|
-
createRoot(container).render(<Demo />);
|
|
55
|
-
`;
|
|
56
|
-
const entryContent = customEntry ? customEntry({
|
|
57
|
-
entryCssPath,
|
|
42
|
+
await Promise.all(Object.entries(globalDemos).map(([pageName, demos])=>{
|
|
43
|
+
const followDemos = demos.filter((demo)=>'iframe-follow' === demo.previewMode);
|
|
44
|
+
const followPromiseList = followDemos.map(async (demo)=>{
|
|
45
|
+
const { id, path: demoPath } = demo;
|
|
46
|
+
const entry = join(VIRTUAL_DEMO_DIR, `${id}.entry.tsx`);
|
|
47
|
+
const entryContent = generateEntry({
|
|
58
48
|
demoPath
|
|
59
|
-
})
|
|
49
|
+
});
|
|
60
50
|
await writeFile(entry, entryContent);
|
|
61
51
|
sourceEntry[id] = entry;
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
import ${JSON.stringify(
|
|
68
|
-
${routes.map((demo, index)=>`import Demo_${index} from ${JSON.stringify(demo.path)}`).join('\n')}
|
|
69
|
-
function App() {
|
|
70
|
-
return (
|
|
71
|
-
<div className="preview-container">
|
|
72
|
-
<div className="preview-nav">{"${routes[0].title}"}</div>
|
|
73
|
-
${routes.map((_demo, index)=>`<Demo_${index} />`).join('\n')}
|
|
74
|
-
</div>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
const container = document.getElementById('root');
|
|
78
|
-
createRoot(container).render(<App />);
|
|
79
|
-
`;
|
|
80
|
-
const solidContent = `
|
|
81
|
-
import { render } from 'solid-js/web';
|
|
82
|
-
import ${JSON.stringify(entryCssPath)};
|
|
83
|
-
${routes.map((demo, index)=>`import Demo_${index} from ${JSON.stringify(demo.path)}`).join('\n')}
|
|
52
|
+
});
|
|
53
|
+
const fixedDemos = demos.filter((demo)=>'iframe-fixed' === demo.previewMode);
|
|
54
|
+
const fixedPromise = (async ()=>{
|
|
55
|
+
if (0 === fixedDemos.length) return;
|
|
56
|
+
const appContent = `
|
|
57
|
+
${fixedDemos.map((demo, index)=>`import Demo_${index} from ${JSON.stringify(demo.path)}`).join('\n')}
|
|
84
58
|
function App() {
|
|
85
59
|
return (
|
|
86
|
-
<div
|
|
87
|
-
<div
|
|
88
|
-
${
|
|
60
|
+
<div className="rp-preview-container">
|
|
61
|
+
<div className="rp-preview-nav">{"${fixedDemos[0].title}"}</div>
|
|
62
|
+
${fixedDemos.map((_demo, index)=>`<Demo_${index} />`).join('\n')}
|
|
89
63
|
</div>
|
|
90
64
|
)
|
|
91
65
|
}
|
|
92
|
-
|
|
66
|
+
export default App;
|
|
93
67
|
`;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
68
|
+
const id = `_${toValidVarName(pageName)}`;
|
|
69
|
+
const demoPath = join(VIRTUAL_DEMO_DIR, `${id}.app.tsx`);
|
|
70
|
+
const entryContent = generateEntry({
|
|
71
|
+
demoPath
|
|
72
|
+
});
|
|
73
|
+
const entry = join(VIRTUAL_DEMO_DIR, `${id}.entry.tsx`);
|
|
74
|
+
await Promise.all([
|
|
75
|
+
writeFile(demoPath, appContent),
|
|
76
|
+
writeFile(entry, entryContent)
|
|
77
|
+
]);
|
|
78
|
+
sourceEntry[id] = entry;
|
|
79
|
+
})();
|
|
80
|
+
return [
|
|
81
|
+
...followPromiseList,
|
|
82
|
+
fixedPromise
|
|
83
|
+
];
|
|
84
|
+
}).flat());
|
|
85
|
+
if (0 === Object.keys(sourceEntry).length) return {
|
|
86
|
+
_index: 'data:text/javascript,console.log("no demo found");'
|
|
87
|
+
};
|
|
100
88
|
return sourceEntry;
|
|
101
89
|
}
|
|
102
90
|
const convert = function(test) {
|
|
@@ -255,109 +243,103 @@ const getASTNodeImport = (name, from)=>({
|
|
|
255
243
|
}
|
|
256
244
|
}
|
|
257
245
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
]
|
|
302
|
-
}
|
|
303
|
-
]
|
|
304
|
-
});
|
|
305
|
-
const remarkPlugin_demos = {};
|
|
306
|
-
const remarkCodeToDemo = function({ getRouteMeta, previewMode, defaultRenderMode, position, previewLanguages, previewCodeTransform }) {
|
|
246
|
+
function parsePreviewInfoFromMeta(options) {
|
|
247
|
+
const { meta, defaultPreviewMode, defaultRenderMode } = options;
|
|
248
|
+
const result = {
|
|
249
|
+
isPure: false,
|
|
250
|
+
isPreview: false,
|
|
251
|
+
previewMode: null
|
|
252
|
+
};
|
|
253
|
+
if (!meta) {
|
|
254
|
+
if ('preview' === defaultRenderMode) {
|
|
255
|
+
result.isPreview = true;
|
|
256
|
+
result.previewMode = defaultPreviewMode;
|
|
257
|
+
} else result.isPure = true;
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
if (meta.includes('pure')) {
|
|
261
|
+
result.isPure = true;
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
const previewMatch = meta.match(/preview(?:="([^"]+)")?/);
|
|
265
|
+
if (previewMatch) {
|
|
266
|
+
result.isPreview = true;
|
|
267
|
+
const explicitMode = previewMatch[1];
|
|
268
|
+
if (explicitMode && [
|
|
269
|
+
'internal',
|
|
270
|
+
'iframe-fixed',
|
|
271
|
+
'iframe-follow'
|
|
272
|
+
].includes(explicitMode)) result.previewMode = explicitMode;
|
|
273
|
+
else result.previewMode = defaultPreviewMode;
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
if (meta.includes('iframe')) logger.warn('The "iframe" meta is deprecated, please use \`\`\`tsx preview="iframe-fixed" or \`\`\`tsx preview="iframe-follow" instead.');
|
|
277
|
+
if ('preview' === defaultRenderMode) {
|
|
278
|
+
result.isPreview = true;
|
|
279
|
+
result.previewMode = defaultPreviewMode;
|
|
280
|
+
} else result.isPure = true;
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
const remarkPlugin_globalDemos = {};
|
|
284
|
+
const isDirtyRef = {
|
|
285
|
+
current: false
|
|
286
|
+
};
|
|
287
|
+
const remarkWriteCodeFile = function({ getRouteMeta, defaultPreviewMode, defaultRenderMode, previewLanguages, previewCodeTransform }) {
|
|
307
288
|
const routeMeta = getRouteMeta();
|
|
308
|
-
node_fs.mkdirSync(
|
|
289
|
+
node_fs.mkdirSync(VIRTUAL_DEMO_DIR, {
|
|
309
290
|
recursive: true
|
|
310
291
|
});
|
|
311
292
|
const data = this.data();
|
|
312
293
|
return (tree, vfile)=>{
|
|
313
|
-
const demoMdx = [];
|
|
314
294
|
const route = routeMeta.find((meta)=>normalizePosixPath(meta.absolutePath) === normalizePosixPath(vfile.path || vfile.history[0]));
|
|
315
295
|
if (!route) return;
|
|
316
296
|
const { pageName } = route;
|
|
317
|
-
remarkPlugin_demos[pageName] = [];
|
|
318
297
|
let title = pageName;
|
|
319
298
|
let index = 1;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (void 0 !== externalDemoIndex) demoMdx.push(getASTNodeImport(tempVar, `!!${demoPath}?raw`));
|
|
331
|
-
if (isMobileMode && 'fixed' === position) void 0 !== externalDemoIndex && Object.assign(currentNode, getExternalDemoContent(tempVar));
|
|
332
|
-
else Object.assign(currentNode, {
|
|
333
|
-
type: 'mdxJsxFlowElement',
|
|
334
|
-
name: 'Container',
|
|
335
|
-
attributes: [
|
|
336
|
-
{
|
|
337
|
-
type: 'mdxJsxAttribute',
|
|
338
|
-
name: 'isMobile',
|
|
339
|
-
value: isMobileMode
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
type: 'mdxJsxAttribute',
|
|
343
|
-
name: 'demoId',
|
|
344
|
-
value: demoId
|
|
345
|
-
}
|
|
346
|
-
],
|
|
347
|
-
children: [
|
|
348
|
-
void 0 === externalDemoIndex ? {
|
|
349
|
-
...currentNode,
|
|
350
|
-
hasVisited: true
|
|
351
|
-
} : getExternalDemoContent(tempVar),
|
|
352
|
-
isMobileMode ? {
|
|
353
|
-
type: 'mdxJsxFlowElement',
|
|
354
|
-
name: null
|
|
355
|
-
} : {
|
|
356
|
-
type: 'mdxJsxFlowElement',
|
|
357
|
-
name: `Demo${demoId}`
|
|
358
|
-
}
|
|
359
|
-
]
|
|
299
|
+
const demoMdxImports = [];
|
|
300
|
+
const demosInCurrPage = {
|
|
301
|
+
[pageName]: []
|
|
302
|
+
};
|
|
303
|
+
function handleCodeBlockByPreviewMode(demoId, demoPath, currentNode, previewMode) {
|
|
304
|
+
if ('iframe-fixed' === previewMode || 'iframe-follow' === previewMode) demosInCurrPage[pageName].push({
|
|
305
|
+
title,
|
|
306
|
+
id: demoId,
|
|
307
|
+
path: demoPath,
|
|
308
|
+
previewMode
|
|
360
309
|
});
|
|
310
|
+
else demoMdxImports.push(getASTNodeImport(`Demo${demoId}`, demoPath));
|
|
311
|
+
if ('internal' === previewMode || 'iframe-follow' === previewMode) {
|
|
312
|
+
const originalCodeAst = {
|
|
313
|
+
...currentNode,
|
|
314
|
+
hasVisited: true
|
|
315
|
+
};
|
|
316
|
+
Object.assign(currentNode, {
|
|
317
|
+
type: 'mdxJsxFlowElement',
|
|
318
|
+
name: 'Preview',
|
|
319
|
+
attributes: [
|
|
320
|
+
{
|
|
321
|
+
type: 'mdxJsxAttribute',
|
|
322
|
+
name: 'previewMode',
|
|
323
|
+
value: previewMode
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
type: 'mdxJsxAttribute',
|
|
327
|
+
name: 'demoId',
|
|
328
|
+
value: demoId
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
children: [
|
|
332
|
+
originalCodeAst,
|
|
333
|
+
'iframe-follow' === previewMode ? {
|
|
334
|
+
type: 'mdxJsxFlowElement',
|
|
335
|
+
name: null
|
|
336
|
+
} : {
|
|
337
|
+
type: 'mdxJsxFlowElement',
|
|
338
|
+
name: `Demo${demoId}`
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
});
|
|
342
|
+
}
|
|
361
343
|
}
|
|
362
344
|
lib_visit(tree, 'heading', (node)=>{
|
|
363
345
|
if (1 === node.depth) {
|
|
@@ -366,49 +348,115 @@ const remarkCodeToDemo = function({ getRouteMeta, previewMode, defaultRenderMode
|
|
|
366
348
|
}
|
|
367
349
|
});
|
|
368
350
|
lib_visit(tree, 'code', (node)=>{
|
|
369
|
-
if ('hasVisited' in node) return;
|
|
351
|
+
if ('hasVisited' in node && true === node.hasVisited) return;
|
|
370
352
|
if (node.lang && previewLanguages.includes(node.lang)) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
353
|
+
const { isPure, previewMode } = parsePreviewInfoFromMeta({
|
|
354
|
+
meta: node.meta,
|
|
355
|
+
defaultPreviewMode,
|
|
356
|
+
defaultRenderMode
|
|
357
|
+
});
|
|
358
|
+
if (isPure || !previewMode) return;
|
|
359
|
+
const virtualFileContent = previewCodeTransform({
|
|
377
360
|
language: node.lang,
|
|
378
361
|
code: node.value
|
|
379
362
|
});
|
|
380
|
-
const isMobileMode = node.meta?.includes('mobile') || node.meta?.includes('iframe') || !node.meta?.includes('web') && !node.meta?.includes('internal') && 'iframe' === previewMode;
|
|
381
363
|
const id = generateId(pageName, index++);
|
|
382
|
-
const virtualModulePath = join(
|
|
383
|
-
constructDemoNode(id, virtualModulePath, node, isMobileMode);
|
|
364
|
+
const virtualModulePath = join(VIRTUAL_DEMO_DIR, `${id}.${getLangFileExt(node.lang)}`);
|
|
384
365
|
if (node_fs.existsSync(virtualModulePath)) {
|
|
385
366
|
const content = node_fs.readFileSync(virtualModulePath, 'utf-8');
|
|
386
|
-
if (content
|
|
387
|
-
}
|
|
388
|
-
|
|
367
|
+
if (content !== virtualFileContent) node_fs.writeFileSync(virtualModulePath, virtualFileContent);
|
|
368
|
+
} else node_fs.writeFileSync(virtualModulePath, virtualFileContent);
|
|
369
|
+
handleCodeBlockByPreviewMode(id, virtualModulePath, node, previewMode);
|
|
389
370
|
}
|
|
390
371
|
});
|
|
391
|
-
tree.children.unshift(...
|
|
392
|
-
if (
|
|
372
|
+
tree.children.unshift(...demoMdxImports);
|
|
373
|
+
if (demosInCurrPage[pageName].some((i)=>'iframe-fixed' === i.previewMode)) data.pageMeta.haveIframeFixedDemos = true;
|
|
374
|
+
if (!isDeepStrictEqual(remarkPlugin_globalDemos[pageName] ?? [], demosInCurrPage[pageName])) isDirtyRef.current = true;
|
|
375
|
+
if (0 !== demosInCurrPage[pageName].length) remarkPlugin_globalDemos[pageName] = demosInCurrPage[pageName];
|
|
393
376
|
};
|
|
394
377
|
};
|
|
395
378
|
let src_routeMeta;
|
|
396
|
-
const DEFAULT_PREVIEW_LANGUAGES = [
|
|
397
|
-
'jsx',
|
|
398
|
-
'tsx'
|
|
399
|
-
];
|
|
400
379
|
function pluginPreview(options) {
|
|
401
|
-
const {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
] : [];
|
|
380
|
+
const { iframeOptions = {}, defaultPreviewMode = 'internal', defaultRenderMode = 'pure', previewLanguages = [
|
|
381
|
+
'jsx',
|
|
382
|
+
'tsx'
|
|
383
|
+
], previewCodeTransform = ({ code })=>code } = options ?? {};
|
|
384
|
+
const { devPort = 7890, framework = 'react', builderConfig = {}, customEntry } = iframeOptions;
|
|
407
385
|
const getRouteMeta = ()=>src_routeMeta;
|
|
408
|
-
let lastDemos;
|
|
409
386
|
let devServer;
|
|
410
387
|
let clientConfig;
|
|
411
388
|
const port = devPort;
|
|
389
|
+
async function rsbuildStartOrBuild(config, isProd) {
|
|
390
|
+
if (devServer && !isProd && !isDirtyRef.current) return;
|
|
391
|
+
if (devServer && !isProd) {
|
|
392
|
+
await devServer.server.close();
|
|
393
|
+
devServer = void 0;
|
|
394
|
+
logger.info('[@rspress/plugin-preview] Restarting preview server due to demo changes...');
|
|
395
|
+
}
|
|
396
|
+
const outDir = join(config.outDir ?? 'doc_build', '~demo');
|
|
397
|
+
const { source, output, performance, resolve } = clientConfig ?? {};
|
|
398
|
+
const { preEntry: _, ...otherSourceOptions } = source ?? {};
|
|
399
|
+
const rsbuildConfig = mergeRsbuildConfig({
|
|
400
|
+
server: {
|
|
401
|
+
port: devPort,
|
|
402
|
+
printUrls: ()=>void 0,
|
|
403
|
+
strictPort: true
|
|
404
|
+
},
|
|
405
|
+
dev: {
|
|
406
|
+
lazyCompilation: false,
|
|
407
|
+
writeToDisk: true
|
|
408
|
+
},
|
|
409
|
+
performance: {
|
|
410
|
+
...performance,
|
|
411
|
+
printFileSize: false,
|
|
412
|
+
buildCache: false
|
|
413
|
+
},
|
|
414
|
+
source: {
|
|
415
|
+
...otherSourceOptions,
|
|
416
|
+
entry: await generateEntry_generateEntry(remarkPlugin_globalDemos, framework, customEntry),
|
|
417
|
+
preEntry: [
|
|
418
|
+
join(STATIC_DIR, 'iframe', 'entry.css'),
|
|
419
|
+
...builderConfig.source?.preEntry ?? []
|
|
420
|
+
]
|
|
421
|
+
},
|
|
422
|
+
html: {
|
|
423
|
+
tags: [
|
|
424
|
+
{
|
|
425
|
+
tag: "script",
|
|
426
|
+
children: entryraw_namespaceObject
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
},
|
|
430
|
+
resolve,
|
|
431
|
+
output: {
|
|
432
|
+
...output,
|
|
433
|
+
target: 'web',
|
|
434
|
+
assetPrefix: output?.assetPrefix ? `${removeTrailingSlash(output.assetPrefix)}/~demo` : '/~demo',
|
|
435
|
+
distPath: {
|
|
436
|
+
root: outDir
|
|
437
|
+
},
|
|
438
|
+
copy: void 0
|
|
439
|
+
},
|
|
440
|
+
tools: {
|
|
441
|
+
rspack: {
|
|
442
|
+
lazyCompilation: false,
|
|
443
|
+
watchOptions: {
|
|
444
|
+
ignored: /\.git/
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}, builderConfig);
|
|
449
|
+
const rsbuildInstance = await createRsbuild({
|
|
450
|
+
callerName: 'rspress',
|
|
451
|
+
rsbuildConfig
|
|
452
|
+
});
|
|
453
|
+
if ('react' === framework) rsbuildInstance.addPlugins([
|
|
454
|
+
pluginReact()
|
|
455
|
+
]);
|
|
456
|
+
if (isProd) rsbuildInstance.build();
|
|
457
|
+
else devServer = await rsbuildInstance.startDevServer();
|
|
458
|
+
isDirtyRef.current = false;
|
|
459
|
+
}
|
|
412
460
|
return {
|
|
413
461
|
name: '@rspress/plugin-preview',
|
|
414
462
|
config (config) {
|
|
@@ -437,57 +485,7 @@ function pluginPreview(options) {
|
|
|
437
485
|
}
|
|
438
486
|
},
|
|
439
487
|
async afterBuild (config, isProd) {
|
|
440
|
-
|
|
441
|
-
lastDemos = cloneDeep(remarkPlugin_demos);
|
|
442
|
-
await devServer?.server?.close();
|
|
443
|
-
devServer = void 0;
|
|
444
|
-
const sourceEntry = await generateEntry(remarkPlugin_demos, framework, position, customEntry);
|
|
445
|
-
const outDir = join(config.outDir ?? 'doc_build', '~demo');
|
|
446
|
-
if (0 === Object.keys(sourceEntry).length) return;
|
|
447
|
-
const { source, output, performance } = clientConfig ?? {};
|
|
448
|
-
const { preEntry: _, ...otherSourceOptions } = source ?? {};
|
|
449
|
-
const rsbuildConfig = mergeRsbuildConfig({
|
|
450
|
-
server: {
|
|
451
|
-
port: devPort,
|
|
452
|
-
printUrls: ()=>void 0,
|
|
453
|
-
strictPort: true
|
|
454
|
-
},
|
|
455
|
-
dev: {
|
|
456
|
-
lazyCompilation: false
|
|
457
|
-
},
|
|
458
|
-
performance: {
|
|
459
|
-
...performance,
|
|
460
|
-
printFileSize: false,
|
|
461
|
-
buildCache: false
|
|
462
|
-
},
|
|
463
|
-
source: {
|
|
464
|
-
...otherSourceOptions,
|
|
465
|
-
entry: sourceEntry
|
|
466
|
-
},
|
|
467
|
-
output: {
|
|
468
|
-
...output,
|
|
469
|
-
assetPrefix: output?.assetPrefix ? `${removeTrailingSlash(output.assetPrefix)}/~demo` : '/~demo',
|
|
470
|
-
distPath: {
|
|
471
|
-
root: outDir
|
|
472
|
-
},
|
|
473
|
-
copy: void 0
|
|
474
|
-
}
|
|
475
|
-
}, builderConfig);
|
|
476
|
-
const rsbuildInstance = await createRsbuild({
|
|
477
|
-
callerName: 'rspress',
|
|
478
|
-
rsbuildConfig
|
|
479
|
-
});
|
|
480
|
-
if ('solid' === framework) rsbuildInstance.addPlugins([
|
|
481
|
-
pluginBabel({
|
|
482
|
-
include: /\.(?:jsx|tsx)$/
|
|
483
|
-
}),
|
|
484
|
-
pluginSolid()
|
|
485
|
-
]);
|
|
486
|
-
if ('react' === framework) rsbuildInstance.addPlugins([
|
|
487
|
-
pluginReact()
|
|
488
|
-
]);
|
|
489
|
-
if (isProd) rsbuildInstance.build();
|
|
490
|
-
else devServer = await rsbuildInstance.startDevServer();
|
|
488
|
+
await rsbuildStartOrBuild(config, isProd);
|
|
491
489
|
},
|
|
492
490
|
builderConfig: {
|
|
493
491
|
source: {
|
|
@@ -506,6 +504,9 @@ function pluginPreview(options) {
|
|
|
506
504
|
}
|
|
507
505
|
}
|
|
508
506
|
},
|
|
507
|
+
performance: {
|
|
508
|
+
buildCache: false
|
|
509
|
+
},
|
|
509
510
|
plugins: [
|
|
510
511
|
{
|
|
511
512
|
name: 'close-demo-server',
|
|
@@ -527,11 +528,10 @@ function pluginPreview(options) {
|
|
|
527
528
|
markdown: {
|
|
528
529
|
remarkPlugins: [
|
|
529
530
|
[
|
|
530
|
-
|
|
531
|
+
remarkWriteCodeFile,
|
|
531
532
|
{
|
|
532
533
|
getRouteMeta,
|
|
533
|
-
|
|
534
|
-
previewMode,
|
|
534
|
+
defaultPreviewMode,
|
|
535
535
|
defaultRenderMode,
|
|
536
536
|
previewLanguages,
|
|
537
537
|
previewCodeTransform
|
|
@@ -539,11 +539,12 @@ function pluginPreview(options) {
|
|
|
539
539
|
]
|
|
540
540
|
],
|
|
541
541
|
globalComponents: [
|
|
542
|
-
join(
|
|
542
|
+
join(STATIC_DIR, 'global-components', 'Preview.tsx')
|
|
543
543
|
]
|
|
544
544
|
},
|
|
545
|
-
globalUIComponents
|
|
546
|
-
|
|
545
|
+
globalUIComponents: [
|
|
546
|
+
join(STATIC_DIR, 'global-components', 'FixedDevice.tsx')
|
|
547
|
+
]
|
|
547
548
|
};
|
|
548
549
|
}
|
|
549
550
|
export { pluginPreview };
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,8 +2,6 @@ export declare const generateId: (pageName: string, index: number) => string;
|
|
|
2
2
|
|
|
3
3
|
export declare const getLangFileExt: (lang: string) => string;
|
|
4
4
|
|
|
5
|
-
export declare const injectDemoBlockImport: (str: string, path: string) => string;
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* remove .html extension and validate
|
|
9
7
|
* @param routePath id from pathname
|