快速开始
本页从一个空目录开始,做出一个经过测试、可以构建和部署的 Cell 后端。开发需要 Node.js ^20.19.0 || >=22.12.0;构建产物可以在 Node.js 18 及以上、Bun 1.2 及以上和 Deno 2 上运行。
创建项目
bash
npx @celljs/cli init backend my-app # 或 fullstack:React 前端 + 经 RPC 调用的后端
cd my-app
npm install
npx cell dev # http://127.0.0.1:3000,保存即重载cell init 从不提问。不带模板名时列出全部模板;目录非空时需要 --force。生成的项目:
text
my-app/
├── cell.yml # 应用配置,用 @Value 读取
├── package.json # 脚本:dev、build、preview、check、test
├── tsconfig.json # experimentalDecorators + emitDecoratorMetadata
├── src/node/
│ ├── module.ts # 后端 DI 模块:导入每个声明了组件的文件
│ └── home-controller.ts
├── test/app.spec.ts # bun test + createTestApp()
├── AGENTS.md、CLAUDE.md # 给 coding agent 的指南,与已安装的版本一致
├── .agents/skills/cell/ # 同一份指南,以 agent skill 的形式提供
└── .mcp.json # 给支持 MCP 的 agent 启动 `npx cell mcp`添加接口
新建一个控制器,再在 src/node/module.ts 里导入它的文件。没有被任何模块导入的文件不会被加载,其中的组件也就不存在。
ts
// src/node/todo-controller.ts
import { Body, Controller, Delete, Get, Param, Post } from '@celljs/mvc/lib/node';
import { NotFoundError } from '@celljs/web/lib/node';
interface Todo { id: number; title: string }
@Controller('todos')
export class TodoController {
protected readonly todos = new Map<number, Todo>();
protected nextId = 1;
@Get()
list(): Todo[] {
return [...this.todos.values()];
}
@Get(':id')
get(@Param('id') id: number): Todo {
const todo = this.todos.get(id);
if (!todo) {
throw new NotFoundError(`No todo ${id}`); // 404
}
return todo; // 对象以 JSON 返回
}
@Post()
create(@Body('title') title: string): Todo {
const todo = { id: this.nextId++, title };
this.todos.set(todo.id, todo);
return todo;
}
@Delete(':id')
remove(@Param('id') id: number): void {
this.todos.delete(id);
}
}ts
// src/node/module.ts
import './home-controller';
import './todo-controller';
import { autoBind } from '@celljs/core';
export default autoBind();@celljs/web 是 @celljs/mvc 的依赖;直接从它导入时,也把它加进 package.json(npm install @celljs/web)。
bash
curl -X POST localhost:3000/todos -H 'content-type: application/json' -d '{"title":"write docs"}'
curl localhost:3000/todos/1状态变多时把它移到服务里,见组件与依赖注入。控制器的装饰器列在 HTTP 接口。
配置
cell.yml 保存应用配置。组件的配置项(server.port 等)写在顶层,你自己的配置写在 app 下;配置默认只在服务端,只有 app.public 和组件标记为 public 的键会进浏览器:
yaml
app:
greeting: Hello from my-app
todos:
max: ${(env.TODOS_MAX ?? 100) * 1} # 服务端启动时求值;app 下的键没有 schema 类型,* 1 把环境变量的文本转成数字ts
@Value('app.todos.max')
protected readonly max: number;npx cell config get app.todos.max --why 给出合并后的值,以及设置过它的每个文件和环境变量。详见项目结构与配置。
检查与测试
bash
npx cell check # TypeScript、配置、装饰器设置、DI 绑定
bun test # test/ 下的测试ts
// test/todo.spec.ts
import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
import { join } from 'node:path';
import { createTestApp, type TestApp } from '@celljs/cli';
describe('todos', () => {
let app: TestApp;
beforeAll(async () => { app = await createTestApp({ root: join(__dirname, '..') }); }, 60000);
afterAll(() => app?.close());
it('creates a todo', async () => {
const res = await app.fetch('/todos', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{"title":"a"}' });
expect(await res.json()).toEqual({ id: 1, title: 'a' });
});
});createTestApp() 在测试进程里启动整个应用,不监听端口。见测试与检查。
构建与运行
bash
npx cell build # .cell/output/server/index.mjs:内联了全部依赖的单个文件
npx cell preview # 按生产环境的方式运行产物
node .cell/output/server/index.mjs--single 把前端也放进这一个文件,--compile 生成不需要 Node.js 的可执行文件。
部署
bash
npx cell deploy --preset cloudflare --dry-run # 只给出计划,不上传
npx cell deploy --preset cloudflarepreset 有 node(默认)、cli、cloudflare、fc、scf、lambda 和 vercel。见构建与部署。
下一步
- 组件目录:数据库、缓存、定时任务、安全、AI 等需求该加哪个
@celljs/*包。 - 与 Coding Agent 协作:
cell init生成的 AGENTS.md、skill 和 MCP 工具。