Project Update
代码工程阅读器:在帖子中展示完整项目目录
为什么需要代码工程阅读器
普通 Markdown 代码块很适合展示一小段示例,但不适合展示包含多个模块、配置文件和测试目录的完整工程。
如果把每个文件分别复制到文章中,会出现几个问题:
- 文件之间的目录关系消失。
- 文章会被大量代码拉得很长。
- 更新项目时容易遗漏某些文件。
- 读者很难像使用编辑器一样快速切换文件。
因此网站新增了一种可选的帖子展示能力:正文继续负责说明,正文下方使用左侧文件树和右侧代码区展示完整工程。
三类帖子共用同一套数据结构
Blog、Study 和 Projects 原本就共用基础内容 schema,因此代码工程配置也放进公共字段中:
codeProject:
enabled: true
archive: /src/code-project-archives/example.zip
entry: src/main.py
title: 示例代码工程
各字段的作用是:
enabled:控制当前帖子是否启用阅读器。archive:CMS 上传的 ZIP 代码包路径。entry:打开页面时默认显示的文件。title:阅读器标题,不填写时使用帖子标题。
旧帖子没有 codeProject 字段时仍然使用原有阅读版式,不需要批量修改历史内容。
CMS 为什么上传 ZIP
Decap CMS 的文件控件适合上传单个文件,但不能稳定地把一个本地文件夹及其层级作为一个字段提交。
第一版采用 ZIP 作为交换格式:
- 在本地将代码文件夹压缩为
.zip。 - 在 CMS 中展开“代码工程阅读器”。
- 开启代码工程展示并上传 ZIP。
- 填写默认打开文件。
- 发布帖子并触发 Cloudflare Pages 重新构建。
目前构建流程只接受 ZIP,不接受 7z、RAR 等其他格式。这样可以保持浏览器上传、Node.js 构建和 Cloudflare 部署环境的一致性。
构建阶段生成安全预览
prepare-code-projects.mjs 会在 Astro 构建前执行。它不会把压缩包直接作为网页目录公开,而是进行以下处理:
CMS 上传 ZIP
-> 构建阶段检查并解压
-> 过滤无关或危险文件
-> 生成 manifest.json
-> 将可预览源码保存为 .txt
-> Astro 构建静态页面
清单记录文件的相对路径、大小、语言、是否可以预览以及对应的安全文本资源。浏览器根据清单生成文件树,点击文件后再按需读取内容。
即使项目中包含 HTML 或 JavaScript 文件,发布产物也使用 .txt 承载源码,避免用户直接打开静态资源时把它当成页面或脚本执行。
代码包安全限制
代码工程是公开内容,但仍然需要避免误传敏感文件和异常压缩包。构建脚本包含以下限制:
- ZIP 最大 20 MB。
- 单个文件最大 2 MB。
- 最多发布 500 个文件。
- 解压后的可发布内容最大 30 MB。
- 拒绝绝对路径和
..路径穿越。 - 拒绝
.env、私钥、证书和常见凭据文件。 - 自动过滤
.git、node_modules、dist、缓存和构建目录。 - 二进制文件只显示在目录中,不读取为代码文本。
代码只用于只读展示,不会在网站中运行。
Monaco Editor 阅读体验
右侧代码区域使用 Monaco Editor,也就是 VS Code 编辑器核心能力的网页版本。当前阅读器提供:
- 文件类型语法高亮。
- 行号、滚动和小地图。
- 明暗主题同步。
- 复制当前文件。
- 自动换行切换。
- 只读与 DOM 只读保护。
- 手机端文件目录抽屉。
Monaco 体积较大,因此采用动态加载。只有真正启用了代码工程的帖子才会加载编辑器,普通文章不会承担这部分资源开销。
自动化验证
项目新增了代码包测试脚本:
npm run test:code-projects
测试会生成临时代码包并验证:
- Python 和 JavaScript 文件能够识别语言。
- 图片等二进制文件不会作为文本预览。
node_modules会被忽略。- 包含
.env的压缩包会构建失败。
完整站点仍然通过以下命令验证:
npm run build
本站实践总结
这套方案没有把网站变成在线 IDE,而是把“完整项目结构”和“文章说明”结合起来。
Markdown 适合讲清楚背景、设计和使用方法,代码工程阅读器适合让读者自由查看实现细节。两者组合后,项目帖子可以同时承担技术记录、源码导览和成果展示三种作用。