跳到主要内容

docusaurus 增加评论系统

背景

像docusaurus这种静态网站本身是没有自带评论系统的,但是我们可以使用第三方的giscus增加。 先看下实现的效果如下:

和整体网页能够保持统一,且打开网页时候会自动进行加载,也可以配置为懒加载。

使用giscus

以下内容出自博客在 Docusaurus 中添加评论系统

先决条件

  • 你的项目运行 Docusaurus,至少有一篇博文或文档
  • 你安装的主题是theme classic,也是默认的。
  • 根据对应的评论插件注册一下拿到配置

配置 giscus

先登录你的github账号安装 giscus 应用 giscus app

进到giscus的官网配置好语言、评论要发到的github仓库、页面与映射关系, 选择一个discussion分类、主题等。

配置的时候注意看这三点

启用Discussions在仓库的Setting中可以找到

页面 ↔️ discussion 映射关系 一般选择Pathname就行。实际生成的评论的时候,会以你的博客请求路径创建一个类似话题的讨论。

拿到配置好的 <script> 标签, 类似:

<script src="https://giscus.app/client.js"
data-repo="xxxxx"
data-repo-id="xxxx"
data-category="xxxx"
data-category-id="xxxxx"
data-mapping="pathname"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="light"
data-lang="zh-CN"
crossorigin="anonymous"
async>

在你的 Docusaurus 项目根目录执行

yarn swizzle @docusaurus/theme-classic BlogPostPage

选择 Eject (Unsafe) 回车

选择 YES: I know what I am doing! 回车

这时你的项目目录下src/theme/BlogPostPage生成了自定义主题的文件

注意:这里生成的文件只对你的Blog目录下的文章插入评论系统 如果你要在docs目录下也插入评论系统,则还需要执行命令: yarn swizzle @docusaurus/theme-classic DocItem/Layout

下一步修改文件

下面三处标注是我们要修改添加代码的地方。 注意版本不同配置可能存在差异 根据标注自己找放评论的位置。

改动文件为:src/theme/BlogPostPage/index.js

//开始1
import React, { useEffect, useRef } from 'react';
//结束1
import clsx from 'clsx';
import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common';
import {BlogPostProvider, useBlogPost} from '@docusaurus/theme-common/internal';
import BlogLayout from '@theme/BlogLayout';
import BlogPostItem from '@theme/BlogPostItem';
import BlogPostPaginator from '@theme/BlogPostPaginator';
import BlogPostPageMetadata from '@theme/BlogPostPage/Metadata';
import TOC from '@theme/TOC';
function BlogPostPageContent({sidebar, children}) {
const {metadata, toc} = useBlogPost();
const {nextItem, prevItem, frontMatter} = metadata;
const {
hide_table_of_contents: hideTableOfContents,
toc_min_heading_level: tocMinHeadingLevel,
toc_max_heading_level: tocMaxHeadingLevel,
} = frontMatter;

//开始2
const commentElement = useRef(null);

useEffect(() => {
// Update the document title using the browser API
let s = document.createElement("script");
s.src = "https://giscus.app/client.js";
s.setAttribute("data-repo", "[你的仓库]");
s.setAttribute("data-repo-id", "[你的仓库 ID]=");
s.setAttribute("data-category", "[你的分类名]");
s.setAttribute("data-category-id", "[你的分类 ID]");
s.setAttribute("data-mapping", "pathname");
s.setAttribute("data-reactions-enabled", "1");
s.setAttribute("data-emit-metadata", "0");
s.setAttribute("data-input-position", "bottom");
s.setAttribute("data-theme", "light");
s.setAttribute("data-lang", "zh-CN");
s.setAttribute("crossorigin", "anonymous");
s.async = true;
commentElement.current.appendChild(s);
}, []);
//结束2

return (
<BlogLayout
sidebar={sidebar}
toc={
!hideTableOfContents && toc.length > 0 ? (
<TOC
toc={toc}
minHeadingLevel={tocMinHeadingLevel}
maxHeadingLevel={tocMaxHeadingLevel}
/>
) : undefined
}>
<BlogPostItem>{children}</BlogPostItem>

{(nextItem || prevItem) && (
<BlogPostPaginator nextItem={nextItem} prevItem={prevItem} />
)}

//开始3
<div style={{marginTop:'20px'}} ref={commentElement}></div>
//结束3

</BlogLayout>
);
}
export default function BlogPostPage(props) {
const BlogPostContent = props.content;
return (
<BlogPostProvider content={props.content} isBlogPostPage>
<HtmlClassNameProvider
className={clsx(
ThemeClassNames.wrapper.blogPages,
ThemeClassNames.page.blogPostPage,
)}>
<BlogPostPageMetadata />
<BlogPostPageContent sidebar={props.sidebar}>
<BlogPostContent />
</BlogPostPageContent>
</HtmlClassNameProvider>
</BlogPostProvider>
);
}

至此评论添加完成。

而如果刚刚你对docs目录也执行yarn swizzle.

那么图片下的两个文件都是需要改的,改动点和上面的一样。

你可以参考我的更改:

import React, { useEffect, useRef }  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 styles from './styles.module.css';
/**
* 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}) {
const docTOC = useDocTOC();
const {
metadata: {unlisted},
} = useDoc();


const commentElement = useRef(null);

useEffect(() => {
// Update the document title using the browser API
let s = document.createElement("script");
s.src = "https://giscus.app/client.js";
s.setAttribute("data-repo", "MingGH/996-ninja-giscus");
s.setAttribute("data-repo-id", "R_kgDOL5y6Fw");
s.setAttribute("data-category", "General");
s.setAttribute("data-category-id", "DIC_kwDOL5y6F84CfRWy");
s.setAttribute("data-mapping", "pathname");
s.setAttribute("data-reactions-enabled", "1");
s.setAttribute("data-emit-metadata", "0");
s.setAttribute("data-input-position", "bottom");
s.setAttribute("data-theme", "preferred_color_scheme");
s.setAttribute("data-lang", "zh-CN");
s.setAttribute("data-loading", "lazy");
s.setAttribute("crossorigin", "anonymous");
s.async = true;
commentElement.current.appendChild(s);
}, []);

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>
<div style={{marginTop: '20px'}} ref={commentElement}></div>
<DocItemFooter/>
</article>
<DocItemPaginator/>
</div>
</div>
{docTOC.desktop && <div className="col col--3">{docTOC.desktop}</div>}
</div>
);
}