跳转到正文
Shane Blog
返回

写了个小工具 shane-new-post,让新建博客文章这件事更省心

写了个小工具 shane-new-post,让新建博客文章这件事更省心

上一篇随笔里提到过,搭博客的过程中受不了每次手动敲 frontmatter 的重复劳动,于是写了个小工具叫 shane-new-post。这篇专门展开讲讲它,算是这个系列的第一篇。

起因:frontmatter 这东西手打太容易出错

用 Astro 的内容集合(Content Collections)功能时,每篇文章开头那段 YAML frontmatter 是要过 schema 校验的——字段名不能错,日期格式不能错,数组语法也不能错。手写的时候最容易翻车的就是这几个地方:

这些错误单个看都不严重,但次数一多就很消耗耐心。shane-new-post 要解决的就是这一件事:把新建文章这个动作变成一条命令或者几个问题,剩下的交给脚本去拼接出合法的 frontmatter。

这个工具是给谁用的

需要说明一下适用范围:shane-new-post 不是给任意博客用的通用工具,它是为 AstroPaper 风格的 Astro 博客准备的——也就是任何一个内容集合的 frontmatter 结构里带有 title / pubDatetime / tags / featured / draft 这一类字段的项目。如果你的博客走的是完全不同的技术栈,这个工具大概率用不上。

安装方式

npm create astro@latest 是同一个套路,装的时候有两种选择。

推荐用一键安装命令,在项目根目录(package.json 所在的目录)执行:

# npm
npm create shane-new-post@latest

# pnpm
pnpm create shane-new-post@latest

# yarn
yarn create shane-new-post

这条命令会自动完成一整套事情:扫描项目里有没有同名或者近似命名的脚本可能会冲突(比如你之前手写过一个 new-post.js),有的话会先问你要不要清理;自动识别当前用的是 npm、pnpm 还是 yarn,用对应的方式安装依赖;如果包管理器跳过了生命周期脚本(新版 pnpm 常见这种情况),会自动兜底手动执行一遍安装脚本,保证流程无论如何都能跑完整。

也可以选择手动安装:

npm install -D shane-new-post
# 或
pnpm add -D shane-new-post
# 或
yarn add -D shane-new-post
pnpm 用户注意

pnpm v9 / v10 默认会拦截新依赖的安装脚本。手动安装完之后记得跑一下 pnpm approve-builds,用方向键选中 shane-new-post,空格勾选,回车确认。或者干脆在 package.json 里提前写好:

"pnpm": { "onlyBuiltDependencies": ["shane-new-post"] }

一劳永逸,以后再装类似的包也不用每次手动确认。

装好之后,项目根目录会多出这些东西:

src/
  content/
    posts/
public/
  img/
scripts/
  new-post.js
.shane-new-post.json   # 保存了语言和默认作者名
package.json           # scripts 里多了 new-post 这一条

pnpm new-post(或者 npm run new-post / yarn new-post)装完就能直接用。

两种使用方式

交互模式

不带任何参数直接跑:

pnpm new-post

会按顺序问你几个问题:标题(必填);文件名(会根据标题自动建议一个 slug,直接回车采用,或者自己输入别的);标签(逗号分隔,可以跳过,跳过前还会把之前用过的标签列出来给你参考);描述、是否精选、是否草稿、要不要用 .mdx 而不是 .md,这几项都可以直接回车用默认值。

命令模式

一条命令直接搞定,适合已经想好内容、不想被一路问下去的场景:

pnpm new-post "getting-started" title:Getting Started/description:An intro post/tags:[astro,web]/draft:F/featured:T/mdx:T

规则很简单:第一个位置参数必须是文件名,这是唯一位置固定的部分;后面的 key:value 键值对用 / 分隔,顺序随便写,也可以拆成多行用反斜杠 \ 接续:

pnpm new-post "getting-started" \
  mdx:T \
  featured:T \
  title:Getting Started \
  tags:[astro,web] \
  draft:F \
  description:An intro post

上面两条命令是完全等价的。

参数表:

别名是否必填说明
title文章标题,命令模式下缺失会直接报错退出
descriptiondesc不填就是空字符串
tagstag方括号包裹、逗号分隔:[tag1,tag2]
draft布尔值,默认 false
featured布尔值,默认 false
mdx布尔值,T/true 生成 .mdx,否则生成 .md

布尔值这块有个统一规则:大小写不敏感,只有 t 或者 true(不管大小写)会被识别成”是”,其它任何值——ffalse、空字符串,甚至干脆不写这个键——都算”否”。没有单独判断”false”这一说,逻辑上就是”不是真就是假”。

遇到拼错的键名或者不认识的键,脚本只会打印一条警告然后跳过,不会因此中断整个创建流程——这点我个人觉得挺重要的,总不能因为一个可选字段打错字就前功尽弃。

每次新建文章会自动做的两件小事

另外这个工具不会覆盖同名文件——如果目标文件名已经存在,会直接报错退出,不会有任何写入动作,避免手滑覆盖掉已经写好的内容。

想看完整文档

这篇算是一个概览,命令模式的每一个参数、交互模式每一步的详细行为、还有一些边界情况(比如 frontmatter 里字符串值的转义规则),我都写进了文档站里,感兴趣可以直接跳过去看:

查看 shane-new-post 完整用法文档 →

源码也是开源的:

GitHub 仓库 →

下一篇打算讲讲它的兄弟工具 shane-new-doc——专门给 Starlight 文档站用的那一个,接口风格类似,但因为要适配文档站的目录结构,细节上有些不一样的地方。


分类:
标签:
分享此文章:

上一篇
shane-new-doc:给 Starlight 文档站配套的脚手架
下一篇
自己动手搭博客:这次选型时我到底在纠结什么