Developing Module documentation

This chapter describes how to quickly build a static documentation site for a module project.

Before we start

Why we need to build a documentation site for a module

  1. a documentation site can help us to better organize the structure of the documentation.
  2. the documentation site has better presentation, such as the ability to execute functions in the page, render components.
  3. to make better use of AI search capabilities.

Preliminary preparation

  1. Enable the documentation feature via micro-generator.
  2. Read Introduction to Rspress.

After finishing the preparation work, we will build a documentation site for the module project based on Rspress.

Basic site structure

The overall layout of the site consists of three parts: the navigation bar, the sidebar and the body part, which also includes the TOC (Table of contents found at the beginning of a book or document).

The Rspress uses File System Routing, on which the module documentation is based, to automate the generation of the sidebar. For example, if you have the following file structure:

docs
├── foo
│ └── bar.md
│ └── index.md
└── foo.md
└── index.md

Then the routing path for foo/bar.md will be /foo/bar, the routing path for foo.md will be /foo, and the routing path for index.md will be /.

The specific mapping rules are as follows:

file-path routing-path
index.md /
/foo.md /foo
/foo/index.md /foo/
/foo/bar.md /foo/bar

The sidebars corresponding in turn to the above file paths and routing paths are shown below:

Configure sidebar

As shown in the figure above, the module documentation has automatically generated sidebars for file system routing, where the text of each column of the sidebar is determined by the file's first level title or directory name. If you need to customize the sidebar, please use _meta.json or configure sidebar directly.

INFO

If your document directory structure complies with internationalization, for example:

docs
├── en
│   ├── button.mdx
│   ├── index.mdx
└── zh
    ├── button.mdx
    ├── index.mdx

You need to follow internationalization guide and configure langlocales, otherwise, the automatically generated sidebar of the module will not handle the zh and en directories.

Writing Documentation

Next, we can focus on writing the content of the document. In addition to the basic Markdown syntax, you may also need to understand the following advanced topics:

Component preview

Module documentation provides preview capabilities for component libraries. The contents in code blocks written in jsx and tsx will be parsed as React components.

Example

Here is a complete example using the component preview feature:

Assuming our project name is demo and we export a Button component.

  1. Add a new docs/Button.mdx file:
Button.mdx
# Button

## Basic Usage

Buttons come in four sizes: small, medium, large

```tsx
import React from 'react';
import { Button } from 'demo';

export default () => {
  return <Button size="large">Click Me</Button>;
};
```
  1. In the tsconfig.json, configure aliases and point the package name to the current project directory, make the way document developers and users use components consistent:
tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "demo": ["."]
    }
  }
}
  1. In the .gitignore, add doc_build/:
.gitignore
doc_build/

Congratulations, you have finished writing a component document, execute pnpm run dev to see the result, remember to build the component library first to make sure the component product exists.

Mobile Preview

Also, we support mobile preview mode, i.e. rendering mobile components using iframe, and set iframe position by iframePosition, support swipe preview and new page opening.

modern.config.ts
import { moduleTools, defineConfig } from '@modern-js/module-tools'.
import { modulePluginDoc } from '@modern-js/plugin-rspress'.

export default defineConfig({
  plugins: [
    moduleTools(),
    modulePluginDoc({
      /**
       * Select the preview method
       * @default internal
       */
      previewMode: 'iframe',
      /**
       * Select iframe position
       * @default 'follow'
       */
      iframePosition: 'fixed',
    }),
  ],
});
TIP

If you only want to change the way a particular jsx and tsx block is previewed, you can use a different modifier to identify it:

```jsx pure
// The content here will not be rendered
```

```jsx internal
// Used to render components in documentation
```

```jsx iframe
// Used to render components in iframe
```

Using external demos

If our demo is very complex, then it is recommended to write the demo separately and then use the code tag in the mdx:

<code src="/path/demo.tsx"></code>

This also supports setting the preview method for each individual code block, for example:

<code src="/path/demo.tsx" previewMode="iframe"></code>

Using built-in components

The plugin implements some built-in components internally so that you can develop module documentation more easily.

API

Display the API content of the module.

Parse file

Before we can use the API component, we first need to specify the files to parse:

modern.config.ts
import { moduleTools, defineConfig } from '@modern-js/module-tools';
import { modulePluginDoc } from '@modern-js/plugin-rspress';

export default defineConfig({
  plugins: [
    moduleTools(),
    modulePluginDoc({
      entries: {
        Button: './src/button.tsx',
      },
      apiParseTool: 'react-docgen-typescript',
    }),
  ],
});

Content generation

Next, we'll see what kind of markdown content is generated based on the parsed file.

Content can be generated with two different tools, react-docgen-typescript or documentation:

  • react-docgen-typescript is targeted at component library scenarios and will only parse props to generate tables.
export type ButtonProps = {
  /**
   * Whether to disable the button
   */
  disabled?: boolean;
  /* * Whether to disable the button */ disabled?
   * Type of Button
   * @default 'default'
   */
  size?: 'mini' | 'small' | 'default' | 'large';
}.
export const Button = (props?: ButtonProps) => {};

The above is a standard writeup where ButtonProps will be extracted into the table and Button will be the title of the table. If you use the default export, the filename will be used as the form title.

Notice that export features declared elsewhere are not available.

const A = () => {};

export { A }; // wrong
export default A; // wrong
export const B = () => {}; // right
export default () => {}; // right

The generated content is as follows:

### ButtonTest

| property |          description          |                   type                   |   default   |
| :------: | :---------------------------: | :--------------------------------------: | :---------: |
| disabled | Whether to disable the button |                `boolean`                 |     `-`     |
|   size   |        Type of Button         | `"mini" \|"small" \|"default" \|"large"` | `'default'` |
WARNING

If React types are used in Props, you need to add the types in tsconfig.json, otherwise the types will not be resolved under the React namespace.

{
  "compilerOptions": {
    "types": ["react"]
  }
}

The best way is that you import the type directly:

import { FC } from 'react';
  • documentation is used in tool library scenarios to parse JSDoc annotations.
/**
 * Greet function that returns a greeting message.
 * @param {string} name - The name of the person to greet.
 * @param {string} [greeting='Hello'] - The greeting to use.
 * @returns {string} The greeting message.
 */
function greet(name: string, greeting = 'Hello') {
  return `${greeting}, ${name}! `;
}

The above is a greet function with a JSDoc annotation. The generated content is as follows:

<! -- Generated by documentation.js. Update this documentation by updating the source code. -->

## greet

Greet function that returns a greeting message.

### Parameters

- `name` **[string][1]** The name of the person to greet.
- `greeting` **[string][1]** The greeting to use. (optional, default `'Hello'`)

Returns **[string][1]** The greeting message.

[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String

Using the component

Next, you can use our built-in API components in your documentation by passing the key value into the moduleName property。

Button.mdx
# Button

## API

<API moduleName="Button" />

Overview

Displays a list of modules that can be placed on the front page to display all modules.

The Overview component has only one list property, which receives an array of objects, and the following properties of the objects

property description type default
icon icon React.ReactNode
text text(required) string
link link(required) string
arrow whether to show arrows boolean false

Plugin options

apiParseTool

API parse tool.

  • Type:'react-docgen-typescript' | 'documentation'
  • Default: 'react-docgen-typescript'

doc

Config.

entries

Module names and relative paths for automatically generated documents.

  • Type:Entries | ToolEntries
  • Default: {}
type Entries = Record<string, string>;
type ToolEntries = {
  documentation: Entries;
  'react-docgen-typescript': Entries;
};

It also supports the use of different parsing tools for different files:

modern.config.ts
import { moduleTools, defineConfig } from '@modern-js/module-tools';
import { modulePluginDoc } from '@modern-js/plugin-rspress';

export default defineConfig({
  plugins: [
    moduleTools(),
    modulePluginDoc({
      entries: {
        documentation: {
          Add: './src/utils/add.ts',
        },
        'react-docgen-typescript': {
          Button: './src/components/button.tsx',
        },
      },
    }),
  ],
});

iframePosition

  • 类型:'follow' | 'fixed'
  • 默认值: 'follow'

When the value is follow, each code block will have an iframe showing its rendered view. When fixed, the iframe will be fixed to the right side of the page, showing the view of all the code blocks on the current page.

parseToolOptions

API parse tool options.

  • Type:ParseToolOptions
  • Default: {}
type ParseToolOptions = {
  // https://github.com/styleguidist/react-docgen-typescript#options
  'react-docgen-typescript'?: ParserOptions;
  // https://github.com/documentationjs/documentation/blob/master/docs/NODE_API.md#parameters-1
  documentation?: DocumentationArgs;
};

previewMode

  • Type:'iframe' | 'internal'
  • Default: 'internal'

In case of internal, the component will be rendered directly in the page, otherwise it will be loaded through an iframe.

deprecated: languages

WARNING

Starting from version 2.44.0, please refer to the Internationalization section to implement multiple languages.

deprecated: useModuleSidebar

WARNING

Starting from version 2.44.0, a sniffing mechanism has been implemented internally, so please directly use _meta.json or directly configure sidebar to implement a custom sidebar.

Scripts

  • modern dev: Start dev server for doc site.
  • modern build --platform: Build doc site in production, by default output directories is doc_build.

Advanced guide

The above has covered the basics of developing module documentation, but this is not enough for developing a complete documentation station. Check out the Rspress for an in-depth look at our documentation framework. You can modify the documentation framework configuration via the doc configuration.

modern.config.ts
import { moduleTools, defineConfig } from '@modern-js/module-tools'.
import { modulePluginDoc } from '@modern-js/plugin-rspress'.

export default defineConfig({
  plugins: [
    moduleTools(),
    modulePluginDoc({
      doc: {
        // Customize the documentation site configuration
      }
    }),
  ],
});