@coze-arch/cli 0.0.1-alpha.ecba20 → 0.0.1-alpha.ee5d83

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 (43) hide show
  1. package/lib/__templates__/expo/.coze +1 -1
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +19 -82
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +62 -81
  4. package/lib/__templates__/expo/README.md +22 -14
  5. package/lib/__templates__/expo/client/app/index.tsx +1 -0
  6. package/lib/__templates__/expo/client/app.config.ts +64 -60
  7. package/lib/__templates__/expo/client/constants/theme.ts +22 -18
  8. package/lib/__templates__/expo/client/hooks/useColorScheme.ts +34 -1
  9. package/lib/__templates__/expo/client/package.json +1 -0
  10. package/lib/__templates__/expo/client/screens/home/index.tsx +12 -37
  11. package/lib/__templates__/expo/client/screens/home/styles.ts +19 -51
  12. package/lib/__templates__/expo/pnpm-lock.yaml +57 -5
  13. package/lib/__templates__/expo/server/package.json +3 -1
  14. package/lib/__templates__/expo/server/src/index.ts +8 -2
  15. package/lib/__templates__/expo/template.config.js +1 -0
  16. package/lib/__templates__/nextjs/.coze +1 -0
  17. package/lib/__templates__/nextjs/_npmrc +1 -0
  18. package/lib/__templates__/nextjs/next.config.ts +11 -0
  19. package/lib/__templates__/nextjs/package.json +3 -5
  20. package/lib/__templates__/nextjs/pnpm-lock.yaml +13 -1025
  21. package/lib/__templates__/nextjs/scripts/dev.sh +1 -1
  22. package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
  23. package/lib/__templates__/nextjs/src/app/globals.css +10 -2
  24. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -16
  25. package/lib/__templates__/nextjs/src/app/page.tsx +33 -21
  26. package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
  27. package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
  28. package/lib/__templates__/nextjs/template.config.js +30 -0
  29. package/lib/__templates__/templates.json +61 -70
  30. package/lib/__templates__/vite/.coze +1 -0
  31. package/lib/__templates__/vite/_npmrc +1 -0
  32. package/lib/__templates__/vite/eslint.config.mjs +9 -0
  33. package/lib/__templates__/vite/package.json +5 -1
  34. package/lib/__templates__/vite/pnpm-lock.yaml +3481 -14
  35. package/lib/__templates__/vite/scripts/prepare.sh +9 -0
  36. package/lib/__templates__/vite/template.config.js +28 -4
  37. package/lib/cli.js +46 -22
  38. package/package.json +1 -1
  39. package/lib/__templates__/nextjs/.babelrc +0 -15
  40. package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
  41. package/lib/__templates__/nextjs/server.mjs +0 -50
  42. package/lib/__templates__/vite/.vscode/settings.json +0 -7
  43. /package/lib/__templates__/expo/client/app/{index.ts → home.tsx} +0 -0
@@ -9,4 +9,4 @@ run = ["bash", ".cozeproj/scripts/dev_run.sh"]
9
9
  [deploy]
10
10
  build = ["bash", ".cozeproj/scripts/prod_build.sh"]
11
11
  run = ["bash", ".cozeproj/scripts/prod_run.sh"]
12
- build_app_dir = "."
12
+ build_app_dir = "./client"
@@ -2,108 +2,45 @@
2
2
  if [ -z "${BASH_VERSION:-}" ]; then exec /usr/bin/env bash "$0" "$@"; fi
3
3
  set -euo pipefail
4
4
  ROOT_DIR="$(pwd)"
5
- PREVIEW_DIR="${COZE_PREVIEW_DIR:-$ROOT_DIR}"
6
- LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
7
- LOG_FILE="$LOG_DIR/app.log"
8
- mkdir -p "$LOG_DIR"
5
+ PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
9
6
 
10
7
  # ==================== 配置项 ====================
11
8
  SERVER_DIR="app"
12
9
  EXPO_DIR="expo"
13
10
  CHECK_HASH_SCRIPT="$ROOT_DIR/check_hash.py"
14
- # ==================== 工具函数 ====================
15
- info() {
16
- echo -e "\033[32m[INFO] $1\033[0m"
17
- }
18
- warn() {
19
- echo -e "\033[33m[WARN] $1\033[0m"
20
- }
21
- error() {
22
- echo -e "\033[31m[ERROR] $1\033[0m"
23
- exit 1
24
- }
11
+
25
12
  check_command() {
26
13
  if ! command -v "$1" &> /dev/null; then
27
- error "命令 $1 未找到,请先安装"
14
+ echo "error:命令 $1 未找到,请先安装"
28
15
  fi
29
16
  }
30
- write_log() {
31
- local level="${1:-INFO}"
32
- local msg="${2:-}"
33
- node -e '
34
- const fs=require("fs");
35
- const path=process.argv[1];
36
- const level=(process.argv[2]||"").toUpperCase();
37
- let msg=String(process.argv[3]||"");
38
- const ts=Date.now();
39
- const dt=new Date();
40
- const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
41
- const o={};
42
- for(const p of parts){o[p.type]=p.value}
43
- const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
44
- msg=msg.replace(/\\n/g,"\n");
45
- msg=`${dt_str} [${level}] ${msg}`;
46
- const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
47
- const fd=fs.openSync(path,"a");
48
- fs.writeSync(fd, record+"\n", null, "utf8");
49
- fs.fsyncSync(fd);
50
- fs.closeSync(fd);
51
- ' "$LOG_FILE" "$level" "$msg"
52
- }
53
17
 
54
- # ==================== 前置检查 ====================
55
- write_log "INFO" "==================== 开始构建 ===================="
18
+ echo "==================== 开始构建 ===================="
56
19
 
57
- write_log "INFO" "检查根目录 pre_install.py"
20
+ echo "检查根目录 pre_install.py"
58
21
  if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
59
- write_log "INFO" "执行:python $PREVIEW_DIR/pre_install.py"
60
- python "$PREVIEW_DIR/pre_install.py" || write_log "ERROR" "pre_install.py 执行失败"
22
+ echo "执行:python $PREVIEW_DIR/pre_install.py"
23
+ python "$PREVIEW_DIR/pre_install.py" || echo "pre_install.py 执行失败"
61
24
  fi
62
25
 
63
- write_log "INFO" "开始执行构建脚本(build_dev.sh)..."
64
- write_log "INFO" "正在检查依赖命令是否存在..."
26
+ echo "开始执行构建脚本(build_dev.sh)..."
27
+ echo "正在检查依赖命令是否存在..."
65
28
  # 检查核心命令
66
- # check_command "pip"
67
- # check_command "python"
68
29
  check_command "pnpm"
69
30
  check_command "npm"
70
31
 
71
- # ==================== 步骤 1:安装项目依赖 ====================
72
- write_log "INFO" "==================== 安装项目依赖 ===================="
32
+ echo "==================== 安装项目依赖 ===================="
73
33
  if [ ! -f "package.json" ]; then
74
- write_log "ERROR" "项目目录下无 package.json,不是合法的 Node.js 项目"
75
- fi
76
- # 步骤 2.1/2.2:安装 Expo 项目依赖(按哈希变化执行)
77
- if [ -f "$CHECK_HASH_SCRIPT" ]; then
78
- write_log "INFO" "检测 package.json 哈希是否变化"
79
- set +e
80
- python "$CHECK_HASH_SCRIPT" --config "package.json" --check
81
- rc_node=$?
82
- set -e
83
- if [ $rc_node -eq 1 ]; then
84
- write_log "INFO" "依赖哈希已变化,执行:pnpm install"
85
- pnpm install --registry=https://registry.npmmirror.com || write_log "ERROR" "Expo 项目依赖安装失败(pnpm 执行出错)"
86
-
87
- write_log "INFO" "依赖哈希已变化,执行:npm run install-missing"
88
- npm run install-missing || write_log "ERROR" "npm run install-missing 执行失败,请检查 package.json 中的脚本配置"
89
-
90
- set +e
91
- python "$CHECK_HASH_SCRIPT" --config "package.json" --update
92
- set -e
93
- else
94
- write_log "INFO" "跳过 pnpm install 与 npm run install-missing"
95
- fi
96
- else
97
- write_log "WARN" "未找到 check_hash.py,默认执行:pnpm install 与 npm run install-missing"
98
- pnpm install --registry=https://registry.npmmirror.com || write_log "ERROR" "Expo 项目依赖安装失败(pnpm 执行出错)"
99
- npm run install-missing || write_log "ERROR" "npm run install-missing 执行失败,请检查 package.json 中的脚本配置"
34
+ echo "项目目录下无 package.json,不是合法的 Node.js 项目"
100
35
  fi
36
+ # 步骤 2.1/2.2:安装项目依赖
37
+ pnpm install --registry=https://registry.npmmirror.com || echo "Expo 项目依赖安装失败(pnpm 执行出错)"
101
38
 
102
- write_log "INFO" "检查根目录 post_install.py"
103
- if [ -f "$ROOT_DIR/post_install.py" ]; then
104
- write_log "INFO" "执行:python $ROOT_DIR/post_install.py"
105
- python "$ROOT_DIR/post_install.py" || write_log "ERROR" "post_install.py 执行失败"
39
+ echo "检查根目录 post_install.py"
40
+ if [ -f "$PREVIEW_DIR/post_install.py" ]; then
41
+ echo "执行:python $PREVIEW_DIR/post_install.py"
42
+ python "$PREVIEW_DIR/post_install.py" || echo "post_install.py 执行失败"
106
43
  fi
107
44
 
108
- write_log "INFO" "==================== 依赖安装完成!====================\n"
109
- write_log "INFO" "下一步:执行 ./deploy_run.sh 启动服务"
45
+ echo "==================== 依赖安装完成!====================\n"
46
+ echo "下一步:执行 ./deploy_run.sh 启动服务"
@@ -1,5 +1,5 @@
1
1
  ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
2
- PREVIEW_DIR="${COZE_PREVIEW_DIR:-$ROOT_DIR}"
2
+ PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
3
3
  LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
4
4
  LOG_FILE="$LOG_DIR/app.log"
5
5
  mkdir -p "$LOG_DIR"
@@ -23,19 +23,9 @@ export EXPO_PUBLIC_BACKEND_BASE_URL EXPO_PACKAGER_PROXY_URL
23
23
  SERVER_PID=""
24
24
  EXPO_PID=""
25
25
  # ==================== 工具函数 ====================
26
- info() {
27
- echo -e "\033[32m[INFO] $1\033[0m"
28
- }
29
- warn() {
30
- echo -e "\033[33m[WARN] $1\033[0m"
31
- }
32
- error() {
33
- echo -e "\033[31m[ERROR] $1\033[0m"
34
- exit 1
35
- }
36
26
  check_command() {
37
27
  if ! command -v "$1" &> /dev/null; then
38
- error "命令 $1 未找到,请先安装"
28
+ echo "error:命令 $1 未找到,请先安装"
39
29
  fi
40
30
  }
41
31
  while [ $# -gt 0 ]; do
@@ -64,10 +54,10 @@ ensure_port() {
64
54
  local var_name=$1
65
55
  local port_val=$2
66
56
  if is_port_free "$port_val"; then
67
- info "端口未占用:$port_val"
57
+ echo "端口未占用:$port_val"
68
58
  eval "$var_name=$port_val"
69
59
  else
70
- warn "端口已占用:$port_val"
60
+ echo "端口已占用:$port_val"
71
61
  local choice
72
62
  if [ "$ASSUME_YES" = "1" ]; then choice="Y"; else read -r -p "是否关闭该端口的进程?[Y/n] " choice || choice="Y"; fi
73
63
  if [ -z "$choice" ] || [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then
@@ -75,15 +65,15 @@ ensure_port() {
75
65
  local pids
76
66
  pids=$(lsof -t -i tcp:"$port_val" -sTCP:LISTEN 2>/dev/null || true)
77
67
  if [ -n "$pids" ]; then
78
- info "正在关闭进程:$pids"
79
- kill -9 $pids 2>/dev/null || warn "关闭进程失败:$pids"
68
+ echo "正在关闭进程:$pids"
69
+ kill -9 $pids 2>/dev/null || echo "关闭进程失败:$pids"
80
70
  eval "$var_name=$port_val"
81
71
  else
82
- warn "未获取到占用该端口的进程"
72
+ echo "未获取到占用该端口的进程"
83
73
  eval "$var_name=$port_val"
84
74
  fi
85
75
  else
86
- warn "缺少 lsof,无法自动关闭进程"
76
+ echo "缺少 lsof,无法自动关闭进程"
87
77
  eval "$var_name=$port_val"
88
78
  fi
89
79
  else
@@ -95,28 +85,18 @@ ensure_port() {
95
85
  fi
96
86
  }
97
87
 
98
- write_log() {
99
- local level="${1:-INFO}"
100
- local msg="${2:-}"
101
- node -e '
102
- const fs=require("fs");
103
- const path=process.argv[1];
104
- const level=(process.argv[2]||"").toUpperCase();
105
- let msg=String(process.argv[3]||"");
106
- const ts=Date.now();
107
- msg=msg.replace(/\\n/g,"\n");
108
- const dt=new Date();
109
- const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
110
- const o={};
111
- for(const p of parts){o[p.type]=p.value}
112
- const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
113
- msg=`${dt_str} [${level}] ${msg}`;
114
- const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
115
- const fd=fs.openSync(path,"a");
116
- fs.writeSync(fd, record+"\n", null, "utf8");
117
- fs.fsyncSync(fd);
118
- fs.closeSync(fd);
119
- ' "$LOG_FILE" "$level" "$msg"
88
+ pipe_to_log() {
89
+ local source="${1:-CLIENT}"
90
+ local raw_log="${2:-}"
91
+ local line timestamp ts msg record
92
+ while IFS= read -r line || [ -n "$line" ]; do
93
+ if [ -n "$raw_log" ]; then
94
+ echo "$line" >> "$raw_log"
95
+ fi
96
+ line=$(echo "[$source] $line" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\[[0-9;]*m//g')
97
+ msg="${line}"
98
+ echo "$msg"
99
+ done
120
100
  }
121
101
 
122
102
  wait_port_connectable() {
@@ -134,12 +114,14 @@ start_expo() {
134
114
  pushd ./client
135
115
 
136
116
  if [ "$offline" = "1" ]; then
137
- EXPO_OFFLINE=1 EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" nohup npx expo start --clear --port "$EXPO_PORT" > ../logs/expo.log 2>&1 &
117
+ ( EXPO_OFFLINE=1 EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" \
118
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "../logs/client.log" ) &
138
119
  else
139
- EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" nohup npx expo start --clear --port "$EXPO_PORT" > ../logs/expo.log 2>&1 &
120
+ ( EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" \
121
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "../logs/client.log" ) &
140
122
  fi
141
123
  EXPO_PID=$!
142
- echo "$EXPO_PID"
124
+ disown $EXPO_PID 2>/dev/null || true
143
125
 
144
126
  popd
145
127
  }
@@ -147,7 +129,7 @@ start_expo() {
147
129
  detect_expo_fetch_failed() {
148
130
  local timeout="${1:-8}"
149
131
  local waited=0
150
- local log_file="logs/expo.log"
132
+ local log_file="logs/client.log"
151
133
  while [ "$waited" -lt "$timeout" ]; do
152
134
  if [ -f "$log_file" ] && grep -q "TypeError: fetch failed" "$log_file" 2>/dev/null; then
153
135
  return 0
@@ -162,78 +144,77 @@ detect_expo_fetch_failed() {
162
144
  # 关掉nginx进程
163
145
  ps -ef | grep nginx | grep -v grep | awk '{print $2}' | xargs -r kill -9
164
146
 
165
- write_log "INFO" "检查根目录 pre_install.py"
147
+ echo "检查根目录 pre_install.py"
166
148
  if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
167
- write_log "INFO" "执行:python $PREVIEW_DIR/pre_install.py"
168
- python "$PREVIEW_DIR/pre_install.py" || write_log "ERROR" "pre_install.py 执行失败"
149
+ echo "执行:python $PREVIEW_DIR/pre_install.py"
150
+ python "$PREVIEW_DIR/pre_install.py" || echo "pre_install.py 执行失败"
169
151
  fi
170
152
 
171
- write_log "INFO" "==================== 开始启动 ===================="
172
- write_log "INFO" "开始执行服务启动脚本(start_dev.sh)..."
173
- write_log "INFO" "正在检查依赖命令和目录是否存在..."
153
+ echo "==================== 开始启动 ===================="
154
+ echo "开始执行服务启动脚本(start_dev.sh)..."
155
+ echo "正在检查依赖命令和目录是否存在..."
174
156
  # 检查核心命令
175
- # check_command "python"
176
157
  check_command "npm"
177
158
  check_command "pnpm"
178
159
  check_command "lsof"
179
160
  check_command "bash"
180
161
 
181
- info "准备日志目录:logs"
162
+ echo "准备日志目录:logs"
182
163
  mkdir -p logs
183
164
  # 端口占用预检查与处理
184
165
  ensure_port SERVER_PORT "$SERVER_PORT"
185
166
  ensure_port EXPO_PORT "$EXPO_PORT"
186
167
 
187
- # ==================== 启动 Server 服务 ====================
188
- write_log "INFO" "==================== 启动 server 服务 ===================="
189
- write_log "INFO" "正在执行:npm run dev"
190
- PORT="$SERVER_PORT" nohup npm run dev --prefix ./server > logs/app.log 2>&1 &
168
+ echo "==================== 启动 server 服务 ===================="
169
+ echo "正在执行:npm run dev"
170
+ ( PORT="$SERVER_PORT" nohup npm run dev --prefix ./server 2>&1 | pipe_to_log "SERVER" "logs/server.log" ) &
191
171
  SERVER_PID=$!
172
+ disown $SERVER_PID 2>/dev/null || true
192
173
  if [ -z "${SERVER_PID}" ]; then
193
- write_log "ERROR" "无法获取 server 后台进程 PID"
174
+ echo "无法获取 server 后台进程 PID"
194
175
  fi
195
- write_log "INFO" "server 服务已启动,进程 ID:${SERVER_PID:-unknown}"
176
+ echo "server 服务已启动,进程 ID:${SERVER_PID:-unknown}"
196
177
 
197
- write_log "INFO" "==================== 启动 Expo 项目 ===================="
198
- write_log "INFO" "开始启动 Expo 服务,端口 ${EXPO_PORT}"
199
- EXPO_PID=$(start_expo 0)
178
+ echo "==================== 启动 Expo 项目 ===================="
179
+ echo "开始启动 Expo 服务,端口 ${EXPO_PORT}"
180
+ start_expo 0
200
181
  if detect_expo_fetch_failed 8; then
201
- write_log "WARN" "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
182
+ echo "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
202
183
  if [ -n "${EXPO_PID}" ]; then kill -9 "$EXPO_PID" 2>/dev/null || true; fi
203
- : > logs/expo.log
204
- EXPO_PID=$(start_expo 1)
184
+ : > logs/client.log
185
+ start_expo 1
205
186
  fi
206
187
  # 输出以下环境变量,确保 Expo 项目能正确连接到 Server 服务
207
- write_log "INFO" "Expo 环境变量配置:"
208
- write_log "INFO" "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
209
- write_log "INFO" "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
188
+ echo "Expo 环境变量配置:"
189
+ echo "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
190
+ echo "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
210
191
  if [ -z "${EXPO_PID}" ]; then
211
- write_log "ERROR" "无法获取 Expo 后台进程 PID"
192
+ echo "无法获取 Expo 后台进程 PID"
212
193
  fi
213
194
 
214
- write_log "INFO" "所有服务已启动。Server PID: ${SERVER_PID}, Expo PID: ${EXPO_PID}"
195
+ echo "所有服务已启动。Server PID: ${SERVER_PID}, Expo PID: ${EXPO_PID}"
215
196
 
216
- write_log "INFO" "检查 Server 服务端口:$SERVER_HOST:$SERVER_PORT"
197
+ echo "检查 Server 服务端口:$SERVER_HOST:$SERVER_PORT"
217
198
  if wait_port_connectable "$SERVER_HOST" "$SERVER_PORT" 10 2; then
218
- write_log "INFO" "端口可连接:$SERVER_HOST:$SERVER_PORT"
199
+ echo "端口可连接:$SERVER_HOST:$SERVER_PORT"
219
200
  else
220
- write_log "WARN" "端口不可连接:$SERVER_HOST:$SERVER_PORT 10 次)"
201
+ echo "端口不可连接:$SERVER_HOST:$SERVER_PORT 10 次)"
221
202
  fi
222
203
 
223
- write_log "INFO" "检查 Expo 服务端口:$EXPO_HOST:$EXPO_PORT"
204
+ echo "检查 Expo 服务端口:$EXPO_HOST:$EXPO_PORT"
224
205
  if wait_port_connectable "$EXPO_HOST" "$EXPO_PORT" 10 2; then
225
- write_log "INFO" "端口可连接:$EXPO_HOST:$EXPO_PORT"
206
+ echo "端口可连接:$EXPO_HOST:$EXPO_PORT"
226
207
  else
227
- write_log "WARN" "端口不可连接:$EXPO_HOST:$EXPO_PORT(已尝试 10 次)"
208
+ echo "端口不可连接:$EXPO_HOST:$EXPO_PORT(已尝试 10 次)"
228
209
  fi
229
210
 
230
- write_log "INFO" "服务端口检查完成"
211
+ echo "服务端口检查完成"
231
212
 
232
- write_log "INFO" "检查根目录 post_run.py"
213
+ echo "检查根目录 post_run.py"
233
214
  if [ -f "$ROOT_DIR/post_run.py" ]; then
234
- write_log "INFO" "启动检查中"
235
- python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" || write_log "ERROR" "post_run.py 执行失败"
236
- write_log "INFO" "启动检查结束"
215
+ echo "启动检查中"
216
+ python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" || echo "post_run.py 执行失败"
217
+ echo "启动检查结束"
237
218
  fi
238
219
 
239
- write_log "INFO" "==================== 服务启动完成 ===================="
220
+ echo "==================== 服务启动完成 ===================="
@@ -3,7 +3,9 @@
3
3
  ## 目录结构规范(严格遵循)
4
4
 
5
5
  当前仓库是一个 monorepo(基于 pnpm 的 workspace)
6
- 其中 Expo 代码在 client 目录,Express.js 代码在 server 目录
6
+
7
+ - Expo 代码在 client 目录,Express.js 代码在 server 目录
8
+ - 本模板默认无 Tab Bar,可按需改造
7
9
 
8
10
  目录结构说明
9
11
 
@@ -14,7 +16,8 @@
14
16
  ├── client/ # React Native 前端代码
15
17
  │ ├── app/ # Expo Router 路由目录(仅路由配置)
16
18
  │ │ ├── _layout.tsx # 根布局文件(必需)
17
- │ │ └── index.ts # 首页
19
+ │ │ ├── home.tsx # 首页
20
+ │ │ └── index.tsx # re-export home.tsx
18
21
  │ ├── screens/ # 页面实现目录(与 app/ 路由对应)
19
22
  │ │ └── home/
20
23
  │ │ ├── index.tsx # 页面组件实现
@@ -29,17 +32,6 @@
29
32
  ├── .cozeproj # 预置脚手架脚本(禁止修改)
30
33
  └── .coze # 配置文件(禁止修改)
31
34
 
32
- ## Expo 路径别名
33
- Expo 配置了 `@/` 路径别名指向 `client/` 目录:
34
-
35
- ```tsx
36
- // 正确
37
- import { Screen } from '@/components/Screen';
38
-
39
- // 避免相对路径
40
- import { Screen } from '../../../components/Screen';
41
- ```
42
-
43
35
  ## 安装依赖
44
36
 
45
37
  ### 命令
@@ -57,7 +49,23 @@ pnpm i
57
49
  - 编辑 `client/package.json` 或 `server/package.json`
58
50
  - 在根目录执行 `pnpm i`
59
51
 
60
- ## 启动前后端服务(开发环境)
52
+ ## Expo 开发规范
53
+
54
+ ### 路径别名
55
+
56
+ Expo 配置了 `@/` 路径别名指向 `client/` 目录:
57
+
58
+ ```tsx
59
+ // 正确
60
+ import { Screen } from '@/components/Screen';
61
+
62
+ // 避免相对路径
63
+ import { Screen } from '../../../components/Screen';
64
+ ```
65
+
66
+ ## 本地开发
67
+
68
+ 运行 coze dev 可以同时启动前端和后端服务,如果端口已占用,该命令会先杀掉占用端口的进程再启动,也可以用来重启前端和后端服务
61
69
 
62
70
  ```bash
63
71
  coze dev
@@ -0,0 +1 @@
1
+ export { default } from './home'
@@ -1,71 +1,75 @@
1
1
  import { ExpoConfig, ConfigContext } from 'expo/config';
2
2
 
3
+ const appName = 'My App';
4
+ const slugAppName = 'my-app';
5
+
3
6
  export default ({ config }: ConfigContext): ExpoConfig => {
4
7
  return {
5
8
  ...config,
6
- "name": "${app_name}",
7
- "slug": "${slug}",
8
- "version": "1.0.0",
9
- "orientation": "portrait",
10
- "icon": "./assets/images/icon.png",
11
- "scheme": "myapp",
12
- "userInterfaceStyle": "automatic",
13
- "newArchEnabled": true,
14
- "ios": {
15
- "supportsTablet": true
9
+ "name": appName,
10
+ "slug": slugAppName,
11
+ "version": "1.0.0",
12
+ "orientation": "portrait",
13
+ "icon": "./assets/images/icon.png",
14
+ "scheme": "myapp",
15
+ "userInterfaceStyle": "automatic",
16
+ "newArchEnabled": true,
17
+ "ios": {
18
+ "supportsTablet": true
19
+ },
20
+ "android": {
21
+ "adaptiveIcon": {
22
+ "foregroundImage": "./assets/images/adaptive-icon.png",
23
+ "backgroundColor": "#ffffff"
16
24
  },
17
- "android": {
18
- "adaptiveIcon": {
19
- "foregroundImage": "./assets/images/adaptive-icon.png",
25
+ "package": "com.anonymous.myapp"
26
+ },
27
+ "web": {
28
+ "bundler": "metro",
29
+ "output": "single",
30
+ "favicon": "./assets/images/favicon.png"
31
+ },
32
+ "plugins": [
33
+ process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
34
+ "expo-router",
35
+ {
36
+ "origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
37
+ }
38
+ ] : 'expo-router',
39
+ [
40
+ "expo-splash-screen",
41
+ {
42
+ "image": "./assets/images/splash-icon.png",
43
+ "imageWidth": 200,
44
+ "resizeMode": "contain",
20
45
  "backgroundColor": "#ffffff"
21
46
  }
22
- },
23
- "web": {
24
- "bundler": "metro",
25
- "output": "single",
26
- "favicon": "./assets/images/favicon.png"
27
- },
28
- "plugins": [
29
- process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
30
- "expo-router",
31
- {
32
- "origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
33
- }
34
- ] : 'expo-router',
35
- [
36
- "expo-splash-screen",
37
- {
38
- "image": "./assets/images/splash-icon.png",
39
- "imageWidth": 200,
40
- "resizeMode": "contain",
41
- "backgroundColor": "#ffffff"
42
- }
43
- ],
44
- [
45
- "expo-image-picker",
46
- {
47
- "photosPermission": "允许${app_name}访问您的相册,以便您上传或保存图片。",
48
- "cameraPermission": "允许${app_name}使用您的相机,以便您直接拍摄照片上传。",
49
- "microphonePermission": "允许${app_name}访问您的麦克风,以便您拍摄带有声音的视频。"
50
- }
51
- ],
52
- [
53
- "expo-location",
54
- {
55
- "locationWhenInUsePermission": "${app_name}需要访问您的位置以提供周边服务及导航功能。"
56
- }
57
- ],
58
- [
59
- "expo-camera",
60
- {
61
- "cameraPermission": "${app_name}需要访问相机以拍摄照片和视频。",
62
- "microphonePermission": "${app_name}需要访问麦克风以录制视频声音。",
63
- "recordAudioAndroid": true
64
- }
65
- ]
66
47
  ],
67
- "experiments": {
68
- "typedRoutes": true
69
- }
48
+ [
49
+ "expo-image-picker",
50
+ {
51
+ "photosPermission": `允许${appName}访问您的相册,以便您上传或保存图片。`,
52
+ "cameraPermission": `允许${appName}使用您的相机,以便您直接拍摄照片上传。`,
53
+ "microphonePermission": `允许${appName}访问您的麦克风,以便您拍摄带有声音的视频。`
54
+ }
55
+ ],
56
+ [
57
+ "expo-location",
58
+ {
59
+ "locationWhenInUsePermission": `${appName}需要访问您的位置以提供周边服务及导航功能。`
60
+ }
61
+ ],
62
+ [
63
+ "expo-camera",
64
+ {
65
+ "cameraPermission": `${appName}需要访问相机以拍摄照片和视频。`,
66
+ "microphonePermission": `${appName}需要访问麦克风以录制视频声音。`,
67
+ "recordAudioAndroid": true
68
+ }
69
+ ]
70
+ ],
71
+ "experiments": {
72
+ "typedRoutes": true
73
+ }
70
74
  }
71
75
  }