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

MDX,文档生花。

概览

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

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

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

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

本节所有代码可在仓库 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 警告提示

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

## 代码演示

### 基本用法


  这是一条警告提示


## API

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

执行脚本命令:

yarn start # or yarn dev

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

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

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

优化文档编写

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

那就抽离吧。

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

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

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

export default () => ;

components/alert/index.mdx

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

...


- 这是一条警告提示
+ 

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

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

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

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

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

优化代码展示

编写 组件

安装依赖:

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

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

最终效果如下:

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

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 = ({ code, title, desc, children }) => {
  const [isEditVisible, toggleEditVisible] = useToggle(false);

  return (
    
{children}
{title || '示例'}
{desc || '暂无描述'}
message.success('复制成功')}>
{renderEditor()}
); /* 代码展示区域 */ function renderEditor() { if (!isEditVisible) return null; return (
{}} highlight={code => highlight(code, languages.jsx)} padding={10} className="container__editor" style={{ fontFamily: '"Fira code", "Fira Mono", monospace', fontSize: 14, }} />
); } }; 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';

...

- 
-   
- 

+ 
+  
+ 

其他

.eslintignore

+ doc-comps
+ demo

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

更多详见 仓库

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

To be Continued…