25

React 组件库搭建指南-开发调试与文档编写

 4 years ago
source link: https://worldzhao.github.io/post/react-ui-library-tutorial-dev-and-doc/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

MDX,文档生花。

概览

上一篇文章中进行了项目的初始化,同时编写了一个 <Alert/> 组件,遗留了一个问题:

编写时完全无法进行预览调试

此处选择 docz 来辅助预览调试。

docz 基于 MDX (Markdown + JSX),可以在 Markdown 中引入 React 组件,使得一边编写文档,一边预览调试成为了可能。而且得益于 React 组件生态,我们可以像编写应用一般编写文档,不仅仅是枯燥的文字。 docz 也内置了一些组件,比如 <Playground>

本节所有代码可在仓库 chapter-2 分支中获取。

安装 docz 以及自定义配置

yarn add docz --dev

yarn add rimraf --dev # 清空目录的一个辅助库

增加 npm scriptspackage.json

"scripts": {
  "dev": "docz dev", // 启动本地开发环境
  "start": "npm run dev", // dev命令别名
  "build:doc": "rimraf doc-site && docz build", // 后续会配置打包出来的文件目录名为doc-site,故每次build前删除
  "preview:doc": "docz serve" // 预览文档站点
},

注意:本节所有操作都是针对站点应用。 打包 指代文档站点打包,而非组件库。

新建 doczrc.js 配置文件,并写入以下内容:

doczrc.js

export default {
  files: './components/**/*.{md,markdown,mdx}', // 识别的文件后缀
  dest: 'doc-site', // 打包出来的文件目录名
  title: 'happy-ui', // 站点标题
  typescript: true, // 组件源文件是通过typescript开发,需要打开此选项
};

由于使用了 less 作为样式预处理器,故需要安装 less 插件。

yarn add less gatsby-plugin-less --dev

新建 gatsby-config.js ,并写入以下内容:

gatsby-config.js

module.exports = {
  plugins: ['gatsby-theme-docz', 'gatsby-plugin-less'],
};

编写文档

新建 components/alert/index.mdx ,并写入以下内容:

---
name: Alert 警告提示
route: /Alert
menu: 组件
---

import { Playground } from 'docz';
import Alert from './alert'; // 引入组件
import './style'; // 引入组件样式

# Alert 警告提示

警告提示,展现需要关注的信息。

## 代码演示

### 基本用法

<Playground>
  <Alert kind="warning">这是一条警告提示</Alert>
</Playground>

## API

| 属性 | 说明     | 类型                                         | 默认值 |
| ---- | -------- | -------------------------------------------- | ------ |
| kind | 警告类型 | 'info'/'positive'/'negative'/'warning'非必填 | 'info' |

执行脚本命令:

yarn start # or yarn dev

可以在 localhost:3000 看到如下页面 :

3ERruu2.jpg!web

现在可以在 index.mdx 中愉快地进行文档编写和调试了!

倘若本文到了这里就结束(其实也可以结束了 (_^▽^_) ),那我只是官方文档的翻译复读机罢了,有兴趣的同学可以继续向下看。

优化文档编写

如果 代码演示 部分的 demo 较多(比如基本用法、高级用法以及各种用法等等),在组件复杂的情况下(毕竟 <Alert/> 着实太简单了),会导致文档很长难以维护,你到底是在写文档呢还是在写代码呢?

那就抽离吧。

components/alert/ 文件夹下新建 demo 文件夹,存放我们在编写文档时需要引用的 demo

components/alert/demo/1-demo-basic.tsx

import React from 'react';
import Alert from '../alert';
import '../style';

export default () => <Alert kind="warning"></Alert>;

components/alert/index.mdx

- import Alert from './alert'; // 引入组件
- import './style'; // 引入组件样式
+ import BasicDemo from './demo/1-demo-basic';

...

<Playground>
- <Alert kind="warning">这是一条警告提示</Alert>
+ <BasicDemo />
</Playground>

这样我们就将 demo 与文档进行了分隔。预览如下:

Erqu6za.jpg!web

等等,你下面显示的那个 <BasicDemo /> 有点撩人,这里应该是给用户爸爸们 copydemo 源码,你弄一个标签在这里,用户爸爸肯定不开心 :no_good:‍♀️。

然而 <Playground /> 组件暂时无法支持上述形式的展示:自定义下方展示的代码,而非 <Playground /> 内部的代码。相关讨论如下:

其实第一条 PR 已经解决了问题,但是被关闭了,无奈。

不过既然都能引入 React 组件了,在 MDX 的环境下自定义一个 Playground 组件又有何难呢,无非就是渲染组件(MDX 自带)和展示源码,简单开放的东西大家都是喜闻乐见的,就叫 HappyBox 吧。

优化代码展示

编写 <HappyBox /> 组件

安装依赖:

yarn add react-use antd react-simple-code-editor prismjs react-copy-to-clipboard raw-loader --dev

这些依赖都是服务于文档站点应用,和组件库自身毫无关联。

最终效果如下:

qEZry2q.jpg!web

根目录下新建 doc-comps 文件夹,存放文档中使用的一些工具组件,比如 <HappyBox />

doc-comps

├── happy-box
│   ├── index.less
│   └── index.tsx
└── index.ts

components/doc-comps/happy-box/index.tsx

import React from 'react';
import Editor from 'react-simple-code-editor';
import CopyToClipboard from 'react-copy-to-clipboard';
import useToggle from 'react-use/esm/useToggle';
import { Divider, Typography, Icon, Tooltip, message } from 'antd';
import { highlight, languages } from 'prismjs/components/prism-core';

import 'prismjs/components/prism-clike';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-markup';
import './index.less';

require('prismjs/components/prism-jsx');

const { Text } = Typography;
interface Props {
  code: string;
  title?: React.ReactNode;
  desc?: React.ReactNode;
}

export const HappyBox: React.FC<Props> = ({ code, title, desc, children }) => {
  const [isEditVisible, toggleEditVisible] = useToggle(false);

  return (
    <div className="code-box">
      <section className="code-box-demo"> {children}</section>
      <section className="code-box-meta">
        <Divider orientation="left">{title || '示例'}</Divider>
        <div className="code-box-description">
          <Text>{desc || '暂无描述'}</Text>
        </div>
        <Divider dashed></Divider>
        <div className="code-box-action">
          <Tooltip placement="top" title={'复制代码'}>
            <CopyToClipboard text={code} onCopy={() => message.success('复制成功')}>
              <Icon type="copy" />
            </CopyToClipboard>
          </Tooltip>
          <Tooltip placement="top" title={isEditVisible ? '收起代码' : '显示代码'}>
            <Icon type="code" onClick={toggleEditVisible} />
          </Tooltip>
        </div>
      </section>
      {renderEditor()}
    </div>
  );

  /* 代码展示区域 */
  function renderEditor() {
    if (!isEditVisible) return null;
    return (
      <div className="container_editor_area">
        <Editor
          readOnly
          value={code}
          onValueChange={() => {}}
          highlight={code => highlight(code, languages.jsx)}
          padding={10}
          className="container__editor"
          style={{
            fontFamily: '"Fira code", "Fira Mono", monospace',
            fontSize: 14,
          }}
        />
      </div>
    );
  }
};

export default HappyBox;

相关配置变更

alias

新建 gatsby-node.js ,写入以下内容以开启 alias

const path = require('path');

exports.onCreateWebpackConfig = args => {
  args.actions.setWebpackConfig({
    resolve: {
      modules: [path.resolve(__dirname, '../src'), 'node_modules'],
      alias: {
        'happy-ui/lib': path.resolve(__dirname, '../components/'),
      },
    },
  });
};

antd 按需引入,安装依赖,并配置 gatsby-config.js

yarn add babel-plugin-import gatsby-plugin-import --dev

gatsby-config.js

module.exports = {
  plugins: [
    'gatsby-theme-docz',
    'gatsby-plugin-less',
    {
      resolve: 'gatsby-plugin-import',
      options: {
        libraryName: 'antd',
        style: 'css',
      },
    },
  ],
};

tsconfig.json 忽略 demo 以及 doc-comps ,避免组件库打包生成 types 时包含其中:

tsconfig.json

{
  "compilerOptions": {
    "rootDir": "components",
    "baseUrl": "components",
    "target": "esnext",
    "module": "commonjs",
    "jsx": "react",
    "declaration": true,
    "outDir": "types",
    "strict": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  },
+ "exclude": ["components/**/demo", "doc-comps"]
}

改造相关文件

components/alert/demo/1-demo-basic.tsx

- import Alert from '../alert';
+ import Alert from 'happy-ui/lib/alert';

- import '../style';
+ import 'happy-ui/lib/alert/style';

components/alert/index.mdx

- import { Playground } from 'docz';
+ import { HappyBox } from '../../doc-comps';

+ import BasicDemoCode from '!raw-loader!./demo/1-demo-basic.tsx';

...

- <Playground>
-   <BasicDemo />
- </Playground>

+ <HappyBox code={BasicDemoCode} title="基本用法" desc="使用kind控制Alert类型">
+  <BasicDemo />
+ </HappyBox>

其他

.eslintignore

+ doc-comps
+ demo

yarn start 卡住时尝试删除根目录 .docz 文件夹,而后重新执行命令。

更多详见 仓库

开发调试与文档编写结束,欢迎指点交流。

To be Continued...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK