@coze-arch/cli 0.0.1-alpha.b0f2c2 → 0.0.1-alpha.b287c1

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.
Files changed (164) hide show
  1. package/README.md +1 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +13 -12
  3. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +9 -8
  4. package/lib/__templates__/expo/AGENTS.md +74 -0
  5. package/lib/__templates__/expo/README.md +0 -73
  6. package/lib/__templates__/expo/_npmrc +1 -0
  7. package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
  8. package/lib/__templates__/expo/client/eslint.config.mjs +7 -0
  9. package/lib/__templates__/expo/client/metro.config.js +3 -0
  10. package/lib/__templates__/expo/client/package.json +35 -35
  11. package/lib/__templates__/expo/client/screens/demo/index.tsx +3 -3
  12. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
  13. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
  14. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
  15. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
  16. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
  17. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
  18. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
  19. package/lib/__templates__/expo/package.json +1 -1
  20. package/lib/__templates__/expo/patches/{expo@54.0.32.patch → expo@54.0.33.patch} +3 -2
  21. package/lib/__templates__/expo/pnpm-lock.yaml +340 -1736
  22. package/lib/__templates__/expo/server/package.json +9 -7
  23. package/lib/__templates__/expo/server/src/index.ts +1 -0
  24. package/lib/__templates__/expo/template.config.js +56 -0
  25. package/lib/__templates__/native-static/.coze +11 -0
  26. package/lib/__templates__/native-static/index.html +33 -0
  27. package/lib/__templates__/native-static/styles/main.css +136 -0
  28. package/lib/__templates__/native-static/template.config.js +22 -0
  29. package/lib/__templates__/nextjs/AGENTS.md +54 -0
  30. package/lib/__templates__/nextjs/README.md +5 -0
  31. package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
  32. package/lib/__templates__/nextjs/next.config.ts +1 -2
  33. package/lib/__templates__/nextjs/package.json +5 -6
  34. package/lib/__templates__/nextjs/pnpm-lock.yaml +1145 -109
  35. package/lib/__templates__/nextjs/scripts/build.sh +4 -1
  36. package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
  37. package/lib/__templates__/nextjs/scripts/start.sh +7 -1
  38. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
  39. package/lib/__templates__/nextjs/src/app/page.tsx +17 -60
  40. package/lib/__templates__/nextjs/src/server.ts +35 -0
  41. package/lib/__templates__/nextjs/template.config.js +49 -14
  42. package/lib/__templates__/nextjs/tsconfig.json +1 -1
  43. package/lib/__templates__/nuxt-vue/.coze +12 -0
  44. package/lib/__templates__/nuxt-vue/AGENTS.md +42 -0
  45. package/lib/__templates__/nuxt-vue/README.md +73 -0
  46. package/lib/__templates__/nuxt-vue/_gitignore +24 -0
  47. package/lib/__templates__/nuxt-vue/_npmrc +23 -0
  48. package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
  49. package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
  50. package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
  51. package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
  52. package/lib/__templates__/nuxt-vue/package.json +35 -0
  53. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
  54. package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
  55. package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
  56. package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
  57. package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
  58. package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
  59. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
  60. package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
  61. package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
  62. package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
  63. package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
  64. package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
  65. package/lib/__templates__/nuxt-vue/template.config.js +87 -0
  66. package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
  67. package/lib/__templates__/taro/.coze +1 -1
  68. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +2 -2
  69. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +4 -3
  70. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +0 -15
  71. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +117 -24
  72. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -1
  73. package/lib/__templates__/taro/README.md +138 -62
  74. package/lib/__templates__/taro/config/index.ts +106 -41
  75. package/lib/__templates__/taro/config/prod.ts +4 -5
  76. package/lib/__templates__/taro/eslint.config.mjs +82 -4
  77. package/lib/__templates__/taro/package.json +22 -13
  78. package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
  79. package/lib/__templates__/taro/pnpm-lock.yaml +1307 -423
  80. package/lib/__templates__/taro/server/package.json +3 -1
  81. package/lib/__templates__/taro/server/src/main.ts +14 -2
  82. package/lib/__templates__/taro/src/app.css +141 -37
  83. package/lib/__templates__/taro/src/app.tsx +9 -0
  84. package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
  85. package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
  86. package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
  87. package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
  88. package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
  89. package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
  90. package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
  91. package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
  92. package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
  93. package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
  94. package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
  95. package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
  96. package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
  97. package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
  98. package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
  99. package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
  100. package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
  101. package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
  102. package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
  103. package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
  104. package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
  105. package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
  106. package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
  107. package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
  108. package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
  109. package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
  110. package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
  111. package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
  112. package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
  113. package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
  114. package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
  115. package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
  116. package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
  117. package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
  118. package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
  119. package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
  120. package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
  121. package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
  122. package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
  123. package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
  124. package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
  125. package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
  126. package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
  127. package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
  128. package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
  129. package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
  130. package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
  131. package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
  132. package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
  133. package/lib/__templates__/taro/src/index.html +20 -1
  134. package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
  135. package/lib/__templates__/taro/src/lib/measure.ts +115 -0
  136. package/lib/__templates__/taro/src/lib/platform.ts +12 -0
  137. package/lib/__templates__/taro/src/lib/utils.ts +6 -0
  138. package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
  139. package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
  140. package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
  141. package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
  142. package/lib/__templates__/taro/src/presets/index.tsx +18 -0
  143. package/lib/__templates__/templates.json +28 -22
  144. package/lib/__templates__/vite/AGENTS.md +41 -0
  145. package/lib/__templates__/vite/README.md +190 -11
  146. package/lib/__templates__/vite/_gitignore +1 -0
  147. package/lib/__templates__/vite/eslint.config.mjs +6 -1
  148. package/lib/__templates__/vite/package.json +14 -3
  149. package/lib/__templates__/vite/pnpm-lock.yaml +820 -1593
  150. package/lib/__templates__/vite/scripts/build.sh +4 -1
  151. package/lib/__templates__/vite/scripts/dev.sh +9 -2
  152. package/lib/__templates__/vite/scripts/start.sh +9 -3
  153. package/lib/__templates__/vite/server/routes/index.ts +31 -0
  154. package/lib/__templates__/vite/server/server.ts +65 -0
  155. package/lib/__templates__/vite/server/vite.ts +67 -0
  156. package/lib/__templates__/vite/src/main.ts +17 -47
  157. package/lib/__templates__/vite/template.config.js +49 -14
  158. package/lib/__templates__/vite/tsconfig.json +4 -3
  159. package/lib/__templates__/vite/vite.config.ts +5 -0
  160. package/lib/cli.js +160 -159
  161. package/package.json +7 -3
  162. package/lib/__templates__/taro/src/app.ts +0 -14
  163. package/lib/__templates__/taro/src/utils/h5-styles.ts +0 -22
  164. package/lib/__templates__/taro/src/utils/wx-debug.ts +0 -23
package/README.md CHANGED
@@ -14,6 +14,7 @@ Coze Coding 的项目模板引擎,提供基于前端技术栈的项目初始
14
14
 
15
15
  ```bash
16
16
  rush update
17
+
17
18
  ```
18
19
 
19
20
  ## 使用
@@ -1,7 +1,7 @@
1
1
  ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
2
2
  PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
3
3
  LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
4
- LOG_FILE="$LOG_DIR/app.log"
4
+ LOG_CLIENT_FILE="$LOG_DIR/client.log"
5
5
  mkdir -p "$LOG_DIR"
6
6
 
7
7
  # ==================== 配置项 ====================
@@ -89,14 +89,17 @@ ensure_port() {
89
89
  pipe_to_log() {
90
90
  local source="${1:-CLIENT}"
91
91
  local raw_log="${2:-}"
92
- local line timestamp ts msg record
92
+ local line clean_line timestamp
93
93
  while IFS= read -r line || [ -n "$line" ]; do
94
+ clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
95
+ if echo "$clean_line" | grep -qE '(^(Web|iOS|Android) node_modules/.*expo-router.*entry\.js.*%|^(Web|iOS|Android) Bundled [0-9]+ms node_modules/.*expo-router.*entry\.js|Logs will appear in the browser)'; then
96
+ continue
97
+ fi
94
98
  if [ -n "$raw_log" ]; then
95
- echo "$line" >> "$raw_log"
99
+ timestamp=$(date '+%Y-%m-%d %H:%M:%S')
100
+ echo "[$timestamp] $clean_line" >> "$raw_log"
96
101
  fi
97
- line=$(echo "[$source] $line" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\[[0-9;]*m//g')
98
- msg="${line}"
99
- echo "$msg"
102
+ printf '[%s] %s\n' "$source" "$clean_line"
100
103
  done
101
104
  }
102
105
 
@@ -116,10 +119,10 @@ start_expo() {
116
119
 
117
120
  if [ "$offline" = "1" ]; then
118
121
  ( EXPO_OFFLINE=1 EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
119
- nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
122
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$LOG_CLIENT_FILE" ) &
120
123
  else
121
124
  ( EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
122
- nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
125
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$LOG_CLIENT_FILE" ) &
123
126
  fi
124
127
  EXPO_PID=$!
125
128
  disown $EXPO_PID 2>/dev/null || true
@@ -130,9 +133,9 @@ start_expo() {
130
133
  detect_expo_fetch_failed() {
131
134
  local timeout="${1:-8}"
132
135
  local waited=0
133
- local log_file="$ROOT_DIR/logs/client.log"
136
+ local log_file="$LOG_CLIENT_FILE"
134
137
  while [ "$waited" -lt "$timeout" ]; do
135
- if [ -f "$log_file" ] && grep -q "TypeError: fetch failed" "$log_file" 2>/dev/null; then
138
+ if [ -f "$log_file" ] && tail -n 100 "$log_file" 2>/dev/null | grep -q "TypeError: fetch failed"; then
136
139
  return 0
137
140
  fi
138
141
  sleep 1
@@ -166,8 +169,6 @@ check_command "pnpm"
166
169
  check_command "lsof"
167
170
  check_command "bash"
168
171
 
169
- echo "准备日志目录:$ROOT_DIR/logs"
170
- mkdir -p "$ROOT_DIR/logs"
171
172
  # 端口占用预检查与处理
172
173
  ensure_port SERVER_PORT "$SERVER_PORT"
173
174
  ensure_port EXPO_PORT "$EXPO_PORT"
@@ -2,8 +2,8 @@
2
2
 
3
3
  ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
4
4
  SERVER_DIR="$ROOT_DIR/server"
5
- LOG_DIR="$ROOT_DIR/logs"
6
- LOG_FILE="$LOG_DIR/server.log"
5
+ LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
6
+ LOG_SERVER_FILE="$LOG_DIR/server.log"
7
7
  SERVER_PORT="${SERVER_PORT:-9091}"
8
8
 
9
9
  mkdir -p "$LOG_DIR"
@@ -11,13 +11,14 @@ mkdir -p "$LOG_DIR"
11
11
  pipe_to_log() {
12
12
  local source="${1:-SERVER}"
13
13
  local raw_log="${2:-}"
14
- local line
14
+ local line clean_line timestamp
15
15
  while IFS= read -r line || [ -n "$line" ]; do
16
+ clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
16
17
  if [ -n "$raw_log" ]; then
17
- echo "$line" >> "$raw_log"
18
+ timestamp=$(date '+%Y-%m-%d %H:%M:%S')
19
+ echo "[$timestamp] $clean_line" >> "$raw_log"
18
20
  fi
19
- line=$(echo "[$source] $line" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\[[0-9;]*m//g')
20
- echo "$line"
21
+ printf '[%s] %s\n' "$source" "$clean_line"
21
22
  done
22
23
  }
23
24
 
@@ -36,10 +37,10 @@ kill_old_server() {
36
37
  echo "==================== Server Dev Run ===================="
37
38
  echo "Server 目录:$SERVER_DIR"
38
39
  echo "Server 端口:$SERVER_PORT"
39
- echo "日志文件:$LOG_FILE"
40
+ echo "日志文件:$LOG_SERVER_FILE"
40
41
 
41
42
  kill_old_server
42
43
 
43
44
  echo "启动 server 服务..."
44
45
  cd "$SERVER_DIR"
45
- NODE_ENV=development PORT="$SERVER_PORT" npx tsx ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_FILE"
46
+ NODE_ENV=development PORT="$SERVER_PORT" npx tsx watch ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_SERVER_FILE"
@@ -0,0 +1,74 @@
1
+ # Expo App + Express.js
2
+
3
+ ## 目录结构规范(严格遵循)
4
+
5
+ 当前仓库是一个 monorepo(基于 pnpm 的 workspace)
6
+
7
+ - Expo 代码在 client 目录,Express.js 代码在 server 目录
8
+ - 本模板默认无 Tab Bar,可按需改造
9
+
10
+ 目录结构说明
11
+
12
+ ├── server/ # 服务端代码根目录 (Express.js)
13
+ | ├── src/
14
+ │ │ └── index.ts # Express 入口文件
15
+ | └── package.json # 服务端 package.json
16
+ ├── client/ # React Native 前端代码
17
+ │ ├── app/ # Expo Router 路由目录(仅路由配置)
18
+ │ │ ├── _layout.tsx # 根布局文件(必需,务必阅读)
19
+ │ │ ├── home.tsx # 首页
20
+ │ │ └── index.tsx # re-export home.tsx
21
+ │ ├── screens/ # 页面实现目录(与 app/ 路由对应)
22
+ │ │ └── demo/ # demo 示例页面
23
+ │ │ ├── index.tsx # 页面组件实现
24
+ │ │ └── styles.ts # 页面样式
25
+ │ ├── components/ # 可复用组件
26
+ │ │ └── Screen.tsx # 页面容器组件(必用)
27
+ │ ├── hooks/ # 自定义 Hooks
28
+ │ ├── contexts/ # React Context 代码
29
+ │ ├── constants/ # 常量定义(如主题配置)
30
+ │ ├── utils/ # 工具函数
31
+ │ ├── assets/ # 静态资源
32
+ | └── package.json # Expo 应用 package.json
33
+ ├── package.json
34
+ ├── .cozeproj # 预置脚手架脚本(禁止修改)
35
+ └── .coze # 配置文件(禁止修改)
36
+
37
+ ## 安装依赖
38
+
39
+ ### 命令
40
+
41
+ ```bash
42
+ pnpm i
43
+ ```
44
+
45
+ ### 新增依赖约束
46
+
47
+ 如果需要新增依赖,需在 client 和 server 各自的目录添加(原因:隔离前后端的依赖),禁止在根目录直接安装依赖
48
+
49
+ ### 新增依赖标准流程
50
+
51
+ - 编辑 `client/package.json` 或 `server/package.json`
52
+ - 在根目录执行 `pnpm i`
53
+
54
+ ## Expo 开发规范
55
+
56
+ ### 路径别名
57
+
58
+ Expo 配置了 `@/` 路径别名指向 `client/` 目录:
59
+
60
+ ```tsx
61
+ // 正确
62
+ import { Screen } from '@/components/Screen';
63
+
64
+ // 避免相对路径
65
+ import { Screen } from '../../../components/Screen';
66
+ ```
67
+
68
+ ## 本地开发
69
+
70
+ 运行 coze dev 可以同时启动前端和后端服务,如果端口已占用,该命令会先杀掉占用端口的进程再启动,也可以用来重启前端和后端服务
71
+
72
+ ```bash
73
+ coze dev
74
+ ```
@@ -1,74 +1 @@
1
1
  # Expo App + Express.js
2
-
3
- ## 目录结构规范(严格遵循)
4
-
5
- 当前仓库是一个 monorepo(基于 pnpm 的 workspace)
6
-
7
- - Expo 代码在 client 目录,Express.js 代码在 server 目录
8
- - 本模板默认无 Tab Bar,可按需改造
9
-
10
- 目录结构说明
11
-
12
- ├── server/ # 服务端代码根目录 (Express.js)
13
- | ├── src/
14
- │ │ └── index.ts # Express 入口文件
15
- | └── package.json # 服务端 package.json
16
- ├── client/ # React Native 前端代码
17
- │ ├── app/ # Expo Router 路由目录(仅路由配置)
18
- │ │ ├── _layout.tsx # 根布局文件(必需,务必阅读)
19
- │ │ ├── home.tsx # 首页
20
- │ │ └── index.tsx # re-export home.tsx
21
- │ ├── screens/ # 页面实现目录(与 app/ 路由对应)
22
- │ │ └── demo/ # demo 示例页面
23
- │ │ ├── index.tsx # 页面组件实现
24
- │ │ └── styles.ts # 页面样式
25
- │ ├── components/ # 可复用组件
26
- │ │ └── Screen.tsx # 页面容器组件(必用)
27
- │ ├── hooks/ # 自定义 Hooks
28
- │ ├── contexts/ # React Context 代码
29
- │ ├── constants/ # 常量定义(如主题配置)
30
- │ ├── utils/ # 工具函数
31
- │ ├── assets/ # 静态资源
32
- | └── package.json # Expo 应用 package.json
33
- ├── package.json
34
- ├── .cozeproj # 预置脚手架脚本(禁止修改)
35
- └── .coze # 配置文件(禁止修改)
36
-
37
- ## 安装依赖
38
-
39
- ### 命令
40
-
41
- ```bash
42
- pnpm i
43
- ```
44
-
45
- ### 新增依赖约束
46
-
47
- 如果需要新增依赖,需在 client 和 server 各自的目录添加(原因:隔离前后端的依赖),禁止在根目录直接安装依赖
48
-
49
- ### 新增依赖标准流程
50
-
51
- - 编辑 `client/package.json` 或 `server/package.json`
52
- - 在根目录执行 `pnpm i`
53
-
54
- ## Expo 开发规范
55
-
56
- ### 路径别名
57
-
58
- Expo 配置了 `@/` 路径别名指向 `client/` 目录:
59
-
60
- ```tsx
61
- // 正确
62
- import { Screen } from '@/components/Screen';
63
-
64
- // 避免相对路径
65
- import { Screen } from '../../../components/Screen';
66
- ```
67
-
68
- ## 本地开发
69
-
70
- 运行 coze dev 可以同时启动前端和后端服务,如果端口已占用,该命令会先杀掉占用端口的进程再启动,也可以用来重启前端和后端服务
71
-
72
- ```bash
73
- coze dev
74
- ```
@@ -1,3 +1,4 @@
1
+ loglevel=error
1
2
  registry=https://registry.npmmirror.com
2
3
 
3
4
  strictStorePkgContentCheck=false
@@ -32,7 +32,7 @@ import {
32
32
  *
33
33
  * ## 2. 沉浸式 Header (推荐)
34
34
  * - 场景:Header 背景色/图片需要延伸到状态栏 (如首页、个人中心)。
35
- * - 用法:`<Screen safeAreaEdges={['left', 'right', 'bottom']}>` (去掉 'top')
35
+ * - 用法:`<Screen safeAreaEdges={['left', 'right', 'bottom']}>` (去掉 'top')
36
36
  * - 配合:页面内部 Header 组件必须手动添加 paddingTop:
37
37
  * ```tsx
38
38
  * const insets = useSafeAreaInsets();
@@ -41,7 +41,7 @@ import {
41
41
  *
42
42
  * ## 3. 底部有 TabBar 或 悬浮按钮
43
43
  * - 场景:页面底部有固定导航栏,或者需要精细控制底部留白。
44
- * - 用法:`<Screen safeAreaEdges={['top', 'left', 'right']}>` (去掉 'bottom')
44
+ * - 用法:`<Screen safeAreaEdges={['top', 'left', 'right']}>` (去掉 'bottom')
45
45
  * - 配合:
46
46
  * - 若是滚动页:`<ScrollView contentContainerStyle={{ paddingBottom: insets.bottom + 80 }}>`
47
47
  * - 若是固定页:`<View style={{ paddingBottom: insets.bottom + 60 }}>`
@@ -8,6 +8,8 @@ import pluginImport from 'eslint-plugin-import';
8
8
  import fontawesome6 from '../eslint-plugins/fontawesome6/index.js';
9
9
  import reanimated from '../eslint-plugins/reanimated/index.js';
10
10
  import reactnative from '../eslint-plugins/react-native/index.js';
11
+ import forbidEmoji from '../eslint-plugins/forbid-emoji/index.js';
12
+ import restrictLinearGradient from '../eslint-plugins/restrict-linear-gradient/index.js';
11
13
 
12
14
  export default [
13
15
  {
@@ -20,6 +22,7 @@ export default [
20
22
  'tailwind.config.js', // 排除 Tailwind 配置文件
21
23
  '**/*.d.ts',
22
24
  'eslint.config.*',
25
+ 'metro.config.*',
23
26
  ],
24
27
  },
25
28
  regexp.configs["flat/recommended"],
@@ -60,6 +63,8 @@ export default [
60
63
  fontawesome6,
61
64
  reanimated,
62
65
  reactnative,
66
+ forbidEmoji,
67
+ restrictLinearGradient,
63
68
  },
64
69
  rules: {
65
70
  // 关闭代码风格规则
@@ -80,6 +85,8 @@ export default [
80
85
  'react/jsx-uses-react': 'off',
81
86
  'fontawesome6/valid-name': 'error',
82
87
  'reanimated/ban-mix-use': 'error',
88
+ 'forbidEmoji/no-emoji': 'error',
89
+ 'restrictLinearGradient/no-linear-gradient-backgroundcolor': 'error',
83
90
  // 禁止使用 via.placeholder.com 服务
84
91
  'no-restricted-syntax': [
85
92
  'error',
@@ -26,6 +26,9 @@ config.resolver.blockList = [
26
26
  // 4. 通用规则
27
27
  /.*\/__tests__\/.*/, // 排除所有测试目录
28
28
  /.*\.git\/.*/, // 排除 Git 目录
29
+
30
+ // 5. pnpm 临时目录(避免 ENOENT 错误)
31
+ /.*node_modules\/\.pnpm\/.*_tmp_\d+.*/,
29
32
  ];
30
33
 
31
34
  const BACKEND_TARGET = 'http://localhost:9091';
@@ -15,38 +15,38 @@
15
15
  "preset": "jest-expo"
16
16
  },
17
17
  "dependencies": {
18
- "@expo/metro-runtime": "^6.1.2",
19
- "@expo/vector-icons": "^15.0.0",
20
- "@react-native-async-storage/async-storage": "^2.2.0",
21
- "@react-native-community/datetimepicker": "^8.5.0",
22
- "@react-native-community/slider": "^5.0.1",
23
- "@react-native-masked-view/masked-view": "^0.3.2",
24
- "@react-native-picker/picker": "^2.11.0",
18
+ "@expo/metro-runtime": "~6.1.2",
19
+ "@expo/vector-icons": "^15.0.3",
20
+ "@react-native-async-storage/async-storage": "2.2.0",
21
+ "@react-native-community/datetimepicker": "8.4.4",
22
+ "@react-native-community/slider": "5.0.1",
23
+ "@react-native-masked-view/masked-view": "0.3.2",
24
+ "@react-native-picker/picker": "2.11.1",
25
25
  "@react-navigation/bottom-tabs": "^7.2.0",
26
26
  "@react-navigation/native": "^7.0.14",
27
27
  "dayjs": "^1.11.19",
28
- "expo": "54.0.32",
29
- "expo-auth-session": "^7.0.9",
30
- "expo-av": "~16.0.6",
31
- "expo-blur": "~15.0.6",
28
+ "expo": "54.0.33",
29
+ "expo-auth-session": "~7.0.10",
30
+ "expo-av": "~16.0.8",
31
+ "expo-blur": "~15.0.8",
32
32
  "expo-camera": "~17.0.10",
33
- "expo-constants": "~18.0.8",
34
- "expo-crypto": "^15.0.7",
33
+ "expo-constants": "~18.0.13",
34
+ "expo-crypto": "~15.0.8",
35
35
  "expo-file-system": "~19.0.21",
36
- "expo-font": "~14.0.7",
37
- "expo-haptics": "~15.0.6",
38
- "expo-image-picker": "~17.0.7",
39
- "expo-linear-gradient": "~15.0.6",
40
- "expo-linking": "~8.0.7",
41
- "expo-location": "~19.0.7",
42
- "expo-image": "^3.0.11",
43
- "js-base64": "^3.7.7",
44
- "expo-router": "~6.0.0",
45
- "expo-splash-screen": "~31.0.8",
46
- "expo-status-bar": "~3.0.7",
47
- "expo-symbols": "~1.0.6",
36
+ "expo-font": "~14.0.11",
37
+ "expo-haptics": "~15.0.8",
38
+ "expo-image": "~3.0.11",
39
+ "expo-image-picker": "~17.0.10",
40
+ "expo-linear-gradient": "~15.0.8",
41
+ "expo-linking": "~8.0.11",
42
+ "expo-location": "~19.0.8",
43
+ "expo-router": "~6.0.23",
44
+ "expo-splash-screen": "~31.0.13",
45
+ "expo-status-bar": "~3.0.9",
46
+ "expo-symbols": "~1.0.8",
48
47
  "expo-system-ui": "~6.0.9",
49
48
  "expo-web-browser": "~15.0.10",
49
+ "js-base64": "^3.7.7",
50
50
  "react": "19.1.0",
51
51
  "react-dom": "19.1.0",
52
52
  "react-native": "0.81.5",
@@ -54,25 +54,26 @@
54
54
  "react-native-gesture-handler": "~2.28.0",
55
55
  "react-native-keyboard-aware-scroll-view": "^0.9.5",
56
56
  "react-native-modal-datetime-picker": "18.0.0",
57
- "react-native-reanimated": "~4.1.0",
57
+ "react-native-reanimated": "~4.1.1",
58
58
  "react-native-safe-area-context": "~5.6.0",
59
59
  "react-native-screens": "~4.16.0",
60
- "react-native-svg": "15.15.0",
60
+ "react-native-svg": "15.12.1",
61
61
  "react-native-toast-message": "^2.3.3",
62
- "react-native-web": "^0.21.2",
63
- "react-native-webview": "~13.15.0",
62
+ "react-native-web": "~0.21.0",
63
+ "react-native-webview": "13.15.0",
64
64
  "react-native-worklets": "0.5.1",
65
65
  "zod": "^4.2.1"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@babel/core": "^7.25.2",
69
- "babel-plugin-module-resolver": "^5.0.2",
70
- "babel-preset-expo": "^54.0.9",
71
69
  "@eslint/js": "^9.27.0",
72
70
  "@types/jest": "^29.5.12",
73
71
  "@types/react": "~19.1.0",
74
72
  "@types/react-test-renderer": "19.1.0",
73
+ "babel-plugin-module-resolver": "^5.0.2",
74
+ "babel-preset-expo": "^54.0.9",
75
75
  "chalk": "^4.1.2",
76
+ "connect": "^3.7.0",
76
77
  "depcheck": "^1.4.7",
77
78
  "esbuild": "0.27.2",
78
79
  "eslint": "^9.39.2",
@@ -83,13 +84,12 @@
83
84
  "eslint-plugin-react-hooks": "^7.0.1",
84
85
  "eslint-plugin-regexp": "^2.10.0",
85
86
  "globals": "^16.1.0",
87
+ "http-proxy-middleware": "^3.0.5",
86
88
  "jest": "^29.2.1",
87
- "jest-expo": "~54.0.10",
89
+ "jest-expo": "~54.0.17",
88
90
  "react-test-renderer": "19.1.0",
89
91
  "tsx": "^4.21.0",
90
92
  "typescript": "^5.8.3",
91
- "typescript-eslint": "^8.32.1",
92
- "connect": "^3.7.0",
93
- "http-proxy-middleware": "^3.0.5"
93
+ "typescript-eslint": "^8.32.1"
94
94
  }
95
95
  }
@@ -15,10 +15,10 @@ export default function DemoPage() {
15
15
  >
16
16
  <Image
17
17
  style={styles.logo}
18
- source="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-coding/expo/coze-loading.gif"
18
+ source="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-coding/icon/coze-coding.gif"
19
19
  ></Image>
20
- <Text style={{...styles.title, color: theme.textPrimary}}>APP 开发中</Text>
21
- <Text style={{...styles.description, color: theme.textSecondary}}>即将为您呈现应用界面</Text>
20
+ <Text style={{...styles.title, color: theme.textPrimary}}>应用开发中</Text>
21
+ <Text style={{...styles.description, color: theme.textSecondary}}>请稍候,界面即将呈现</Text>
22
22
  </View>
23
23
  </Screen>
24
24
  );
@@ -9,7 +9,7 @@ const { execSync } = require('child_process');
9
9
  const fs = require('fs');
10
10
  const path = require('path');
11
11
 
12
- console.log('🔍 检测缺失的依赖...\n');
12
+ console.log('检测缺失的依赖...\n');
13
13
 
14
14
  try {
15
15
  // 运行 depcheck 并获取 JSON 输出
@@ -61,11 +61,11 @@ try {
61
61
  });
62
62
 
63
63
  if (missingPackages.length === 0) {
64
- console.log('✅ 没有发现缺失的依赖!');
64
+ console.log('没有发现缺失的依赖');
65
65
  process.exit(0);
66
66
  }
67
67
 
68
- console.log('📦 发现以下缺失的依赖:');
68
+ console.log('发现以下缺失的依赖:');
69
69
  missingPackages.forEach((pkg, index) => {
70
70
  const files = missing[pkg];
71
71
  console.log(` ${index + 1}. ${pkg}`);
@@ -74,7 +74,7 @@ try {
74
74
  );
75
75
  });
76
76
 
77
- console.log('\n🚀 开始安装...\n');
77
+ console.log('\n开始安装...\n');
78
78
 
79
79
  // 使用 expo install 安装所有缺失的包
80
80
  const packagesToInstall = missingPackages.join(' ');
@@ -84,22 +84,22 @@ try {
84
84
  stdio: 'inherit',
85
85
  });
86
86
 
87
- console.log('\n✅ 所有缺失的依赖已安装完成!');
87
+ console.log('\n所有缺失的依赖已安装完成');
88
88
  } catch (installError) {
89
- console.log('\n⚠️ expo install 失败,尝试使用 npm install...\n');
89
+ console.log('\nexpo install 失败,尝试使用 npm install...\n');
90
90
 
91
91
  execSync(`npm install ${packagesToInstall}`, {
92
92
  stdio: 'inherit',
93
93
  });
94
94
 
95
- console.log('\n所有缺失的依赖已通过 npm 安装完成!');
95
+ console.log('\n所有缺失的依赖已通过 npm 安装完成');
96
96
  }
97
97
  } catch (error) {
98
98
  if (error.message.includes('depcheck')) {
99
- console.error('depcheck 未安装或运行失败');
100
- console.log('💡 尝试运行: npm install -g depcheck');
99
+ console.error('depcheck 未安装或运行失败');
100
+ console.log('尝试运行: npm install -g depcheck');
101
101
  } else {
102
- console.error('发生错误:', error.message);
102
+ console.error('发生错误:', error.message);
103
103
  }
104
104
  process.exit(1);
105
105
  }
@@ -0,0 +1,9 @@
1
+ const noEmoji = require('./rule')
2
+
3
+ const plugin = {
4
+ rules: {
5
+ 'no-emoji': noEmoji,
6
+ },
7
+ }
8
+
9
+ module.exports = plugin
@@ -0,0 +1,112 @@
1
+ const DEFAULTS = {
2
+ ignorePatterns: [],
3
+ }
4
+
5
+ const RE_EMOJI =
6
+ // 匹配完整 emoji 序列:基础图形 + 可选变体选择符/肤色 + 可选 ZWJ 连接序列;以及国旗与 keycap
7
+ /(?:\p{Extended_Pictographic}(?:\uFE0F|[\u{1F3FB}-\u{1F3FF}])?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|[\u{1F3FB}-\u{1F3FF}])?)*)|(?:[\u{1F1E6}-\u{1F1FF}]{2})|(?:[#*0-9]\uFE0F?\u20E3)/gu
8
+
9
+ function buildIgnoreRegexes(patterns) {
10
+ if (!Array.isArray(patterns)) return []
11
+ const result = []
12
+ for (const pattern of patterns) {
13
+ if (typeof pattern !== 'string') continue
14
+ try {
15
+ result.push(new RegExp(pattern))
16
+ } catch (_) {
17
+ continue
18
+ }
19
+ }
20
+ return result
21
+ }
22
+
23
+ function shouldIgnore(text, ignoreRegexes) {
24
+ if (!ignoreRegexes.length) return false
25
+ for (const re of ignoreRegexes) {
26
+ if (re.test(text)) return true
27
+ }
28
+ return false
29
+ }
30
+
31
+ function hasEmoji(text) {
32
+ if (!text) return false
33
+ RE_EMOJI.lastIndex = 0
34
+ return RE_EMOJI.test(text)
35
+ }
36
+
37
+ function collectEmojis(text) {
38
+ if (!text) return []
39
+ RE_EMOJI.lastIndex = 0
40
+ const result = []
41
+ const seen = new Set()
42
+ for (const match of text.matchAll(RE_EMOJI)) {
43
+ if (match[0] && !seen.has(match[0])) {
44
+ seen.add(match[0])
45
+ result.push(match[0])
46
+ }
47
+ }
48
+ return result
49
+ }
50
+
51
+ module.exports = {
52
+ meta: {
53
+ type: 'problem',
54
+ docs: {
55
+ description: 'Disallow emoji in code',
56
+ recommended: 'error',
57
+ },
58
+ schema: [
59
+ {
60
+ type: 'object',
61
+ additionalProperties: false,
62
+ properties: {
63
+ ignorePatterns: {
64
+ type: 'array',
65
+ items: { type: 'string' },
66
+ default: DEFAULTS.ignorePatterns,
67
+ },
68
+ },
69
+ },
70
+ ],
71
+ messages: {
72
+ noEmoji: '禁止在代码中使用 emoji:{{emojis}},请移除或者使用 @expo/vector-icons 图标',
73
+ },
74
+ },
75
+
76
+ create(context) {
77
+ const options = context.options && context.options[0] ? context.options[0] : {}
78
+ const ignoreRegexes = buildIgnoreRegexes(
79
+ Array.isArray(options.ignorePatterns) ? options.ignorePatterns : DEFAULTS.ignorePatterns
80
+ )
81
+
82
+ function checkText(node, text) {
83
+ if (!text) return
84
+ if (shouldIgnore(text, ignoreRegexes)) return
85
+ if (hasEmoji(text)) {
86
+ const emojis = collectEmojis(text)
87
+ const emojiText = emojis.length ? emojis.join(' ') : ''
88
+ context.report({ node, messageId: 'noEmoji', data: { emojis: emojiText } })
89
+ }
90
+ }
91
+
92
+ return {
93
+ Literal(node) {
94
+ if (typeof node.value !== 'string') return
95
+ checkText(node, node.value)
96
+ },
97
+ TemplateLiteral(node) {
98
+ for (const quasi of node.quasis) {
99
+ const cooked = quasi.value && typeof quasi.value.cooked === 'string'
100
+ ? quasi.value.cooked
101
+ : quasi.value && typeof quasi.value.raw === 'string'
102
+ ? quasi.value.raw
103
+ : ''
104
+ checkText(quasi, cooked)
105
+ }
106
+ },
107
+ JSXText(node) {
108
+ checkText(node, node.value)
109
+ },
110
+ }
111
+ },
112
+ }