umijs / dumi

📖 Static Site Generator for component library development
https://d.umijs.org
MIT License
3.56k stars 1.18k forks source link

按照文档使用 API 组件报错 #732

Closed QiShaoXuan closed 3 years ago

QiShaoXuan commented 3 years ago

Versions

Steps to reproduce

新建一个文件夹下创建一个 index.tsx,内容复制文档

import React from 'react';

export interface IHelloProps {
  /**
   * 可以这样写属性描述
   * @description       也可以显式加上描述名
   * @description.zh-CN 还支持不同的 locale 后缀来实现多语言描述
   * @default           支持定义默认值
   */
  className?: string; // 支持识别 TypeScript 可选类型为非必选属性
}

const Hello: React.FC<IHelloProps> = () => <>Hello World!</>;

export default Hello;

然后在同文件夹下创建一个 index.md,内容如下

---
group:
  path: /atom-components
---

<API src="./index.tsx"></API>

终端报错:

 in ./components/Tabs/index.md

Module build failed (from ./node_modules/@umijs/preset-dumi/lib/loader/index.js):
TypeError: (tag.text || "").trim is not a function
    at /Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:750:44
    at Array.forEach (<anonymous>)
    at Parser.getFullJsDocComment (/Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:749:10)
    at Parser.findDocComment (/Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:707:26)
    at /Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:654:33
    at Array.forEach (<anonymous>)
    at Parser.getPropsInfo (/Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:645:23)
    at Parser.getComponentInfo (/Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:363:26)
    at /Users/qishaoxuan/work/pango-ui/node_modules/react-docgen-typescript/src/parser.ts:1351:28
    at Array.forEach (<anonymous>)

 @ ./.umi/core/routes.ts 112:19-87
 @ ./.umi/umi.ts
 @ multi ./.umi/umi.ts

如果把注释改变成如下:

import React from 'react';

export interface IHelloProps {
  /**
   * 注释改成没有修饰符
   */
  className?: string; // 支持识别 TypeScript 可选类型为非必选属性
}

const Hello: React.FC<IHelloProps> = () => <>Hello World!</>;

export default Hello;

则能正常编译,正常展示

我只是想让 API 能显示 default 值,这个应该怎么做?

QiShaoXuan commented 3 years ago

使用 npx @umijs/create-dumi-lib 生成的文件按照文档也会报错,但不是终端报错

TypeError: Cannot convert undefined or null to object
getApiData
./node_modules/@umijs/preset-dumi/lib/theme/hooks/useApiData.js:55
  52 |  * @param isDefaultLocale default locale flag
  53 |  */
  54 | function getApiData(identifier, locale, isDefaultLocale) {
> 55 |   return Object.entries(_apis().default[identifier]).reduce((expts, [expt, rows]) => {
  56 |     expts[expt] = rows.map(props => {
  57 |       // copy original data
  58 |       const result = Object.assign({}, props);
View compiled
_default
./node_modules/@umijs/preset-dumi/lib/theme/hooks/useApiData.js:91
  88 | 
  89 | const isDefaultLocale = !locales.length || locales[0].name === locale;
  90 | 
> 91 | const _useState = (0, _react().useState)(getApiData(identifier, locale, isDefaultLocale)),
     | ^  92 |       _useState2 = _slicedToArray(_useState, 2),
  93 |       data = _useState2[0],
  94 |       setData = _useState2[1];
View compiled
(anonymous function)
./node_modules/dumi-theme-default/es/builtins/API.js:22
  19 | export default (function (_ref) {
  20 |   var identifier = _ref.identifier,
  21 |       expt = _ref.export;
> 22 |   var data = useApiData(identifier);
  23 | 
  24 |   var _useContext = useContext(context),
  25 |       locale = _useContext.locale;
View compiled
renderWithHooks
./node_modules/react-dom/cjs/react-dom.development.js:14803
  14800 |   }
  14801 | }
  14802 | 
> 14803 | var children = Component(props, secondArg); // Check if there was a render phase update
        | ^  14804 | 
  14805 | if (workInProgress.expirationTime === renderExpirationTime) {
  14806 |   // Keep rendering in a loop for as long as render phase updates continue to
View compiled
mountIndeterminateComponent
./node_modules/react-dom/cjs/react-dom.development.js:17482
  17479 | 
  17480 |   setIsRendering(true);
  17481 |   ReactCurrentOwner$1.current = workInProgress;
> 17482 |   value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime);
        | ^  17483 |   setIsRendering(false);
  17484 | } // React DevTools reads this flag.
  17485 | 
View compiled
beginWork
./node_modules/react-dom/cjs/react-dom.development.js:18596
  18593 | switch (workInProgress.tag) {
  18594 |   case IndeterminateComponent:
  18595 |     {
> 18596 |       return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderExpirationTime);
        | ^  18597 |     }
  18598 | 
  18599 |   case LazyComponent:
View compiled
HTMLUnknownElement.callCallback
./node_modules/react-dom/cjs/react-dom.development.js:188
  185 |     window.event = windowEvent;
  186 |   }
  187 | 
> 188 |   func.apply(context, funcArgs);
      | ^  189 |   didError = false;
  190 | } // Create a global error event handler. We use this to capture the value
  191 | // that was thrown. It's possible that this error handler will fire more
View compiled
invokeGuardedCallbackDev
./node_modules/react-dom/cjs/react-dom.development.js:237
  234 | // errors, it will trigger our global error handler.
  235 | 
  236 | evt.initEvent(evtType, false, false);
> 237 | fakeNode.dispatchEvent(evt);
      | ^  238 | 
  239 | if (windowEventDescriptor) {
  240 |   Object.defineProperty(window, 'event', windowEventDescriptor);
View compiled
invokeGuardedCallback
./node_modules/react-dom/cjs/react-dom.development.js:292
  289 | function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) {
  290 |   hasError = false;
  291 |   caughtError = null;
> 292 |   invokeGuardedCallbackImpl$1.apply(reporter, arguments);
  293 | }
  294 | /**
  295 |  * Same as invokeGuardedCallback, but instead of returning an error, it stores
View compiled
beginWork$1
./node_modules/react-dom/cjs/react-dom.development.js:23203
  23200 | } // Run beginWork again.
  23201 | 
  23202 | 
> 23203 | invokeGuardedCallback(null, beginWork, null, current, unitOfWork, expirationTime);
        | ^  23204 | 
  23205 | if (hasCaughtError()) {
  23206 |   var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.
View compiled
performUnitOfWork
./node_modules/react-dom/cjs/react-dom.development.js:22154
  22151 | 
  22152 | if ( (unitOfWork.mode & ProfileMode) !== NoMode) {
  22153 |   startProfilerTimer(unitOfWork);
> 22154 |   next = beginWork$1(current, unitOfWork, renderExpirationTime$1);
        | ^  22155 |   stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
  22156 | } else {
  22157 |   next = beginWork$1(current, unitOfWork, renderExpirationTime$1);
View compiled
workLoopSync
./node_modules/react-dom/cjs/react-dom.development.js:22130
  22127 | function workLoopSync() {
  22128 |   // Already timed out, so perform work without checking if we need to yield.
  22129 |   while (workInProgress !== null) {
> 22130 |     workInProgress = performUnitOfWork(workInProgress);
  22131 |   }
  22132 | }
  22133 | /** @noinline */
View compiled
performSyncWorkOnRoot
./node_modules/react-dom/cjs/react-dom.development.js:21756
  21753 | 
  21754 | do {
  21755 |   try {
> 21756 |     workLoopSync();
        | ^  21757 |     break;
  21758 |   } catch (thrownValue) {
  21759 |     handleError(root, thrownValue);
View compiled
scheduleUpdateOnFiber
./node_modules/react-dom/cjs/react-dom.development.js:21188
  21185 |   // root inside of batchedUpdates should be synchronous, but layout updates
  21186 |   // should be deferred until the end of the batch.
  21187 | 
> 21188 |   performSyncWorkOnRoot(root);
        | ^  21189 | } else {
  21190 |   ensureRootIsScheduled(root);
  21191 |   schedulePendingInteractions(root, expirationTime);
View compiled
updateContainer
./node_modules/react-dom/cjs/react-dom.development.js:24373
  24370 |   }
  24371 | 
  24372 |   enqueueUpdate(current$1, update);
> 24373 |   scheduleWork(current$1, expirationTime);
  24374 |   return expirationTime;
  24375 | }
  24376 | function getPublicRootInstance(container) {
View compiled
(anonymous function)
./node_modules/react-dom/cjs/react-dom.development.js:24758
  24755 | 
  24756 | 
  24757 |   unbatchedUpdates(function () {
> 24758 |     updateContainer(children, fiberRoot, parentComponent, callback);
        | ^  24759 |   });
  24760 | } else {
  24761 |   fiberRoot = root._internalRoot;
View compiled
unbatchedUpdates
./node_modules/react-dom/cjs/react-dom.development.js:21903
  21900 | executionContext |= LegacyUnbatchedContext;
  21901 | 
  21902 | try {
> 21903 |   return fn(a);
        | ^  21904 | } finally {
  21905 |   executionContext = prevExecutionContext;
  21906 | 
View compiled
legacyRenderSubtreeIntoContainer
./node_modules/react-dom/cjs/react-dom.development.js:24757
  24754 |   } // Initial mount should not be batched.
  24755 | 
  24756 | 
> 24757 |   unbatchedUpdates(function () {
        | ^  24758 |     updateContainer(children, fiberRoot, parentComponent, callback);
  24759 |   });
  24760 | } else {
View compiled
render
./node_modules/react-dom/cjs/react-dom.development.js:24840
  24837 |     }
  24838 |   }
  24839 | 
> 24840 |   return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
  24841 | }
  24842 | function unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) {
  24843 |   if (!isValidContainer(containerNode)) {
View compiled
renderClient
./node_modules/@umijs/renderer-react/dist/index.js:687
  684 |       reactDom.hydrate(rootContainer, rootElement, callback);
  685 |     }
  686 |   } else {
> 687 |     reactDom.render(rootContainer, rootElement, callback);
      | ^  688 |   }
  689 | } else {
  690 |   return rootContainer;
View compiled
initialValue
./src/.umi/umi.ts:30
  27 |         defaultTitle: `dumi`,
  28 |       },
  29 |     });
> 30 |     return renderClient(opts);
  31 |   },
  32 |   args,
  33 | });
View compiled
(anonymous function)
./node_modules/@umijs/runtime/dist/index.esm.js:434
Module../src/.umi/umi.ts
./src/.umi/umi.ts:36
  33 | });
  34 | 
  35 | const clientRender = getClientRender();
> 36 | export default clientRender();
  37 | 
  38 | 
  39 |     window.g_umi = {
View compiled
__webpack_require__
./webpack/bootstrap:789
  786 | };
  787 | 
  788 | // Execute the module function
> 789 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
      | ^  790 | 
  791 | // Flag the module as loaded
  792 | module.l = true;
View compiled
fn
./webpack/bootstrap:100
   97 |         );
   98 |         hotCurrentParents = [];
   99 |     }
> 100 |     return __webpack_require__(request);
      | ^  101 | };
  102 | var ObjectFactory = function ObjectFactory(name) {
  103 |     return {
View compiled
0
http://localhost:8000/umi.js:76498:18
__webpack_require__
./webpack/bootstrap:789
  786 | };
  787 | 
  788 | // Execute the module function
> 789 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
      | ^  790 | 
  791 | // Flag the module as loaded
  792 | module.l = true;
View compiled
(anonymous function)
./webpack/bootstrap:856
  853 | 
  854 | 
  855 | // Load entry module and return exports
> 856 | return hotCreateRequire(0)(__webpack_require__.s = 0);
      | ^  857 | 
View compiled
(anonymous function)
http://localhost:8000/umi.js:860:10
PeachScript commented 3 years ago

dumi 还没升级 react-docgen-typescript 大版本,不支持 TypeScript 4.3+,可以先把 typescript 锁到 4.2.3

QiShaoXuan commented 3 years ago

dumi 还没升级 react-docgen-typescript 大版本,不支持 TypeScript 4.3+,可以先把 typescript 锁到 4.2.3

感谢

hulk4fe commented 3 years ago

dumi 还没升级 react-docgen-typescript 大版本,不支持 TypeScript 4.3+,可以先把 typescript 锁到 4.2.3

希望官方能尽快支持最新版的ts

PeachScript commented 3 years ago

@QiShaoXuan @me-hotel v1.1.22 已修复该问题,可以解锁 TypeScript 版本了

react-docgen-typescript@2.0.0 还不能 work,所以 dumi 侧先基于 1.x 修改发临时包修复了,如果各位关注到 react-docgen-typescript 有新进展,也可以到这里同步一下

xoptimal commented 3 years ago

我想请教下, 如果一个tsx文件, 有多个 interface or type , 但是只导出了 组件上声明的 props 对应的 interface, 请问如何导出所有的 interface/type API @PeachScript

eg.

interface A { person: PersonType }
interface PersonType { name: string, age: number }

exprot default function Foo(props: A) { ... }

只输出 A API,

按照可配置的 > <API exports='["default", "Other"]'></API> 生成会出现 TypeError: Cannot read property 'map' of undefined .

PeachScript commented 3 years ago

目前只支持读取 React Component 的 Props,其他 interface 会忽略

xoptimal commented 3 years ago

@PeachScript exports 不是为了支持导出其他的 interface 的吗, 那怎么才能实现呢!除了手动方式, 另外 API title 的 hideTitle 的如何声明的,我这边尝试了没有作用

PeachScript commented 3 years ago

exports 是用于导出多个 React Component 的情况;title 目前不支持隐藏,在 #699 跟进