添加 giscus 评论功能
安装依赖
- npm
- Yarn
- pnpm
npm install --save @giscus/react
yarn add @giscus/react
pnpm add @giscus/react
创建评论组件
import React from 'react'
import { useThemeConfig, useColorMode } from '@docusaurus/theme-common'
import Giscus, { GiscusProps } from '@giscus/react'
import { useLocation } from '@docusaurus/router';
const defaultConfig: Partial<GiscusProps> = {
id: 'comments',
mapping: 'specific',
reactionsEnabled: '1',
emitMetadata: '0',
inputPosition: 'top',
loading: 'lazy',
strict: '1', // 用根据路径标题自动生成的 sha1 值,精确匹配 github discussion,避免路径 重叠(比如父和子路径)时评论加载串了
lang: 'zh-CN',
}
export default function Comment(): JSX.Element {
const themeConfig = useThemeConfig()
// merge default config
const giscus = { ...defaultConfig, ...themeConfig.giscus }
if (!giscus.repo || !giscus.repoId || !giscus.categoryId) {
throw new Error(
'You must provide `repo`, `repoId`, and `categoryId` to `themeConfig.giscus`.',
)
}
const path = useLocation().pathname.replace(/^\/|\/$/g, '');
const firstSlashIndex = path.indexOf('/');
var subPath: string = ""
if (firstSlashIndex !== -1) {
subPath = path.substring(firstSlashIndex + 1)
} else {
subPath = "index"
}
giscus.term = subPath
giscus.theme =
useColorMode().colorMode === 'dark' ? 'transparent_dark' : 'light'
return (
<Giscus {...giscus} />
)
}
是否需要支持隐藏评论?
在让页面支持评论功能之前,先确定下,是否需要支持隐藏评论。
因为需要通过 swizzling 的方式修改页面将评论功能嵌 入进去。如果需要隐藏评论就需要通过 eject
的方式完全自定义页面以便拿到页面的 metadata 来判断是否要隐藏评论;而如果不需要隐藏评论,就只需要使用 wrap
的方式对页面进行跟轻量的修改。
两者都需要修改文档页面组件,有一定的侵入性,但 eject
方式相比 wrap
方式侵入性更大,在升级 docusaurus 的时候,前者更容易出现兼容性问题,如果出现不兼容就需要按照下文的方式重新 swizzle 并修改代码。
最佳实践是:如果不需要隐藏评论这种功能,就用 wrap
方式修改页面组件。
不支持隐藏的评论
本人就是使用的这种方式,因为没有隐藏评论的需求,也避免升级 docusaurus 时出现兼容性问题,下面介绍具体操作步骤。
文档页面启用评论
文档页面由 docusaurus 的 DocItem/Layout
组件渲染,下面是自定义方法。
- swizzle
DocItem
:
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic DocItem/Layout -- --wrap --typescript
yarn swizzle @docusaurus/theme-classic DocItem/Layout --wrap --typescript
pnpm run swizzle @docusaurus/theme-classic DocItem/Layout --wrap --typescript
- 修改以下自动生成的源码文件(高亮的行是增加的内容):
import React from 'react';
import Layout from '@theme-original/DocItem/Layout';
import type LayoutType from '@theme/DocItem/Layout';
import type { WrapperProps } from '@docusaurus/types';
import Comment from '@site/src/components/Comment';
type Props = WrapperProps<typeof LayoutType>;
export default function LayoutWrapper(props: Props): JSX.Element {
return (
<>
<Layout {...props} />
<Comment />
</>
);
}
文档目录页面启用评论
所谓文档目录页面就是自动生成的目录页面 (category
),没有对应的 markdown 文件,这种页面是由 docusaurus 的 DocCategoryGeneratedIndexPage
渲染的,下面是自定义方法。
- swizzle
DocCategoryGeneratedIndexPage
:
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic DocCategoryGeneratedIndexPage -- --wrap --typescript
yarn swizzle @docusaurus/theme-classic DocCategoryGeneratedIndexPage --wrap --typescript
pnpm run swizzle @docusaurus/theme-classic DocCategoryGeneratedIndexPage --wrap --typescript
- 修改以下自动生成的源码文件(高亮的行是增加的内容):
import React from 'react';
import DocCategoryGeneratedIndexPage from '@theme-original/DocCategoryGeneratedIndexPage';
import type DocCategoryGeneratedIndexPageType from '@theme/DocCategoryGeneratedIndexPage';
import type { WrapperProps } from '@docusaurus/types';
import Comment from '@site/src/components/Comment';
type Props = WrapperProps<typeof DocCategoryGeneratedIndexPageType>;
export default function DocCategoryGeneratedIndexPageWrapper(props: Props): JSX.Element {
return (
<>
<DocCategoryGeneratedIndexPage {...props} />
<Comment />
</>
);
}
支持隐藏的评论
如果有隐藏评论的需求,就需要对页面做更深度的自定义,使用 eject
方式将页面组件源码弹出到 theme
下,基于源码进行修改。
文档页面支持评论
- swizzle
DocItem
:
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic DocItem/Layout -- --eject --typescript
yarn swizzle @docusaurus/theme-classic DocItem/Layout --eject --typescript
pnpm run swizzle @docusaurus/theme-classic DocItem/Layout --eject --typescript
- 修改以下自动生成的源码文件(高亮的行是增加的内容):
import React from 'react';
import clsx from 'clsx';
import { useWindowSize } from '@docusaurus/theme-common';
import { useDoc } from '@docusaurus/theme-common/internal';
import DocItemPaginator from '@theme/DocItem/Paginator';
import DocVersionBanner from '@theme/DocVersionBanner';
import DocVersionBadge from '@theme/DocVersionBadge';
import DocItemFooter from '@theme/DocItem/Footer';
import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile';
import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop';
import DocItemContent from '@theme/DocItem/Content';
import DocBreadcrumbs from '@theme/DocBreadcrumbs';
import Unlisted from '@theme/Unlisted';
import type { Props } from '@theme/DocItem/Layout';
import styles from './styles.module.css';
import Comment from '../../../components/Comment';
/**
* Decide if the toc should be rendered, on mobile or desktop viewports
*/
function useDocTOC() {
const { frontMatter, toc } = useDoc();
const windowSize = useWindowSize();
const hidden = frontMatter.hide_table_of_contents;
const canRender = !hidden && toc.length > 0;
const mobile = canRender ? <DocItemTOCMobile /> : undefined;
const desktop =
canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? (
<DocItemTOCDesktop />
) : undefined;
return {
hidden,
mobile,
desktop,
};
}
export default function DocItemLayout({ children }: Props): JSX.Element {
const docTOC = useDocTOC();
const { frontMatter } = useDoc();
const { hide_comment: hideComment } = frontMatter;
const {
metadata: { unlisted },
} = useDoc();
return (
<div className="row">
<div className={clsx('col', !docTOC.hidden && styles.docItemCol)}>
{unlisted && <Unlisted />}
<DocVersionBanner />
<div className={styles.docItemContainer}>
<article>
<DocBreadcrumbs />
<DocVersionBadge />
{docTOC.mobile}
<DocItemContent>{children}</DocItemContent>
<DocItemFooter />
</article>
<DocItemPaginator />
</div>
{!hideComment && <Comment />}
</div>
{docTOC.desktop && <div className="col col--3">{docTOC.desktop}</div>}
</div>
);
}
大功告成!
对于不需要启用评论的文章,在 markdown 文件前面加上 hide_comment: true
即可,示例:
---
hide_comment: true
---
其它页面支持评论
对于文档目录页面如何判断是否隐藏评论,思路与文档页面类似,拿到目录(category
)相关的 metadata,判断 hide_comment
的值来决定是否隐藏评论;对于首页,如果需要评论,就固定 import 并在文末使用 <Comment />
标签即可,如果不需要则不需要做什么。
但本文没用此方案,所以也没有深入研究,有需要的可参考这里说的思路进行实现。
配置 giscus
Giscus 的评论数据是存放在 GitHub 仓库的 Discussions 中,所以先准备一个 GitHub 仓库(如果是 docusaurus 构建的开源站点,通常用存放网站源码仓库),在设置里启用 Discussions:
然后进入 giscus 官网网站,输入 GitHub 仓库和 Discussion 分类(通常用 General):
下面会自动生成 giscus 配置所需的关系 ID 信息:
将其贴在 docusaurus.config.ts
配置文件中:
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
// giscus 评论功能
giscus: {
repo: '***************',
repoId: '************',
category: 'General',
categoryId: '********************',
},
然后就会自动启用评论了。