@tbox.cn/app-template-h5 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +10 -6
- package/README.md +1 -1
- package/apps/client/vite.config.ts +4 -0
- package/apps/server/src/dev.ts +1 -1
- package/package.json +4 -3
- package/pnpm-lock.template.yaml +34 -16
- package/pnpm-workspace.template.yaml +4 -4
- package/scripts/check-workspace.mjs +24 -0
- package/apps/client/src/business/App.test.tsx +0 -18
package/AGENTS.md
CHANGED
|
@@ -13,23 +13,26 @@ template-h5 是面向 AI 生成 H5 应用的单 workspace 模板:`apps/client`
|
|
|
13
13
|
## 运行与验证(平台沙箱)
|
|
14
14
|
|
|
15
15
|
应用构建与运行在平台沙箱中,启动/停止/重启由平台负责——不要运行 `pnpm dev` 等长驻进程
|
|
16
|
-
|
|
17
|
-
验证:
|
|
16
|
+
命令。你只改代码与配置,用一次性命令验证:
|
|
18
17
|
|
|
19
18
|
```sh
|
|
20
19
|
pnpm install # 会话开始时 node_modules 缺失先装
|
|
21
20
|
pnpm typecheck
|
|
22
21
|
pnpm test
|
|
23
|
-
pnpm build
|
|
24
|
-
pnpm verify # typecheck + test + lint + build + check:inspector
|
|
22
|
+
pnpm verify:fast # typecheck + test + check(不含 build/lint)
|
|
25
23
|
pnpm check:inspector # inspector 接线守卫(随 @tbox.cn/app-sdk-server 分发)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **编译验证 = typecheck**;运行效果看平台托管的 8000 活体(`curl /api/health`,连接被拒 ≠ 应用损坏)。
|
|
27
|
+
- **不要运行 `pnpm build` / `pnpm verify`**:冷构建超过沙箱命令时限,且 dev 不消费 `dist`。
|
|
28
|
+
- 环境变量见 [README.md](README.md) 的「环境变量」节。
|
|
26
29
|
|
|
27
30
|
## SDK 复用点(优先复用,勿手写)
|
|
28
31
|
|
|
29
32
|
- `@tbox.cn/app-sdk-client`:`configureRuntime`(API base 注入,勿硬编码 host)、`httpGet/httpPost/createService`(HTTP 客户端)、`ErrorBoundary`、`createLogger`、`installGlobalErrorReporting`
|
|
30
33
|
- `@tbox.cn/app-sdk-server`:`createLogger`
|
|
31
34
|
- `@tbox.cn/app-sdk-server/platform`:`installInspector`;vite `code-inspect` 插件入口为 `@tbox.cn/app-sdk-client/platform/code-inspect`(页面微调基线,受 `check:inspector` 守卫)
|
|
32
|
-
- 不直接 import `@tbox-dev-js/sdk`——平台能力一律经 `@tbox.cn/app-sdk-client` / `@tbox.cn/app-sdk-server`
|
|
35
|
+
- 不直接 import `@tbox-dev-js/sdk`——平台能力一律经 `@tbox.cn/app-sdk-client` / `@tbox.cn/app-sdk-server` 公开入口。
|
|
33
36
|
|
|
34
37
|
## 关键入口
|
|
35
38
|
|
|
@@ -46,6 +49,7 @@ apps/server/src/dev.ts # vite dev 入口(仅 tsx 运行;
|
|
|
46
49
|
- 单端口 8000(dev 与生产统一;端口经 `process.env.PORT || 8000`,lint 禁止硬编码)
|
|
47
50
|
- `installInspector` 接线 + `apps/client/index.html` 的 `/__vs_inspector__.js` 标签(页面微调契约)
|
|
48
51
|
- `GET /api/health` 恒返回 `{ "status": "ok" }`;未知 `/api/*` 恒 JSON 404
|
|
52
|
+
- `apps/server/tests` 契约测试随模板分发勿删(health/JSON 404 断言);client 业务面测试由应用自建——模板出厂零 client 测试文件(`passWithNoTests` 保绿,新增测试后本约定不变)
|
|
49
53
|
- 服务端凭证/环境变量不进 client bundle(客户端环境值仅 `import.meta.env.VITE_*` 且经 `configureRuntime` 注入)
|
|
50
54
|
|
|
51
55
|
## web-view 样式约定(嵌入支付宝小程序 web-view 壳时遵守)
|
|
@@ -58,6 +62,6 @@ apps/server/src/dev.ts # vite dev 入口(仅 tsx 运行;
|
|
|
58
62
|
## 边界
|
|
59
63
|
|
|
60
64
|
- 保持单 workspace 的 `apps/client` + `apps/server` 两成员;不新增 `apps/client/` 之外的 Vite 配置或嵌套 lockfile(`pnpm check:workspace` 校验)。
|
|
61
|
-
- 无模块/Provider/主题装配面:缺双端 `apps/*/src/modules.ts`——`tbox-
|
|
65
|
+
- 无模块/Provider/主题装配面:缺双端 `apps/*/src/modules.ts`——`npx --yes @tbox.cn/app-cli module add`、`npx --yes @tbox.cn/app-cli new module`、`npx --yes @tbox.cn/app-cli new provider` 会被 CLI 直接拒绝;`npx --yes @tbox.cn/app-cli theme use` 因无主题接线点也不适用。
|
|
62
66
|
- 模板不预设端形态(移动/桌面/自适应)——适配策略由应用自定;全局样式挂点 = `apps/client/src/styles/base.css`(仅设备无关卫生规则)。
|
|
63
67
|
- 结构、路由、命令、依赖或环境变量变化时同步 README 与本文件。
|
package/README.md
CHANGED
|
@@ -18,4 +18,8 @@ export default defineConfig(({ command }) => ({
|
|
|
18
18
|
build: {
|
|
19
19
|
rollupOptions: { input: { index: resolve(__dirname, 'index.html') } },
|
|
20
20
|
},
|
|
21
|
+
// 模板出厂零 client 测试文件:随发测试禁钉用户实施面(business/App.tsx 是用户首个改写对象,
|
|
22
|
+
// 出厂断言其内容必随应用构建失败——testing/2026-10-20-template-shipped-test-boundary.md);
|
|
23
|
+
// 新增客户端测试时移除本旗标。
|
|
24
|
+
test: { passWithNoTests: true },
|
|
21
25
|
}));
|
package/apps/server/src/dev.ts
CHANGED
|
@@ -72,7 +72,7 @@ const vite = await createViteServer({
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
const runtime = createTboxDevRuntime({
|
|
75
|
-
vite: { middlewares: vite.middlewares, transformIndexHtml: vite.transformIndexHtml },
|
|
75
|
+
vite: { middlewares: vite.middlewares, transformIndexHtml: vite.transformIndexHtml, ws: vite.ws },
|
|
76
76
|
hmrHub,
|
|
77
77
|
hmrPath: path.posix.join(vite.config.base, HMR_WS_PATH),
|
|
78
78
|
tokenState,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-template-h5",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "tbox H5 全栈模板(单 workspace:apps/client + apps/server),运行时与页面微调经 @tbox.cn/app-sdk。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"eslint-plugin-react-hooks": "5.2.0",
|
|
36
36
|
"typescript-eslint": "8.67.0",
|
|
37
37
|
"vite": "6.4.3",
|
|
38
|
-
"@tbox.cn/app-sdk-server": "0.26.
|
|
38
|
+
"@tbox.cn/app-sdk-server": "0.26.2"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"dev": "pnpm --filter ./apps/server dev",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"verify": "pnpm typecheck && pnpm test && pnpm lint && pnpm build && pnpm check:inspector",
|
|
48
48
|
"check": "pnpm check:workspace && pnpm check:inspector",
|
|
49
49
|
"check:workspace": "node scripts/check-workspace.mjs",
|
|
50
|
-
"check:inspector": "tbox-inspector-check"
|
|
50
|
+
"check:inspector": "tbox-inspector-check",
|
|
51
|
+
"verify:fast": "pnpm typecheck && pnpm test && pnpm check"
|
|
51
52
|
}
|
|
52
53
|
}
|
package/pnpm-lock.template.yaml
CHANGED
|
@@ -10,8 +10,8 @@ catalogs:
|
|
|
10
10
|
specifier: 0.21.3
|
|
11
11
|
version: 0.21.3
|
|
12
12
|
'@tbox.cn/app-sdk-server':
|
|
13
|
-
specifier: 0.26.
|
|
14
|
-
version: 0.26.
|
|
13
|
+
specifier: 0.26.2
|
|
14
|
+
version: 0.26.2
|
|
15
15
|
'@types/express':
|
|
16
16
|
specifier: 4.17.25
|
|
17
17
|
version: 4.17.25
|
|
@@ -79,7 +79,7 @@ importers:
|
|
|
79
79
|
devDependencies:
|
|
80
80
|
'@tbox.cn/app-sdk-server':
|
|
81
81
|
specifier: 'catalog:'
|
|
82
|
-
version: 0.26.
|
|
82
|
+
version: 0.26.2
|
|
83
83
|
eslint:
|
|
84
84
|
specifier: 'catalog:'
|
|
85
85
|
version: 9.39.5
|
|
@@ -134,7 +134,7 @@ importers:
|
|
|
134
134
|
dependencies:
|
|
135
135
|
'@tbox.cn/app-sdk-server':
|
|
136
136
|
specifier: 'catalog:'
|
|
137
|
-
version: 0.26.
|
|
137
|
+
version: 0.26.2
|
|
138
138
|
express:
|
|
139
139
|
specifier: 'catalog:'
|
|
140
140
|
version: 4.22.2
|
|
@@ -959,8 +959,12 @@ packages:
|
|
|
959
959
|
resolution: {integrity: sha512-8sqP/23MoUlbTX9enFNotP5bu7XKFfigDUJ6sEn1Ff2a0rRlSTWzLWmDv9lP70cfZMPjh4MHoLKFoukr8QPvMA==}
|
|
960
960
|
engines: {node: '>=20.0.0'}
|
|
961
961
|
|
|
962
|
-
'@tbox.cn/app-contracts@0.13.
|
|
963
|
-
resolution: {integrity: sha512-
|
|
962
|
+
'@tbox.cn/app-contracts@0.13.2':
|
|
963
|
+
resolution: {integrity: sha512-0lY9g29ice7xYbmV5XDnEiMmM70jvSzeK2cciUZVpzHgGykWqZiPRlqXIGkIRY7uObDQ1cICHC4mS67HuNQ8Jg==}
|
|
964
|
+
engines: {node: '>=20.0.0'}
|
|
965
|
+
|
|
966
|
+
'@tbox.cn/app-contracts@0.13.3':
|
|
967
|
+
resolution: {integrity: sha512-P16LFd+ZzIASrujs6fyaOEwRnsLg7Lh5k1qOVDNblmohrvUbVIOK5ntn+7mupJxnjK7SY43RUT4mtWtfM85/rQ==}
|
|
964
968
|
engines: {node: '>=20.0.0'}
|
|
965
969
|
|
|
966
970
|
'@tbox.cn/app-sdk-client@0.21.3':
|
|
@@ -971,13 +975,17 @@ packages:
|
|
|
971
975
|
resolution: {integrity: sha512-4kcoxnZnPgsO0RwAsjsodOXRhZNQcr9r3INN3Z03/JR2e3E+izkW2YHsgGcdbVSVX81s8gZrkaBbE+xco3wSqg==}
|
|
972
976
|
engines: {node: '>=20.0.0'}
|
|
973
977
|
|
|
974
|
-
'@tbox.cn/app-sdk-
|
|
975
|
-
resolution: {integrity: sha512-
|
|
978
|
+
'@tbox.cn/app-sdk-core@0.20.5':
|
|
979
|
+
resolution: {integrity: sha512-HLLRg1y2jB32uJPL3/a387eABdNZUxrmkGoJwIv44XV9B94DXmTgb9vxYzbyBa0FazxXG0WudyzFnmH5eeqqrw==}
|
|
980
|
+
engines: {node: '>=20.0.0'}
|
|
981
|
+
|
|
982
|
+
'@tbox.cn/app-sdk-server@0.26.2':
|
|
983
|
+
resolution: {integrity: sha512-TY9oo3VnsHtLv5im9eu9UUBzDJoluk/YRR7MFwU98G1ZzUDoSLagelb0kamhx5j/R9sXZjwV0NY3Kv6dz/WVmw==}
|
|
976
984
|
engines: {node: '>=20.0.0'}
|
|
977
985
|
hasBin: true
|
|
978
986
|
|
|
979
|
-
'@tbox.cn/app-toolkit@0.8.
|
|
980
|
-
resolution: {integrity: sha512-
|
|
987
|
+
'@tbox.cn/app-toolkit@0.8.3':
|
|
988
|
+
resolution: {integrity: sha512-i+rz8tUwndygwCw/T5dp/59p2JKW+Xpfy2UznKOY8vuKbqbe2ANCUTDUuNf8IDuyfvy158Iw/+5H/hLVNAD/3w==}
|
|
981
989
|
engines: {node: '>=20.0.0'}
|
|
982
990
|
|
|
983
991
|
'@types/babel__core@7.20.5':
|
|
@@ -2823,7 +2831,13 @@ snapshots:
|
|
|
2823
2831
|
react: 18.3.1
|
|
2824
2832
|
zod: 3.25.76
|
|
2825
2833
|
|
|
2826
|
-
'@tbox.cn/app-contracts@0.13.
|
|
2834
|
+
'@tbox.cn/app-contracts@0.13.2':
|
|
2835
|
+
dependencies:
|
|
2836
|
+
'@ag-ui/core': 0.0.47
|
|
2837
|
+
react: 18.3.1
|
|
2838
|
+
zod: 3.25.76
|
|
2839
|
+
|
|
2840
|
+
'@tbox.cn/app-contracts@0.13.3':
|
|
2827
2841
|
dependencies:
|
|
2828
2842
|
'@ag-ui/core': 0.0.47
|
|
2829
2843
|
react: 18.3.1
|
|
@@ -2840,19 +2854,23 @@ snapshots:
|
|
|
2840
2854
|
dependencies:
|
|
2841
2855
|
'@tbox.cn/app-contracts': 0.13.0
|
|
2842
2856
|
|
|
2843
|
-
'@tbox.cn/app-sdk-
|
|
2857
|
+
'@tbox.cn/app-sdk-core@0.20.5':
|
|
2858
|
+
dependencies:
|
|
2859
|
+
'@tbox.cn/app-contracts': 0.13.2
|
|
2860
|
+
|
|
2861
|
+
'@tbox.cn/app-sdk-server@0.26.2':
|
|
2844
2862
|
dependencies:
|
|
2845
2863
|
'@ag-ui/core': 0.0.47
|
|
2846
|
-
'@tbox.cn/app-contracts': 0.13.
|
|
2847
|
-
'@tbox.cn/app-sdk-core': 0.20.
|
|
2848
|
-
'@tbox.cn/app-toolkit': 0.8.
|
|
2864
|
+
'@tbox.cn/app-contracts': 0.13.3
|
|
2865
|
+
'@tbox.cn/app-sdk-core': 0.20.5
|
|
2866
|
+
'@tbox.cn/app-toolkit': 0.8.3
|
|
2849
2867
|
express: 4.22.2
|
|
2850
2868
|
jose: 6.2.8
|
|
2851
2869
|
zod: 3.25.76
|
|
2852
2870
|
transitivePeerDependencies:
|
|
2853
2871
|
- supports-color
|
|
2854
2872
|
|
|
2855
|
-
'@tbox.cn/app-toolkit@0.8.
|
|
2873
|
+
'@tbox.cn/app-toolkit@0.8.3':
|
|
2856
2874
|
dependencies:
|
|
2857
2875
|
ajv: 8.20.0
|
|
2858
2876
|
zod: 3.25.76
|
|
@@ -35,11 +35,11 @@ catalog:
|
|
|
35
35
|
"@types/express": 4.17.25
|
|
36
36
|
"@tbox.cn/app-sdk-core": 0.20.5
|
|
37
37
|
"@tbox.cn/app-sdk-client": 0.21.3
|
|
38
|
-
"@tbox.cn/app-sdk-server": 0.26.
|
|
39
|
-
"@tbox.cn/app-agent-sdk-server": 0.3.
|
|
38
|
+
"@tbox.cn/app-sdk-server": 0.26.2
|
|
39
|
+
"@tbox.cn/app-agent-sdk-server": 0.3.3
|
|
40
40
|
"@tbox.cn/app-agent-sdk-client": 0.2.0
|
|
41
|
-
"@tbox.cn/app-contracts": 0.13.
|
|
42
|
-
"@tbox.cn/app-contracts-mall": 0.13.
|
|
41
|
+
"@tbox.cn/app-contracts": 0.13.3
|
|
42
|
+
"@tbox.cn/app-contracts-mall": 0.13.2
|
|
43
43
|
eslint: 9.39.5
|
|
44
44
|
typescript-eslint: 8.67.0
|
|
45
45
|
eslint-plugin-react-hooks: 5.2.0
|
|
@@ -31,6 +31,24 @@ const nestedLockfiles = new Set([
|
|
|
31
31
|
]);
|
|
32
32
|
const viteConfigPattern = /^vite\.config\.(?:js|mjs|cjs|ts|mts|cts)$/;
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* CLI 裸简写防线:应用文档里不得出现 `tbox-app <cmd>`(agent 照抄后 PATH 无 bin → 命令失败)。
|
|
36
|
+
* 唯一合法形态 = `npx --yes @tbox.cn/app-cli <cmd>`;`tbox-app-dev`(私有 CLI)不匹配。
|
|
37
|
+
*/
|
|
38
|
+
const bareCliPattern = /\btbox-app\s+(?:module|provider|theme|starter|new|create|schema|skills|doctor|miniapp-container)\b/g;
|
|
39
|
+
const cliDocFiles = ['AGENTS.md', 'README.md', 'ENV.md'];
|
|
40
|
+
|
|
41
|
+
async function checkCliShorthand(findings) {
|
|
42
|
+
for (const rel of cliDocFiles) {
|
|
43
|
+
const file = path.join(projectDir, rel);
|
|
44
|
+
if (!existsSync(file)) continue;
|
|
45
|
+
const text = await readFile(file, 'utf8');
|
|
46
|
+
for (const match of text.matchAll(bareCliPattern)) {
|
|
47
|
+
findings.bareCliShorthands.push(`${rel}: ${match[0]}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
function relativeDir(filePath) {
|
|
35
53
|
const relative = path.relative(projectDir, path.dirname(filePath));
|
|
36
54
|
return relative === '' ? '.' : relative.split(path.sep).join('/');
|
|
@@ -74,6 +92,10 @@ function printFailure(findings) {
|
|
|
74
92
|
console.error('\n检测到 apps/client/ 之外的 Vite 项目配置:');
|
|
75
93
|
for (const file of findings.detachedViteConfigs) console.error(` - ${file}`);
|
|
76
94
|
}
|
|
95
|
+
if (findings.bareCliShorthands.length > 0) {
|
|
96
|
+
console.error('\n检测到 CLI 裸简写(须写全 npx --yes @tbox.cn/app-cli <cmd>):');
|
|
97
|
+
for (const item of findings.bareCliShorthands) console.error(` - ${item}`);
|
|
98
|
+
}
|
|
77
99
|
|
|
78
100
|
console.error('');
|
|
79
101
|
process.exitCode = 1;
|
|
@@ -102,9 +124,11 @@ async function main() {
|
|
|
102
124
|
const findings = {
|
|
103
125
|
nestedLockfiles: [],
|
|
104
126
|
detachedViteConfigs: [],
|
|
127
|
+
bareCliShorthands: [],
|
|
105
128
|
};
|
|
106
129
|
|
|
107
130
|
await walk(projectDir, findings);
|
|
131
|
+
await checkCliShorthand(findings);
|
|
108
132
|
|
|
109
133
|
if (Object.values(findings).some((items) => items.length > 0)) {
|
|
110
134
|
printFailure(findings);
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// @vitest-environment happy-dom
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { createRoot } from 'react-dom/client';
|
|
4
|
-
import { flushSync } from 'react-dom';
|
|
5
|
-
import { createElement } from 'react';
|
|
6
|
-
import BusinessApp from './App';
|
|
7
|
-
|
|
8
|
-
describe('BusinessApp', () => {
|
|
9
|
-
it('渲染中性入口', () => {
|
|
10
|
-
const container = document.createElement('div');
|
|
11
|
-
document.body.appendChild(container);
|
|
12
|
-
flushSync(() => {
|
|
13
|
-
createRoot(container).render(createElement(BusinessApp));
|
|
14
|
-
});
|
|
15
|
-
expect(container.querySelector('main')?.textContent).toBe('应用从这里开始');
|
|
16
|
-
container.remove();
|
|
17
|
-
});
|
|
18
|
-
});
|