close
  • 中文
  • 代码块

    Rspress 默认使用 Shiki 提供语法高亮,高亮计算都在编译期完成,这意味着运行时会有更高的性能。

    在使用多种语言代码块的时候,会在编译时自动获取对应语言,也不会增大运行时包体,支持的编程语言可参考 Shiki 支持的语言列表

    基本使用

    你可以使用 ``` 语法来创建代码块。例如:

    ```js
    console.log('Hello World');
    ```

    它将被渲染为:

    console.log('Hello World');

    代码块标题

    你可以使用 title="..." 属性为代码块添加标题。

    ```jsx title="src/components/HelloCodeBlockTitle.tsx"
    const HelloCodeBlockTitle = props => {
      return <h1>Hello CodeBlock Title</h1>;
    };
    ```

    它将被渲染为:

    src/components/HelloCodeBlockTitle.tsx
    const HelloCodeBlockTitle = props => {
      return <h1>Hello CodeBlock Title</h1>;
    };

    文件代码块

    你可以使用 file="./path/to/file" 属性并不书写任何代码块内容,来引用外部文件中的文本。

    相对路径

    使用以 ./../ 开头的相对路径来引用相对于当前 MDX 文件的文件:

    foo.mdx
    _tsx-component.tsx
    ```tsx file="./_tsx-component.tsx"
    
    ```

    它将被渲染为:

    import { useState } from 'react';
    
    export default () => {
      const [count, setCount] = useState(0);
      return (
        <p>
          这是来自 tsx 的组件{' '}
          <button onClick={() => setCount(count => count + 1)}>{count}</button>
        </p>
      );
    };
    

    使用 / 前缀的绝对路径

    使用 / 前缀来引用相对于 docs 目录的绝对路径文件。当你需要从文档的不同位置引用共享的代码文件时,这非常有用:

    ```tsx file="/components/Button.tsx"
    
    ```

    例如,如果你的 docs 目录是 /project/docs,那么 /components/Button.tsx 将解析为 /project/docs/components/Button.tsx

    使用 <root>/ 前缀的绝对路径

    使用 <root>/ 前缀来引用相对于项目根目录的绝对路径文件。当你需要从文档的不同位置引用共享的代码文件时,这非常有用:

    ```tsx file="<root>/src/components/Button.tsx"
    
    ```

    例如,如果你的项目根目录是 /project,那么 <root>/src/components/Button.tsx 将解析为 /project/src/components/Button.tsx

    Tip

    在使用外部文件代码块时,经常配合 路由约定 一起使用。将文件命名为 _ 开头。

    Notation 行高亮

    你可以使用 Shiki transformers 中的 transformerNotationHighlight 配合 // [!code highlight] 注释来高亮代码行。

    代码
    rspress.config.ts
    ```ts
    console.log('Highlighted'); // [!code highlight]
    console.log('Not highlighted');
    // [!code highlight:2]
    console.log('Highlighted');
    console.log('Highlighted');
    ```

    它将被渲染为:

    highlight.ts
    console.log('Highlighted'); 
    console.log('Not highlighted');
    console.log('Highlighted');
    console.log('Highlighted');

    Meta 行高亮

    Warning

    使用 meta 信息行高亮,需注意格式化工具可能会导致行号改变。可维护性上更推荐使用 Notation 行高亮

    你可以使用 @rspress/core/shiki-transformers 中的 transformerCompatibleMetaHighlight 配合 meta 信息注释来高亮代码行。

    代码
    rspress.config.ts
    ```ts {1,3-4}
    console.log('Highlighted');
    console.log('Not highlighted');
    console.log('Highlighted');
    console.log('Highlighted');
    ```

    它将被渲染为:

    console.log('Highlighted');
    console.log('Not highlighted');
    console.log('Highlighted');
    console.log('Highlighted');

    显示代码行号

    你可以使用 lineNumbers meta 属性为单个代码块显示行号:

    ```ts lineNumbers
    function hello() {
      console.log('此代码块启用了行号');
    }
    ```

    它将被渲染为:

    function hello() {
      console.log('此代码块启用了行号');
    }

    你也可以通过在配置文件中设置 showLineNumbers 选项来全局启用行号:

    rspress.config.ts
    export default {
      // ...
      markdown: {
        showLineNumbers: true,
      },
    };

    当全局启用 showLineNumbers 时,所有代码块默认都会显示行号。你可以使用 lineNumbers=false 为特定代码块禁用行号:

    ```ts lineNumbers=false
    function hello() {
      console.log('此代码块禁用了行号');
    }
    ```

    代码换行

    你可以使用 wrapCode meta 属性为单个代码块启用代码换行:

    ```ts wrapCode
    const longLine = '这是一行很长的代码,当存在 wrapCode meta 属性时会自动换行显示';
    ```

    它将被渲染为:

    const longLine = '这是一行很长的代码,当存在 wrapCode meta 属性时会自动换行显示';

    你也可以通过在配置文件中设置 defaultWrapCode 选项来全局启用代码换行:

    rspress.config.ts
    export default {
      // ...
      markdown: {
        defaultWrapCode: true,
      },
    };

    当全局启用 defaultWrapCode 时,所有代码块默认都会换行显示长代码。你可以使用 wrapCode=false 为特定代码块禁用代码换行:

    ```ts wrapCode=false
    const longLine = '此代码块不会换行,即使全局启用了 defaultWrapCode';
    ```

    代码块高度

    你可以通过 heightfold meta 属性控制代码块的高度行为。共有三种情况:

    • fold:可折叠代码块,底部显示展开按钮。高度默认 300px。
    • height=X:固定高度,显示垂直滚动条。如果同时使用 fold,则以指定高度折叠而非滚动。
    • 无 meta:默认完全展开。可通过 markdown.defaultCodeOverflow 全局配置默认行为。

    折叠

    使用 fold 属性启用展开/收起功能,也可以通过 height 属性自定义收起高度(单位为像素,默认 300):

    ```tsx fold height="350"
    // 这里放较长的代码内容即可触发展开/收起
    ```

    它将被渲染为:

    fold-demo.tsx
    import { useState } from 'react';
    
    export default () => {
      const [count, setCount] = useState(0);
      return (
        <div>
          <div>Line 1</div>
          <div>Line 2</div>
          <div>Line 3</div>
          <div>Line 4</div>
          <div>Line 5</div>
          <div>Line 6</div>
          <div>Line 7</div>
          <div>Line 8</div>
          <div>Line 9</div>
          <div>Line 10</div>
          <div>Line 11</div>
          <div>Line 12</div>
          <div>Line 13</div>
          <div>Line 14</div>
          <div>Line 15</div>
          <div>Line 16</div>
          <div>Line 17</div>
          <div>Line 18</div>
          <div>Line 19</div>
          <div>Line 20</div>
          <div>{count}</div>
          <button onClick={() => setCount(c => c + 1)}>{count}</button>
        </div>
      );
    };
    Tip

    当代码块实际内容高度小于 height 时,展开/收起按钮不会显示。

    滚动

    单独使用 height 属性(不加 fold)来设置固定高度并显示垂直滚动条:

    ```tsx height="200"
    // 这里放较长的代码内容即可触发滚动
    ```

    它将被渲染为:

    scroll-demo.tsx
    const lines = Array.from({ length: 20 }, (_, index) => `Line ${index + 1}`);
    
    export default function ScrollDemo() {
      return (
        <div>
          {lines.map(line => (
            <div key={line}>{line}</div>
          ))}
        </div>
      );
    }

    组合使用 meta 属性

    你可以将多个 meta 属性组合使用:

    ```ts lineNumbers wrapCode title="example.ts"
    const longLine = '此代码块同时具有行号、代码换行和标题';
    ```

    它将被渲染为:

    example.ts
    const longLine = '此代码块同时具有行号、代码换行和标题';

    Diff 代码块

    ```diff
    function test() {
    - console.log('deleted');
    + console.log('added');
      console.log('unchanged');
    }
    ```

    它将被渲染为:

    function test() {
    - console.log('deleted');
    + console.log('added');
      console.log('unchanged');
    }

    Shiki transformers

    Rspress 在 V2 中,使用 Shiki 进行编译时的代码高亮,提供了灵活扩展的代码块能力。

    通过配置 markdown.shiki.transformers 添加自定义 shiki transformers 来实现更加丰富的代码块效果。

    除了上文中的 transformerNotationHighlight,Rspress 默认支持 @shikijs/transformers 中的以下 transformers。

    transformerNotationDiff

    语法
    rspress.config.ts
    ```ts
    console.log('deleted'); // [!code --]
    console.log('added'); // [!code ++]
    console.log('unchanged');
    ```

    它将被渲染为:

    console.log('deleted'); 
    console.log('added'); 
    console.log('unchanged');

    transformerNotationErrorLevel

    语法
    rspress.config.ts
    ```ts
    console.log('No errors or warnings');
    console.error('Error'); // [!code error]
    console.warn('Warning'); // [!code warning]
    ```

    它将被渲染为:

    console.log('No errors or warnings');
    console.error('Error'); 
    console.warn('Warning'); 

    transformerNotationFocus

    语法
    rspress.config.ts
    ```ts
    console.log('Not focused');
    console.log('Focused'); // [!code focus]
    console.log('Not focused');
    ```

    它将被渲染为:

    console.log('Not focused');
    console.log('Focused'); 
    console.log('Not focused');

    Twoslash

    TwoSlash 是一种用于 TypeScript 代码的标记格式,适合创建自包含的代码示例,并让 TypeScript 编译器自动补充类型信息和提示,广泛应用于 TypeScript 官网。

    Rspress 提供了 @rspress/plugin-twoslash 插件,它可以在 Rspress 中使用 Twoslash 功能。详见 @rspress/plugin-twoslash 文档

    const str: string = 1;
    Type 'number' is not assignable to type 'string'.

    运行时语法高亮

    当需要在运行时动态渲染代码块,比如在交互式文档中,或者需要远程拉取代码块内容。Rspress 提供了 CodeBlockRuntime 组件

    以下是一个示例:

    foo.mdx
    import { CodeBlockRuntime } from '@rspress/core/theme';
    import { transformerNotationHighlight } from '@shikijs/transformers';
    
    <CodeBlockRuntime
      lang="ts"
      title="highlight.ts"
      code={`console.log('Highlighted'); // [!code highlight]
    // [!code highlight:1]
    console.log('Highlighted');
    console.log('Not highlighted');`}
      shikiOptions={{
        transformers: [transformerNotationHighlight()],
      }}
    />
    highlight.ts
    console.log('Highlighted'); // [!code highlight]
    // [!code highlight:1]
    console.log('Highlighted');
    console.log('Not highlighted');
    Warning

    建议仅在必要条件下使用 CodeBlockRuntime,因为它会增加运行时的包体积,并且无法享受编译时高亮带来的性能优势。