880 字
4 分钟
从主题到 npm 包:同一份代码的两种活法

最初我以为博客主题只有一种使用方式:克隆仓库、改配置、写文章。后来才发现,同一份代码还可以发布成 npm 包,让其他人在自己的 Astro 项目里安装使用。

这两种模式共享同一套源码,但运行环境完全不同。

两种模式的分界#

flowchart TB
  Source[主题源码]
  Source --> A[源码模式:项目直接持有 src/]
  Source --> B[npm 模式:用户项目安装 shirones]
  A --> A1[配置在 src/config]
  B --> B1[配置覆盖在用户项目]
  B --> B2[内容在 shirones/content]

源码模式下,项目拥有所有文件,想改哪里就改哪里。npm 模式下,主题代码在 node_modules 里,用户的配置和内容必须放在包外的位置。

同一个改动,在两种模式下都成立,才算真正完成。

配置不能假设自己在哪#

源码模式里,读取 src/config/siteConfig.ts 看起来理所当然。到了 npm 模式,这个路径可能属于主题包,而不是用户项目。

因此配置读取需要遵循「用户覆盖优先」的规则,而不是直接读主题目录里的默认值。

配置覆层的思路
const userConfig = readUserConfig("site");
const finalConfig = userConfig
? mergeWithDefaults(userConfig)
: defaults;

构建配置需要重新生成#

Astro 的集成机制允许主题在启动时重建 astro.config.mjs,把必需的插件、路由和资源注入用户项目。这意味着配置文件不是静态的,而是会根据模式动态生成。

发布前必须检查依赖边界#

最容易出问题的地方,是「本地能构建,安装后失败」。原因通常是某个包写在了 devDependencies,但运行时需要它。

项目专门有一条检查命令,用来发现这种情况:

Terminal window
pnpm check:package-manifest

它会在发布前扫描源码里的 import,确认每个运行时依赖都出现在正确的位置。

依赖类型用途是否随包安装
dependencies运行时必需是
peerDependencies由用户项目提供否
devDependencies仅主题仓库开发使用否

文档也是交付物#

npm 模式最容易让用户困惑的,不是代码,而是「我的配置应该放哪」「内容目录在哪」「为什么改了没生效」。这些问题需要在文档里给出明确答案,而不是让用户读源码。

双模式最累的部分是什么?

不是写两套代码,而是每次改动都要问:这个改动在另一种模式下还成立吗?路径、配置、资源归属,任何一项假设错了,都会在发布后才暴露。

小结#

从主题到 npm 包,增加的是一层交付责任。源码模式可以只对自己负责,npm 模式必须对陌生环境负责。

也正因为如此,双模式反而逼着我把路径、配置和依赖边界想清楚。能经得起别人安装的代码,通常也会让自己的项目更干净。

第 12 篇,共 12 篇本文属于系列

从主题到 npm 包:同一份代码的两种活法
https://www.ycera.cn/posts/theme-to-npm-package/
作者
初月_Yuechu
发布于
2026-10-31
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取