TypeDoc 插件扩展 #

插件系统概述 #

TypeDoc 拥有强大的插件系统,允许开发者扩展和定制文档生成功能。

text
┌─────────────────────────────────────────────────────────────┐
│                    TypeDoc 插件架构                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                  TypeDoc Core                        │   │
│  └───────────────────────┬─────────────────────────────┘   │
│                          │                                  │
│                          ▼                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              Plugin Manager                          │   │
│  └───────────────────────┬─────────────────────────────┘   │
│                          │                                  │
│         ┌────────────────┼────────────────┐                │
│         │                │                │                │
│         ▼                ▼                ▼                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │ 输出插件    │  │ 主题插件    │  │ 解析插件    │        │
│  │ Markdown    │  │ Hierarchy   │  │ External    │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

常用插件介绍 #

typedoc-plugin-markdown #

将文档输出为 Markdown 格式:

bash
npm install --save-dev typedoc-plugin-markdown

配置:

json
{
  "plugin": ["typedoc-plugin-markdown"],
  "theme": "markdown",
  "out": "docs/markdown"
}

高级配置:

json
{
  "plugin": ["typedoc-plugin-markdown"],
  "theme": "markdown",
  "out": "docs/markdown",
  "entryDocument": "README.md",
  "hideInPageTOC": true,
  "hideBreadcrumbs": true,
  "hidePageHeader": false,
  "indexFormat": "table",
  "memberFormat": "list",
  "textContentMappings": {
    "title.indexPage": "API Reference",
    "header.readme": "Getting Started"
  }
}

typedoc-theme-hierarchy #

层级结构主题:

bash
npm install --save-dev typedoc-theme-hierarchy

配置:

json
{
  "plugin": ["typedoc-theme-hierarchy"],
  "theme": "hierarchy"
}

typedoc-plugin-merge-modules #

合并模块输出:

bash
npm install --save-dev typedoc-plugin-merge-modules

配置:

json
{
  "plugin": ["typedoc-plugin-merge-modules"],
  "mergeModulesMergeMode": "module"
}

typedoc-plugin-external-module-name #

自定义模块名称:

bash
npm install --save-dev typedoc-plugin-external-module-name

配置:

json
{
  "plugin": ["typedoc-plugin-external-module-name"],
  "externalModulemap": ".*\\/src\\/([^\\/]+)\\/.*"
}

typedoc-plugin-pages #

添加自定义页面:

bash
npm install --save-dev typedoc-plugin-pages

配置:

json
{
  "plugin": ["typedoc-plugin-pages"],
  "pages": [
    {
      "title": "Getting Started",
      "source": "./docs/getting-started.md"
    },
    {
      "title": "Guide",
      "source": "./docs/guide.md",
      "children": [
        {
          "title": "Installation",
          "source": "./docs/installation.md"
        },
        {
          "title": "Configuration",
          "source": "./docs/configuration.md"
        }
      ]
    }
  ]
}

typedoc-plugin-coverage #

生成文档覆盖率报告:

bash
npm install --save-dev typedoc-plugin-coverage

配置:

json
{
  "plugin": ["typedoc-plugin-coverage"],
  "coverageOutput": "coverage.json"
}

typedoc-plugin-rename-defaults #

重命名默认导出:

bash
npm install --save-dev typedoc-plugin-rename-defaults

配置:

json
{
  "plugin": ["typedoc-plugin-rename-defaults"]
}

typedoc-plugin-reference-excluder #

排除特定引用:

bash
npm install --save-dev typedoc-plugin-reference-excluder

配置:

json
{
  "plugin": ["typedoc-plugin-reference-excluder"],
  "excludeReferences": ["React", "Vue"]
}

插件配置方法 #

命令行配置 #

bash
npx typedoc --plugin typedoc-plugin-markdown --theme markdown

配置文件 #

json
// typedoc.json
{
  "plugin": [
    "typedoc-plugin-markdown",
    "typedoc-plugin-coverage"
  ],
  "theme": "markdown"
}

多插件配置 #

json
{
  "plugin": [
    "typedoc-plugin-markdown",
    "typedoc-plugin-pages",
    "typedoc-plugin-coverage"
  ],
  "theme": "markdown",
  "pages": [
    {
      "title": "Guide",
      "source": "./docs/guide.md"
    }
  ],
  "coverageOutput": "coverage.json"
}

禁用插件 #

json
{
  "plugin": []
}

开发自定义插件 #

插件项目结构 #

text
my-typedoc-plugin/
├── src/
│   ├── index.ts           # 插件入口
│   ├── plugin.ts          # 插件逻辑
│   └── types.ts           # 类型定义
├── package.json
├── tsconfig.json
└── README.md

基本插件模板 #

typescript
// src/index.ts
import { Application } from 'typedoc';
import { MyPlugin } from './plugin';

export function load(app: Application) {
  new MyPlugin(app);
}

export { MyPlugin };

插件类实现 #

typescript
// src/plugin.ts
import {
  Application,
  Context,
  Converter,
  Reflection,
  ReflectionKind,
  DeclarationReflection
} from 'typedoc';

export class MyPlugin {
  private app: Application;

  constructor(app: Application) {
    this.app = app;
    this.initialize();
  }

  private initialize() {
    // 监听转换事件
    this.app.converter.on(
      Converter.EVENT_CREATE_DECLARATION,
      this.onDeclaration.bind(this)
    );

    // 监听解析完成事件
    this.app.converter.on(
      Converter.EVENT_RESOLVE_END,
      this.onResolveEnd.bind(this)
    );
  }

  private onDeclaration(context: Context, reflection: DeclarationReflection) {
    // 处理声明
    if (reflection.kind === ReflectionKind.Function) {
      this.processFunction(reflection);
    }
  }

  private onResolveEnd(context: Context) {
    // 解析完成后的处理
    console.log('Documentation resolved');
  }

  private processFunction(reflection: DeclarationReflection) {
    // 自定义处理逻辑
    reflection.comment?.addTag('custom', 'processed');
  }
}

添加配置选项 #

typescript
// src/plugin.ts
import {
  Application,
  BindOption,
  DeclarationOption,
  StringDeclarationOption
} from 'typedoc';

const myOption: StringDeclarationOption = {
  name: 'myCustomOption',
  type: DeclarationOption.String,
  defaultValue: 'default-value',
  help: 'A custom option for my plugin'
};

export class MyPlugin {
  @BindOption('myCustomOption')
  private myCustomOption!: string;

  constructor(app: Application) {
    // 注册选项
    app.options.addDeclaration(myOption);
  }

  private useOption() {
    console.log('Custom option value:', this.myCustomOption);
  }
}

修改反射对象 #

typescript
// src/plugin.ts
import {
  Application,
  Context,
  Converter,
  DeclarationReflection,
  ReflectionKind,
  ReflectionFlag
} from 'typedoc';

export class MyPlugin {
  constructor(app: Application) {
    app.converter.on(
      Converter.EVENT_CREATE_DECLARATION,
      this.modifyReflection.bind(this)
    );
  }

  private modifyReflection(
    context: Context,
    reflection: DeclarationReflection
  ) {
    // 添加自定义标志
    if (reflection.name.startsWith('_')) {
      reflection.setFlag(ReflectionFlag.Internal);
    }

    // 修改注释
    if (reflection.comment) {
      reflection.comment.summary.push({
        kind: 'text',
        text: '\n\n*Added by custom plugin*'
      });
    }

    // 添加自定义标签
    reflection.comment?.addTag('custom', 'value');
  }
}

添加自定义渲染 #

typescript
// src/plugin.ts
import {
  Application,
  Renderer,
  Theme,
  PageEvent,
  Reflection
} from 'typedoc';

export class MyPlugin {
  constructor(app: Application) {
    // 监听渲染事件
    app.renderer.on(
      PageEvent.BEGIN,
      this.onPageBegin.bind(this)
    );

    app.renderer.on(
      PageEvent.END,
      this.onPageEnd.bind(this)
    );
  }

  private onPageBegin(page: PageEvent<Reflection>) {
    // 页面渲染前
    console.log('Rendering page:', page.url);
  }

  private onPageEnd(page: PageEvent<Reflection>) {
    // 页面渲染后,修改 HTML
    if (page.contents) {
      page.contents = this.modifyHtml(page.contents);
    }
  }

  private modifyHtml(html: string): string {
    // 添加自定义脚本
    const customScript = `
      <script>
        console.log('Custom plugin loaded');
      </script>
    `;
    return html.replace('</body>', `${customScript}</body>`);
  }
}

完整插件示例 #

typescript
// src/index.ts
import {
  Application,
  Context,
  Converter,
  DeclarationReflection,
  ReflectionKind,
  ReflectionFlag,
  Renderer,
  PageEvent,
  Reflection,
  BindOption,
  DeclarationOption,
  BooleanDeclarationOption
} from 'typedoc';

// 定义选项
const addInternalTag: BooleanDeclarationOption = {
  name: 'markPrivateAsInternal',
  type: DeclarationOption.Boolean,
  defaultValue: false,
  help: 'Mark private members as @internal'
};

class AutoInternalPlugin {
  @BindOption('markPrivateAsInternal')
  private markPrivateAsInternal!: boolean;

  constructor(private app: Application) {
    // 注册选项
    this.app.options.addDeclaration(addInternalTag);

    // 注册事件监听
    this.registerEventListeners();
  }

  private registerEventListeners() {
    // 转换阶段
    this.app.converter.on(
      Converter.EVENT_CREATE_DECLARATION,
      this.onDeclaration.bind(this)
    );

    // 渲染阶段
    this.app.renderer.on(
      PageEvent.END,
      this.onPageEnd.bind(this)
    );
  }

  private onDeclaration(
    context: Context,
    reflection: DeclarationReflection
  ) {
    if (!this.markPrivateAsInternal) return;

    // 将私有成员标记为内部
    if (reflection.flags.hasFlag(ReflectionFlag.Private)) {
      reflection.setFlag(ReflectionFlag.Private, false);
      reflection.setFlag(ReflectionFlag.Internal, true);
      
      reflection.comment?.addTag('internal', 'Auto-marked from private');
    }
  }

  private onPageEnd(page: PageEvent<Reflection>) {
    if (!page.contents) return;

    // 添加生成时间戳
    const timestamp = `<!-- Generated at ${new Date().toISOString()} -->`;
    page.contents = page.contents.replace('</html>', `${timestamp}\n</html>`);
  }
}

export function load(app: Application) {
  new AutoInternalPlugin(app);
}

发布插件 #

json
// package.json
{
  "name": "typedoc-plugin-auto-internal",
  "version": "1.0.0",
  "description": "Automatically mark private members as internal",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "keywords": [
    "typedoc",
    "plugin",
    "typedoc-plugin"
  ],
  "peerDependencies": {
    "typedoc": ">=0.25.0"
  },
  "devDependencies": {
    "typedoc": "^0.25.0",
    "typescript": "^5.0.0"
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "tsc",
    "prepublishOnly": "npm run build"
  }
}
json
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

插件 API 参考 #

Application #

TypeDoc 应用实例:

typescript
import { Application } from 'typedoc';

// 访问配置
app.options.getValue('name');

// 访问转换器
app.converter;

// 访问渲染器
app.renderer;

Converter #

文档转换器:

typescript
import { Converter, Context } from 'typedoc';

// 事件
Converter.EVENT_BEGIN           // 转换开始
Converter.EVENT_END             // 转换结束
Converter.EVENT_CREATE_DECLARATION  // 创建声明
Converter.EVENT_CREATE_PARAMETER    // 创建参数
Converter.EVENT_CREATE_SIGNATURE    // 创建签名
Converter.EVENT_RESOLVE_BEGIN   // 解析开始
Converter.EVENT_RESOLVE_END     // 解析结束

Renderer #

文档渲染器:

typescript
import { Renderer, PageEvent } from 'typedoc';

// 事件
Renderer.EVENT_BEGIN            // 渲染开始
Renderer.EVENT_END              // 渲染结束
PageEvent.BEGIN                 // 页面开始
PageEvent.END                   // 页面结束

Reflection #

反射对象类型:

typescript
import {
  Reflection,
  ReflectionKind,
  ReflectionFlag,
  DeclarationReflection,
  SignatureReflection,
  ParameterReflection
} from 'typedoc';

// 类型判断
if (reflection.kind === ReflectionKind.Class) {
  // 处理类
}

// 标志操作
reflection.setFlag(ReflectionFlag.Internal, true);
reflection.hasFlag(ReflectionFlag.Private);

// 注释操作
reflection.comment?.addTag('custom', 'value');

插件开发最佳实践 #

1. 遵循命名规范 #

text
typedoc-plugin-{功能名称}
typedoc-theme-{主题名称}

2. 声明 peerDependencies #

json
{
  "peerDependencies": {
    "typedoc": ">=0.25.0"
  }
}

3. 导出 load 函数 #

typescript
export function load(app: Application) {
  // 插件初始化逻辑
}

4. 提供类型定义 #

typescript
// src/types.ts
export interface MyPluginOptions {
  enabled: boolean;
  customValue: string;
}

export type MyPluginCallback = (reflection: Reflection) => void;

5. 错误处理 #

typescript
export class MyPlugin {
  private handleError(error: Error, context?: string) {
    this.app.logger.error(
      `[MyPlugin] ${context ? context + ': ' : ''}${error.message}`
    );
  }

  private safeProcess(reflection: Reflection) {
    try {
      this.processReflection(reflection);
    } catch (error) {
      this.handleError(error as Error, `Processing ${reflection.name}`);
    }
  }
}

下一步 #

现在你已经掌握了 TypeDoc 插件的使用和开发方法,接下来学习 高级主题,了解 CI/CD 集成、性能优化等高级技巧!

最后更新:2026-03-29