|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +## 项目说明 |
| 4 | + |
| 5 | +这个仓库是一个基于 Electron 的静态博客管理与生成桌面应用。运行层面的主要特征如下: |
| 6 | + |
| 7 | +- 主进程很薄,核心业务逻辑基本都在 `App/` 目录下的渲染进程 JavaScript 模块里。 |
| 8 | +- UI 由原生 HTML、Bootstrap、Fluent UI Web Components、CommonJS 模块和直接 DOM 操作组成。 |
| 9 | +- 站点数据采用文件持久化,不使用数据库: |
| 10 | + - 站点元数据:博客根目录下的 `data/index.json` |
| 11 | + - 内容文件:`data/articles/*.md` 和 `data/pages/*.md` |
| 12 | +- 应用级偏好设置通过 `electron-json-storage` 保存。 |
| 13 | + |
| 14 | +## 高层结构 |
| 15 | + |
| 16 | +- `main.js` |
| 17 | + - Electron 生产环境入口 |
| 18 | + - 创建主 `BrowserWindow` |
| 19 | + - 加载 `App/start.html` |
| 20 | + - 提供少量 IPC,用于返回开始页和重绘原生菜单 |
| 21 | +- `main_dev.js` |
| 22 | + - 开发环境入口 |
| 23 | + - 支持热重载和 DevTools |
| 24 | +- `App/start.html` + `App/start.js` |
| 25 | + - 启动页 |
| 26 | + - 负责语言、样式等应用初始化 |
| 27 | + - 支持从模板创建新站点,或者打开已有站点 |
| 28 | +- `App/manage.html` + `App/manage.js` |
| 29 | + - 主管理壳页面 |
| 30 | + - 从 URL 参数中的 `rootdir` 读取博客根目录 |
| 31 | + - 执行数据迁移检查 |
| 32 | + - 根据 `currentPage` 分发到文章管理、页面管理、博客设置、Markdown 编辑器、预览发布等界面 |
| 33 | +- `App/markdown_editor.html` |
| 34 | + - 通过设置 `currentPage = "markdown_editor"` 复用 `App/manage.js` |
| 35 | +- `App/ui/*.html` |
| 36 | + - 运行时插入的 HTML 片段模板 |
| 37 | +- `App/render_*.js` |
| 38 | + - UI 渲染模块 |
| 39 | +- `App/add_*`、`App/edit_*`、`App/delete_*`、`App/save_*`、`App/change_*` |
| 40 | + - 各类增删改和排序功能模块 |
| 41 | +- `App/blog_source`、`App/blog_indexjson_template`、`App/default_theme_src` |
| 42 | + - 新建站点时使用的模板资源 |
| 43 | + |
| 44 | +## 关键运行流程 |
| 45 | + |
| 46 | +1. Electron 从 `main.js` 启动。 |
| 47 | +2. 主窗口加载 `App/start.html`。 |
| 48 | +3. `App/start.js` 从 `electron-json-storage` 读取应用级配置。 |
| 49 | +4. 用户执行两类操作之一: |
| 50 | + - 创建新博客根目录,复制模板并初始化 `data/index.json` |
| 51 | + - 打开已有博客根目录,并校验 `data/index.json` |
| 52 | +5. 页面跳转到 `App/manage.html?rootdir=...` |
| 53 | +6. `App/manage.js` 会: |
| 54 | + - 从查询参数中读取 `rootdir` |
| 55 | + - 创建 `BlogInstance = new BlogData(rootDir)` |
| 56 | + - 从 `data/index.json` 载入全局 `blog` 数据 |
| 57 | + - 调用迁移检查 |
| 58 | + - 渲染当前选中的管理界面 |
| 59 | +7. 各个功能模块会直接修改全局 `blog` 对象,再调用 `BlogInstance.writeBlogData()` 落盘。 |
| 60 | + |
| 61 | +## 架构和设计风格 |
| 62 | + |
| 63 | +这个项目没有使用 React、Vue 或 MVVM,更接近一个“脚本驱动的桌面应用”,只是按功能拆成了多个模块文件。 |
| 64 | + |
| 65 | +目前观察到的模式: |
| 66 | + |
| 67 | +- 主进程薄,渲染进程胖 |
| 68 | +- 按动作和功能拆分模块文件 |
| 69 | +- 通过 `insertAdjacentHTML` 做字符串模板式渲染 |
| 70 | +- 大量共享的隐式全局状态: |
| 71 | + - `blog` |
| 72 | + - `rootDir` |
| 73 | + - `lang_name` |
| 74 | + - `currentPage` |
| 75 | + - `BlogInstance` |
| 76 | +- 通过 `App/BlogData.js` 实现一个很薄的文件仓储层,但写入仍然依赖全局 `blog` |
| 77 | +- 通过 `App/check_migrate.js` 和 `App/migrate_core.js` 实现数据结构迁移 |
| 78 | + |
| 79 | +## 关键数据和状态约定 |
| 80 | + |
| 81 | +- `App/BlogData.js` |
| 82 | + - `getBlogData()` 从 `rootDir/data/index.json` 读取数据 |
| 83 | + - `writeBlogData()` 将当前全局 `blog` 对象写回磁盘 |
| 84 | +- 很多模块默认假设以下变量已经在渲染进程全局作用域中存在: |
| 85 | + - `blog` |
| 86 | + - `rootDir` |
| 87 | + - `lang_name` |
| 88 | + - 一些辅助函数 |
| 89 | +- 页面路由主要依赖 URL 查询参数,尤其是 `rootdir` 和 `path` |
| 90 | + |
| 91 | +## UI 组织方式 |
| 92 | + |
| 93 | +- UI 外壳主要由以下模块渲染: |
| 94 | + - `App/render_container.js` |
| 95 | + - `App/render_nav.js` |
| 96 | +- HTML 片段通过 `App/getUiFileContent.js` 加载 |
| 97 | +- `App/getUiFileContent.js` 会动态求值模板字符串,因此 UI 片段可以直接访问当前渲染作用域中的全局变量 |
| 98 | +- 样式通过 `App/loadUniStyle.js` 动态加载,并结合应用级配置生效 |
| 99 | + |
| 100 | +## 文章和页面编辑流程 |
| 101 | + |
| 102 | +- 文章列表渲染:`App/render_article_manager.js` |
| 103 | +- 打开正文编辑器:`App/edit_article.js` |
| 104 | + - 会打开 `markdown_editor.html?rootdir=...&path=...` |
| 105 | +- 编辑器实现:`App/render_markdown_editor.js` |
| 106 | + - 左侧原生 textarea |
| 107 | + - 右侧实时预览 |
| 108 | + - 使用 `marked` 渲染 Markdown |
| 109 | + - 支持加密/解密相关能力 |
| 110 | + - 支持可选的 AI 辅助写作 |
| 111 | +- 元信息编辑: |
| 112 | + - UI:`App/edit_article_meta.js` |
| 113 | + - 保存:`App/save_article_meta.js` |
| 114 | +- 保存行为通常是: |
| 115 | + - 修改 `blog["文章列表"]` |
| 116 | + - 按需创建或重命名 markdown 文件 |
| 117 | + - 调用 `BlogInstance.writeBlogData()` 持久化 |
| 118 | + - 如果启用,则触发 RSS / sitemap 钩子 |
| 119 | + |
| 120 | +## 预览和发布流程 |
| 121 | + |
| 122 | +- `App/manage.js` 在非 Markdown 编辑模式下会启动一个 `localhost:41701` 的 Express 静态服务器 |
| 123 | +- `App/render_preview_and_publish_page.js` 在预览发布页中也会再次启动同端口静态服务器 |
| 124 | +- `App/preview_and_publish.js` 没有内建完整的 Git/SSH 客户端,而是通过外部终端执行命令来辅助发布: |
| 125 | + - `git add / commit / push` |
| 126 | + - 基于 `scp` 的上传 |
| 127 | + |
| 128 | +## 注意点 |
| 129 | + |
| 130 | +- 安全模型比较宽松: |
| 131 | + - `nodeIntegration: true` |
| 132 | + - `contextIsolation: false` |
| 133 | + - 大量使用 `@electron/remote` |
| 134 | +- 模块之间通过全局变量强耦合,而不是显式依赖注入 |
| 135 | +- UI 渲染、状态修改、文件持久化经常混在同一个模块里 |
| 136 | +- `App/getUiFileContent.js` 使用了动态求值 |
| 137 | +- 预览服务在多个位置重复启动,后续容易出现端口和职责重复问题 |
| 138 | + |
| 139 | +## 建议阅读顺序 |
| 140 | + |
| 141 | +分析或修改这个项目时,建议优先按下面顺序阅读: |
| 142 | + |
| 143 | +1. `package.json` |
| 144 | +2. `main.js` |
| 145 | +3. `App/start.js` |
| 146 | +4. `App/manage.js` |
| 147 | +5. `App/BlogData.js` |
| 148 | +6. 相关的 `App/render_*.js` |
| 149 | +7. 相关的 `App/save_*` / `App/edit_*` / `App/delete_*` |
| 150 | +8. `App/check_migrate.js` |
| 151 | +9. `App/migrate_core.js` |
0 commit comments