数字花园持续集成与部署
此方案为配置与Obsidian Vault分离的方案
Quartz4
安装
在这里我们通过克隆官方仓库开始:
git clone https://github.com/jackyzha0/quartz.git blog
然后进入blog文件夹安装相关依赖并创建我们自己的数字花园:
npm i
npx quartz create
接下来我们选择Symlink
,链接content到我们的ownCloud同步笔记目录即可。
如果不需要本地预览,也可以不创建。
配置
由于配置和Obsidian Vault是分离的,所以我们首先将content目录忽略,配置.gitignore
,如下:
.DS_Store
.gitignore
node_modules
public
prof
tsconfig.tsbuildinfo
.obsidian
.quartz-cache
private/
.replit
replit.nix
content
然后改quartz.config.ts
,参考如下:
import { QuartzConfig } from "./quartz/cfg"
import * as Plugin from "./quartz/plugins"
/**
* Quartz 4 Configuration
*
* See https://quartz.jzhao.xyz/configuration for more information.
*/
const config: QuartzConfig = {
configuration: {
pageTitle: "Evalexp's Digital Garden",
pageTitleSuffix: "",
enableSPA: true,
enablePopovers: true,
analytics: {
provider: "plausible",
},
locale: "zh-CN",
baseUrl: "blog.evalexp.top",
ignorePatterns: ["private", "Template 模板", ".obsidian", ".trash", "Daily Note 日记"],
defaultDateType: "modified",
theme: {
fontOrigin: "googleFonts",
cdnCaching: false,
typography: {
header: "Schibsted Grotesk",
body: "Source Sans Pro",
code: "IBM Plex Mono",
},
colors: {
lightMode: {
light: "#faf8f8",
lightgray: "#e5e5e5",
gray: "#b8b8b8",
darkgray: "#4e4e4e",
dark: "#2b2b2b",
secondary: "#284b63",
tertiary: "#84a59d",
highlight: "rgba(143, 159, 169, 0.15)",
textHighlight: "#fff23688",
},
darkMode: {
light: "#161618",
lightgray: "#393639",
gray: "#646464",
darkgray: "#d4d4d4",
dark: "#ebebec",
secondary: "#7b97aa",
tertiary: "#84a59d",
highlight: "rgba(143, 159, 169, 0.15)",
textHighlight: "#b3aa0288",
},
},
},
},
plugins: {
transformers: [
Plugin.FrontMatter(),
Plugin.CreatedModifiedDate({
priority: ["frontmatter", "git", "filesystem"],
}),
Plugin.SyntaxHighlighting({
theme: {
light: "github-light",
dark: "github-dark",
},
keepBackground: false,
}),
Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
Plugin.GitHubFlavoredMarkdown(),
Plugin.TableOfContents(),
Plugin.CrawlLinks({ markdownLinkResolution: "relative" }),
Plugin.Description(),
Plugin.Latex({ renderEngine: "katex" }),
],
filters: [Plugin.ExplicitPublish()],
emitters: [
Plugin.AliasRedirects(),
Plugin.ComponentResources(),
Plugin.ContentPage(),
Plugin.FolderPage(),
Plugin.TagPage(),
Plugin.ContentIndex({
enableSiteMap: true,
enableRSS: true,
}),
Plugin.Assets(),
Plugin.Static(),
Plugin.Favicon(),
Plugin.NotFoundPage(),
// Comment out CustomOgImages to speed up build time
Plugin.CustomOgImages(),
],
},
}
export default config
基本上只需要改这两个配置即可;然后启用在线预览查看一下是否满意。
本土化
我们会发现在使用这个配置预览时,如果我们的网络环境不错,能够访问到Google等服务时,加载是不会有问题的;可是在大陆,应该大部分人的网络都无法访问到Google;因此我们需要做一点本土化的操作。
加载出错的核心问题在于Google字体库和KaTeX的加载问题,因此我们需要稍微改一下插件代码:
贴出一下改动,首先将配置中的cdn重新打开,然后替换quartz/util/theme.ts
的Google Fonts字体为国内源:
https://fonts.font.im/
再将jsdelivr的地址改为Cloudflare CDNJS的地址,替换quartz/plugins/transformers/latex.ts
:
https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css
https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/copy-tex.min.js
注意这个不能直接换域名,url需整体替换;这样完成后在国内应该访问就没有问题了。
容器化
为了更方便的将笔记发布,我们通过将构建的静态数字花园构建为容器镜像,这样可以直接使用watchtower监控容器镜像状态从而实现无人值守的自动更新。
在blog目录下创建builder文件夹,首先我们配置Nginx,创建nginx.conf文件:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html/;
index index.html;
try_files $uri $uri.html $uri/ /404.html;
}
}
在这里为了保证页面效果和本地一致,我们需要通过使用tri_files
来匹配可能的路径,如果路径不存在则返回404.html。
然后在builder下创建Dockerfile:
FROM nginx
COPY public /usr/share/nginx/html
COPY builder/nginx.conf /etc/nginx/conf.d/default.conf
这个就很简单了,不赘述。
Actions 自动构建
如果你的代码仓库选择为Github,则需要对应创建
.github/workflows
文件夹。
在blog目录下创建.gitea/workflows
文件夹,然后我们在其中创建build.yaml
;填写自动构建流程:
name: Auto Build Blog on Push
on:
push:
tags:
- "*-build"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Login Registry
uses: docker/login-action@v3
with:
registry: ccr.ccs.tencentyun.com
username: ${{ secrets.TENCENT_USER }}
password: ${{ secrets.TENCENT_PASSWORD }}
- name: Get Tag
id: meta
uses: docker/metadata-action@v5
with:
images: ccr.ccs.tencentyun.com/evalexp-gz/blog
- name: Setup rclone
run: curl https://rclone.org/install.sh | bash
- name: Configure rclone
run: |
rclone config create ocis webdav 'url=${{ secrets.OCIS_URL }}' 'vendor=other' 'user=${{ secrets.OCIS_USER }}' 'pass=${{ secrets.OCIS_PASSWORD }}'
- name: Cache content
uses: actions/cache@v4
with:
path: content
key: webdav-${{ steps.meta.outputs.version }}
restore-keys: |
webdav-
- name: Sync content from OCIS
run: rclone sync ocis:/Notes/Notes ./content
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Build Blog
run: npx quartz build -d content -v
- name: Set up docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./builder/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
上面的自动流程仅当推送标签为*-build
时才会自动触发,其流程如下:
- git checkout
- 登陆容器仓库
- 获取元信息
- 安装rclone
- 配置rclone的webdav信息
- 为webdav同步的内容启用缓存
- 同步webdav中的笔记
- 安装Nodejs 22
- 为npm 依赖启用缓存
- 安装相关依赖
- quartz4 静态编译
- 安装docker buildx
- 构建容器镜像并推送远程仓库
之所以使用tag是因为在配置和Vault分离的情况下,即便不变更此仓库内容,也能自由的推送tag,从而引发自动构建
请注意上面引用了许多的secrets,这些需要在仓库的Actions配置中进行添加:
- TENCENT_USER
- TENCENT_PASSWORD
- OCIS_URL
- OCIS_USER
- OCIS_PASSWORD
数字花园更新
如果说某一天写了一篇文章,需要发布,此时我们仅需在当前的blog仓库下打一个tag,例如2025.09.07-v1-build
,将其推送到Git仓库,就会自动触发流程并推送最新镜像到远程仓库。
注意,如果需要自动部署,你需要在远程服务器上使用腾讯云的该镜像部署,并且使用watchtower持续监控镜像更新操作。