dumi 2.4.49 → 2.4.50

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.
@@ -176,7 +176,11 @@ var compile_default = (api) => {
176
176
  routes: api.appData.routes,
177
177
  locales: api.config.locales,
178
178
  pkg: api.pkg,
179
- disableLiveDemo: (0, import_utils2.shouldDisabledLiveDemo)(api)
179
+ disableLiveDemo: (0, import_utils2.shouldDisabledLiveDemo)(api),
180
+ codeBlockBabelPlugins: (0, import_utils2.getCodeBlockBabelPlugins)(
181
+ api.config.extraBabelPlugins,
182
+ api.cwd
183
+ )
180
184
  };
181
185
  memo.module.rule("watch-parent").pre().resourceQuery(/watch=parent/).use("null-loader").loader(require.resolve("../../loaders/null")).end();
182
186
  const mdRule = memo.module.rule("dumi-md").type("javascript/auto").test(/\.md$/);
@@ -55,6 +55,10 @@ var customRunLoaders = async (options) => {
55
55
  var mdLoaderPath = require.resolve("../../loaders/markdown");
56
56
  var getLoadHook = (api) => {
57
57
  const disableLiveDemo = (0, import_utils2.shouldDisabledLiveDemo)(api);
58
+ const codeBlockBabelPlugins = (0, import_utils2.getCodeBlockBabelPlugins)(
59
+ api.config.extraBabelPlugins,
60
+ api.cwd
61
+ );
58
62
  return async (filePath) => {
59
63
  var _a, _b, _c, _d;
60
64
  const loaderBaseOpts = {
@@ -67,7 +71,8 @@ var getLoadHook = (api) => {
67
71
  routes: api.appData.routes,
68
72
  locales: api.config.locales || [],
69
73
  pkg: api.pkg,
70
- disableLiveDemo
74
+ disableLiveDemo,
75
+ codeBlockBabelPlugins
71
76
  };
72
77
  const requestUrl = import_url.default.parse(filePath);
73
78
  const query = import_querystring.default.parse(requestUrl.query);
@@ -1,2 +1,10 @@
1
+ import type { PluginItem } from '@umijs/bundler-utils/compiled/@babel/core';
1
2
  import { IApi } from 'umi';
2
3
  export declare const shouldDisabledLiveDemo: (api: IApi) => boolean;
4
+ /**
5
+ * pick babel plugins which should be applied to code-block demos from `extraBabelPlugins`
6
+ * @param extraBabelPlugins `extraBabelPlugins` config of umi
7
+ * @param cwd project root, used to resolve plugin package
8
+ * @returns resolved plugin items, always JSON-serializable (loader options of utoopack require it)
9
+ */
10
+ export declare function getCodeBlockBabelPlugins(extraBabelPlugins: unknown, cwd: string): PluginItem[];
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  // src/features/compile/utils.ts
20
20
  var utils_exports = {};
21
21
  __export(utils_exports, {
22
+ getCodeBlockBabelPlugins: () => getCodeBlockBabelPlugins,
22
23
  shouldDisabledLiveDemo: () => shouldDisabledLiveDemo
23
24
  });
24
25
  module.exports = __toCommonJS(utils_exports);
@@ -36,7 +37,49 @@ var shouldDisabledLiveDemo = (api) => {
36
37
  }
37
38
  return disableFlag;
38
39
  };
40
+ var IMPORT_SENSITIVE_BABEL_PLUGINS = {
41
+ "@emotion": "@emotion/babel-plugin",
42
+ "@emotion/babel-plugin": "@emotion/babel-plugin"
43
+ };
44
+ var warnedMissingPlugins = /* @__PURE__ */ new Set();
45
+ function getImportSensitivePluginTarget(name) {
46
+ if (name in IMPORT_SENSITIVE_BABEL_PLUGINS) {
47
+ return IMPORT_SENSITIVE_BABEL_PLUGINS[name];
48
+ }
49
+ const normalized = name.replace(/\\/g, "/");
50
+ const isPluginPath = Object.values(IMPORT_SENSITIVE_BABEL_PLUGINS).some(
51
+ (pkg) => normalized.endsWith(`/${pkg}`) || normalized.includes(`/${pkg}/`)
52
+ );
53
+ return isPluginPath ? name : void 0;
54
+ }
55
+ function getCodeBlockBabelPlugins(extraBabelPlugins, cwd) {
56
+ if (!(0, import_lodash.isArray)(extraBabelPlugins))
57
+ return [];
58
+ return extraBabelPlugins.reduce((ret, item) => {
59
+ const [name, options] = (0, import_lodash.isArray)(item) ? item : [item];
60
+ if (typeof name !== "string")
61
+ return ret;
62
+ const target = getImportSensitivePluginTarget(name);
63
+ if (!target)
64
+ return ret;
65
+ let pluginPath;
66
+ try {
67
+ pluginPath = require.resolve(target, { paths: [cwd] });
68
+ } catch {
69
+ if (!warnedMissingPlugins.has(target)) {
70
+ warnedMissingPlugins.add(target);
71
+ import_utils.logger.warn(
72
+ `\`${target}\` cannot be resolved, it will be skipped for code-block demos in markdown, install it if you need the transform result (e.g. auto label of emotion) for those demos.`
73
+ );
74
+ }
75
+ return ret;
76
+ }
77
+ ret.push(options === void 0 ? pluginPath : [pluginPath, options]);
78
+ return ret;
79
+ }, []);
80
+ }
39
81
  // Annotate the CommonJS export names for ESM import in node:
40
82
  0 && (module.exports = {
83
+ getCodeBlockBabelPlugins,
41
84
  shouldDisabledLiveDemo
42
85
  });
@@ -219,6 +219,10 @@ var getUtoopackRules = (api, config = api.config) => {
219
219
  locales: config.locales || [],
220
220
  pkg: api.pkg,
221
221
  disableLiveDemo,
222
+ codeBlockBabelPlugins: (0, import_utils2.getCodeBlockBabelPlugins)(
223
+ config.extraBabelPlugins,
224
+ api.cwd
225
+ ),
222
226
  [UTOOPACK_LOADER_CTX_KEY]: loaderContextPath
223
227
  });
224
228
  const externalDemoLoader = {
@@ -1,6 +1,7 @@
1
1
  import type { IParsedBlockAsset } from '../../../assetParsers/block';
2
2
  import type { ILocalesConfig, IRouteMeta } from '@/client/theme-api/types';
3
3
  import type { IApi, IDumiConfig, IDumiTechStack } from '../../../types';
4
+ import type { PluginItem } from '@umijs/bundler-utils/compiled/@babel/core';
4
5
  import { type ResolveOptions } from 'enhanced-resolve';
5
6
  import type { IRoute } from 'umi';
6
7
  import type { Data } from 'vfile';
@@ -59,6 +60,11 @@ export interface IMdTransformerOptions {
59
60
  routes: Record<string, IRoute>;
60
61
  locales: ILocalesConfig;
61
62
  pkg: IApi['pkg'];
63
+ /**
64
+ * babel plugins which should be applied to code-block demos before wrapping,
65
+ * must be serializable, see `getCodeBlockBabelPlugins`
66
+ */
67
+ codeBlockBabelPlugins?: PluginItem[];
62
68
  }
63
69
  export interface IMdTransformerResult {
64
70
  content: string;
@@ -115,7 +115,8 @@ var transformer_default = async (raw, opts) => {
115
115
  fileLocale,
116
116
  useUtoopackDemoHMR: opts.useUtoopackDemoHMR,
117
117
  resolve: opts.resolve,
118
- resolver
118
+ resolver,
119
+ codeBlockBabelPlugins: opts.codeBlockBabelPlugins
119
120
  }).use(import_rehypeSlug.default).use(import_rehypeLink.default, {
120
121
  fileAbsPath: opts.fileAbsPath,
121
122
  routes: opts.routes
@@ -6,7 +6,7 @@ export declare const DEMO_PROP_VALUE_KEY = "$demo-prop-value-key";
6
6
  export declare const DUMI_DEMO_TAG = "DumiDemo";
7
7
  export declare const DUMI_DEMO_GRID_TAG = "DumiDemoGrid";
8
8
  export declare const SKIP_DEMO_PARSE = "pure";
9
- type IRehypeDemoOptions = Pick<IMdTransformerOptions, 'techStacks' | 'cwd' | 'fileAbsPath' | 'resolve'> & {
9
+ type IRehypeDemoOptions = Pick<IMdTransformerOptions, 'techStacks' | 'cwd' | 'fileAbsPath' | 'resolve' | 'codeBlockBabelPlugins'> & {
10
10
  resolver: typeof sync;
11
11
  fileLocaleLessPath: string;
12
12
  fileLocale?: string;
@@ -298,7 +298,8 @@ function rehypeDemo(opts) {
298
298
  );
299
299
  component = techStack.transformCode(codeValue, {
300
300
  type: "code-block",
301
- fileAbsPath: parseOpts.fileAbsPath
301
+ fileAbsPath: parseOpts.fileAbsPath,
302
+ babelPlugins: opts.codeBlockBabelPlugins
302
303
  });
303
304
  }
304
305
  const propDemo = { id: parseOpts.id };
@@ -51,7 +51,8 @@ var ReactTechStack = class {
51
51
  parserConfig: {
52
52
  syntax: isTSX ? "typescript" : "ecmascript",
53
53
  [isTSX ? "tsx" : "jsx"]: true
54
- }
54
+ },
55
+ babelPlugins: opts.babelPlugins
55
56
  });
56
57
  return `React.memo(React.lazy(${code}))`;
57
58
  }
@@ -1,4 +1,5 @@
1
1
  import type { ParserConfig } from '@swc/core';
2
+ import type { PluginItem } from '@umijs/bundler-utils/compiled/@babel/core';
2
3
  import { IDumiTechStack } from '../types';
3
4
  export { IDumiTechStack, IDumiTechStackOnBlockLoadArgs, IDumiTechStackOnBlockLoadResult, IDumiTechStackRuntimeOpts, } from '../types';
4
5
  /**
@@ -10,7 +11,21 @@ export declare function extractScript(htmlLike: string): string;
10
11
  export interface IWrapDemoWithFnOptions {
11
12
  filename: string;
12
13
  parserConfig: ParserConfig;
14
+ /**
15
+ * babel plugins which will be applied to the original code before wrapping.
16
+ * The wrapping rewrites static imports into dynamic imports, so plugins which
17
+ * rely on import declarations (e.g. @emotion/babel-plugin) must run before it,
18
+ * otherwise they never see the original `import` statements.
19
+ */
20
+ babelPlugins?: PluginItem[];
13
21
  }
22
+ /**
23
+ * Apply babel plugins to the demo code while keeping its syntax as-is
24
+ * (no preset, only parse & print), so the result can still be handled by swc.
25
+ */
26
+ export declare function applyBabelPlugins(code: string, opts: Pick<IWrapDemoWithFnOptions, 'filename' | 'parserConfig'> & {
27
+ plugins: PluginItem[];
28
+ }): string;
14
29
  /**
15
30
  * Use swc to convert es module into async function.
16
31
  * More transform process detail, refer to:
@@ -33,6 +33,7 @@ __export(utils_exports, {
33
33
  IDumiTechStackOnBlockLoadArgs: () => import_types.IDumiTechStackOnBlockLoadArgs,
34
34
  IDumiTechStackOnBlockLoadResult: () => import_types.IDumiTechStackOnBlockLoadResult,
35
35
  IDumiTechStackRuntimeOpts: () => import_types.IDumiTechStackRuntimeOpts,
36
+ applyBabelPlugins: () => applyBabelPlugins,
36
37
  defineTechStack: () => defineTechStack,
37
38
  extractScript: () => extractScript,
38
39
  wrapDemoWithFn: () => wrapDemoWithFn
@@ -50,9 +51,40 @@ function extractScript(htmlLike) {
50
51
  }
51
52
  return scripts;
52
53
  }
54
+ function applyBabelPlugins(code, opts) {
55
+ const { filename, parserConfig, plugins } = opts;
56
+ if (!plugins.length)
57
+ return code;
58
+ const babel = require("@umijs/bundler-utils/compiled/babel/core");
59
+ const parserPlugins = [];
60
+ if (parserConfig.syntax === "typescript") {
61
+ parserPlugins.push("typescript");
62
+ if (parserConfig.tsx)
63
+ parserPlugins.push("jsx");
64
+ } else if (parserConfig.jsx) {
65
+ parserPlugins.push("jsx");
66
+ }
67
+ const result = babel.transformSync(code, {
68
+ filename,
69
+ babelrc: false,
70
+ configFile: false,
71
+ browserslistConfigFile: false,
72
+ sourceType: "module",
73
+ sourceMaps: false,
74
+ compact: false,
75
+ parserOpts: { plugins: parserPlugins },
76
+ plugins
77
+ });
78
+ return (result == null ? void 0 : result.code) ?? code;
79
+ }
53
80
  function wrapDemoWithFn(code, opts) {
54
- const { filename, parserConfig } = opts;
55
- const result = (0, import_core.transformSync)(code, {
81
+ const { filename, parserConfig, babelPlugins } = opts;
82
+ const source = (babelPlugins == null ? void 0 : babelPlugins.length) ? applyBabelPlugins(code, {
83
+ filename,
84
+ parserConfig,
85
+ plugins: babelPlugins
86
+ }) : code;
87
+ const result = (0, import_core.transformSync)(source, {
56
88
  filename,
57
89
  jsc: {
58
90
  parser: parserConfig,
@@ -84,6 +116,7 @@ function defineTechStack(options) {
84
116
  IDumiTechStackOnBlockLoadArgs,
85
117
  IDumiTechStackOnBlockLoadResult,
86
118
  IDumiTechStackRuntimeOpts,
119
+ applyBabelPlugins,
87
120
  defineTechStack,
88
121
  extractScript,
89
122
  wrapDemoWithFn
package/dist/types.d.ts CHANGED
@@ -4,6 +4,7 @@ import type { IDumiDemoProps } from '@/client/theme-api/DumiDemo';
4
4
  import type { ILocalesConfig, IThemeConfig } from '@/client/theme-api/types';
5
5
  import type { IContentTab } from './features/tabs';
6
6
  import type { IThemeLoadResult } from './features/theme/loader';
7
+ import type { PluginItem } from '@umijs/bundler-utils/compiled/@babel/core';
7
8
  import { OnLoadArgs, OnLoadResult } from '@umijs/bundler-utils/compiled/esbuild';
8
9
  import type { IModify } from '@umijs/core';
9
10
  import type { AssetsPackage, ExampleBlockAsset } from 'dumi-assets-types';
@@ -98,6 +99,12 @@ export declare abstract class IDumiTechStack {
98
99
  abstract transformCode(raw: string, opts: {
99
100
  type: 'external' | 'code-block';
100
101
  fileAbsPath: string;
102
+ /**
103
+ * babel plugins which should be applied to the original source of code-block demo,
104
+ * before it is wrapped into an async function (which rewrites static imports
105
+ * into dynamic imports), e.g. @emotion/babel-plugin
106
+ */
107
+ babelPlugins?: PluginItem[];
101
108
  }): string;
102
109
  /**
103
110
  * generator for return asset metadata
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dumi",
3
- "version": "2.4.49",
3
+ "version": "2.4.50",
4
4
  "description": "📖 Documentation Generator of React Component",
5
5
  "keywords": [
6
6
  "generator",
@@ -135,6 +135,7 @@
135
135
  "devDependencies": {
136
136
  "@commitlint/cli": "^17.6.7",
137
137
  "@commitlint/config-conventional": "^17.6.7",
138
+ "@emotion/babel-plugin": "^11.13.5",
138
139
  "@types/github-slugger": "^1.3.0",
139
140
  "@types/highlight-words-core": "^1.2.1",
140
141
  "@types/hosted-git-info": "^3.0.2",