Ghost 单仓库(Monorepo)架构导航:pnpm Workspace + Nx 驱动的全栈发布流水线
【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost
Ghost(README)是当前采用pnpm workspace + Nx组织的单仓库(Monorepo):pnpm 负责把apps/、ghost/core/、koenig/、packages/等子项目链接成一份本地依赖图,Nx 则基于这份依赖图调度 build、lint、test、dev 等任务并缓存产物。阅读本指南后,你将掌握:在仓库中定位任一模块(前端应用 / 服务端 Core / 编辑器 / 共享库)的方法;workspace:与catalog:依赖声明的区别与用法;以及"开发期直接跑 TypeScript 源码、生产期用编译产物"这套双轨构建机制是如何实现的。
Monorepo 概览:pnpm 提供依赖图,Nx 驱动任务
根 package.json 把仓库声明为名为ghost-monorepo的私有根包("private": true),并锁定包管理器与运行环境:
"packageManager": "pnpm@12.2.1+...,且通过preinstall钩子执行 scripts/enforce-package-manager.js 强制使用 pnpm;"engines": { "node": "^22.23.1 || ^24.20.0" }约束 Node 版本。
pnpm-workspace.yaml 是"哪些目录是工作区"的唯一事实来源,它通过 glob 声明了全部工作区:
packages: - 'ghost/*' - 'apps/*' - 'e2e' - 'koenig/*' - 'packages/**' - '!packages/_template' # 新包模板本身不参与工作区 - 'configs/*' - 'scripts'文件里还包含一批现代 pnpm 加固配置:strictDepBuilds: true、catalogMode: strict、通过allowBuilds对原生依赖构建做版本级白名单(如better-sqlite3@12.11.1、sharp@0.35.3)、通过overrides统一收敛传递依赖版本(典型例子是把knex-migrator>knex钉回 2.4.2,与 ghost/core 使用的 knex 主版本对齐)。这些配置共同决定了依赖解析的安全边界。
而 nx.json 定义了 Nx 的运行行为:parallel: 4控制并行度、cacheDirectory: ".nxcache"存放缓存、namedInputs中的sharedGlobals把根级配置文件(pnpm-workspace.yaml、pnpm-lock.yaml、ghost/tsconfig.json等)纳入每个任务的输入指纹。修改某个应用或包之前,先阅读它旁边(同目录)的 README,这是仓库内约定俗成的守则。
顶层目录总览
| 目录 | 内容 |
|---|---|
| apps/ | Admin 应用、面向浏览器的公开应用与前端库 |
| ghost/core/ | Ghost 服务端、前端渲染、数据库迁移与服务端测试 |
| koenig/ | Koenig 编辑器,以及内容存取 / 转换 / 渲染相关的kg-*包 |
| packages/ | 共享库、schema、翻译、测试数据与适配器(adapter)契约 |
| configs/ | 共享的 ESLint、TypeScript、Vite 与 Vitest 配置包 |
| e2e/ | 覆盖完整 Admin 与公开站点旅程的 Playwright 测试 |
| docker/ | 本地开发与 CI 用容器及配套服务 |
| scripts/ | 仓库初始化、校验、构建与发布工具链 |
前端应用布局:apps/下的三类工程
apps/下并存着定位截然不同的前端工程,改动前必须分清它们属于哪一类:
- admin —— 新的 React Admin 应用,正逐步取代旧版;
- ember-admin —— 遗留的 Ember Admin,路由正随时间推移陆续从 Ember 迁到 React;
- activitypub —— 内嵌在 Admin 中的 React 应用;
- portal、comments-ui、signup-form、sodo-search、announcement-bar、admin-toolbar —— 发布到 npm、并通过 CDN 以
<script>标签加载的公开应用(public apps); - shade —— 当前 Admin 的设计系统;
- admin-x-framework —— 提供共享 Admin API hooks、路由与工具函数。
公开应用的运行模型与普通 SPA 不同:它们把浏览器产物打包成 UMD(例如 apps/portal/package.json 的 根 package.json 里的 这是本仓库最具特色的构建设计。部分 TypeScript 包在导出中把 生产环境不启用 Koenig 已发布的 Ghost 的若干组成部分仍然维护在独立仓库中: 对本仓库而言,最值得记住的实践结论是:改包之前先看对应目录的 README,改外部依赖版本先去 【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.files只包含umd/、LICENSE、README.md),页面通过 script 标签加载,运行时配置来自 DOM 的>pnpm nx show projects # 列出所有可识别的工作区项目 pnpm nx show project <project-name> # 查看单个项目的 targets 与依赖 pnpm nx graph # 浏览器中打开依赖关系图 pnpm nx run <project-name>:<target> # 运行指定项目的某个 target,如 pnpm nx run @tryghost/admin:buildpnpm build、pnpm lint、pnpm test本质都是pnpm nx run-many -t <target>——即对全仓各项目执行同名 target;例如pnpm build=run-many -t build,而pnpm lint除了 run-many 还会追加lint:boundaries(依赖巡航边界检查)与lint:packages(校验内部包黄金路径)。日常开发可先执行一次pnpm setup(安装 + 初始化 submodule),再按需pnpm dev(基于 compose.dev.yaml 的 Docker 开发栈)。源码与生产构建:
source导出条件的双轨机制source条件放在编译产物之前(见 packages/README.md 的示例 exports:"source": "./src/index.ts"→"types"→"default")。Ghost Core 的开发服务器与测试会启用source条件,从而直接加载@tryghost/kg-default-nodes这类包的原始 TypeScript——每次改动无需tsc重编译即可被正在运行的 dev server 和 core 测试命中。source:Node 走default条件加载build/里的编译产物,Ghost 发布归档包含的也是这些编译文件而非包源码;浏览器应用同样使用各自的常规构建输出。一个直接推论是:源码改动可能在开发环境立刻生效,但涉及产物内容的生产构建仍需要重新执行pnpm build——当你改动包导出、构建配置或任何进入发布产物的代码时,务必补跑构建。kg-*包作为既有对外契约,保留了独立的 ESM 与 CommonJS 双输出:import从build/esm/解析,require从build/cjs/解析。它们的files列表包含build/但不包含src/,因此source条件所用的原始 TypeScript 永远不会被发布出去;而新建的内部包一律采用 ESM-only 契约。此外,由于 Ghost Core 本身是 CommonJS 却跑在支持require(esm)的 Node 上(仓库 engines 要求 Node ≥ 22),内部 ESM 包可同时服务import与require()两类消费者——前提是整个被引用的模块图不能出现顶层await(ESLint 会强制这一限制)。仓库之外的关联项目
gscan负责校验 Ghost 主题;Ghost-CLI用于安装与管理生产环境站点;Source、Casper、Themes存放官方主题;framework承载 Ghost 使用的共享 Node.js 包;SDK提供围绕 Ghost API 的工具链。本文只聚焦本仓库内部结构,这些外部仓库的具体用法以它们各自的文档为准。pnpm-workspace.yaml的 catalog,改包导出/构建配置后记得跑pnpm build——遵循这三条,你就能在 Ghost 这个庞大的 monorepo 里安全地穿梭于编辑器、服务端与共享库之间。项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考