dumi 2.3.0-alpha.8 → 2.3.0-beta.0

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.
Files changed (87) hide show
  1. package/compiled/crates/swc_plugin_react_demo.wasm +0 -0
  2. package/dist/assetParsers/block.d.ts +7 -1
  3. package/dist/assetParsers/block.js +14 -6
  4. package/dist/client/pages/Demo/index.js +19 -5
  5. package/dist/client/pages/Loading.d.ts +1 -0
  6. package/dist/client/pages/Loading.js +2 -0
  7. package/dist/client/theme-api/DumiDemo/index.js +4 -4
  8. package/dist/client/theme-api/{context/index.d.ts → context.d.ts} +4 -12
  9. package/dist/client/theme-api/context.js +16 -0
  10. package/dist/client/theme-api/index.d.ts +2 -3
  11. package/dist/client/theme-api/index.js +2 -3
  12. package/dist/client/theme-api/types.d.ts +6 -4
  13. package/dist/client/theme-api/useLiveDemo.d.ts +6 -0
  14. package/dist/client/theme-api/useLiveDemo.js +70 -0
  15. package/dist/client/theme-api/useRouteMeta.js +73 -20
  16. package/dist/client/theme-api/useSiteSearch/index.d.ts +1 -1
  17. package/dist/client/theme-api/useSiteSearch/index.js +20 -48
  18. package/dist/client/theme-api/useSiteSearch/useSearchData.d.ts +9 -6
  19. package/dist/client/theme-api/useSiteSearch/useSearchData.js +55 -60
  20. package/dist/client/theme-api/useTabMeta.js +1 -1
  21. package/dist/client/theme-api/utils.d.ts +10 -0
  22. package/dist/client/theme-api/utils.js +25 -0
  23. package/dist/constants.d.ts +0 -1
  24. package/dist/constants.js +0 -4
  25. package/dist/features/compile/index.js +11 -18
  26. package/dist/features/exports.js +3 -3
  27. package/dist/features/meta.js +12 -31
  28. package/dist/features/theme/index.js +8 -5
  29. package/dist/loaders/markdown/index.d.ts +1 -7
  30. package/dist/loaders/markdown/index.js +39 -113
  31. package/dist/loaders/markdown/transformer/index.d.ts +1 -1
  32. package/dist/loaders/markdown/transformer/rehypeDemo.js +8 -2
  33. package/dist/loaders/page/index.js +1 -3
  34. package/dist/preset.js +1 -2
  35. package/dist/templates/ContextWrapper.ts.tpl +2 -10
  36. package/dist/templates/meta/exports.ts.tpl +160 -0
  37. package/dist/templates/meta/index.ts.tpl +26 -0
  38. package/dist/templates/{meta-runtime.ts.tpl → meta/runtime.ts.tpl} +11 -22
  39. package/dist/types.d.ts +2 -2
  40. package/index.d.ts +1 -4
  41. package/package.json +2 -1
  42. package/theme-default/builtins/Previewer/index.d.ts +1 -1
  43. package/theme-default/builtins/Previewer/index.js +35 -33
  44. package/theme-default/builtins/Previewer/index.less +34 -0
  45. package/theme-default/builtins/SourceCode/index.d.ts +2 -1
  46. package/theme-default/builtins/SourceCode/index.js +3 -3
  47. package/theme-default/builtins/SourceCode/index.less +1 -0
  48. package/theme-default/locales/en-US.json +2 -0
  49. package/theme-default/locales/zh-CN.json +2 -0
  50. package/theme-default/slots/Loading/index.d.ts +5 -0
  51. package/theme-default/slots/Loading/index.js +18 -0
  52. package/theme-default/slots/Loading/index.less +20 -0
  53. package/theme-default/slots/PreviewerActions/index.d.ts +7 -1
  54. package/theme-default/slots/PreviewerActions/index.js +49 -6
  55. package/theme-default/slots/PreviewerActions/index.less +58 -14
  56. package/theme-default/slots/SearchBar/Mask.js +1 -1
  57. package/theme-default/slots/SearchBar/index.js +1 -1
  58. package/theme-default/slots/SearchResult/index.js +1 -10
  59. package/theme-default/slots/SourceCodeEditor/index.d.ts +18 -0
  60. package/theme-default/slots/SourceCodeEditor/index.js +106 -0
  61. package/theme-default/slots/SourceCodeEditor/index.less +45 -0
  62. package/dist/client/theme-api/context/index.js +0 -50
  63. package/dist/client/theme-api/context/use.d.ts +0 -10
  64. package/dist/client/theme-api/context/use.js +0 -25
  65. package/dist/client/theme-api/evalCode.d.ts +0 -2
  66. package/dist/client/theme-api/evalCode.js +0 -17
  67. package/dist/client/theme-api/live/LiveProvider.d.ts +0 -16
  68. package/dist/client/theme-api/live/LiveProvider.js +0 -74
  69. package/dist/client/theme-api/live/index.d.ts +0 -3
  70. package/dist/client/theme-api/live/index.js +0 -3
  71. package/dist/client/theme-api/live/useDemoScopes.d.ts +0 -2
  72. package/dist/client/theme-api/live/useDemoScopes.js +0 -15
  73. package/dist/features/live.d.ts +0 -3
  74. package/dist/features/live.js +0 -74
  75. package/dist/templates/live/demo-scopes.ts.tpl +0 -22
  76. package/dist/templates/live/disabled.ts.tpl +0 -1
  77. package/dist/templates/meta-demos.ts.tpl +0 -34
  78. package/dist/templates/meta-frontmatter.ts.tpl +0 -9
  79. package/dist/templates/meta-route.ts.tpl +0 -43
  80. package/dist/templates/meta-search.ts.tpl +0 -41
  81. package/theme-default/slots/LiveDemo/index.d.ts +0 -3
  82. package/theme-default/slots/LiveDemo/index.js +0 -8
  83. package/theme-default/slots/LiveEditor/index.d.ts +0 -4
  84. package/theme-default/slots/LiveEditor/index.js +0 -20
  85. package/theme-default/slots/LiveError/index.d.ts +0 -4
  86. package/theme-default/slots/LiveError/index.js +0 -15
  87. package/theme-default/slots/LiveError/index.less +0 -22
@@ -40,8 +40,8 @@ var import_transformer = __toESM(require("./transformer"));
40
40
  var import_rehypeText = require("./transformer/rehypeText");
41
41
  function getDemoSourceFiles(demos = []) {
42
42
  return demos.reduce((ret, demo) => {
43
- if ("sources" in demo) {
44
- ret.push(...Object.values(demo.sources));
43
+ if ("resolveMap" in demo) {
44
+ ret.push(...Object.values(demo.resolveMap));
45
45
  }
46
46
  return ret;
47
47
  }, []);
@@ -49,6 +49,7 @@ function getDemoSourceFiles(demos = []) {
49
49
  function emitDefault(opts, ret) {
50
50
  const { frontmatter, demos } = ret.meta;
51
51
  const isTabContent = (0, import_tabs.isTabRouteFile)(this.resourcePath);
52
+ const wrapper = isTabContent ? "" : "DumiPage";
52
53
  if (demos && opts.onResolveDemos) {
53
54
  opts.onResolveDemos(demos);
54
55
  }
@@ -56,14 +57,21 @@ function emitDefault(opts, ret) {
56
57
  opts.onResolveAtomMeta(frontmatter.atomId, frontmatter);
57
58
  }
58
59
  return `${Object.values(opts.builtins).map((item) => `import ${item.specifier} from '${item.source}';`).join("\n")}
59
- import React from 'react';
60
- ${isTabContent ? `import { useTabMeta } from 'dumi';` : `import { DumiPage, useRouteMeta } from 'dumi';`}
60
+ import LoadingComponent from '@@/dumi/theme/loading';
61
+ import React, { Suspense } from 'react';
62
+ import { DumiPage, useTabMeta, useRouteMeta } from 'dumi';
63
+
64
+ function DumiMarkdownInner() {
65
+ const { texts: ${import_rehypeText.CONTENT_TEXTS_OBJ_NAME} } = use${isTabContent ? "TabMeta" : "RouteMeta"}();
66
+
67
+ return ${ret.content};
68
+ }
61
69
 
62
70
  // export named function for fastRefresh
63
71
  // ref: https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#edits-always-lead-to-full-reload
64
72
  function DumiMarkdownContent() {
65
- const { texts: ${import_rehypeText.CONTENT_TEXTS_OBJ_NAME} } = use${isTabContent ? "TabMeta" : "RouteMeta"}();
66
- return ${isTabContent ? ret.content : `<DumiPage>${ret.content}</DumiPage>`};
73
+ // wrap suspense for catch async meta data
74
+ return <${wrapper}><Suspense fallback={<LoadingComponent />}><DumiMarkdownInner /></Suspense></${wrapper}>;
67
75
  }
68
76
 
69
77
  export default DumiMarkdownContent;`;
@@ -77,7 +85,8 @@ export const demos = {
77
85
  {{#demos}}
78
86
  '{{{id}}}': {
79
87
  component: {{{component}}},
80
- asset: {{{renderAsset}}}
88
+ asset: {{{renderAsset}}},
89
+ context: {{{renderContext}}}
81
90
  },
82
91
  {{/demos}}
83
92
  };`,
@@ -87,14 +96,26 @@ export const demos = {
87
96
  if (!("asset" in this))
88
97
  return "null";
89
98
  let { asset } = this;
90
- const { sources } = this;
91
- Object.keys(this.sources).forEach((file) => {
99
+ const { resolveMap } = this;
100
+ Object.keys(this.resolveMap).forEach((file) => {
92
101
  if (!asset.dependencies[file])
93
102
  return;
94
103
  asset = import_plugin_utils.lodash.cloneDeep(asset);
95
- asset.dependencies[file].value = `{{{require('-!${sources[file]}?dumi-raw').default}}}`;
104
+ asset.dependencies[file].value = `{{{require('-!${resolveMap[file]}?dumi-raw').default}}}`;
96
105
  });
97
106
  return JSON.stringify(asset, null, 2).replace(/"{{{|}}}"/g, "");
107
+ },
108
+ renderContext: function renderContext() {
109
+ if (!("resolveMap" in this))
110
+ return "undefined";
111
+ const context = Object.entries(this.resolveMap).reduce(
112
+ (acc, [key, path]) => ({
113
+ ...acc,
114
+ [key]: `{{{require('${path}')}}}`
115
+ }),
116
+ {}
117
+ );
118
+ return JSON.stringify(context, null, 2).replace(/"{{{|}}}"/g, "");
98
119
  }
99
120
  }
100
121
  );
@@ -117,112 +138,21 @@ function emitDemoIndex(opts, ret) {
117
138
  );
118
139
  }
119
140
  function emitFrontmatter(opts, ret) {
120
- const { frontmatter } = ret.meta;
121
- return import_plugin_utils.Mustache.render(`export const frontmatter = {{{frontmatter}}};`, {
122
- frontmatter: JSON.stringify(frontmatter)
123
- });
124
- }
125
- function emitText(opts, ret) {
126
- const { texts, toc } = ret.meta;
141
+ const { frontmatter, toc } = ret.meta;
127
142
  return import_plugin_utils.Mustache.render(
128
143
  `export const toc = {{{toc}}};
129
- export const texts = {{{texts}}};`,
144
+ export const frontmatter = {{{frontmatter}}};`,
130
145
  {
131
146
  toc: JSON.stringify(toc),
132
- texts: JSON.stringify(texts)
133
- }
134
- );
135
- }
136
- function emitScope(opts, ret) {
137
- const { demos } = ret.meta;
138
- const importReg = /import(?!(\stype)).*from.*;/g;
139
- return import_plugin_utils.Mustache.render(
140
- `{{#renderImport}}
141
- {{{.}}}
142
- {{/renderImport}}
143
-
144
- export const scopes = {
145
- {{#demos}}
146
- '{{{id}}}': { {{{renderScope}}} },
147
- {{/demos}}
148
- }`,
149
- {
150
- demos,
151
- renderImport: function renderImport() {
152
- if (!demos)
153
- return [];
154
- const imports = {};
155
- for (const demo of demos) {
156
- if ("asset" in demo) {
157
- const { asset } = demo;
158
- Object.entries(asset.dependencies).forEach(([filename, file]) => {
159
- if (filename.endsWith(".tsx")) {
160
- const fileImports = file.value.match(importReg) || [];
161
- fileImports.forEach((item) => {
162
- var _a;
163
- const scope = item.replace(/import(.*)from.*;/, "$1").trim();
164
- const dep = item.replace(/import.*from(.*);/, "$1").trim();
165
- const namedReg = /.*\{(.*)}/g;
166
- const namedScope = namedReg.test(scope) ? scope.replace(namedReg, "$1").split(",").map((item2) => item2.trim()).filter(Boolean) : [];
167
- const defaultReg = /(?:(?![,{]).)*/;
168
- const defaultScope = (_a = scope.match(defaultReg)) == null ? void 0 : _a[0].trim();
169
- imports[dep] ?? (imports[dep] = []);
170
- if (defaultScope) {
171
- const defaultImport = `default as ${defaultScope}`;
172
- if (!imports[dep].includes(defaultImport)) {
173
- imports[dep].push(defaultImport);
174
- }
175
- }
176
- if (namedScope.length) {
177
- for (const item2 of namedScope) {
178
- if (!imports[dep].includes(item2)) {
179
- imports[dep].push(item2);
180
- }
181
- }
182
- }
183
- });
184
- }
185
- });
186
- }
187
- }
188
- return Object.entries(imports).map(([key, value]) => {
189
- return value.length ? `import { ${value.join(", ")} } from ${key};` : "";
190
- }).filter(Boolean);
191
- },
192
- renderScope: function renderScope() {
193
- if (!("asset" in this))
194
- return "";
195
- const { asset } = this;
196
- const demoScopes = [];
197
- Object.entries(asset.dependencies).forEach(([filename, file]) => {
198
- if (filename.endsWith(".tsx")) {
199
- const imports = file.value.match(importReg) || [];
200
- const scopes = imports.reduce((acc, item) => {
201
- const scope = item.replace(/import(.*)from.*;/, "$1").trim();
202
- const scopeList = scope.replace(/[{}]/g, "").trim();
203
- return [...acc, scopeList];
204
- }, []);
205
- demoScopes.push(...scopes);
206
- }
207
- });
208
- return demoScopes.join(", ");
209
- }
147
+ frontmatter: JSON.stringify(frontmatter)
210
148
  }
211
149
  );
212
150
  }
213
- function emitScopeIndex(opts, ret) {
214
- const { demos } = ret.meta;
215
- return import_plugin_utils.Mustache.render(
216
- `export const scopeIndex = {
217
- {{#demos}}
218
- '{{{id}}}': {{{getter}}},
219
- {{/demos}}
220
- };`,
221
- {
222
- demos,
223
- getter: `() => import('${(0, import_plugin_utils.winPath)(this.resourcePath)}?type=scope')`
224
- }
225
- );
151
+ function emitText(opts, ret) {
152
+ const { texts } = ret.meta;
153
+ return import_plugin_utils.Mustache.render(`export const texts = {{{texts}}};`, {
154
+ texts: JSON.stringify(texts)
155
+ });
226
156
  }
227
157
  function emit(opts, ret) {
228
158
  const { demos, embeds } = ret.meta;
@@ -237,10 +167,6 @@ function emit(opts, ret) {
237
167
  return emitFrontmatter.call(this, opts, ret);
238
168
  case "text":
239
169
  return emitText.call(this, opts, ret);
240
- case "scope":
241
- return emitScope.call(this, opts, ret);
242
- case "scope-index":
243
- return emitScopeIndex.call(this, opts, ret);
244
170
  default:
245
171
  return emitDefault.call(this, opts, ret);
246
172
  }
@@ -21,7 +21,7 @@ declare module 'vfile' {
21
21
  id: string;
22
22
  component: string;
23
23
  asset: IParsedBlockAsset['asset'];
24
- sources: IParsedBlockAsset['sources'];
24
+ resolveMap: IParsedBlockAsset['resolveMap'];
25
25
  } | {
26
26
  id: string;
27
27
  component: string;
@@ -225,7 +225,7 @@ function rehypeDemo(opts) {
225
225
  demoIds.push(parseOpts.id);
226
226
  deferrers.push(
227
227
  (0, import_block.default)(parseOpts).then(
228
- async ({ asset, sources, frontmatter }) => {
228
+ async ({ asset, resolveMap, frontmatter }) => {
229
229
  var _a2, _b2, _c2;
230
230
  if (demoIds.indexOf(parseOpts.id) !== demoIds.lastIndexOf(parseOpts.id)) {
231
231
  const startLine = (_a2 = node.position) == null ? void 0 : _a2.start.line;
@@ -293,7 +293,13 @@ function rehypeDemo(opts) {
293
293
  id: asset.id,
294
294
  component,
295
295
  asset: techStack.generateMetadata ? await techStack.generateMetadata(asset, techStackOpts) : asset,
296
- sources: techStack.generateSources ? await techStack.generateSources(sources, techStackOpts) : sources
296
+ /**
297
+ * keep `generateSources` rather than `generateResolveMap` for compatibility
298
+ */
299
+ resolveMap: techStack.generateSources ? await techStack.generateSources(
300
+ resolveMap,
301
+ techStackOpts
302
+ ) : resolveMap
297
303
  };
298
304
  }
299
305
  )
@@ -44,7 +44,5 @@ function pageMetaLoader(raw) {
44
44
  frontmatter || (frontmatter = {});
45
45
  frontmatter.title ?? (frontmatter.title = import_plugin_utils.lodash.startCase(import_path.default.basename(pathWithoutIndex)));
46
46
  return `export const frontmatter = ${JSON.stringify(frontmatter)};
47
- export const toc = [];
48
- export const texts = [];
49
- export const demos = {};`;
47
+ export const toc = [];`;
50
48
  }
package/dist/preset.js CHANGED
@@ -52,8 +52,7 @@ var preset_default = (api) => {
52
52
  require.resolve("./features/assets"),
53
53
  require.resolve("./features/exportStatic"),
54
54
  require.resolve("./features/sitemap"),
55
- require.resolve("./features/html2sketch"),
56
- require.resolve("./features/live")
55
+ require.resolve("./features/html2sketch")
57
56
  ]
58
57
  };
59
58
  };
@@ -3,8 +3,6 @@ import { useOutlet, history } from 'dumi';
3
3
  import { warning } from 'rc-util';
4
4
  import { SiteContext, type ISiteContext } from '{{{contextPath}}}';
5
5
  import { components } from '../meta/atoms';
6
- import { tabs } from '../meta/tabs';
7
- import { getDemoById } from '../meta/demos';
8
6
  import { locales } from '../locales/config';
9
7
  {{{defaultExport}}}
10
8
  {{{namedExport}}}
@@ -48,20 +46,18 @@ export default function DumiContextWrapper() {
48
46
  entryExports,
49
47
  demos: null,
50
48
  components,
51
- tabs,
52
49
  locales,
53
50
  loading,
54
51
  setLoading,
55
52
  hostname,
56
53
  themeConfig,
57
54
  _2_level_nav_available,
58
- getDemoById,
59
55
  };
60
56
 
61
57
  // Proxy do not warning since `Object.keys` will get nothing to loop
62
58
  Object.defineProperty(ctx, 'demos', {
63
59
  get: () => {
64
- warning(false, '`demos` return empty in latest version.');
60
+ warning(false, '`demos` return empty in latest version, please use `useDemo` instead.');
65
61
  return {};
66
62
  },
67
63
  });
@@ -72,21 +68,17 @@ export default function DumiContextWrapper() {
72
68
  historyType,
73
69
  entryExports,
74
70
  components,
75
- tabs,
76
71
  locales,
77
72
  loading,
78
73
  setLoading,
79
74
  hostname,
80
75
  themeConfig,
81
76
  _2_level_nav_available,
82
- getDemoById,
83
77
  ]);
84
78
 
85
-
86
-
87
79
  return (
88
80
  <SiteContext.Provider value={context}>
89
81
  {outlet}
90
82
  </SiteContext.Provider>
91
83
  );
92
- }
84
+ }
@@ -0,0 +1,160 @@
1
+ import { filesMeta, tabsMeta } from '.';
2
+ import type { IDemoData, IRouteMeta } from 'dumi/dist/client/theme-api/types';
3
+ import { use } from 'dumi/dist/client/theme-api/utils';
4
+
5
+ const demoIdMap = Object.keys(filesMeta).reduce((total, current) => {
6
+ if (filesMeta[current].demoIndex) {
7
+ const { ids, getter } = filesMeta[current].demoIndex;
8
+
9
+ ids.forEach((id) => {
10
+ total[id] = getter;
11
+ });
12
+ }
13
+
14
+ return total;
15
+ }, {});
16
+
17
+ const demosCache = new Map<string, Promise<IDemoData | undefined>>();
18
+
19
+ /**
20
+ * expand context for source omit extension
21
+ * why not do this in compile-time?
22
+ * asset metadata also has extension and for reduce bundle size
23
+ */
24
+ function expandDemoContext(context?: IDemoData['context']) {
25
+ if (context) {
26
+ Object.keys(context).forEach((src) => {
27
+ const withoutExt = src.match(/^(.+)\.(js|jsx|ts|tsx|json)$/)?.[1];
28
+
29
+ if (withoutExt && !context[withoutExt]) {
30
+ context[withoutExt] = context[src];
31
+ }
32
+ });
33
+ }
34
+ }
35
+
36
+ /**
37
+ * use demo data by id
38
+ */
39
+ export function useDemo(id: string): IDemoData | undefined {
40
+ if (!demosCache.get(id)) {
41
+ demosCache.set(
42
+ id,
43
+ demoIdMap[id]?.().then(({ demos }) => {
44
+ // expand context for omit ext
45
+ expandDemoContext(demos[id].context);
46
+
47
+ return demos[id];
48
+ }),
49
+ );
50
+ }
51
+
52
+ return use(demosCache.get(id)!);
53
+ }
54
+
55
+ /**
56
+ * get all demos
57
+ */
58
+ export async function getFullDemos() {
59
+ const demoFilesMeta = Object.entries(filesMeta).filter(
60
+ ([_id, meta]) => meta.demoIndex,
61
+ );
62
+
63
+ return Promise.all(
64
+ demoFilesMeta.map(async ([id, meta]) => ({
65
+ id,
66
+ demos: (await meta.demoIndex.getter()).demos as Record<string, IDemoData>,
67
+ })),
68
+ ).then((ret) =>
69
+ ret.reduce<Record<string, IDemoData>>((total, { id, demos }) => {
70
+ Object.values(demos).forEach((demo) => {
71
+ // set route id in runtime for reduce bundle size
72
+ demo.routeId = id;
73
+
74
+ // expand context for omit ext
75
+ expandDemoContext(demo.context);
76
+ });
77
+
78
+ return {
79
+ ...total,
80
+ ...demos,
81
+ };
82
+ }, {}),
83
+ );
84
+ }
85
+
86
+ type ITab = NonNullable<IRouteMeta['tabs']>[0];
87
+
88
+ /**
89
+ * generate final data for tab
90
+ */
91
+ function genTab(id: string, meta?: ITab['meta']): ITab {
92
+ return {
93
+ ...tabsMeta[id],
94
+ meta: meta ?? {
95
+ frontmatter: { title: tabsMeta[id].title },
96
+ toc: [],
97
+ texts: [],
98
+ },
99
+ };
100
+ }
101
+
102
+ /**
103
+ * get route meta by id
104
+ */
105
+ export function getRouteMetaById<T extends { syncOnly?: boolean }>(
106
+ id: string,
107
+ opts?: T,
108
+ ): T extends { syncOnly: true }
109
+ ? undefined | IRouteMeta
110
+ : Promise<undefined | IRouteMeta> | undefined {
111
+ if (filesMeta[id]) {
112
+ const { frontmatter, toc, textGetter, tabs = [] } = filesMeta[id];
113
+ const routeMeta: IRouteMeta = {
114
+ frontmatter,
115
+ toc: toc,
116
+ texts: [],
117
+ };
118
+
119
+ if (opts?.syncOnly) {
120
+ routeMeta.tabs = tabs.map((tabId) =>
121
+ genTab(tabId, getRouteMetaById(tabId, opts)),
122
+ );
123
+ } else {
124
+ return new Promise(async (resolve) => {
125
+ if (textGetter) {
126
+ ({ texts: routeMeta.texts } = await textGetter());
127
+ }
128
+
129
+ routeMeta.tabs = await Promise.all(
130
+ tabs.map(async (tabId) =>
131
+ genTab(tabId, await getRouteMetaById(tabId, opts)),
132
+ ),
133
+ );
134
+ resolve(routeMeta);
135
+ });
136
+ }
137
+
138
+ return routeMeta;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * get all routes meta
144
+ */
145
+ export async function getFullRoutesMeta(): Promise<Record<string, IRouteMeta>> {
146
+ return await Promise.all(
147
+ Object.keys(filesMeta).map(async (id) => ({
148
+ id,
149
+ meta: await getRouteMetaById(id),
150
+ })),
151
+ ).then((ret) =>
152
+ ret.reduce(
153
+ (total, { id, meta }) => ({
154
+ ...total,
155
+ [id]: meta,
156
+ }),
157
+ {},
158
+ ),
159
+ );
160
+ }
@@ -0,0 +1,26 @@
1
+ {{#metaFiles}}
2
+ import { frontmatter as fm{{{index}}}, toc as t{{{index}}} } from '{{{file}}}?type=frontmatter';
3
+ {{#isMarkdown}}
4
+ import { demoIndex as dmi{{{index}}} } from '{{{file}}}?type=demo-index';
5
+ {{/isMarkdown}}
6
+ {{/metaFiles}}
7
+
8
+ export const filesMeta = {
9
+ {{#metaFiles}}
10
+ '{{{id}}}': {
11
+ frontmatter: fm{{{index}}},
12
+ toc: t{{{index}}},
13
+ {{#isMarkdown}}
14
+ demoIndex: dmi{{{index}}},
15
+ {{/isMarkdown}}
16
+ {{#tabs}}
17
+ tabs: {{{tabs}}},
18
+ {{/tabs}}
19
+ {{#isMarkdown}}
20
+ textGetter: () => import({{{chunkName}}}'{{{file}}}?type=text'),
21
+ {{/isMarkdown}}
22
+ },
23
+ {{/metaFiles}}
24
+ }
25
+
26
+ export { tabs as tabsMeta } from './tabs';
@@ -1,13 +1,12 @@
1
1
  import { warning } from 'rc-util';
2
- import { tabs } from './tabs';
3
- import { filesFrontmatter } from './frontmatter';
4
2
  import deepmerge from '{{{deepmerge}}}';
3
+ import { getRouteMetaById } from './exports';
5
4
 
6
5
  // Proxy do not warning since `Object.keys` will get nothing to loop
7
6
  function wrapEmpty(meta, fieldName, defaultValue) {
8
7
  Object.defineProperty(meta, fieldName, {
9
8
  get: () => {
10
- warning(false, `'${fieldName}' return empty in latest version.`);
9
+ warning(false, `'${fieldName}' return empty in latest version, please use \`useRouteMeta\` instead.`);
11
10
  return defaultValue;
12
11
  },
13
12
  });
@@ -15,32 +14,22 @@ function wrapEmpty(meta, fieldName, defaultValue) {
15
14
 
16
15
  export const patchRoutes = ({ routes }) => {
17
16
  Object.values(routes).forEach((route) => {
18
- if (filesFrontmatter[route.id]) {
19
- if (process.env.NODE_ENV === 'production' && (route.meta?.frontmatter?.debug || filesFrontmatter[route.id].debug)) {
17
+ const routeMeta = getRouteMetaById(route.id, { syncOnly: true });
18
+
19
+ if (routeMeta) {
20
+ if (process.env.NODE_ENV === 'production' && (route.meta?.frontmatter?.debug || routeMeta.debug)) {
20
21
  // hide route in production which set hide frontmatter
21
22
  delete routes[route.id];
22
23
  } else {
23
24
  // merge meta to route object
24
- route.meta = deepmerge(route.meta, { frontmatter: filesFrontmatter[route.id] });
25
+ route.meta = deepmerge(route.meta, routeMeta);
25
26
 
26
- wrapEmpty(route.meta, 'demos', {});
27
+ wrapEmpty(route.meta, 'toc', []);
27
28
  wrapEmpty(route.meta, 'texts', []);
28
29
 
29
- // apply real tab data from id
30
- route.meta.tabs = route.meta.tabs?.map((id) => {
31
- const meta = {
32
- frontmatter: filesFrontmatter[id] || { title: tabs[id].title },
33
- toc: [],
34
- texts: [],
35
- }
36
-
37
- wrapEmpty(meta, 'demos', {});
38
- wrapEmpty(meta, 'texts', []);
39
-
40
- return {
41
- ...tabs[id],
42
- meta,
43
- }
30
+ route.meta.tabs?.forEach((tab) => {
31
+ wrapEmpty(tab, 'toc', []);
32
+ wrapEmpty(tab, 'texts', []);
44
33
  });
45
34
  }
46
35
  }
package/dist/types.d.ts CHANGED
@@ -7,7 +7,7 @@ import type { IThemeLoadResult } from "./features/theme/loader";
7
7
  import type { IModify } from '@umijs/core';
8
8
  import type { AssetsPackage, ExampleBlockAsset } from 'dumi-assets-types';
9
9
  import type { Element } from 'hast';
10
- import type { defineConfig as defineUmiConfig, IApi as IUmiApi } from 'umi';
10
+ import type { IApi as IUmiApi, defineConfig as defineUmiConfig } from 'umi';
11
11
  type Subset<K> = {
12
12
  [attr in keyof K]?: K[attr] extends Array<any> ? K[attr] : K[attr] extends Function | undefined ? K[attr] : K[attr] extends object ? Subset<K[attr]> : K[attr] extends object | null ? Subset<K[attr]> | null : K[attr] extends object | null | undefined ? Subset<K[attr]> | null | undefined : K[attr];
13
13
  };
@@ -80,7 +80,7 @@ export declare abstract class IDumiTechStack {
80
80
  /**
81
81
  * generator for return file path of demo sources
82
82
  */
83
- abstract generateSources?(sources: IParsedBlockAsset['sources'], opts: Parameters<NonNullable<IDumiTechStack['generateMetadata']>>[1]): Promise<IParsedBlockAsset['sources']> | IParsedBlockAsset['sources'];
83
+ abstract generateSources?(sources: IParsedBlockAsset['resolveMap'], opts: Parameters<NonNullable<IDumiTechStack['generateMetadata']>>[1]): Promise<IParsedBlockAsset['resolveMap']> | IParsedBlockAsset['resolveMap'];
84
84
  }
85
85
  export type IApi = IUmiApi & {
86
86
  config: IDumiConfig & {
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from '@@/dumi/exports';
1
2
  export { Root as HastRoot } from 'hast';
2
3
  export * from 'umi';
3
4
  export {
@@ -7,8 +8,4 @@ export {
7
8
  export * from './dist';
8
9
  // override umi exported defineConfig
9
10
  export { defineConfig } from './dist';
10
- export * from './dist/client/theme-api';
11
11
  export { IApi } from './dist/types';
12
- export function getRouteMetaById(id: string): Promise<any>;
13
- /** @private Internal usage. Safe to remove */
14
- export function loadFilesMeta(): Promise<any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dumi",
3
- "version": "2.3.0-alpha.8",
3
+ "version": "2.3.0-beta.0",
4
4
  "description": "📖 Documentation Generator of React Component",
5
5
  "keywords": [
6
6
  "generator",
@@ -122,6 +122,7 @@
122
122
  "react-copy-to-clipboard": "^5.1.0",
123
123
  "react-error-boundary": "^4.0.10",
124
124
  "react-intl": "^6.4.4",
125
+ "react-loading-skeleton": "^3.1.1",
125
126
  "react-simple-code-editor": "^0.13.1",
126
127
  "rehype-autolink-headings": "^6.1.1",
127
128
  "rehype-remove-comments": "^5.0.0",
@@ -1,4 +1,4 @@
1
- import { IPreviewerProps } from 'dumi';
1
+ import { type IPreviewerProps } from 'dumi';
2
2
  import { type FC } from 'react';
3
3
  import './index.less';
4
4
  declare const Previewer: FC<IPreviewerProps>;