dumi 2.4.51 → 2.4.52

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.
@@ -11,6 +11,8 @@ export interface IParsedBlockAsset {
11
11
  * }
12
12
  */
13
13
  resolveMap: Record<string, string>;
14
+ /** Resolved ordinary styles requested exclusively by side-effect imports. */
15
+ sideEffectStyles?: string[];
14
16
  frontmatter: ReturnType<typeof parseCodeFrontmatter>['frontmatter'];
15
17
  }
16
18
  interface IParseBlockAssetOptions {
@@ -22,6 +24,7 @@ interface IParseBlockAssetOptions {
22
24
  resolver: typeof sync;
23
25
  techStack: IDumiTechStack;
24
26
  cacheable?: boolean;
27
+ collectSideEffectStyles?: boolean;
25
28
  }
26
29
  declare function parseBlockAsset(opts: IParseBlockAssetOptions): Promise<IParsedBlockAsset>;
27
30
  export default parseBlockAsset;
@@ -33,6 +33,7 @@ __export(block_exports, {
33
33
  });
34
34
  module.exports = __toCommonJS(block_exports);
35
35
  var import_utils = require("../utils");
36
+ var import_core = require("@swc/core");
36
37
  var import_esbuild = require("@umijs/bundler-utils/compiled/esbuild");
37
38
  var import_assert = __toESM(require("assert"));
38
39
  var import_fs = __toESM(require("fs"));
@@ -42,9 +43,11 @@ var import_constants = require("../constants");
42
43
  var MAX_BLOCK_ASSET_CACHE_SIZE = 512;
43
44
  var blockAssetCache = /* @__PURE__ */ new Map();
44
45
  function cloneParsedBlockAsset(ret) {
46
+ var _a;
45
47
  return {
46
48
  asset: JSON.parse(JSON.stringify(ret.asset)),
47
49
  resolveMap: { ...ret.resolveMap },
50
+ sideEffectStyles: (_a = ret.sideEffectStyles) == null ? void 0 : _a.slice(),
48
51
  frontmatter: ret.frontmatter ? JSON.parse(JSON.stringify(ret.frontmatter)) : ret.frontmatter
49
52
  };
50
53
  }
@@ -72,7 +75,8 @@ function getParseCacheKey(opts) {
72
75
  runtimeOpts: opts.techStack.runtimeOpts,
73
76
  hasOnBlockLoad: Boolean(opts.techStack.onBlockLoad),
74
77
  hasGenerateMetadata: Boolean(opts.techStack.generateMetadata),
75
- hasGenerateSources: Boolean(opts.techStack.generateSources)
78
+ hasGenerateSources: Boolean(opts.techStack.generateSources),
79
+ collectSideEffectStyles: Boolean(opts.collectSideEffectStyles)
76
80
  });
77
81
  }
78
82
  function getParseDeps(ret, entryFile) {
@@ -98,6 +102,31 @@ function setCachedBlockAsset(cacheKey, ret, deps) {
98
102
  result: cloneParsedBlockAsset(ret)
99
103
  });
100
104
  }
105
+ function getSideEffectImports(code, ext) {
106
+ const imports = /* @__PURE__ */ Object.create(null);
107
+ try {
108
+ const program = (0, import_core.parseSync)(
109
+ code,
110
+ ext === ".ts" || ext === ".tsx" ? { syntax: "typescript", tsx: ext === ".tsx", decorators: true } : { syntax: "ecmascript", jsx: ext === ".jsx", decorators: true }
111
+ );
112
+ for (const item of program.body) {
113
+ if (item.type === "ImportDeclaration") {
114
+ if (item.typeOnly || item.specifiers.length > 0 && item.specifiers.every(
115
+ (specifier) => specifier.type === "ImportSpecifier" && specifier.isTypeOnly
116
+ )) {
117
+ continue;
118
+ }
119
+ const source = item.source.value;
120
+ imports[source] = imports[source] !== false && item.specifiers.length === 0;
121
+ } else if ((item.type === "ExportNamedDeclaration" || item.type === "ExportAllDeclaration") && item.source && !(item.type === "ExportNamedDeclaration" && item.typeOnly)) {
122
+ imports[item.source.value] = false;
123
+ }
124
+ }
125
+ } catch {
126
+ return {};
127
+ }
128
+ return imports;
129
+ }
101
130
  async function parseBlockAsset(opts) {
102
131
  const cacheKey = opts.cacheable ? getParseCacheKey(opts) : "";
103
132
  const cached = cacheKey ? getCachedBlockAsset(cacheKey) : void 0;
@@ -114,8 +143,10 @@ async function parseBlockAsset(opts) {
114
143
  const result = {
115
144
  asset,
116
145
  resolveMap: {},
146
+ sideEffectStyles: [],
117
147
  frontmatter: null
118
148
  };
149
+ const styleImports = /* @__PURE__ */ new Map();
119
150
  const deferrer = (0, import_esbuild.build)({
120
151
  // do not emit file
121
152
  write: false,
@@ -132,12 +163,20 @@ async function parseBlockAsset(opts) {
132
163
  name: "plugin-dumi-collect-deps",
133
164
  setup: (builder) => {
134
165
  builder.onResolve({ filter: /.*/ }, (args) => {
135
- if (args.kind !== "entry-point" && !args.path.startsWith(".")) {
136
- const resolved = opts.resolver(args.resolveDir, args.path);
137
- (0, import_assert.default)(
138
- resolved,
139
- `Can't resolve ${args.path} from ${args.resolveDir}`
166
+ var _a, _b;
167
+ const resolved = args.kind === "entry-point" ? import_path.default.join(args.resolveDir, args.path) : opts.resolver(args.resolveDir, args.path);
168
+ (0, import_assert.default)(
169
+ resolved,
170
+ `Can't resolve ${args.path} from ${args.resolveDir}`
171
+ );
172
+ if (opts.collectSideEffectStyles && opts.techStack.runtimeOpts && args.kind !== "entry-point" && !/[?#]/.test(args.path) && /\.(css|less|sass|scss|styl)$/i.test(resolved) && !/\.module\.[^.]+$/i.test(resolved)) {
173
+ const key = args.path.startsWith(".") ? (0, import_plugin_utils.winPath)(resolved) : args.path;
174
+ styleImports.set(
175
+ key,
176
+ styleImports.get(key) !== false && args.kind === "import-statement" && ((_b = (_a = args.pluginData) == null ? void 0 : _a.sideEffectImports) == null ? void 0 : _b[args.path]) === true
140
177
  );
178
+ }
179
+ if (args.kind !== "entry-point" && !args.path.startsWith(".")) {
141
180
  const pkgJsonPath = import_plugin_utils.pkgUp.pkgUpSync({
142
181
  cwd: resolved
143
182
  });
@@ -153,7 +192,7 @@ async function parseBlockAsset(opts) {
153
192
  return { path: args.path, external: true };
154
193
  }
155
194
  return {
156
- path: args.kind !== "entry-point" ? opts.resolver(args.resolveDir, args.path) : import_path.default.join(args.resolveDir, args.path),
195
+ path: resolved,
157
196
  pluginData: {
158
197
  kind: args.kind,
159
198
  resolveDir: args.resolveDir,
@@ -219,7 +258,10 @@ async function parseBlockAsset(opts) {
219
258
  return {
220
259
  // only continue to load for module files
221
260
  contents: isModule ? contents ?? file.value : "",
222
- loader: isModule ? ext.slice(1) : "text"
261
+ loader: isModule ? ext.slice(1) : "text",
262
+ pluginData: {
263
+ sideEffectImports: opts.collectSideEffectStyles && isModule ? getSideEffectImports(contents ?? file.value, ext) : {}
264
+ }
223
265
  };
224
266
  }
225
267
  });
@@ -233,6 +275,9 @@ async function parseBlockAsset(opts) {
233
275
  } catch {
234
276
  hasError = true;
235
277
  }
278
+ if (!hasError) {
279
+ result.sideEffectStyles = Array.from(styleImports).filter(([, sideEffectOnly]) => sideEffectOnly).map(([key]) => key);
280
+ }
236
281
  if (!hasError && cacheKey) {
237
282
  setCachedBlockAsset(
238
283
  cacheKey,
@@ -142,7 +142,8 @@ var compile_default = (api) => {
142
142
  api.config.extraRemarkPlugins,
143
143
  api.config.extraRehypePlugins,
144
144
  ((_b = api.service.configManager) == null ? void 0 : _b.files) ?? [],
145
- demoAssetsFile
145
+ demoAssetsFile,
146
+ api.config.alias
146
147
  )
147
148
  });
148
149
  }
@@ -5,5 +5,5 @@ export declare const UTOOPACK_DEMO_ASSETS_FILENAME = "dumi-utoopack-demo-assets.
5
5
  export declare function buildLoaderContextContent(techStacks: IDumiTechStack[], builtins?: Record<string, {
6
6
  specifier: string;
7
7
  source: string;
8
- }>, routes?: Record<string, unknown>, extraRemarkPlugins?: IApi['config']['extraRemarkPlugins'], extraRehypePlugins?: IApi['config']['extraRehypePlugins'], sourceFiles?: string[], demoAssetsFile?: string): string;
8
+ }>, routes?: Record<string, unknown>, extraRemarkPlugins?: IApi['config']['extraRemarkPlugins'], extraRehypePlugins?: IApi['config']['extraRehypePlugins'], sourceFiles?: string[], demoAssetsFile?: string, alias?: IApi['config']['alias']): string;
9
9
  export declare const getUtoopackRules: (api: IApi, config?: IApi['config']) => Record<string, unknown>;
@@ -171,7 +171,7 @@ function toPluginRefs(plugins = [], sourceFiles = []) {
171
171
  return toPluginTargetRef(plugin, sourceFiles);
172
172
  }).join(", ")}]`;
173
173
  }
174
- function buildLoaderContextContent(techStacks, builtins = {}, routes = {}, extraRemarkPlugins = [], extraRehypePlugins = [], sourceFiles = [], demoAssetsFile) {
174
+ function buildLoaderContextContent(techStacks, builtins = {}, routes = {}, extraRemarkPlugins = [], extraRehypePlugins = [], sourceFiles = [], demoAssetsFile, alias) {
175
175
  const refs = toTechStackRefs(techStacks);
176
176
  return `'use strict';
177
177
  try {
@@ -186,6 +186,7 @@ try {
186
186
  exports.techStacks = [${refs.join(", ")}];
187
187
  exports.builtins = ${JSON.stringify(builtins)};
188
188
  exports.routes = ${JSON.stringify(routes)};
189
+ exports.alias = ${JSON.stringify(alias)};
189
190
  exports.demoAssetsFile = ${JSON.stringify(demoAssetsFile)};
190
191
  exports.extraRemarkPlugins = ${toPluginRefs(
191
192
  extraRemarkPlugins,
@@ -46,6 +46,7 @@ var import_path = __toESM(require("path"));
46
46
  var import_plugin_utils = require("umi/plugin-utils");
47
47
  var import_transformer = __toESM(require("./transformer"));
48
48
  var import_rehypeText = require("./transformer/rehypeText");
49
+ var MD_LOADER_CACHE_VERSION = 1;
49
50
  function isMalformedCacheError(err) {
50
51
  return err instanceof SyntaxError || err instanceof Error && /Unexpected end of JSON input|Unterminated string in JSON/.test(
51
52
  err.message
@@ -153,6 +154,7 @@ function emitDemo(opts, ret) {
153
154
  const shareDepsMap = {};
154
155
  const demoDepsMap = {};
155
156
  const relativeDepsMap = {};
157
+ const sideEffectDepsMap = /* @__PURE__ */ new Map();
156
158
  demos == null ? void 0 : demos.forEach((demo) => {
157
159
  var _a, _b;
158
160
  if ("resolveMap" in demo && "asset" in demo) {
@@ -160,10 +162,15 @@ function emitDemo(opts, ret) {
160
162
  demoDepsMap[_a = demo.id] ?? (demoDepsMap[_a] = {});
161
163
  relativeDepsMap[_b = demo.id] ?? (relativeDepsMap[_b] = {});
162
164
  Object.keys(demo.resolveMap).forEach((key, index) => {
165
+ var _a2;
163
166
  const specifier = `${demo.id.replace(/[^\w\d]/g, "_")}_deps_${index}`;
164
167
  if (key !== entryFileName) {
165
168
  const isRelative = isRelativePath(key);
166
169
  const normalizedKey = isRelative ? (0, import_plugin_utils.winPath)(demo.resolveMap[key]) : key;
170
+ sideEffectDepsMap.set(
171
+ normalizedKey,
172
+ sideEffectDepsMap.get(normalizedKey) !== false && ((_a2 = demo.sideEffectStyles) == null ? void 0 : _a2.includes(normalizedKey)) === true
173
+ );
167
174
  if (!shareDepsMap[normalizedKey]) {
168
175
  demoDepsMap[demo.id][normalizedKey] = specifier;
169
176
  shareDepsMap[normalizedKey] = specifier;
@@ -182,7 +189,12 @@ function emitDemo(opts, ret) {
182
189
  Object.entries(deps).map(([key, specifier]) => {
183
190
  const existingIndex = acc.findIndex((obj) => obj.key === key);
184
191
  if (existingIndex === -1) {
185
- return { key, specifier };
192
+ return {
193
+ key,
194
+ specifier,
195
+ // Preserve webpack's namespace behavior, including custom style exports.
196
+ sideEffectOnly: Boolean(opts[import_utoopackLoaders.UTOOPACK_LOADER_CTX_KEY]) && sideEffectDepsMap.get(key) === true
197
+ };
186
198
  }
187
199
  return void 0;
188
200
  }).filter((item) => item !== void 0)
@@ -193,7 +205,13 @@ function emitDemo(opts, ret) {
193
205
  `import React from 'react';
194
206
  import '${(0, import_plugin_utils.winPath)(this.resourcePath)}?watch=parent';
195
207
  {{#dedupedDemosDeps}}
208
+ {{#sideEffectOnly}}
209
+ import '{{{key}}}';
210
+ const {{{specifier}}} = {};
211
+ {{/sideEffectOnly}}
212
+ {{^sideEffectOnly}}
196
213
  import * as {{{specifier}}} from '{{{key}}}';
214
+ {{/sideEffectOnly}}
197
215
  {{/dedupedDemosDeps}}
198
216
  export const demos = {
199
217
  {{#demos}}
@@ -496,6 +514,9 @@ function mdLoader(content) {
496
514
  if (!((_a = opts.techStacks) == null ? void 0 : _a.length)) {
497
515
  opts.techStacks = ctx.techStacks;
498
516
  }
517
+ if (ctx.alias !== void 0) {
518
+ opts = { ...opts, alias: ctx.alias };
519
+ }
499
520
  if (ctx.builtins && !Object.keys(opts.builtins ?? {}).length) {
500
521
  opts.builtins = ctx.builtins;
501
522
  }
@@ -520,6 +541,7 @@ function mdLoader(content) {
520
541
  }
521
542
  const cache = (0, import_utils.getCache)("md-loader");
522
543
  const baseCacheKey = [
544
+ MD_LOADER_CACHE_VERSION,
523
545
  this.resourcePath,
524
546
  (0, import_utils.getContentHash)(content),
525
547
  useUtoopackDemoHMR,
@@ -542,7 +564,8 @@ function mdLoader(content) {
542
564
  deferrer[cacheKey] = (0, import_transformer.default)(content, {
543
565
  ...import_plugin_utils.lodash.omit(opts, ["mode", "builtins", "onResolveDemos"]),
544
566
  fileAbsPath: (0, import_plugin_utils.winPath)(this.resourcePath),
545
- useUtoopackDemoHMR
567
+ useUtoopackDemoHMR,
568
+ collectSideEffectStyles: Boolean(loaderContextPath)
546
569
  });
547
570
  deferrer[cacheKey].then((ret) => {
548
571
  depsMapping[this.resourcePath] = ret.meta.embeds.concat(
@@ -24,6 +24,7 @@ declare module 'vfile' {
24
24
  component: string;
25
25
  asset: IParsedBlockAsset['asset'];
26
26
  resolveMap: IParsedBlockAsset['resolveMap'];
27
+ sideEffectStyles?: IParsedBlockAsset['sideEffectStyles'];
27
28
  renderOpts: {
28
29
  type?: string;
29
30
  rendererPath?: string;
@@ -51,6 +52,7 @@ export interface IMdTransformerOptions {
51
52
  cwd: string;
52
53
  fileAbsPath: string;
53
54
  useUtoopackDemoHMR?: boolean;
55
+ collectSideEffectStyles?: boolean;
54
56
  alias: ResolveOptions['alias'];
55
57
  parentAbsPath?: string;
56
58
  techStacks: IDumiTechStack[];
@@ -114,6 +114,7 @@ var transformer_default = async (raw, opts) => {
114
114
  fileLocaleLessPath,
115
115
  fileLocale,
116
116
  useUtoopackDemoHMR: opts.useUtoopackDemoHMR,
117
+ collectSideEffectStyles: opts.collectSideEffectStyles,
117
118
  resolve: opts.resolve,
118
119
  resolver,
119
120
  codeBlockBabelPlugins: opts.codeBlockBabelPlugins
@@ -11,6 +11,7 @@ type IRehypeDemoOptions = Pick<IMdTransformerOptions, 'techStacks' | 'cwd' | 'fi
11
11
  fileLocaleLessPath: string;
12
12
  fileLocale?: string;
13
13
  useUtoopackDemoHMR?: boolean;
14
+ collectSideEffectStyles?: boolean;
14
15
  };
15
16
  export default function rehypeDemo(opts: IRehypeDemoOptions): Transformer<Root>;
16
17
  export {};
@@ -310,9 +310,15 @@ function rehypeDemo(opts) {
310
310
  deferrers.push(
311
311
  (0, import_block.default)({
312
312
  ...parseOpts,
313
- cacheable: opts.useUtoopackDemoHMR
313
+ cacheable: opts.useUtoopackDemoHMR,
314
+ collectSideEffectStyles: opts.collectSideEffectStyles
314
315
  }).then(
315
- async ({ asset, resolveMap, frontmatter }) => {
316
+ async ({
317
+ asset,
318
+ resolveMap,
319
+ frontmatter,
320
+ sideEffectStyles
321
+ }) => {
316
322
  var _a2, _b2, _c2;
317
323
  if (demoIds.indexOf(parseOpts.id) !== demoIds.lastIndexOf(parseOpts.id)) {
318
324
  const startLine = (_a2 = node.position) == null ? void 0 : _a2.start.line;
@@ -396,6 +402,8 @@ function rehypeDemo(opts) {
396
402
  resolveMap,
397
403
  techStackOpts
398
404
  ) : resolveMap,
405
+ // Custom source mappings may replace the original dependencies.
406
+ sideEffectStyles: techStack.generateSources ? void 0 : sideEffectStyles,
399
407
  renderOpts: {
400
408
  rendererPath: runtimeOpts == null ? void 0 : runtimeOpts.rendererPath,
401
409
  compilePath: runtimeOpts == null ? void 0 : runtimeOpts.compilePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dumi",
3
- "version": "2.4.51",
3
+ "version": "2.4.52",
4
4
  "description": "📖 Documentation Generator of React Component",
5
5
  "keywords": [
6
6
  "generator",