一句话生成Node.js学习官网秒发布上线

0 阅读10分钟

哪里不会点哪里,AI快速创造个人专属文档、交付应用,连服务器部署都省了 _百万前端向前冲

发布网址: nodejs-zh-docs.app.workbuddy.host/

QQ_1790077836820.png

QQ_1790078388465.png

夜间模式

QQ_1790078422260.png


a486a36cd6305b2ef184348eed550254.png


QQ_1790077062521.png

Node.js 中文知识站

一个以 Node.js / JavaScript 为核心的全栈知识站点:Express 5 提供 REST API,SQLite(Node 内置 node:sqlite)承载内容与中文全文检索,原生 ESM 前端以 History 路由渲染。

内容覆盖 5 大板块、38 篇原创中文文档,参考 Node.js 官方 API 文档 的组织脉络重新编排,每篇都包含可运行代码、真实踩坑点与最佳实践,而不是 API 签名的翻译搬运。


一、功能一览

能力说明
知识库浏览38 篇文档,按「板块 → 顺序」组织的目录树,支持折叠与状态记忆
中文全文检索SQLite FTS5 + trigram 分词,支持「背压」「微任务」这类中文子串搜索
多维筛选按板块 / 难度 / 标签筛选,按课程顺序 / 最近更新 / 篇幅 / 难度排序
快捷搜索面板Ctrl + K 唤起,防抖 + 竞态保护,支持 ↑↓ Enter Esc 全键盘操作
文章阅读体验阅读进度条、本页目录(ScrollSpy)、代码高亮 + 一键复制、上下篇、相关推荐
数据看板板块篇幅条形图、难度分布环形图、标签云(全部原生 SVG/CSS,零图表库)
双主题浅色 / 深色一键切换,首次绘制前完成主题判定,无闪白
响应式桌面三栏 → 平板两栏 → 移动端抽屉式目录
健康探针/api/health(存活)与 /api/ready(就绪,校验数据库)分离

二、技术栈

后端

  • Node.js ≥ 22.13(依赖内置 node:sqlite,该版本起免实验性 flag)
  • Express 5 · marked(Markdown 渲染)
  • SQLite + FTS5(trigram 分词器)

前端

  • 原生 HTML / CSS / ES Modules,零构建步骤
  • History API 路由 + 动态 import() 代码分割
  • highlight.js(本地 vendor,不依赖 CDN,可离线运行)

依赖极简:运行时只有 2 个 npm 依赖(expressmarked)。数据库、加密、测试工具全部走 Node 内置模块,没有原生编译环节。


三、快速开始

# 1. 安装依赖
npm install

# 2. 一条命令完成初始化:复制前端资源 → 建表 → 导入 content 目录内容
npm run setup

# 3. 启动
npm start          # 生产模式
npm run dev        # 开发模式(--watch 自动重载)

打开 http://127.0.0.1:3000 即可。

第 2 步其实可以省略:server.js 检测到数据库尚未就绪时,会自动完成建表与内容导入。npm run setup 保留给「想在启动前先把库建好」以及 CI 场景使用。

全部可用命令

命令作用
npm start启动服务
npm run dev启动并监听文件变化自动重启
npm run setup完整初始化(vendor + migrate + seed)
npm run migrate只建表 / 执行数据库迁移
npm run seed只把 content/ 导入数据库(幂等,只有内容变化才写库)
npm run seed -- --prune导入并删除库中已从 content/ 移除的文章
npm run vendor只复制 highlight.js 等前端第三方资源
npm run smoke后端端到端冒烟测试(20 项断言,自动起停服务)
npm run verify:ui前端真实渲染验证(无头 Chrome,27 项断言)

四、目录结构

nodejs-zh-docs/
├── server.js                     # 服务入口:启动前校验配置与数据库,优雅停机
├── src/
│   ├── config/index.js           # 环境变量集中校验,失败快速退出
│   ├── lib/
│   │   ├── errors.js             # 类型化错误体系 + 统一错误响应
│   │   ├── logger.js             # 结构化 JSON 日志(含敏感字段脱敏)
│   │   ├── markdown.js           # Markdown → HTML(含 XSS 防护、锚点、TOC)
│   │   ├── respond.js            # 统一响应封装
│   │   └── validate.js           # 入参校验与 FTS/LIKE 查询串构造
│   ├── db/
│   │   ├── index.js              # 连接、事务、健康检查、优雅关闭
│   │   └── migrations/001_init.sql
│   ├── middleware/               # requestContext / httpLogger / securityHeaders
│   │                             # cors / rateLimit / errorHandler
│   ├── features/                 # 按功能组织,每个模块三层:routes → service → repository
│   │   ├── articles/
│   │   ├── categories/
│   │   ├── search/
│   │   ├── stats/
│   │   └── health/
│   └── routes/index.js           # API 路由聚合
├── scripts/
│   ├── migrate.js                # 迁移执行器(schema_migrations 记录版本)
│   ├── seed.js                   # 内容导入(差异报告 + 事务 + 幂等)
│   ├── copy-vendor.js            # 复制前端第三方资源
│   ├── smoke.js                  # 后端冒烟测试
│   └── verify-ui.js              # 前端渲染验证
├── content/                      # ★ 内容源,内容即代码
│   ├── categories.json           # 分类元数据(中文名、图标、排序、简介)
│   ├── 01-入门基础/*.md
│   ├── 02-核心模块API/*.md
│   ├── 03-异步与并发/*.md
│   ├── 04-工程与工具链/*.md
│   └── 05-进阶主题/*.md
└── public/                       # 前端静态资源(无构建)
    ├── index.html
    ├── assets/css/style.css
    ├── assets/js/                # api / router / ui / sidebar / search-panel / app + views/
    └── vendor/                   # highlight.js(由 npm run vendor 生成)

五、API 接口

统一响应结构,客户端一个分支即可处理全部接口:

// 成功
{ "ok": true, "data": {}, "meta": {} }

// 失败
{ "ok": false, "error": { "code": "NOT_FOUND", "message": "…", "details": [] }, "requestId": "…" }
方法路径说明
GET/api接口索引
GET/api/health存活探针
GET/api/ready就绪探针(校验数据库可读)
GET/api/home首页聚合(概览 + 分类 + 最近更新 + 入门推荐 + 热门搜索)
GET/api/stats完整统计(板块篇幅、难度分布、标签)
GET/api/categories全部分类(含文章数、字数、阅读时长)
GET/api/categories/:slug单个分类
GET/api/articles文章列表,支持 category tag difficulty sort page pageSize
GET/api/articles/recent最近更新
GET/api/articles/:slug文章详情(含渲染 HTML、目录、上下篇、相关推荐)
GET/api/search?q=全文搜索(返回高亮片段与命中策略)
GET/api/search/hot热门搜索词
GET/api/tags标签及出现次数
GET/api/difficulties难度分布

错误码:VALIDATION_ERROR(400)、NOT_FOUND(404)、TOO_MANY_REQUESTS(429)、INTERNAL_ERROR(500)、SERVICE_UNAVAILABLE(503)。


六、如何新增一篇文档

内容与代码分离:只需要往 content/ 目录放一个 Markdown 文件,再跑一次 npm run seed,无需改动任何代码。

# content/02-核心模块API/19-worker_threads.md
---
title: "worker_threads 多线程"
slug: "worker-threads-api"
category: "core-modules"
order: 19
summary: "60 字以内的中文摘要,会展示在卡片与搜索片段里。"
difficulty: "高级"
readTime: 10
tags: ["多线程", "CPU 密集"]
since: "v12.11.0"
---

## 概述
……

字段规则:

字段必填说明
title中文标题
slug全小写英文/连字符,决定文章 URL(/docs/<slug>
category分类 slug,须与 categories.json 一致
order分类内排序(也可用文件名的数字前缀)
summary摘要,用于卡片与搜索片段
difficulty入门 / 进阶 / 高级(数据库有 CHECK 约束)
readTime预计阅读分钟数
tags标签数组,用于筛选与相关推荐
since该 API 在 Node.js 中引入的版本号

导入脚本会做内容校验(缺字段、正文过短、slug 与文件名不一致、分类不匹配、slug 重复),问题会以清单形式打印出来;--prune 才会真正删除库中多余的文章。

新增分类:在 categories.json 里加一项并创建对应目录即可。


七、设计决策记录

几个「为什么这么选」的说明,避免后来者误改:

  1. 为什么用 node:sqlite 而不是 better-sqlite3 内置模块,零原生编译、零额外依赖,clone 下来 npm install 即可跑。代价是绑定了 Node 版本,node:sqlite 的可用性分三档:

    Node 版本node:sqlite 可用性
    ≥ 22.13.0(含 23.4+)直接可用,无需任何参数
    22.5.0 ~ 22.12.x、23.0 ~ 23.3可用,但必须加 --experimental-sqlite
    < 22.5.0不存在此模块,只能用 better-sqlite3

    启动时会自动检测并把结论写进日志,所以部署到新机器上出现问题时,看一眼启动日志即可判断是不是版本问题。

  2. 为什么 tags 用 JSON 字符串而不是关联表 标签量小、只用于筛选不做聚合统计,关联表属于过度设计。查询侧用 json_each() 展开即可;若日后要做标签维度的复杂分析,再迁移到关联表。

  3. 为什么全文索引用 trigram 分词器 SQLite 默认的 unicode61 会把一整段中文当成一个 token,「背压」这类子串搜索会全部失配。trigram 按三字符滑窗建索引,中文子串才能命中。代价是查询必须 ≥ 3 个字符——所以搜索服务层做了策略分流:≥ 3 字符走 FTS5,1–2 字符自动降级为 LIKE 模糊匹配。

  4. 为什么前端不用框架、不用构建 本站是读多写少的文档站,原生 ESM + History 路由足够,省掉打包与依赖升级的长期成本。视图按路由动态 import(),首屏只加载首页需要的代码。

  5. 为什么 Markdown 在服务端渲染 渲染结果带 LRU 缓存(键含 updated_at,内容一变自动失效),比每次在浏览器里解析更快;同时 API 会同时返回原始 Markdown 与渲染 HTML,便于后续导出或二次加工。

  6. 为什么 CSP 里没有 'unsafe-inline'(script 部分) 全站没有一行内联脚本,主题初始化也刻意做成独立外部文件。这是防 XSS 最有效的一条;代价是不能写内联 <script>,改代码时需要注意。

  7. 已知约束 node:sqlite 是同步 API。本站是低写入的文档站,同步查询反而更快;若将来引入高频写入场景,需评估是否切换到异步驱动。


八、配置

复制 .env.example.env 后按需修改(.env 已在 .gitignore 中):

变量默认值说明
PORT3000监听端口
HOST自动推断不填时:本机启动 → 127.0.0.1;检测到平台注入的 PORTNODE_ENV=production0.0.0.0。需要固定绑定时再显式指定
NODE_ENVdevelopmentdevelopment / test / production
DB_FILEdata/nodejs-zh-docs.dbSQLite 文件路径
CORS_ORIGINS本机两个地址允许来源,逗号分隔;生产禁用 *
LOG_LEVELdebug / 生产 infodebug / info / warn / error

配置在启动时集中校验,任何非法值都会一次性全部报出并拒绝启动。


九、验证

npm run smoke       # 后端 20 项断言:接口、分页、中文搜索两条分支、错误路径、安全头
npm run verify:ui   # 前端 27 项断言:真实浏览器渲染 + 路由 + 控制台报错

两者都会自己拉起服务并在结束时关闭,可直接接入 CI。verify:ui 需要本机有 Chrome/Edge,可用 CHROME_PATH 指定路径。


十、部署

已部署实例

访问地址nodejs-zh-docs.app.workbuddy.host/
托管形态单端口 HTTP 服务(Node.js 运行时,SQLite 随应用走)
内容规模38 篇文章 / 5 个板块

首次启动自愈

部署时不需要单独执行 npm run setupserver.js 会先检查数据库是否就绪,若表不存在则自动依次执行 scripts/migrate.jsscripts/seed.js,最后复核一次再开始监听。

这样设计的原因:data/*.db 属于运行期产物(已在 .gitignore 中),容器与云平台打包时通常不会带上它。把初始化绑在「安装阶段」会让部署多出一个隐式前置条件。自愈逻辑复用已经过测试的两个脚本、不重复实现,并会透传 process.execArgv,保证 --experimental-sqlite 这类运行参数不会丢。

云端 / 容器部署

  1. 服务监听 PORT 环境变量并绑定 0.0.0.0 —— 未显式设置 HOST 时会自动判断,无需手工配置。
  2. 只占用一个 HTTP 端口,没有任何外部服务依赖(数据库是随应用走的单文件 SQLite),可直接放进容器或 Serverless 平台。
  3. 打包时排除 node_modules/data/,上传后执行 npm install 即可;首次启动自动完成建表与内容导入。

自有服务器部署

  1. NODE_ENV=production,明确列出 CORS_ORIGINS(禁止 *)。
  2. 用反向代理(Nginx)终止 TLS,服务监听 127.0.0.1(显式设置 HOST=127.0.0.1);trust proxy 已按环境自动设置。
  3. 数据文件在 data/ 目录,注意纳入备份;数据库使用 WAL 模式,备份时把 -wal / -shm 一并处理或使用 VACUUM INTO
  4. 用进程管理器(systemd / PM2)托管,SIGTERM 已实现优雅停机(等待在途请求 → 关闭数据库 → 退出)。
  5. 内容更新流程:修改 content/npm run seed → 重启服务(渲染缓存按 updated_at 自动失效,重启不是必须的)。

若服务器上没有 Nginx(由 Node.js 直接对外提供 HTTPS),把上面第 2 条替换为:在 server.js 之外用 node:https 承载 TLS,createApp() 产出的 Express 实例可直接作为其 handler 传入;服务本身仍监听回环地址,TLS 与证书轮换交给外层。这样 React/Express 侧代码零改动,也不用为了一个静态知识站额外引入 Nginx。