The journal now owns command history and tracking, so retire the md-commander widget. Its dice engine was extracted to src/components/dice in the previous commit. Removes the custom element, tracker/command stores, completions, useCommander, Emmet parser, the doc entry, test fixtures, and the known-element catalog entry (reference docs regenerated). BREAKING CHANGE: :md-commander is no longer a known element; content using it now fails tttk check with TTTK-D001.
334 lines
7.8 KiB
Markdown
334 lines
7.8 KiB
Markdown
# 开发和项目说明
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 安装依赖
|
||
npm install
|
||
|
||
# 开发模式(同时启动 CLI 内容服务器 :3000 与 Web 前端 :5173)
|
||
npm run dev
|
||
|
||
# 也可分别启动
|
||
npm run dev:cli
|
||
npm run dev:web
|
||
|
||
# 构建(Web)
|
||
npm run build
|
||
|
||
# 预览构建结果
|
||
npm run preview
|
||
|
||
# CLI 开发模式
|
||
npm run cli:dev
|
||
|
||
# CLI 构建
|
||
npm run cli:build
|
||
|
||
# 运行测试
|
||
npm test
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
tttk/
|
||
├── src/
|
||
│ ├── cli/ # CLI 工具源码
|
||
│ │ ├── commands/ # 命令实现 (serve, check, compile)
|
||
│ │ ├── validate/ # tttk check 校验器(扫描、规则、诊断)
|
||
│ │ ├── content-registry.ts # 内容注册表(CLI / 前端共享)
|
||
│ │ ├── content-index.ts # 目录文件递归读取
|
||
│ │ ├── index.ts # CLI 入口
|
||
│ │ └── types.ts # 类型定义
|
||
│ ├── components/ # TTRPG 组件
|
||
│ │ ├── md-dice.tsx # 骰子组件
|
||
│ │ ├── md-table.tsx # 表格组件
|
||
│ │ ├── md-deck/ # 卡牌组件
|
||
│ │ ├── md-pins.tsx # 标记组件
|
||
│ │ ├── md-yarn-spinner.tsx # 叙事线组件
|
||
|
||
│ │ ├── Article.tsx # 文章组件
|
||
│ │ ├── Sidebar.tsx # 侧边栏
|
||
│ │ ├── FileTree.tsx # 文件树
|
||
│ │ └── utils/ # 工具函数
|
||
│ ├── markdown/ # Markdown 解析器
|
||
│ │ ├── index.ts # marked 配置
|
||
│ │ └── mermaid.ts # mermaid 支持
|
||
│ ├── data-loader/ # 数据加载器
|
||
│ ├── plotcutter/ # 剧情切割工具
|
||
│ ├── yarn-spinner/ # 叙事线解析
|
||
│ ├── App.tsx # 主应用
|
||
│ ├── main.tsx # 入口文件
|
||
│ ├── styles.css # 样式
|
||
│ ├── index.html # HTML 模板
|
||
│ └── global.d.ts # 类型声明
|
||
├── .agents/
|
||
│ └── skills/
|
||
│ └── tttk-authoring/ # 随项目维护的 agent skill(见下文)
|
||
├── bin/
|
||
│ └── cli/ # CLI 二进制文件
|
||
├── content/ # 示例内容
|
||
├── docs/ # 文档
|
||
├── package.json
|
||
├── tsconfig.json
|
||
├── tsconfig.cli.json
|
||
├── rsbuild.config.ts
|
||
└── jest.config.js
|
||
```
|
||
|
||
## Agent skills
|
||
|
||
`tttk-authoring` skill 由本项目维护,源码位于
|
||
`.agents/skills/tttk-authoring/`。要让 agent 加载它,把全局 skill 目录
|
||
链接到仓库内的副本:
|
||
|
||
```bash
|
||
# Windows(无需管理员权限的目录联接)
|
||
cmd //c mklink /J %USERPROFILE%\.agents\skills\tttk-authoring "%CD%\.agents\skills\tttk-authoring"
|
||
|
||
# macOS / Linux
|
||
ln -s "$PWD/.agents/skills/tttk-authoring" ~/.agents/skills/tttk-authoring
|
||
```
|
||
|
||
`reference.md` 由 `known.ts` 生成,不要手改:
|
||
|
||
```bash
|
||
npm run gen:skill-reference
|
||
```
|
||
|
||
其余文件(`SKILL.md`、`yaml-tag.md`、`csv.md`、`layout.md`、`markdown.md`)
|
||
为手写内容。
|
||
|
||
## 技术栈
|
||
|
||
| 类别 | 技术 |
|
||
|------|------|
|
||
| 前端框架 | Solid.js 1.9+ |
|
||
| 构建工具 | Rsbuild |
|
||
| 样式 | Tailwind CSS 4 + @tailwindcss/typography |
|
||
| Markdown | marked + marked-directive + marked-alert + marked-gfm-heading-id |
|
||
| 图表 | mermaid |
|
||
|
||
| 测试 | Jest |
|
||
| CLI | commander + chokidar |
|
||
|
||
## 开发规范
|
||
|
||
### Solid.js 最佳实践
|
||
|
||
- **优先使用 `createEffect` 和 `createMemo`** 实现响应式
|
||
- 在 JSX 中直接引用 `props` 保持响应式
|
||
- 避免滥用 `onMount` + `createSignal`
|
||
|
||
```tsx
|
||
// ✅ 推荐
|
||
const doubled = createMemo(() => count() * 2);
|
||
createEffect(() => console.log(count()));
|
||
|
||
// ❌ 避免
|
||
onMount(() => {
|
||
const [value, setValue] = createSignal(0);
|
||
});
|
||
```
|
||
|
||
### 组件开发
|
||
|
||
- **不使用 Shadow DOM**:使用 `noShadowDOM()`
|
||
- **继承 Tailwind CSS 样式系统**
|
||
- 使用 `customElement` 注册自定义元素
|
||
|
||
```tsx
|
||
import { customElement, noShadowDOM } from "solid-element";
|
||
|
||
customElement("md-dice", { key: "" }, (props, { element }) => {
|
||
noShadowDOM();
|
||
// 组件逻辑
|
||
});
|
||
```
|
||
|
||
### 类型检查
|
||
|
||
开发完成后检查类型错误:
|
||
|
||
```bash
|
||
npx tsc --noEmit
|
||
```
|
||
|
||
### 代码风格
|
||
|
||
- 使用 TypeScript 严格模式
|
||
- 遵循 ESLint 配置(如有)
|
||
- 使用 2 空格缩进
|
||
|
||
## 添加新组件
|
||
|
||
### 1. 创建组件文件
|
||
|
||
```tsx
|
||
// src/components/md-new-component.tsx
|
||
import { customElement, noShadowDOM } from "solid-element";
|
||
import { createSignal } from "solid-js";
|
||
|
||
export interface NewComponentProps {
|
||
prop1?: string;
|
||
}
|
||
|
||
customElement("md-new-component", { prop1: "" }, (props, { element }) => {
|
||
noShadowDOM();
|
||
|
||
const [state, setState] = createSignal("");
|
||
|
||
return (
|
||
<div class="new-component">
|
||
{/* 组件内容 */}
|
||
</div>
|
||
);
|
||
});
|
||
```
|
||
|
||
### 2. 注册组件
|
||
|
||
```tsx
|
||
// src/components/index.ts
|
||
import './md-new-component';
|
||
```
|
||
|
||
### 3. 导出类型(可选)
|
||
|
||
```tsx
|
||
// src/components/index.ts
|
||
export type { NewComponentProps } from './md-new-component';
|
||
```
|
||
|
||
## 构建配置
|
||
|
||
### Rsbuild 配置
|
||
|
||
```ts
|
||
// rsbuild.config.ts
|
||
import { defineConfig } from '@rsbuild/core';
|
||
import { pluginBabel } from '@rsbuild/plugin-babel';
|
||
import { pluginSolid } from '@rsbuild/plugin-solid';
|
||
import tailwindcss from '@tailwindcss/postcss';
|
||
|
||
export default defineConfig({
|
||
plugins: [pluginBabel(), pluginSolid()],
|
||
tools: {
|
||
postcss: {
|
||
postcssOptions: {
|
||
plugins: [tailwindcss()],
|
||
},
|
||
},
|
||
},
|
||
html: {
|
||
template: './src/index.html',
|
||
},
|
||
});
|
||
```
|
||
|
||
### TypeScript 配置
|
||
|
||
- `tsconfig.json` - 主项目配置(Web)
|
||
- `tsconfig.cli.json` - CLI 工具配置(Node.js)
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
npm test
|
||
|
||
# 运行特定测试文件
|
||
npm test -- src/components/md-dice.test.ts
|
||
|
||
# 监听模式
|
||
npm test -- --watch
|
||
```
|
||
|
||
## 调试
|
||
|
||
开发环境由两个进程组成,必须使用不同端口:
|
||
|
||
- Web 前端:rsbuild 开发服务器,端口 **5173**
|
||
- CLI 内容服务器:`tttk serve`,端口 **3000**(内容 API + Journal)
|
||
|
||
rsbuild 会把 `/__CONTENT_INDEX.json`、`/__COMPLETIONS.json`、`/__CONTENT_REGISTRY.json`、`/content`、`/.ttrpg` 代理到 CLI 的
|
||
3000 端口,因此必须先启动 CLI,否则前端拿不到内容。
|
||
|
||
### Web 开发
|
||
|
||
`npm run dev` 会同时启动两个进程;也可以分开运行:
|
||
|
||
```bash
|
||
# 同时启动 CLI(3000)与 Web(5173)
|
||
npm run dev
|
||
|
||
# 或分别启动
|
||
npm run dev:cli # CLI 内容服务器,占用 3000
|
||
npm run dev:web # Web 前端,占用 5173
|
||
# 访问 http://localhost:5173
|
||
```
|
||
|
||
### CLI 调试
|
||
|
||
CLI 通过 ts-node 运行,加上 `--inspect` 与 `--enable-source-maps` 后即可在编辑器中附加断点。
|
||
如需调试启动/扫描逻辑,用 `--inspect-brk` 在用户代码执行前暂停:
|
||
|
||
```bash
|
||
node --inspect-brk --enable-source-maps --loader ts-node/esm ./src/cli/index.ts serve ./content
|
||
|
||
# 或使用脚本(不带 --inspect-brk)
|
||
npm run tttk:inspect -- serve ./content
|
||
```
|
||
|
||
然后在 Zed / VS Code 中附加到 `localhost:9229`,或打开 `chrome://inspect`。
|
||
|
||
CLI 只监听内容目录(`.md`/`.csv`/`.yarn`/`.svg`)并重建内存中的注册表,**不会**热重载自身源码;
|
||
修改 `src/cli/**` 后需要重启进程。
|
||
|
||
```bash
|
||
# 或构建后运行
|
||
npm run cli:build
|
||
node dist/cli/index.js serve ./content
|
||
```
|
||
|
||
## 发布流程
|
||
|
||
1. 更新版本号
|
||
2. 运行测试和类型检查
|
||
3. 构建 Web 和 CLI
|
||
4. 发布到 npm
|
||
|
||
```bash
|
||
npm run build
|
||
npm run cli:build
|
||
npm test
|
||
npx tsc --noEmit
|
||
npm publish
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### Windows 换行符
|
||
|
||
开发环境主要在 Windows 上,注意使用 CRLF 换行符。
|
||
|
||
### 依赖安装失败
|
||
|
||
```bash
|
||
# 清理缓存
|
||
npm cache clean --force
|
||
rm -rf node_modules package-lock.json
|
||
npm install
|
||
```
|
||
|
||
### 构建错误
|
||
|
||
```bash
|
||
# 检查类型
|
||
npx tsc --noEmit
|
||
|
||
# 重新构建
|
||
npm run build
|
||
```
|