dumi 2.4.35 → 2.4.37
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/assetParsers/block.d.ts +4 -2
- package/dist/assetParsers/block.js +73 -0
- package/dist/client/pages/Demo/index.js +5 -2
- package/dist/client/theme-api/DumiDemo/index.d.ts +7 -1
- package/dist/client/theme-api/DumiDemo/index.js +7 -3
- package/dist/features/meta.d.ts +1 -0
- package/dist/features/meta.js +14 -0
- package/dist/loaders/markdown/index.js +23 -2
- package/dist/loaders/markdown/transformer/index.d.ts +1 -0
- package/dist/loaders/markdown/transformer/index.js +1 -0
- package/dist/loaders/markdown/transformer/rehypeDemo.d.ts +1 -0
- package/dist/loaders/markdown/transformer/rehypeDemo.js +24 -2
- package/dist/templates/meta/demoIndex.ts.tpl +10 -0
- package/dist/templates/meta/exports.ts.tpl +148 -22
- package/dist/templates/meta/index.ts.tpl +6 -6
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ export interface IParsedBlockAsset {
|
|
|
13
13
|
resolveMap: Record<string, string>;
|
|
14
14
|
frontmatter: ReturnType<typeof parseCodeFrontmatter>['frontmatter'];
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
interface IParseBlockAssetOptions {
|
|
17
17
|
fileAbsPath: string;
|
|
18
18
|
fileLocale?: string;
|
|
19
19
|
id: string;
|
|
@@ -21,5 +21,7 @@ declare function parseBlockAsset(opts: {
|
|
|
21
21
|
entryPointCode?: string;
|
|
22
22
|
resolver: typeof sync;
|
|
23
23
|
techStack: IDumiTechStack;
|
|
24
|
-
|
|
24
|
+
cacheable?: boolean;
|
|
25
|
+
}
|
|
26
|
+
declare function parseBlockAsset(opts: IParseBlockAssetOptions): Promise<IParsedBlockAsset>;
|
|
25
27
|
export default parseBlockAsset;
|
|
@@ -39,7 +39,71 @@ var import_fs = __toESM(require("fs"));
|
|
|
39
39
|
var import_path = __toESM(require("path"));
|
|
40
40
|
var import_plugin_utils = require("umi/plugin-utils");
|
|
41
41
|
var import_constants = require("../constants");
|
|
42
|
+
var MAX_BLOCK_ASSET_CACHE_SIZE = 512;
|
|
43
|
+
var blockAssetCache = /* @__PURE__ */ new Map();
|
|
44
|
+
function cloneParsedBlockAsset(ret) {
|
|
45
|
+
return {
|
|
46
|
+
asset: JSON.parse(JSON.stringify(ret.asset)),
|
|
47
|
+
resolveMap: { ...ret.resolveMap },
|
|
48
|
+
frontmatter: ret.frontmatter ? JSON.parse(JSON.stringify(ret.frontmatter)) : ret.frontmatter
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function getContentHashFromFile(file) {
|
|
52
|
+
try {
|
|
53
|
+
return (0, import_utils.getContentHash)(import_fs.default.readFileSync(file, "utf-8"));
|
|
54
|
+
} catch {
|
|
55
|
+
return "missing";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getDepsKey(deps) {
|
|
59
|
+
return JSON.stringify(
|
|
60
|
+
Array.from(new Set(deps)).sort().map((file) => `${(0, import_plugin_utils.winPath)(file)}:${getContentHashFromFile(file)}`)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function getParseCacheKey(opts) {
|
|
64
|
+
const entryContent = opts.entryPointCode ?? import_fs.default.readFileSync(opts.fileAbsPath, "utf-8");
|
|
65
|
+
return JSON.stringify({
|
|
66
|
+
file: (0, import_plugin_utils.winPath)(opts.fileAbsPath),
|
|
67
|
+
fileLocale: opts.fileLocale,
|
|
68
|
+
id: opts.id,
|
|
69
|
+
refAtomIds: opts.refAtomIds,
|
|
70
|
+
entryHash: (0, import_utils.getContentHash)(entryContent),
|
|
71
|
+
techStack: opts.techStack.name,
|
|
72
|
+
runtimeOpts: opts.techStack.runtimeOpts,
|
|
73
|
+
hasOnBlockLoad: Boolean(opts.techStack.onBlockLoad),
|
|
74
|
+
hasGenerateMetadata: Boolean(opts.techStack.generateMetadata),
|
|
75
|
+
hasGenerateSources: Boolean(opts.techStack.generateSources)
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function getParseDeps(ret, entryFile) {
|
|
79
|
+
return Object.values(ret.resolveMap).filter(
|
|
80
|
+
(file) => import_path.default.isAbsolute(file) && file !== entryFile
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function getCachedBlockAsset(cacheKey) {
|
|
84
|
+
const cached = blockAssetCache.get(cacheKey);
|
|
85
|
+
if (cached && cached.depsKey === getDepsKey(cached.deps)) {
|
|
86
|
+
return cloneParsedBlockAsset(cached.result);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function setCachedBlockAsset(cacheKey, ret, deps) {
|
|
90
|
+
if (blockAssetCache.size >= MAX_BLOCK_ASSET_CACHE_SIZE) {
|
|
91
|
+
const firstKey = blockAssetCache.keys().next().value;
|
|
92
|
+
if (firstKey)
|
|
93
|
+
blockAssetCache.delete(firstKey);
|
|
94
|
+
}
|
|
95
|
+
blockAssetCache.set(cacheKey, {
|
|
96
|
+
deps,
|
|
97
|
+
depsKey: getDepsKey(deps),
|
|
98
|
+
result: cloneParsedBlockAsset(ret)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
42
101
|
async function parseBlockAsset(opts) {
|
|
102
|
+
const cacheKey = opts.cacheable ? getParseCacheKey(opts) : "";
|
|
103
|
+
const cached = cacheKey ? getCachedBlockAsset(cacheKey) : void 0;
|
|
104
|
+
if (cached) {
|
|
105
|
+
return cached;
|
|
106
|
+
}
|
|
43
107
|
const asset = {
|
|
44
108
|
type: "BLOCK",
|
|
45
109
|
id: opts.id,
|
|
@@ -163,9 +227,18 @@ async function parseBlockAsset(opts) {
|
|
|
163
227
|
}
|
|
164
228
|
]
|
|
165
229
|
});
|
|
230
|
+
let hasError = false;
|
|
166
231
|
try {
|
|
167
232
|
await deferrer;
|
|
168
233
|
} catch {
|
|
234
|
+
hasError = true;
|
|
235
|
+
}
|
|
236
|
+
if (!hasError && cacheKey) {
|
|
237
|
+
setCachedBlockAsset(
|
|
238
|
+
cacheKey,
|
|
239
|
+
result,
|
|
240
|
+
getParseDeps(result, opts.fileAbsPath)
|
|
241
|
+
);
|
|
169
242
|
}
|
|
170
243
|
return result;
|
|
171
244
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { useDemo, useLiveDemo, useParams } from 'dumi';
|
|
1
|
+
import { useDemo, useLiveDemo, useLocation, useParams } from 'dumi';
|
|
2
2
|
import { createElement, useEffect } from 'react';
|
|
3
3
|
import { useRenderer } from "../../theme-api/useRenderer";
|
|
4
4
|
import "./index.less";
|
|
5
5
|
var DemoRenderPage = function DemoRenderPage() {
|
|
6
6
|
var params = useParams();
|
|
7
|
+
var _useLocation = useLocation(),
|
|
8
|
+
search = _useLocation.search;
|
|
7
9
|
var id = params.id;
|
|
8
|
-
var
|
|
10
|
+
var routeId = new URLSearchParams(search).get('routeId') || undefined;
|
|
11
|
+
var demo = useDemo(id, undefined, undefined, routeId);
|
|
9
12
|
var _useRenderer = useRenderer({
|
|
10
13
|
id: id,
|
|
11
14
|
component: demo.component,
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { type FC } from 'react';
|
|
2
|
-
import type { IPreviewerProps } from '../types';
|
|
2
|
+
import type { IDemoData, IPreviewerProps } from '../types';
|
|
3
|
+
type DemoGetter = () => Promise<{
|
|
4
|
+
demos: Record<string, IDemoData>;
|
|
5
|
+
}>;
|
|
3
6
|
export interface IDumiDemoProps {
|
|
4
7
|
demo: {
|
|
5
8
|
id: string;
|
|
6
9
|
inline?: boolean;
|
|
10
|
+
loader?: DemoGetter;
|
|
11
|
+
version?: string;
|
|
7
12
|
};
|
|
8
13
|
previewerProps: Omit<IPreviewerProps, 'asset' | 'children'>;
|
|
9
14
|
}
|
|
10
15
|
export declare const DumiDemo: FC<IDumiDemoProps>;
|
|
16
|
+
export {};
|
|
@@ -10,8 +10,11 @@ var InternalDumiDemo = function InternalDumiDemo(props) {
|
|
|
10
10
|
historyType = _useSiteData.historyType;
|
|
11
11
|
var _useAppData = useAppData(),
|
|
12
12
|
basename = _useAppData.basename;
|
|
13
|
-
var
|
|
14
|
-
|
|
13
|
+
var _props$demo = props.demo,
|
|
14
|
+
id = _props$demo.id,
|
|
15
|
+
loader = _props$demo.loader,
|
|
16
|
+
version = _props$demo.version;
|
|
17
|
+
var demo = useDemo(id, loader, version);
|
|
15
18
|
var component = demo.component,
|
|
16
19
|
asset = demo.asset,
|
|
17
20
|
renderOpts = demo.renderOpts;
|
|
@@ -31,12 +34,13 @@ var InternalDumiDemo = function InternalDumiDemo(props) {
|
|
|
31
34
|
return demoNode;
|
|
32
35
|
}
|
|
33
36
|
var isHashRoute = historyType === 'hash';
|
|
37
|
+
var routeQuery = demo.routeId ? "?routeId=".concat(encodeURIComponent(demo.routeId)) : '';
|
|
34
38
|
return /*#__PURE__*/React.createElement(Previewer, _extends({
|
|
35
39
|
asset: asset,
|
|
36
40
|
demoUrl:
|
|
37
41
|
// allow user override demoUrl by frontmatter
|
|
38
42
|
props.previewerProps.demoUrl || // when use hash route, browser can automatically handle relative paths starting with #
|
|
39
|
-
"".concat(isHashRoute ? "#" : '').concat(basename).concat(SP_ROUTE_PREFIX, "demos/").concat(props.demo.id)
|
|
43
|
+
"".concat(isHashRoute ? "#" : '').concat(basename).concat(SP_ROUTE_PREFIX, "demos/").concat(props.demo.id).concat(routeQuery)
|
|
40
44
|
}, props.previewerProps), props.previewerProps.iframe ? null : demoNode);
|
|
41
45
|
};
|
|
42
46
|
export var DumiDemo = /*#__PURE__*/React.memo(InternalDumiDemo, function (prev, next) {
|
package/dist/features/meta.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IApi } from '../types';
|
|
2
2
|
export declare const TABS_META_PATH = "dumi/meta/tabs.ts";
|
|
3
3
|
export declare const ATOMS_META_PATH = "dumi/meta/atoms.ts";
|
|
4
|
+
export declare const DEMO_INDEX_META_PATH = "dumi/meta/demoIndex.ts";
|
|
4
5
|
export default _default;
|
|
5
6
|
declare function _default(api: IApi): void;
|
package/dist/features/meta.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var meta_exports = {};
|
|
31
31
|
__export(meta_exports, {
|
|
32
32
|
ATOMS_META_PATH: () => ATOMS_META_PATH,
|
|
33
|
+
DEMO_INDEX_META_PATH: () => DEMO_INDEX_META_PATH,
|
|
33
34
|
TABS_META_PATH: () => TABS_META_PATH,
|
|
34
35
|
default: () => meta_default
|
|
35
36
|
});
|
|
@@ -40,6 +41,7 @@ var import_plugin_utils = require("umi/plugin-utils");
|
|
|
40
41
|
var import_tabs = require("./tabs");
|
|
41
42
|
var TABS_META_PATH = "dumi/meta/tabs.ts";
|
|
42
43
|
var ATOMS_META_PATH = "dumi/meta/atoms.ts";
|
|
44
|
+
var DEMO_INDEX_META_PATH = "dumi/meta/demoIndex.ts";
|
|
43
45
|
var meta_default = (api) => {
|
|
44
46
|
const metaFiles = [];
|
|
45
47
|
api.register({
|
|
@@ -71,8 +73,11 @@ var meta_default = (api) => {
|
|
|
71
73
|
key: "dumi.modifyMetaFiles",
|
|
72
74
|
initialValue: JSON.parse(JSON.stringify(metaFiles))
|
|
73
75
|
});
|
|
76
|
+
const useUtoopackDemoHMR = api.env === "development" && Boolean(api.config.utoopack);
|
|
74
77
|
parsedMetaFiles.forEach((metaFile) => {
|
|
75
78
|
metaFile.isMarkdown = metaFile.file.endsWith(".md");
|
|
79
|
+
metaFile.loadDemoIndex = metaFile.isMarkdown && !useUtoopackDemoHMR;
|
|
80
|
+
metaFile.loadDemoIndexMap = metaFile.isMarkdown && useUtoopackDemoHMR;
|
|
76
81
|
});
|
|
77
82
|
api.writeTmpFile({
|
|
78
83
|
noPluginDir: true,
|
|
@@ -93,6 +98,14 @@ var meta_default = (api) => {
|
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
});
|
|
101
|
+
api.writeTmpFile({
|
|
102
|
+
noPluginDir: true,
|
|
103
|
+
path: DEMO_INDEX_META_PATH,
|
|
104
|
+
tplPath: require.resolve("../templates/meta/demoIndex.ts.tpl"),
|
|
105
|
+
context: {
|
|
106
|
+
metaFiles: parsedMetaFiles
|
|
107
|
+
}
|
|
108
|
+
});
|
|
96
109
|
api.writeTmpFile({
|
|
97
110
|
noPluginDir: true,
|
|
98
111
|
path: "dumi/meta/runtime.ts",
|
|
@@ -118,5 +131,6 @@ var meta_default = (api) => {
|
|
|
118
131
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
132
|
0 && (module.exports = {
|
|
120
133
|
ATOMS_META_PATH,
|
|
134
|
+
DEMO_INDEX_META_PATH,
|
|
121
135
|
TABS_META_PATH
|
|
122
136
|
});
|
|
@@ -53,6 +53,17 @@ function getDemoSourceFiles(demos = []) {
|
|
|
53
53
|
function isRelativePath(path2) {
|
|
54
54
|
return /^\.{1,2}(?!\w)/.test(path2);
|
|
55
55
|
}
|
|
56
|
+
function normalizeRouteFile(file) {
|
|
57
|
+
return (0, import_plugin_utils.winPath)(file).replace(/\.(mdx?)\.js$/, ".$1");
|
|
58
|
+
}
|
|
59
|
+
function getRouteId(opts, fileAbsPath) {
|
|
60
|
+
const normalizedFile = normalizeRouteFile(fileAbsPath);
|
|
61
|
+
const route = Object.values(opts.routes ?? {}).find((item) => {
|
|
62
|
+
const routeFile = item.file || item.__absFile;
|
|
63
|
+
return routeFile && normalizeRouteFile(routeFile) === normalizedFile;
|
|
64
|
+
});
|
|
65
|
+
return route == null ? void 0 : route.id;
|
|
66
|
+
}
|
|
56
67
|
function emitDefault(opts, ret) {
|
|
57
68
|
const { frontmatter, demos } = ret.meta;
|
|
58
69
|
const isTabContent = (0, import_tabs.isTabRouteFile)(this.resourcePath);
|
|
@@ -133,6 +144,7 @@ function emitDemo(opts, ret) {
|
|
|
133
144
|
}).filter((item) => item !== void 0)
|
|
134
145
|
);
|
|
135
146
|
}, []);
|
|
147
|
+
const routeId = getRouteId(opts, this.resourcePath);
|
|
136
148
|
return import_plugin_utils.Mustache.render(
|
|
137
149
|
`import React from 'react';
|
|
138
150
|
import '${(0, import_plugin_utils.winPath)(this.resourcePath)}?watch=parent';
|
|
@@ -146,6 +158,9 @@ export const demos = {
|
|
|
146
158
|
component: {{{component}}},
|
|
147
159
|
{{/component}}
|
|
148
160
|
asset: {{{renderAsset}}},
|
|
161
|
+
{{#routeId}}
|
|
162
|
+
routeId: '{{{routeId}}}',
|
|
163
|
+
{{/routeId}}
|
|
149
164
|
context: {{{renderContext}}},
|
|
150
165
|
renderOpts: {{{renderRenderOpts}}},
|
|
151
166
|
},
|
|
@@ -154,6 +169,7 @@ export const demos = {
|
|
|
154
169
|
{
|
|
155
170
|
demos,
|
|
156
171
|
dedupedDemosDeps,
|
|
172
|
+
routeId,
|
|
157
173
|
renderAsset: function renderAsset() {
|
|
158
174
|
if (!("asset" in this))
|
|
159
175
|
return "null";
|
|
@@ -291,7 +307,9 @@ function emitText(opts, ret) {
|
|
|
291
307
|
function emit(opts, ret) {
|
|
292
308
|
const { demos, embeds } = ret.meta;
|
|
293
309
|
embeds.forEach((file) => this.addDependency(file));
|
|
294
|
-
|
|
310
|
+
if (opts.mode !== "demo-index") {
|
|
311
|
+
getDemoSourceFiles(demos).forEach((file) => this.addDependency(file));
|
|
312
|
+
}
|
|
295
313
|
if (this.resourceQuery.includes("watch=parent"))
|
|
296
314
|
return null;
|
|
297
315
|
switch (opts.mode) {
|
|
@@ -320,6 +338,7 @@ function mdLoader(content) {
|
|
|
320
338
|
var _a, _b, _c;
|
|
321
339
|
let opts = this.getOptions();
|
|
322
340
|
const loaderContextPath = opts[import_utoopackLoaders.UTOOPACK_LOADER_CTX_KEY];
|
|
341
|
+
const useUtoopackDemoHMR = process.env.NODE_ENV !== "production" && Boolean(loaderContextPath);
|
|
323
342
|
if (loaderContextPath) {
|
|
324
343
|
const ctx = require(loaderContextPath);
|
|
325
344
|
if (!((_a = opts.techStacks) == null ? void 0 : _a.length)) {
|
|
@@ -346,6 +365,7 @@ function mdLoader(content) {
|
|
|
346
365
|
const baseCacheKey = [
|
|
347
366
|
this.resourcePath,
|
|
348
367
|
(0, import_utils.getContentHash)(content),
|
|
368
|
+
useUtoopackDemoHMR,
|
|
349
369
|
JSON.stringify(import_plugin_utils.lodash.omit(opts, ["mode", "builtins", "onResolveDemos"]))
|
|
350
370
|
].join(":");
|
|
351
371
|
const cacheKey = [
|
|
@@ -364,7 +384,8 @@ function mdLoader(content) {
|
|
|
364
384
|
}
|
|
365
385
|
deferrer[cacheKey] = (0, import_transformer.default)(content, {
|
|
366
386
|
...import_plugin_utils.lodash.omit(opts, ["mode", "builtins", "onResolveDemos"]),
|
|
367
|
-
fileAbsPath: (0, import_plugin_utils.winPath)(this.resourcePath)
|
|
387
|
+
fileAbsPath: (0, import_plugin_utils.winPath)(this.resourcePath),
|
|
388
|
+
useUtoopackDemoHMR
|
|
368
389
|
});
|
|
369
390
|
deferrer[cacheKey].then((ret) => {
|
|
370
391
|
depsMapping[this.resourcePath] = ret.meta.embeds.concat(
|
|
@@ -113,6 +113,7 @@ var transformer_default = async (raw, opts) => {
|
|
|
113
113
|
fileAbsPath: opts.fileAbsPath,
|
|
114
114
|
fileLocaleLessPath,
|
|
115
115
|
fileLocale,
|
|
116
|
+
useUtoopackDemoHMR: opts.useUtoopackDemoHMR,
|
|
116
117
|
resolve: opts.resolve,
|
|
117
118
|
resolver
|
|
118
119
|
}).use(import_rehypeSlug.default).use(import_rehypeLink.default, {
|
|
@@ -10,6 +10,7 @@ type IRehypeDemoOptions = Pick<IMdTransformerOptions, 'techStacks' | 'cwd' | 'fi
|
|
|
10
10
|
resolver: typeof sync;
|
|
11
11
|
fileLocaleLessPath: string;
|
|
12
12
|
fileLocale?: string;
|
|
13
|
+
useUtoopackDemoHMR?: boolean;
|
|
13
14
|
};
|
|
14
15
|
export default function rehypeDemo(opts: IRehypeDemoOptions): Transformer<Root>;
|
|
15
16
|
export {};
|
|
@@ -47,6 +47,8 @@ var toString;
|
|
|
47
47
|
var isElement;
|
|
48
48
|
var DEMO_NODE_CONTAINER = "$demo-container";
|
|
49
49
|
var DEMO_PROP_VALUE_KEY = "$demo-prop-value-key";
|
|
50
|
+
var DEMO_LOADER_PLACEHOLDER = "__DUMI_DEMO_LOADER__";
|
|
51
|
+
var DEMO_LOADER_PLACEHOLDER_VALUE = DEMO_LOADER_PLACEHOLDER;
|
|
50
52
|
var DUMI_DEMO_TAG = "DumiDemo";
|
|
51
53
|
var DUMI_DEMO_GRID_TAG = "DumiDemoGrid";
|
|
52
54
|
var SKIP_DEMO_PARSE = "pure";
|
|
@@ -249,9 +251,15 @@ function rehypeDemo(opts) {
|
|
|
249
251
|
});
|
|
250
252
|
}
|
|
251
253
|
const propDemo = { id: parseOpts.id };
|
|
254
|
+
if (opts.useUtoopackDemoHMR) {
|
|
255
|
+
propDemo.loader = DEMO_LOADER_PLACEHOLDER_VALUE;
|
|
256
|
+
}
|
|
252
257
|
demoIds.push(parseOpts.id);
|
|
253
258
|
deferrers.push(
|
|
254
|
-
(0, import_block.default)(
|
|
259
|
+
(0, import_block.default)({
|
|
260
|
+
...parseOpts,
|
|
261
|
+
cacheable: opts.useUtoopackDemoHMR
|
|
262
|
+
}).then(
|
|
255
263
|
async ({ asset, resolveMap, frontmatter }) => {
|
|
256
264
|
var _a2, _b2, _c2;
|
|
257
265
|
if (demoIds.indexOf(parseOpts.id) !== demoIds.lastIndexOf(parseOpts.id)) {
|
|
@@ -287,6 +295,11 @@ function rehypeDemo(opts) {
|
|
|
287
295
|
if (originalProps[key])
|
|
288
296
|
asset[key] = originalProps[key];
|
|
289
297
|
});
|
|
298
|
+
if (opts.useUtoopackDemoHMR) {
|
|
299
|
+
propDemo.version = (0, import_utils.getContentHash)(
|
|
300
|
+
JSON.stringify(asset.dependencies)
|
|
301
|
+
);
|
|
302
|
+
}
|
|
290
303
|
if (/ inline/.test(String((_b2 = codeNode.data) == null ? void 0 : _b2.meta)) || originalProps.inline) {
|
|
291
304
|
propDemo.inline = true;
|
|
292
305
|
return {
|
|
@@ -368,7 +381,16 @@ function rehypeDemo(opts) {
|
|
|
368
381
|
await Promise.all(deferrers).then((demos) => {
|
|
369
382
|
vFile.data.demos = demos;
|
|
370
383
|
replaceNodes.forEach((node) => {
|
|
371
|
-
const
|
|
384
|
+
const demoLoader = `() => import('${(0, import_plugin_utils.winPath)(
|
|
385
|
+
opts.fileAbsPath
|
|
386
|
+
)}?type=demo')`;
|
|
387
|
+
let value = JSON.stringify(node.data[DEMO_PROP_VALUE_KEY]);
|
|
388
|
+
if (opts.useUtoopackDemoHMR) {
|
|
389
|
+
value = value.replace(
|
|
390
|
+
new RegExp(`"${DEMO_LOADER_PLACEHOLDER}"`, "g"),
|
|
391
|
+
demoLoader
|
|
392
|
+
);
|
|
393
|
+
}
|
|
372
394
|
if (node.JSXAttributes[0].type === "JSXAttribute") {
|
|
373
395
|
node.JSXAttributes[0].value = value;
|
|
374
396
|
} else {
|
|
@@ -34,19 +34,53 @@ export function use<T>(promise: ReactPromise<T>): T {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
type DemoGetter = () => Promise<{ demos: Record<string, IDemoData> }>;
|
|
38
|
+
type DemoIndex = {
|
|
39
|
+
ids: string[];
|
|
40
|
+
getter: DemoGetter;
|
|
41
|
+
};
|
|
42
|
+
type DemoIndexGetter = () => Promise<DemoIndex>;
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const demoIndexes = Object.entries(filesMeta)
|
|
45
|
+
.map(([id, meta]) => ({
|
|
46
|
+
id,
|
|
47
|
+
demoIndex: meta.demoIndex,
|
|
48
|
+
}))
|
|
49
|
+
.filter(
|
|
50
|
+
(item): item is { id: string; demoIndex: DemoIndex } =>
|
|
51
|
+
Boolean(item.demoIndex),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const demoIdMap = demoIndexes.reduce<Record<string, DemoGetter>>(
|
|
55
|
+
(total, { demoIndex }) => {
|
|
56
|
+
if (demoIndex) {
|
|
57
|
+
const { ids, getter } = demoIndex;
|
|
58
|
+
|
|
59
|
+
ids.forEach((id) => {
|
|
60
|
+
total[id] = getter;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
45
63
|
|
|
46
|
-
|
|
47
|
-
},
|
|
64
|
+
return total;
|
|
65
|
+
},
|
|
66
|
+
{},
|
|
67
|
+
);
|
|
48
68
|
|
|
49
69
|
const demosCache = new Map<string, Promise<IDemoData | undefined>>();
|
|
70
|
+
let demoIndexMapPromise:
|
|
71
|
+
| Promise<Record<string, DemoIndexGetter | undefined>>
|
|
72
|
+
| undefined;
|
|
73
|
+
|
|
74
|
+
function loadDemoIndexMap() {
|
|
75
|
+
if (!demoIndexMapPromise) {
|
|
76
|
+
demoIndexMapPromise = import('./demoIndex').then(
|
|
77
|
+
({ demoIndexMap }) =>
|
|
78
|
+
demoIndexMap as Record<string, DemoIndexGetter | undefined>,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return demoIndexMapPromise;
|
|
83
|
+
}
|
|
50
84
|
|
|
51
85
|
/**
|
|
52
86
|
* expand context for source omit extension
|
|
@@ -65,36 +99,128 @@ function expandDemoContext(context?: IDemoData['context']) {
|
|
|
65
99
|
}
|
|
66
100
|
}
|
|
67
101
|
|
|
102
|
+
function getDemoIdCandidates(id: string) {
|
|
103
|
+
const ids = [id];
|
|
104
|
+
const localeLessId = id.replace(/-[a-z]{2}(?:-[A-Z]{2})?$/, '');
|
|
105
|
+
|
|
106
|
+
if (localeLessId !== id) {
|
|
107
|
+
ids.push(localeLessId);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return ids;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function getDemoFromDemoIndex(
|
|
114
|
+
id: string,
|
|
115
|
+
demoIndexGetter: DemoIndexGetter,
|
|
116
|
+
) {
|
|
117
|
+
const demoIndex = await demoIndexGetter();
|
|
118
|
+
const demoId = getDemoIdCandidates(id).find((candidate) =>
|
|
119
|
+
demoIndex.ids.includes(candidate),
|
|
120
|
+
);
|
|
121
|
+
const getter = demoId ? demoIndex.getter : undefined;
|
|
122
|
+
|
|
123
|
+
if (!getter) return undefined;
|
|
124
|
+
|
|
125
|
+
demoIdMap[id] = getter;
|
|
126
|
+
const { demos } = await getter();
|
|
127
|
+
const demo = demos[id] ?? demos[demoId!];
|
|
128
|
+
|
|
129
|
+
if (!demo) return undefined;
|
|
130
|
+
|
|
131
|
+
expandDemoContext(demo.context);
|
|
132
|
+
return demo;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function getDemoFromRouteIndex(id: string, routeId: string) {
|
|
136
|
+
const demoIndexMap = await loadDemoIndexMap();
|
|
137
|
+
const demoIndexGetter = demoIndexMap[routeId];
|
|
138
|
+
|
|
139
|
+
if (!demoIndexGetter) return getDemoFromIndexMap(id);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
(await getDemoFromDemoIndex(id, demoIndexGetter)) ??
|
|
143
|
+
getDemoFromIndexMap(id)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function getDemoFromIndexMap(id: string) {
|
|
148
|
+
const demoIndexMap = await loadDemoIndexMap();
|
|
149
|
+
const demoIndexGetters = Object.values(demoIndexMap).filter(
|
|
150
|
+
(item): item is DemoIndexGetter => Boolean(item),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
for (const demoIndexGetter of demoIndexGetters) {
|
|
154
|
+
const demo = await getDemoFromDemoIndex(id, demoIndexGetter).catch(
|
|
155
|
+
() => undefined,
|
|
156
|
+
);
|
|
157
|
+
if (demo) return demo;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
68
161
|
/**
|
|
69
162
|
* use demo data by id
|
|
70
163
|
*/
|
|
71
|
-
export function useDemo(
|
|
72
|
-
|
|
164
|
+
export function useDemo(
|
|
165
|
+
id: string,
|
|
166
|
+
loader?: DemoGetter,
|
|
167
|
+
version?: string,
|
|
168
|
+
routeId?: string,
|
|
169
|
+
): IDemoData | undefined {
|
|
170
|
+
const cacheKey = version
|
|
171
|
+
? `${id}:${version}`
|
|
172
|
+
: routeId
|
|
173
|
+
? `${id}:route=${routeId}`
|
|
174
|
+
: id;
|
|
175
|
+
const getter = loader ?? demoIdMap[id];
|
|
176
|
+
|
|
177
|
+
if (!demosCache.get(cacheKey)) {
|
|
73
178
|
demosCache.set(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
179
|
+
cacheKey,
|
|
180
|
+
getter
|
|
181
|
+
? getter().then(({ demos }) => {
|
|
182
|
+
const demo = demos[id];
|
|
183
|
+
if (!demo) return undefined;
|
|
184
|
+
|
|
185
|
+
// expand context for omit ext
|
|
186
|
+
expandDemoContext(demo.context);
|
|
187
|
+
return demo;
|
|
188
|
+
})
|
|
189
|
+
: routeId
|
|
190
|
+
? getDemoFromRouteIndex(id, routeId)
|
|
191
|
+
: getDemoFromIndexMap(id),
|
|
80
192
|
);
|
|
193
|
+
|
|
194
|
+
// Reuse local demo data for consumers that still call useDemo(id), such as useLiveDemo.
|
|
195
|
+
demosCache.set(id, demosCache.get(cacheKey)!);
|
|
81
196
|
}
|
|
82
197
|
|
|
83
|
-
return use(demosCache.get(
|
|
198
|
+
return use(demosCache.get(cacheKey)!);
|
|
84
199
|
}
|
|
85
200
|
|
|
86
201
|
/**
|
|
87
202
|
* get all demos
|
|
88
203
|
*/
|
|
89
204
|
export async function getFullDemos() {
|
|
90
|
-
const
|
|
91
|
-
|
|
205
|
+
const demoIndexMap = await loadDemoIndexMap();
|
|
206
|
+
const lazyDemoIndexes = await Promise.all(
|
|
207
|
+
Object.entries(demoIndexMap).map(async ([id, demoIndexGetter]) => ({
|
|
208
|
+
id,
|
|
209
|
+
demoIndex: await demoIndexGetter?.().catch(() => undefined),
|
|
210
|
+
})),
|
|
211
|
+
);
|
|
212
|
+
const allDemoIndexes = [
|
|
213
|
+
...demoIndexes,
|
|
214
|
+
...lazyDemoIndexes,
|
|
215
|
+
].filter(
|
|
216
|
+
(item): item is { id: string; demoIndex: DemoIndex } =>
|
|
217
|
+
Boolean(item.demoIndex),
|
|
92
218
|
);
|
|
93
219
|
|
|
94
220
|
return Promise.all(
|
|
95
|
-
|
|
221
|
+
allDemoIndexes.map(async ({ id, demoIndex }) => ({
|
|
96
222
|
id,
|
|
97
|
-
demos: (await
|
|
223
|
+
demos: (await demoIndex.getter()).demos as Record<string, IDemoData>,
|
|
98
224
|
})),
|
|
99
225
|
).then((ret) =>
|
|
100
226
|
ret.reduce<Record<string, IDemoData>>((total, { id, demos }) => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{{#metaFiles}}
|
|
2
|
-
{{#
|
|
2
|
+
{{#loadDemoIndex}}
|
|
3
3
|
import { frontmatter as fm{{{index}}}, toc as t{{{index}}}, demoIndex as dmi{{{index}}} } from '{{{file}}}?type=frontmatter';
|
|
4
|
-
{{/
|
|
5
|
-
{{^
|
|
4
|
+
{{/loadDemoIndex}}
|
|
5
|
+
{{^loadDemoIndex}}
|
|
6
6
|
import { frontmatter as fm{{{index}}}, toc as t{{{index}}} } from '{{{file}}}?type=frontmatter';
|
|
7
|
-
{{/
|
|
7
|
+
{{/loadDemoIndex}}
|
|
8
8
|
{{/metaFiles}}
|
|
9
9
|
|
|
10
10
|
export const filesMeta = {
|
|
@@ -12,9 +12,9 @@ export const filesMeta = {
|
|
|
12
12
|
'{{{id}}}': {
|
|
13
13
|
frontmatter: fm{{{index}}},
|
|
14
14
|
toc: t{{{index}}},
|
|
15
|
-
{{#
|
|
15
|
+
{{#loadDemoIndex}}
|
|
16
16
|
demoIndex: dmi{{{index}}},
|
|
17
|
-
{{/
|
|
17
|
+
{{/loadDemoIndex}}
|
|
18
18
|
{{#tabs}}
|
|
19
19
|
tabs: {{{tabs}}},
|
|
20
20
|
{{/tabs}}
|