我如何创建一个博客CLI工具

记录我如何为零门槛创建博客 CLI 工具的完整思路和方案

背景

写博客时,我经常需要重复执行:创建新文章、列出现有的文章、删除旧文章、启动预览服务等操作。每次手动做这些很繁琐,于是我决定写一个 CLI 工具来自动化这些流程。

方案设计

目标

创建一个轻量的、仅依赖 Node.js 内置模块的 CLI 工具,用于管理博客文章。

核心功能

  • successli new <title> - 根据标题创建新的 MDX 文章
  • successli list - 列出所有已发布的文章
  • successli delete <slug> - 将文章移动到 trash 目录(软删除)
  • successli preview - 启动开发服务器预览

技术选型

技术选择理由
Node.js ESM原生支持现代 JavaScript,无需额外编译
内置模块仅使用 fspathchild_process,零依赖
Content CollectionsAstro 的内容管理方式,MDX 文件即博客

实现步骤

1. 创建入口脚本

scripts/successli.mjs 中编写主逻辑:

#!/usr/bin/env node

import { readdir, readFile, writeFile, rename, access, mkdir } from "node:fs/promises";
import { join } from "node:path";
import { spawn } from "node:child_process";

// 生成 URL 友好的 slug
function slugify(title) {
  return title
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

// 创建新文章
async function createPost(title) {
  const slug = slugify(title);
  const today = formatDate(new Date());
  const filePath = join(getPostsDir(), `${slug}.mdx`);

  const frontmatter = `---
title: "${title}"
description: "TODO: add description"
pubDate: ${today}
tags:
  - Uncategorized
draft: true
---

`;

  await writeFile(filePath, frontmatter);
  console.log(`Created: ${filePath}`);
}

2. 注册 bin 字段

package.json 中添加:

{
  "bin": {
    "successli": "./scripts/successli.mjs"
  }
}

3. 链接到全局

npm link

执行后,successli 命令即可在全局使用。

核心代码解析

文件结构

src/content/posts/    # 文章目录
src/content/.trash/posts/    # 回收站目录
scripts/successli.mjs # CLI 入口

关键函数

slugify - 将标题转换为 URL 友好的 slug:

"我的第一篇文章""wo-de-di-yi-pian-wenzhang"

formatDate - 生成标准日期格式:

new Date() → "2026-04-19"

softDeletePost - 软删除,移至 trash 而非直接删除:

await rename(postPath, trashPath);

使用效果

# 创建新文章
successli new 我如何创建一个博客CLI工具
# Created: src/content/posts/cli.mdx

# 列出所有文章
successli list

# 启动预览
successli preview

总结

这个 CLI 工具的核心思路是:以文件系统为中心,用 Node.js 内置模块完成所有操作。不依赖任何外部库,只需要 MDX 文件符合 Astro Content Collections 的 frontmatter 规范即可正常工作。

下一步可以继续优化:添加文章搜索、标签管理、自动发布到 Git 等功能。