nextjs-notion-starter-kit是什么
nextjs-notion-starter-kit 是Github上transitive-bullshit个人开发的一个基于Next.js和Notion API的开源项目,提供了快速搭建Notion博客的模板和工具集。
此项目提供了一个现代化的博客界面和许多有用的功能,通过Notion API获取Notion中的内容快速构建出一个美观高效的博客,并且方便的管理和更新博客内容。
演示地址
优点
- 内容为Notion页面,不需要懂代码既可以布置版式
- 使用reaction-notion-x库渲染Notion笔记的元素样式,与Notion软件中的样式基本一致
- 支持侧边Table Contents文章目录
- 支持Collection、Database等复杂Block的展示
- 支持手动白天黑夜模式
- 支持调用NotionAPI搜索文章
准备工作
1、Github 上fork项目
注册并登录Github,然后访问这个项目,然后fork(复制)这个项目。
fork后的项目名称可以在
Settings 中修改为自己想要的项目名。
2、在Notion中创建笔记
在Notion创建笔记作为网站首页,需要注意的是这个笔记是需要公开分享的,所以请注意避免在这个笔记内发布一些涉及隐私的内容。
注意笔记内容是公开所有人可见的,请注意隐私内容!
笔记页面可以自由设计,在创建好之后,点击右上角的
Share按钮,将Share to web 选项打开,复制下面的链接。之后需要用的是链接中
https://****.notion.site/ 之后的这一串ID。配置文件
基础配置
一般使用只需要修改site.config.js 这个文件,点击进入配置文件页面,然后点击右上角的编辑按钮,进入编辑状态,这里可以修改信息主要是:
- notion页面ID(必需)
rootNotionPageId对应上面分享的notion笔记的Share to web后面那一串ID
- 网站基本信息(必需)
name对应网站名domain对应网站域名author对应网站站长名
- 网站描述(可选)
description对应站点描述socialImageTitlesocialImageSubtitle
- 社交账号信息(可选)如果不需要展示社交信息可以注释掉
- github
修改完之后到页面底部 点击 Commit changes 直接提交修改。
进阶配置
关于搜索
网站支持搜索且支持中文搜索,但是需要注意的是访问的域名必需与配置文件site.config.js 中的
domain 对应的域名一致,如果不一致则无法搜索。更换网站图标
网站的图标位于
public 文件夹中,使用相同名字和规格的图片上传替换,就可以换成自己喜欢的图标。修改右上角跳转指向
网站右上角默认为跳转到github项目页面,可以修改为自己想要跳转的网址,比如跳转为自己的其他网站或者导航页面。
修改 components 目录下的
GitHubShareButton.tsx文件,将代码中的链接替换为自己想要的链接就可以了。href='https://github.com/transitive-bullshit/nextjs-notion-starter-kit'
将页面限制为单个Notion工作区
site.config.js 文件中的 rootNotionSpaceId 的值,可以将页面限制在Notion的单个工作区。如果没有这个值,外部浏览者只要访问并非你workspace下面的页面id,也会可以在你的域名下生成无关内容。
获取
rootNotionSpaceId 的值使用浏览器(建议使用Chrome)打开Notion,定位到自己网站所使用的笔记的首页,打开浏览器开发者工具(按浏览器页面F12),定位到网络,选择
fetch 标签,再访问另外一个页面,就可以看到json中的 space_id
解决因缓存设置导致新页面指向404的问题
具体参看项目的issues 中的这条问题
因为resolveNotionPage 函数相关,导致部署之后新创建的页面和改名的页面无法及时更新,访问页面的时候被重定向到404.
在项目未更新解决之前,可以按照如下方式修改代码解决,参考这里。
修改
lib/get-site-map.ts中的代码为如下:import pMemoize from 'p-memoize' import { getAllPagesInSpace, uuidToId } from 'notion-utils' import { includeNotionIdInUrls } from './config' import { notion } from './notion-api' import { getCanonicalPageId } from './get-canonical-page-id' import * as config from './config' import * as types from './types' import ExpiryMap from 'expiry-map' const uuid = !!includeNotionIdInUrls const cache = new ExpiryMap(10000) export async function getSiteMap(): Promise<types.SiteMap> { const partialSiteMap = await getAllPages( config.rootNotionPageId, config.rootNotionSpaceId ) return { site: config.site, ...partialSiteMap } as types.SiteMap } const getAllPages = pMemoize(getAllPagesImpl, { cacheKey: (...args) => JSON.stringify(args), cache }) async function getAllPagesImpl( rootNotionPageId: string, rootNotionSpaceId: string ): Promise<Partial<types.SiteMap>> { const getPage = async (pageId: string, ...args) => { console.log('\nnotion getPage', uuidToId(pageId)) return notion.getPage(pageId, ...args) } const pageMap = await getAllPagesInSpace( rootNotionPageId, rootNotionSpaceId, getPage ) const canonicalPageMap = Object.keys(pageMap).reduce( (map, pageId: string) => { const recordMap = pageMap[pageId] if (!recordMap) { throw new Error(`Error loading page "${pageId}"`) } const canonicalPageId = getCanonicalPageId(pageId, recordMap, { uuid }) if (map[canonicalPageId]) { // you can have multiple pages in different collections that have the same id // TODO: we may want to error if neither entry is a collection page console.warn('error duplicate canonical page id', { canonicalPageId, pageId, existingPageId: map[canonicalPageId] }) return map } else { return { ...map, [canonicalPageId]: pageId } } }, {} ) return { pageMap, canonicalPageMap } }
增加备案信息
在
lib/site-config.ts中新增一行:import * as types from './types' export interface SiteConfig { rootNotionPageId: string rootNotionSpaceId?: string name: string domain: string author: string description?: string language?: string beian?: string
在
site.config.js 中添加一行备案信息// basic site info (required) name: 'Transitive Bullshit', domain: 'transitivebullsh.it', author: 'Travis Fischer', beian: '浙ICP备2021******号',
在
lib/config.ts 中新增一行// general site config export const name: string = getSiteConfig('name') export const author: string = getSiteConfig('author') export const domain: string = getSiteConfig('domain') export const description: string = getSiteConfig('description', 'Notion Blog') export const beian: string = getSiteConfig('beian')
修改
components/Footer.tsx文件.删除其中的社交信息按钮,新增备案信息显示。
import * as React from 'react' import { IoMoonSharp } from '@react-icons/all-files/io5/IoMoonSharp' import { IoSunnyOutline } from '@react-icons/all-files/io5/IoSunnyOutline' import * as config from '@/lib/config' import { useDarkMode } from '@/lib/use-dark-mode' import styles from './styles.module.css' // TODO: merge the data and icons from PageSocial with the social links in Footer export const FooterImpl: React.FC = () => { const [hasMounted, setHasMounted] = React.useState(false) const { isDarkMode, toggleDarkMode } = useDarkMode() const onToggleDarkMode = React.useCallback( (e) => { e.preventDefault() toggleDarkMode() }, [toggleDarkMode] ) React.useEffect(() => { setHasMounted(true) }, []) return ( <footer className={styles.footer}> <div className={styles.copyright}>Copyright 2022 {config.author}</div> <div className={styles.settings}> {hasMounted && ( <a className={styles.toggleDarkMode} href='#' role='button' onClick={onToggleDarkMode} title='Toggle dark mode' > {isDarkMode ? <IoMoonSharp /> : <IoSunnyOutline />} </a> )} </div> <div className={styles.copyright}> <a href={`https://beian.miit.gov.cn/`} target='noreferrer noopener' > <div>{config.beian}</div> </a> </div> </footer> ) } export const Footer = React.memo(FooterImpl)
简化命令
为在本地部署更新的时候简化代码,在
package.json 中增加一行 "restart":"next build && pm2 restart notion","deploy": "vercel --prod", "restart": "next build && pm2 restart notion", ## 新增命令 "deps": "run-s deps:*",
更新依赖
Notion更新版本之后,有部分样式不被支持,实际上只是代码中的依赖没有更新。
将
package.json 的以下四个依赖版本号更新到最新即可。"notion-client": "^4.14.1", "notion-types": "^4.14.1", "notion-utils": "^4.14.1", "react-notion-x": "^4.14.2",
代码块偶尔不渲染的问题
具体参看:代码块不会偶尔渲染#477
某些时候页面刷新的时候,代码块无法渲染出来,这个问题偶尔出现,根据网友的修改,可以临时解决这个问题。
将
components/NotionPage.tsx 中的code的部分,将await Promise.all 更改为 await Promise.allSettledconst Code = dynamic(() => import('react-notion-x/build/third-party/code').then(async (m) => { // add / remove any prism syntaxes here await Promise.allSettled([ import('prismjs/components/prism-markup-templating.js'), import('prismjs/components/prism-markup.js'), import('prismjs/components/prism-bash.js'),
部署方式
一、vercel部署
在修改完配置之后,就可以登录Vercel 进行部署,推荐使用Github账号进行登录。
1、创建项目

选择你github上的对应项目,Import 后,点击 deploy ,然后等待部署完成,返回Successful 的提示。

部署完成之后如下图,点击黑色按钮 Visit 即可以访问部署成功的网站了。

2、添加域名
在部署完成的项目中找到 settings — Domains 输入域名,点击 Add
如果你使用的是主域名,可以有三个选择:
- Add www.nasci.cn and redirect nasci.cn to it 添加www并且重定向到主域名
- Add nasci.cn and redirect www.nasci.cn to it 添加www并且重定向到www域名
- Add nasci.cn 只使用主域名

根据提示,在域名服务商后台配置Vercel的Cname。
到这里,网站就建设完成,已经可以通过域名访问,也可以不实用域名直接用vercel的域名进行访问。
二、服务器部署
部署到Vercel上,国内访问速度一般,而且有时候还存在访问障碍,这里记录的是在自己服务器上部署。
我使用的是腾讯云的轻量应用服务器,操作系统为CentOS 7.9 64bit,安装的是宝塔Linux面板 7.6.0
以及之后在群晖7.1内安装的centos+宝塔面板,也可以同样操作。
群晖内安装宝塔面板参看 群晖Docker安装宝塔面板
安装Git
宝塔面板直接在软件商店搜索
git,选择一个版本进行安装。安装Nodejs环境
宝塔面板在软件商店搜索
node,安装PM2管理器安装完成之后,点击
PM2管理器 - 设置,切换nodejs版本到 v16.19.1等切换完成之后,进入
模块管理,需要安装以下模块- npm
- pm2
- yarn
- eslint
拉取项目
我的宝塔默认在网站在
/www/wwwroot 文件夹下宝塔面板可以直接在文件夹下使用终端,或者在终端通过代码进入文件夹
git clone https://github.com/yunzhongci/notion
或者
先创建一个文件夹比如 notion文件夹,然后进入文件夹初始化这个新文件夹的git仓库
git init
然后在git仓库的代码过来(非公开的仓库):
git pull git@github.com:*****/notion.git
安装依赖
按照教程,在项目根目录通过
npm 或者 yarn 安装依赖。可以先查看npm或者yarn的当前版(比较推荐实用yarn)。
npm -v
yarn -v
如果有需要可以先将npm升级到最新版本,这样可以避免版本太低产生的某些问题。
npm install npm@latest -g
升级npm的时候,可能需要以管理员或 root 用户身份运行该命令,可以尝试使用 sudo 再次运行该命令:
sudo npm install npm@latest -g
然后安装所有依赖,也可以跳过更新最新版本直接先执行安装依赖,有问题再试着升级版本或者其他方式解决遇到的问题。
yarn install
如果实用npm则是
npm install 后续也可以通过npm outdated 来检查项目的依赖包是否过期,如果过期则会列出它们的最新版本。然后通过npm update更新当前项目中的所有 npm 包。它会读取项目中的 package.json 文件,并将所有已安装的包更新到其最新版本。在依赖安装完成之后执行:
如果是npm则是用
npm runyarn build
这一步会在终端中打印很多页面内容,相当于是把Notion上的页面内容抓取到服务器存起来。
启动服务:
yarn start
返回
[root@centos notion]# yarn start yarn run v1.22.17 $ next start ready - started server on 0.0.0.0:3000, url: http://localhost:3000
这时候就可以访问本地3000端口查看了。
确定服务启动成功,并且没有问题,使用
ctrl + C 返回,进行下一步。使用PM2管理进程持久化
这时候的测试的,关闭终端就没有内容了
需要使Node进程持久化,使用进程管理工具,推荐使用
pm2安装
pm2yarn install -g pm2
在项目目录下,启动进程
pm2 start npm --name notion -- run start # --name 后面可以修改为你喜欢的名字
检查进程是否启动成功,即查看该进程的日志,检查是否有 error,
pm2 logs notion
查看所有进程
pm2 l
有时会遇到服务卡死的情况,这时就需要重启该进程
nginx reload notion
以上是常规pm2操作,在宝塔面板下,我们可以使用pm2管理器来查看、关闭和启用进程。位置在 pm2管理器 - 设置 - 项目列表
更新服务
之后如果项目有代码更新,关闭进程,进入项目根文件夹依次执行以下步骤即可
## 更新项目代码 git pull ## 重新启动进程 pm2 start npm --name "notion" -- start
反向代理到域名
宝塔面板反向代理非常简单
直接在面板中点 网站 - 添加站点,加上域名,PHP版本选择静态。
然后站点设置中,添加反向代理,将网站指向 3000 端口,如下图:

之后做好域名解析,就可以通过域名访问了。
同时也可以通过这里设置SSL,并且强制https访问。
其他Linux服务器
其他Linux服务器上部署,基本方式是一样的
安装Git,安装Nodejs环境,最后使用Nginx来反向代理。
Nginx反向代理
使用源里默认的nginx
apt install nginx -y
在
/etc/nginx/site-enables 创建配置文件 yourdomian.confserver { listen 80; listen [::]:80; server_name yourdomain.com; server_name www.yourdomain.com; listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/nginx/ssl/youdomian.com/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/youdomian.com/key.pem; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; }
修改
server_name 后面的 domain 为你的域名,为你的域名申请证书并放到指定目录下,配置正确的 ssl_certificate 和 ssl_certificate_key ,配置完成后,检验nginx 配置nginx -t
如有错误,可根据错误Debug,如无误,重载nginx 配置,
nginx -s reload
设置好对应的域名解析,即可顺利用你的域名访问你的网站了。
指令说明
部分在安装、调试和后续更新中可能用到到指令
指令 | 说明 |
-v | 用于查看版本,比如 node -v 查看nodejs版本,或者查看yarn 或者 nmp 、 pm2的版本 |
yarn install | 默认安装 package.json中所有依赖的模块的指定版本 |
yarn add <模块名> | 安装指定依赖模块的最新版本 |
yarn build | yarn run build 或者 npm run build 启动 package.json 文件 scripts 区域的 build 指令应用程序拉取到静态文件中进行生产。 |
yarn strat | yarn run start 或者 npm run start 启动 package.json 文件 scripts 区域的 start 指令 |
pm2 delete 0 | 关闭并删除指定id为 0 的应用 |
pm2 delete all | 关闭并删除所有应用 |
pm2 restart all | 重启所有应用 |
更新依赖
部分Notion后续更新的特性不被支持,其实只是依赖没有更新到最新
将
package.json 的 notion-client 、 notion-types 、 notion-utils 、 react-notion-x 四项更新到更新的版本就可以。其他依赖如果不懂不要乱动,容易出问题
npm更新指定指定的依赖到最新版本,可以使用以下命令:
npm install <package-name>@latest --save
"--save" 选项将更新的包版本写入 package.json 文件。例如本项目需要更新四个依赖如下:
npm install notion-client@latest --save npm install notion-types@latest --save npm install notion-utils@latest --save npm install react-notion-x@latest --save
yarn更新指定依赖到方式:
yarn add notion-client yarn add notion-types yarn add notion-utils yarn add react-notion-x
