@lark-apaas/coding-templates 0.1.23 → 0.1.24

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/README.md CHANGED
@@ -4,39 +4,32 @@ OpenClaw 项目模板包,供 mclaw CLI 使用。
4
4
 
5
5
  ## 模板列表
6
6
 
7
- | 模板 | 目录 | 说明 |
8
- |---|---|---|
9
- | html | `template-html/` | 纯 HTML,零依赖,原型验证 |
10
- | vite-react | `template-vite-react/` | Vite + React 19 + Tailwind CSS + shadcn/ui |
7
+ | 模板 | 目录 | 类型 | 说明 |
8
+ |---|---|---|---|
9
+ | html | `template-html/` | 纯前端 | 纯 HTML,零依赖,原型验证 |
10
+ | vite-react | `template-vite-react/` | 纯前端 | Vite + React 19 + Tailwind CSS + shadcn/ui |
11
+ | apex | `template-apex/` | 全栈 | Vite + React + Express + Drizzle + PostgreSQL |
11
12
 
12
13
  ## 包结构
13
14
 
14
15
  ```
15
16
  coding-templates/
16
- ├── package.json # npm 包定义(@lark-apaas/coding-templates)
17
- ├── meta.json # 模板元数据(业务侧生成,名称/描述/特性标签)
17
+ ├── package.json
18
+ ├── meta.json # 模板元数据
18
19
  ├── template-html/
19
- ├── _gitignore
20
- │ ├── package.json # mclaw.stack: "html"
21
- │ └── index.html
22
- └── template-vite-react/
23
- ├── _gitignore # CLI 复制时重命名为 .gitignore
24
- ├── package.json # mclaw.stack: "vite-react",name 为 {{projectName}}
25
- ├── vite.config.ts
26
- ├── eslint.config.js
27
- ├── components.json
28
- ├── client/
20
+ ├── template-vite-react/
21
+ └── template-apex/
22
+ ├── client/ # 前端(Vite + React)
29
23
  │ ├── index.html
30
- │ ├── public/
31
24
  │ └── src/
32
- ├── app.tsx # 路由注册
33
- ├── index.css # 全局样式 + 主题变量
34
- ├── components/ui/ # shadcn/ui 组件(new-york 风格)
35
- ├── pages/
36
- ├── hooks/
37
- │ └── lib/
38
- └── shared/ # 前后端共享代码
39
- └── types.ts
25
+ ├── server/ # 后端(Express + Drizzle)
26
+ ├── index.ts
27
+ ├── db/
28
+ └── routes/
29
+ ├── shared/ # 前后端共享类型和 API 契约
30
+ ├── scripts/build.sh # 构建脚本
31
+ ├── tsconfig.server.json # 服务端 CJS 编译配置
32
+ └── vite.config.ts
40
33
  ```
41
34
 
42
35
  ## 特殊文件命名
@@ -48,28 +41,45 @@ npm publish 会忽略 `.gitignore` 和 `.env*`,因此模板中使用 `_` 前
48
41
  | `_gitignore` | `.gitignore` |
49
42
  | `_env.local` | `.env.local` |
50
43
 
51
- ## 模板类型标识
44
+ ## 模板元数据
52
45
 
53
- 每个模板的 `package.json` 包含 `mclaw.stack` 字段,标识模板类型:
46
+ 每个模板的 `package.json` 包含 `mclaw` 字段:
54
47
 
55
48
  ```json
56
49
  {
57
50
  "mclaw": {
58
- "stack": "vite-react",
59
- "stackVersion": "0.1.0"
51
+ "stack": "apex",
52
+ "stackVersion": "0.1.0",
53
+ "features": ["client", "server"]
60
54
  }
61
55
  }
62
56
  ```
63
57
 
58
+ | 字段 | 说明 |
59
+ |---|---|
60
+ | `stack` | 技术栈标识 |
61
+ | `stackVersion` | 模板版本 |
62
+ | `features` | 应用能力,`init` 时自动推导 archType |
63
+
64
64
  ## 技术栈
65
65
 
66
- vite-react 模板技术选型:
66
+ ### apex(全栈)
67
+
68
+ - **前端**: Vite 8 + React 19 + TypeScript 5.9 + Tailwind CSS 4 + shadcn/ui
69
+ - **后端**: Express 5 + Drizzle ORM + PostgreSQL
70
+ - **平台集成**: @lark-apaas/express-core(用户上下文、CSRF、RLS、viewContext)
71
+ - **开发**: Vite middleware mode 集成到 Express,单进程 HMR
72
+ - **构建**: 前端 Vite build,服务端 tsc CJS 输出
73
+ - **部署**: server.zip(服务端 + 裁剪 node_modules + run.sh)→ FaaS
74
+
75
+ ### vite-react(纯前端)
76
+
77
+ - Vite 8 + React 19 + TypeScript 5 + Tailwind CSS 4 + shadcn/ui
78
+ - ESLint 9 flat config + react-router-dom
79
+
80
+ ### html(纯前端)
67
81
 
68
- - **Vite 8** + React 19 + TypeScript 5
69
- - **Tailwind CSS 4**(`@tailwindcss/vite`,CSS-first 配置)
70
- - **shadcn/ui**(new-york 风格,lucide 图标,radix-ui 基础组件)
71
- - **ESLint 9** flat config
72
- - **react-router-dom** 客户端路由
82
+ - HTML + Tailwind CDN,零构建依赖
73
83
 
74
84
  ## 发版
75
85
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-templates",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "OpenClaw project templates for mclaw CLI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,10 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <script>
12
- window.__APP_CONFIG__ = {
13
- appId: "{{{appId}}}",
14
- cdnDomain: "{{{cdnDomain}}}"
15
- };
12
+ window.__APP_CONFIG__ = {{{appConfig}}};
16
13
  </script>
17
14
  <div id="root"></div>
18
15
  <script type="module" src="/src/main.tsx"></script>
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -5,12 +5,14 @@
5
5
  "type": "module",
6
6
  "mclaw": {
7
7
  "stack": "apex",
8
- "stackVersion": "0.1.0"
8
+ "stackVersion": "0.1.0",
9
+ "features": [
10
+ "client",
11
+ "server"
12
+ ]
9
13
  },
10
14
  "scripts": {
11
- "dev": "npx tsx --watch server/index.ts & npx vite --host",
12
- "dev:server": "tsx --watch server/index.ts",
13
- "dev:client": "vite --host",
15
+ "dev": "tsx --watch --watch-path server --watch-path shared server/index.ts",
14
16
  "build": "bash scripts/build.sh",
15
17
  "lint": "npm run lint:client && npm run lint:server",
16
18
  "lint:client": "eslint client/src",
@@ -45,20 +47,20 @@
45
47
  "@radix-ui/react-toggle-group": "^1.1.10",
46
48
  "@radix-ui/react-tooltip": "^1.1.18",
47
49
  "@lark-apaas/client-toolkit-lite": "^0.0.2",
50
+ "@lark-apaas/express-core": "^0.0.3",
48
51
  "@formkit/auto-animate": "^0.9.0",
49
52
  "framer-motion": "^12.38.0",
50
53
  "class-variance-authority": "^0.7.1",
51
54
  "clsx": "^2.1.1",
52
55
  "cmdk": "^1.1.1",
53
56
  "date-fns": "^4.1.0",
54
- "drizzle-orm": "^0.45.1",
57
+ "drizzle-orm": "0.44.6",
55
58
  "embla-carousel-react": "^8.6.0",
56
59
  "express": "^5.1.0",
57
60
  "hbs": "^4.2.0",
58
61
  "input-otp": "^1.4.2",
59
62
  "lucide-react": "^1.7.0",
60
63
  "next-themes": "^0.4.6",
61
- "postgres": "^3.4.8",
62
64
  "react": "^19.2.4",
63
65
  "react-day-picker": "^9.14.0",
64
66
  "react-dom": "^19.2.4",
@@ -76,6 +78,7 @@
76
78
  "devDependencies": {
77
79
  "@lark-apaas/coding-presets": "^0.2.0",
78
80
  "@lark-apaas/coding-vite-preset": "^0.1.0",
81
+ "@vercel/nft": "^0.29.2",
79
82
  "@types/express": "^5",
80
83
  "@types/node": "^24",
81
84
  "@types/react": "^19",
@@ -32,8 +32,7 @@ echo '{ "version": 1, "type": "apex", "fallback": "index.html" }' > "$OUTPUT/rou
32
32
  # 服务端产物(tsc 输出保留 server/、shared/ 子目录)
33
33
  cp -r "$ROOT/dist/server/"* "$OUTPUT/"
34
34
 
35
- # 复制 package.json(运行时需要依赖信息)
36
- cp "$ROOT/package.json" "$OUTPUT/package.json"
35
+ # package.json 和 node_modules 由 mclaw-dev deploy 的 prune 步骤生成
37
36
 
38
37
  # 4. assets/ → dist/output_resource/(JS/CSS/字体,上传到 CDN)
39
38
  if [ -d "$ROOT/dist/client/assets" ]; then
@@ -1,34 +1,83 @@
1
- import express from "express";
1
+ import express, { type Request, type Response } from "express";
2
2
  import path from "path";
3
3
  import fs from "fs";
4
- import { fileURLToPath } from "url";
5
4
  import hbs from "hbs";
5
+ import { setup, safeStringify, createViewContextMiddleware } from "@lark-apaas/express-core";
6
+ import * as schema from "./db/schema";
6
7
  import { registerRoutes } from "./routes/index";
7
8
 
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const port = Number(process.env.PORT) || 3000;
9
+ const port = Number(process.env.FORCE_SERVER_PORT) || 3000;
10
+ const host = process.env.FORCE_SERVER_HOST || "localhost";
11
+ const isDev = process.env.NODE_ENV !== "production";
10
12
 
11
13
  const app = express();
12
14
 
13
- // JSON body parsing
14
- app.use(express.json());
15
+ // Platform middleware: body parsing, cookie, user context, DB + RLS, view context
16
+ const { close } = setup(app, {
17
+ database: { schema },
18
+ csrf: { enabled: false },
19
+ viewContext: { enabled: false },
20
+ });
15
21
 
16
22
  // Register API routes
17
23
  registerRoutes(app);
18
24
 
19
- // Page rendering: compile index.html as hbs template, inject runtime data
20
- // Static assets (JS/CSS/images) are served by the deployment platform / CDN
21
- const templatePath = path.resolve(__dirname, "../public/index.html");
22
- const template = hbs.compile(fs.readFileSync(templatePath, "utf-8"));
25
+ // HTML rendering: dev uses Vite middleware mode, prod reads build output
26
+ async function setupHtmlRendering() {
27
+ if (isDev) {
28
+ // @ts-ignore -- vite types require bundler moduleResolution, dev-only import
29
+ const { createServer } = await import("vite");
30
+ const vite = await createServer({
31
+ server: { middlewareMode: true },
32
+ appType: "custom",
33
+ });
34
+
35
+ // Vite handles static assets, module serving, and HMR
36
+ app.use(vite.middlewares);
37
+
38
+ app.get("/{*path}", createViewContextMiddleware(), async (req: Request, res: Response) => {
39
+ const rawHtml = fs.readFileSync(
40
+ path.resolve(__dirname, "../client/index.html"),
41
+ "utf-8",
42
+ );
43
+ // Vite transform: inject HMR client, resolve module imports
44
+ const transformed = await vite.transformIndexHtml(req.originalUrl, rawHtml);
45
+ // HBS render: inject platform data
46
+ const template = hbs.compile(transformed);
47
+ const html = template({
48
+ ...res.locals,
49
+ appConfig: safeStringify({
50
+ appId: res.locals.appId || process.env.MCLAW_APP_ID || "",
51
+ cdnDomain: process.env.MCLAW_CDN_DOMAIN || "",
52
+ }),
53
+ });
54
+ res.type("html").send(html);
55
+ });
56
+ } else {
57
+ const templatePath = path.resolve(__dirname, "../index.html");
58
+ const template = hbs.compile(fs.readFileSync(templatePath, "utf-8"));
23
59
 
24
- app.get("*", (_req, res) => {
25
- const html = template({
26
- appId: process.env.MCLAW_APP_ID || "",
27
- cdnDomain: process.env.MCLAW_CDN_DOMAIN || "",
60
+ app.get("/{*path}", createViewContextMiddleware(), (_req: Request, res: Response) => {
61
+ const html = template({
62
+ ...res.locals,
63
+ appConfig: safeStringify({
64
+ appId: res.locals.appId || process.env.MCLAW_APP_ID || "",
65
+ cdnDomain: process.env.MCLAW_CDN_DOMAIN || "",
66
+ }),
67
+ });
68
+ res.type("html").send(html);
69
+ });
70
+ }
71
+ }
72
+
73
+ setupHtmlRendering().then(() => {
74
+ const server = app.listen(port, host, () => {
75
+ console.log(`Server running at http://${host}:${port}`);
28
76
  });
29
- res.type("html").send(html);
30
- });
31
77
 
32
- app.listen(port, "0.0.0.0", () => {
33
- console.log(`Server running at http://localhost:${port}`);
78
+ // Graceful shutdown
79
+ process.on("SIGTERM", async () => {
80
+ server.close();
81
+ await close();
82
+ });
34
83
  });
@@ -3,6 +3,10 @@
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist/server",
5
5
  "rootDir": ".",
6
+ "module": "commonjs",
7
+ "moduleResolution": "node",
8
+ "verbatimModuleSyntax": false,
9
+ "esModuleInterop": true,
6
10
  "noEmit": false,
7
11
  "allowImportingTsExtensions": false,
8
12
  "noUnusedParameters": false,
@@ -4,7 +4,8 @@
4
4
  "private": true,
5
5
  "mclaw": {
6
6
  "stack": "html",
7
- "stackVersion": "0.1.0"
7
+ "stackVersion": "0.1.0",
8
+ "features": ["client"]
8
9
  },
9
10
  "scripts": {
10
11
  "build": "bash scripts/build.sh"
@@ -1,6 +1,6 @@
1
- import { clsx, type ClassValue } from "clsx";
2
- import { twMerge } from "tailwind-merge";
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
3
 
4
4
  export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
5
+ return twMerge(clsx(inputs))
6
6
  }
@@ -5,7 +5,8 @@
5
5
  "type": "module",
6
6
  "mclaw": {
7
7
  "stack": "vite-react",
8
- "stackVersion": "0.1.0"
8
+ "stackVersion": "0.1.0",
9
+ "features": ["client"]
9
10
  },
10
11
  "scripts": {
11
12
  "dev": "vite",
@@ -1,8 +0,0 @@
1
- import { drizzle } from "drizzle-orm/postgres-js";
2
- import postgres from "postgres";
3
- import * as schema from "./schema";
4
-
5
- const connectionString = process.env.DATABASE_URL!;
6
- const client = postgres(connectionString);
7
-
8
- export const db = drizzle(client, { schema });