为什么一行 npm install 都不用

2024 年接第一个建站单子时,我在 package.json 面前犹豫了很久。Express?Koa?Fastify?每个框架都有学习成本、版本兼容问题、以及最重要的——客户的维护成本。

最后我关掉了 npm,打开了一个空文件夹。

零依赖不等于原始。 Node.js 内置的 httpfscryptozlib 模块已经覆盖了建站需要的全部能力。你缺的不是框架,是把这些模块组合起来的经验。

真实项目架构

以鲜味居(粤菜餐厅官网)为例,完整技术栈:

前端: 纯 HTML + CSS + JS(零框架)
后端: Node.js 原生 http 模块
数据库: JSON 文件读写
启动: node server.js

整个项目没有 node_modules 目录,克隆下来就能跑。部署到客户的 Windows 服务器上,不需要配环境、不需要解决依赖冲突——双击 bat 脚本就上线。

原生 http 路由表

很多人觉得不用 Express 写路由会很痛苦。实际上,一个简单的路由分发器不超过 20 行:

const routes = [];
function route(method, pattern, handler) {
  routes.push({ method, regex: new RegExp('^' + pattern + '$'), handler });
}

async function handleAPI(req, res) {
  for (const r of routes) {
    if (r.method !== req.method) continue;
    const match = req.url.match(r.regex);
    if (!match) continue;
    await r.handler(req, res);
    return true;
  }
  return false;
}

鲜味居项目有 16 个 API 端点,全部通过这个分发器处理。路由注册用 if-else 链还是用上面的 route 函数,纯粹是组织方式的区别——效果一样。

JSON 数据库的原子写入

很多人担心 JSON 文件作数据库不可靠。解决方法是原子写入

function writeJSON(filename, data) {
  const p = path.join(DATA_DIR, filename);
  fs.writeFileSync(p + '.tmp', JSON.stringify(data, null, 2));
  fs.renameSync(p + '.tmp', p);
}

先写 .tmp,再 rename。rename 是原子操作——要么成功,要么失败,不存在写一半崩溃导致数据损坏。这是操作系统保证的,不是 Node.js 的特性。

安全:零依赖意味着零供应链攻击

2024-2025 年 npm 供应链攻击频发。left-pad 事件、event-stream 后门、ua-parser-js 挖矿——每次都是成千上万项目受影响。

零依赖架构天然免疫这些。你的攻击面缩小到了 4 个内置模块:httpcryptofszlib。Go 标准库经过 Google 审查,Node.js 核心模块经过社区审查,安全性远超任何第三方 npm 包。

真正的边界在哪

零依赖不是万能药。以下场景不适用:

  • 复杂模板渲染:用 EJS/Pug 比手写字符串拼接更高效
  • ORM:数据关系复杂时,手写 SQL/JSON 查询容易出错
  • WebSocket:原生 ws 需要手动处理帧协议,不如直接用 ws

但对于中小实体店官网这个细分市场——零依赖是最优解。

实战建议

如果你也想尝试零依赖全栈:

  1. 从 server.js 骨架开始:路由分发 + 静态文件 + JSON 读写,200 行就够
  2. 安全优先:scrypt 密码哈希 + XSS 转义 + 速率限制,一个不能少
  3. Gzip 压缩zlib.gzipSync() 一行代码,HTML/CSS/JS 体积减 70%
  4. 原子写入:数据永远用 .tmp + rename 模式
  5. 部署用 Vercelapi/index.js 单文件全路由,零配置上线
  6. 完整项目源码在 GitHub 开源,欢迎参考。