@coze-arch/cli 0.0.1-alpha.f9be02 → 0.0.1-alpha.fd3d56
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/lib/__templates__/expo/.coze +1 -1
- package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +19 -82
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +75 -86
- package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +45 -0
- package/lib/__templates__/expo/README.md +68 -7
- package/lib/__templates__/expo/client/app/+not-found.tsx +30 -0
- package/lib/__templates__/expo/client/{src/app → app}/_layout.tsx +15 -12
- package/lib/__templates__/expo/client/app/index.tsx +1 -0
- package/lib/__templates__/expo/client/app.config.ts +65 -60
- package/lib/__templates__/expo/client/{src/components → components}/Screen.tsx +1 -17
- package/lib/__templates__/expo/client/{src/components → components}/ThemedView.tsx +1 -2
- package/lib/__templates__/expo/client/constants/theme.ts +177 -0
- package/lib/__templates__/expo/client/declarations.d.ts +5 -0
- package/lib/__templates__/expo/client/eslint.config.mjs +30 -10
- package/lib/__templates__/expo/client/hooks/useColorScheme.tsx +48 -0
- package/lib/__templates__/expo/client/hooks/useSafeRouter.ts +152 -0
- package/lib/__templates__/expo/client/hooks/useTheme.ts +33 -0
- package/lib/__templates__/expo/client/package.json +6 -3
- package/lib/__templates__/expo/client/screens/demo/index.tsx +25 -0
- package/lib/__templates__/expo/client/screens/demo/styles.ts +28 -0
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +1 -0
- package/lib/__templates__/expo/client/tsconfig.json +1 -1
- package/lib/__templates__/expo/client/{src/utils → utils}/index.ts +22 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +1889 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +174 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/v5-only-names.js +388 -0
- package/lib/__templates__/expo/eslint-plugins/reanimated/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/reanimated/rule.js +88 -0
- package/lib/__templates__/expo/package.json +7 -98
- package/lib/__templates__/expo/patches/expo@54.0.32.patch +44 -0
- package/lib/__templates__/expo/pnpm-lock.yaml +2001 -2124
- package/lib/__templates__/expo/server/build.js +21 -0
- package/lib/__templates__/expo/server/package.json +19 -4
- package/lib/__templates__/expo/server/src/index.ts +9 -2
- package/lib/__templates__/expo/server/tsconfig.json +24 -0
- package/lib/__templates__/expo/template.config.js +1 -0
- package/lib/__templates__/nextjs/.babelrc +15 -0
- package/lib/__templates__/nextjs/.coze +1 -0
- package/lib/__templates__/nextjs/_npmrc +1 -0
- package/lib/__templates__/nextjs/next.config.ts +12 -0
- package/lib/__templates__/nextjs/package.json +10 -11
- package/lib/__templates__/nextjs/pnpm-lock.yaml +2543 -1747
- package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
- package/lib/__templates__/nextjs/src/app/globals.css +10 -2
- package/lib/__templates__/nextjs/src/app/layout.tsx +5 -14
- package/lib/__templates__/nextjs/src/app/page.tsx +35 -23
- package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
- package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
- package/lib/__templates__/nextjs/template.config.js +30 -0
- package/lib/__templates__/templates.json +61 -43
- package/lib/__templates__/vite/.coze +1 -0
- package/lib/__templates__/vite/_npmrc +1 -0
- package/lib/__templates__/vite/eslint.config.mjs +9 -0
- package/lib/__templates__/vite/package.json +10 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +3115 -126
- package/lib/__templates__/vite/scripts/prepare.sh +9 -0
- package/lib/__templates__/vite/src/main.ts +1 -2
- package/lib/__templates__/vite/template.config.js +30 -4
- package/lib/cli.js +691 -130
- package/package.json +5 -3
- package/lib/__templates__/expo/client/src/app/index.ts +0 -1
- package/lib/__templates__/expo/client/src/constants/theme.ts +0 -850
- package/lib/__templates__/expo/client/src/hooks/useColorScheme.ts +0 -1
- package/lib/__templates__/expo/client/src/hooks/useTheme.ts +0 -13
- package/lib/__templates__/expo/client/src/screens/home/index.tsx +0 -50
- package/lib/__templates__/expo/client/src/screens/home/styles.ts +0 -60
- package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
- package/lib/__templates__/vite/.vscode/settings.json +0 -7
- /package/lib/__templates__/expo/client/{src/assets → assets}/fonts/SpaceMono-Regular.ttf +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/adaptive-icon.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/default-avatar.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/favicon.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/icon.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/partial-react-logo.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@2x.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@3x.png +0 -0
- /package/lib/__templates__/expo/client/{src/assets → assets}/images/splash-icon.png +0 -0
- /package/lib/__templates__/expo/client/{src/components → components}/SmartDateInput.tsx +0 -0
- /package/lib/__templates__/expo/client/{src/components → components}/ThemedText.tsx +0 -0
- /package/lib/__templates__/expo/client/{src/contexts → contexts}/AuthContext.tsx +0 -0
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
20
|
+
echo "检查根目录 pre_install.py"
|
|
58
21
|
if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
|
|
59
|
-
|
|
60
|
-
python "$PREVIEW_DIR/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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
72
|
-
write_log "INFO" "==================== 安装项目依赖 ===================="
|
|
32
|
+
echo "==================== 安装项目依赖 ===================="
|
|
73
33
|
if [ ! -f "package.json" ]; then
|
|
74
|
-
|
|
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
|
-
|
|
103
|
-
if [ -f "$
|
|
104
|
-
|
|
105
|
-
python "$
|
|
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
|
-
|
|
109
|
-
|
|
45
|
+
echo "==================== 依赖安装完成!====================\n"
|
|
46
|
+
echo "下一步:执行 ./deploy_run.sh 启动服务"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
2
|
-
PREVIEW_DIR="${COZE_PREVIEW_DIR
|
|
1
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
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"
|
|
@@ -15,27 +15,18 @@ EXPO_PORT="5000"
|
|
|
15
15
|
WEB_URL="${COZE_PROJECT_DOMAIN_DEFAULT:-http://127.0.0.1:${SERVER_PORT}}"
|
|
16
16
|
ASSUME_YES="1"
|
|
17
17
|
EXPO_PUBLIC_BACKEND_BASE_URL="${EXPO_PUBLIC_BACKEND_BASE_URL:-$WEB_URL}"
|
|
18
|
-
|
|
18
|
+
EXPO_PUBLIC_COZE_PROJECT_ID="${COZE_PROJECT_ID:-}"
|
|
19
19
|
|
|
20
20
|
EXPO_PACKAGER_PROXY_URL="${EXPO_PUBLIC_BACKEND_BASE_URL}"
|
|
21
|
-
export EXPO_PUBLIC_BACKEND_BASE_URL EXPO_PACKAGER_PROXY_URL
|
|
21
|
+
export EXPO_PUBLIC_BACKEND_BASE_URL EXPO_PACKAGER_PROXY_URL EXPO_PUBLIC_COZE_PROJECT_ID
|
|
22
22
|
# 运行时变量(为避免 set -u 的未绑定错误,预置为空)
|
|
23
23
|
SERVER_PID=""
|
|
24
24
|
EXPO_PID=""
|
|
25
|
+
|
|
25
26
|
# ==================== 工具函数 ====================
|
|
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
27
|
check_command() {
|
|
37
28
|
if ! command -v "$1" &> /dev/null; then
|
|
38
|
-
|
|
29
|
+
echo "error:命令 $1 未找到,请先安装"
|
|
39
30
|
fi
|
|
40
31
|
}
|
|
41
32
|
while [ $# -gt 0 ]; do
|
|
@@ -64,10 +55,10 @@ ensure_port() {
|
|
|
64
55
|
local var_name=$1
|
|
65
56
|
local port_val=$2
|
|
66
57
|
if is_port_free "$port_val"; then
|
|
67
|
-
|
|
58
|
+
echo "端口未占用:$port_val"
|
|
68
59
|
eval "$var_name=$port_val"
|
|
69
60
|
else
|
|
70
|
-
|
|
61
|
+
echo "端口已占用:$port_val"
|
|
71
62
|
local choice
|
|
72
63
|
if [ "$ASSUME_YES" = "1" ]; then choice="Y"; else read -r -p "是否关闭该端口的进程?[Y/n] " choice || choice="Y"; fi
|
|
73
64
|
if [ -z "$choice" ] || [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then
|
|
@@ -75,15 +66,15 @@ ensure_port() {
|
|
|
75
66
|
local pids
|
|
76
67
|
pids=$(lsof -t -i tcp:"$port_val" -sTCP:LISTEN 2>/dev/null || true)
|
|
77
68
|
if [ -n "$pids" ]; then
|
|
78
|
-
|
|
79
|
-
kill -9 $pids 2>/dev/null ||
|
|
69
|
+
echo "正在关闭进程:$pids"
|
|
70
|
+
kill -9 $pids 2>/dev/null || echo "关闭进程失败:$pids"
|
|
80
71
|
eval "$var_name=$port_val"
|
|
81
72
|
else
|
|
82
|
-
|
|
73
|
+
echo "未获取到占用该端口的进程"
|
|
83
74
|
eval "$var_name=$port_val"
|
|
84
75
|
fi
|
|
85
76
|
else
|
|
86
|
-
|
|
77
|
+
echo "缺少 lsof,无法自动关闭进程"
|
|
87
78
|
eval "$var_name=$port_val"
|
|
88
79
|
fi
|
|
89
80
|
else
|
|
@@ -95,28 +86,18 @@ ensure_port() {
|
|
|
95
86
|
fi
|
|
96
87
|
}
|
|
97
88
|
|
|
98
|
-
|
|
99
|
-
local
|
|
100
|
-
local
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
msg=
|
|
108
|
-
|
|
109
|
-
|
|
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"
|
|
89
|
+
pipe_to_log() {
|
|
90
|
+
local source="${1:-CLIENT}"
|
|
91
|
+
local raw_log="${2:-}"
|
|
92
|
+
local line timestamp ts msg record
|
|
93
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
94
|
+
if [ -n "$raw_log" ]; then
|
|
95
|
+
echo "$line" >> "$raw_log"
|
|
96
|
+
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"
|
|
100
|
+
done
|
|
120
101
|
}
|
|
121
102
|
|
|
122
103
|
wait_port_connectable() {
|
|
@@ -131,15 +112,17 @@ wait_port_connectable() {
|
|
|
131
112
|
start_expo() {
|
|
132
113
|
local offline="${1:-0}"
|
|
133
114
|
|
|
134
|
-
pushd
|
|
115
|
+
pushd "$ROOT_DIR/client"
|
|
135
116
|
|
|
136
117
|
if [ "$offline" = "1" ]; then
|
|
137
|
-
EXPO_OFFLINE=1
|
|
118
|
+
( 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" ) &
|
|
138
120
|
else
|
|
139
|
-
|
|
121
|
+
( 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" ) &
|
|
140
123
|
fi
|
|
141
124
|
EXPO_PID=$!
|
|
142
|
-
|
|
125
|
+
disown $EXPO_PID 2>/dev/null || true
|
|
143
126
|
|
|
144
127
|
popd
|
|
145
128
|
}
|
|
@@ -147,7 +130,7 @@ start_expo() {
|
|
|
147
130
|
detect_expo_fetch_failed() {
|
|
148
131
|
local timeout="${1:-8}"
|
|
149
132
|
local waited=0
|
|
150
|
-
local log_file="logs/
|
|
133
|
+
local log_file="$ROOT_DIR/logs/client.log"
|
|
151
134
|
while [ "$waited" -lt "$timeout" ]; do
|
|
152
135
|
if [ -f "$log_file" ] && grep -q "TypeError: fetch failed" "$log_file" 2>/dev/null; then
|
|
153
136
|
return 0
|
|
@@ -162,78 +145,84 @@ detect_expo_fetch_failed() {
|
|
|
162
145
|
# 关掉nginx进程
|
|
163
146
|
ps -ef | grep nginx | grep -v grep | awk '{print $2}' | xargs -r kill -9
|
|
164
147
|
|
|
165
|
-
|
|
148
|
+
echo "检查根目录 pre_install.py"
|
|
166
149
|
if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
|
|
167
|
-
|
|
168
|
-
python "$PREVIEW_DIR/pre_install.py" ||
|
|
150
|
+
echo "执行:python $PREVIEW_DIR/pre_install.py"
|
|
151
|
+
python "$PREVIEW_DIR/pre_install.py" || echo "pre_install.py 执行失败"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
echo "检查根目录 post_install.py"
|
|
155
|
+
if [ -f "$PREVIEW_DIR/post_install.py" ]; then
|
|
156
|
+
echo "执行:python $PREVIEW_DIR/post_install.py"
|
|
157
|
+
python "$PREVIEW_DIR/post_install.py" || echo "post_install.py 执行失败"
|
|
169
158
|
fi
|
|
170
159
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
160
|
+
echo "==================== 开始启动 ===================="
|
|
161
|
+
echo "开始执行服务启动脚本(start_dev.sh)..."
|
|
162
|
+
echo "正在检查依赖命令和目录是否存在..."
|
|
174
163
|
# 检查核心命令
|
|
175
|
-
# check_command "python"
|
|
176
164
|
check_command "npm"
|
|
177
165
|
check_command "pnpm"
|
|
178
166
|
check_command "lsof"
|
|
179
167
|
check_command "bash"
|
|
180
168
|
|
|
181
|
-
|
|
182
|
-
mkdir -p logs
|
|
169
|
+
echo "准备日志目录:$ROOT_DIR/logs"
|
|
170
|
+
mkdir -p "$ROOT_DIR/logs"
|
|
183
171
|
# 端口占用预检查与处理
|
|
184
172
|
ensure_port SERVER_PORT "$SERVER_PORT"
|
|
185
173
|
ensure_port EXPO_PORT "$EXPO_PORT"
|
|
186
174
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
PORT="$SERVER_PORT" nohup npm run dev --prefix ./server > logs/app.log 2>&1 &
|
|
175
|
+
echo "==================== 启动 server 服务 ===================="
|
|
176
|
+
echo "正在执行:pnpm run dev (server)"
|
|
177
|
+
( pushd "$ROOT_DIR/server" > /dev/null && SERVER_PORT="$SERVER_PORT" nohup pnpm run dev; popd > /dev/null ) &
|
|
191
178
|
SERVER_PID=$!
|
|
179
|
+
disown $SERVER_PID 2>/dev/null || true
|
|
192
180
|
if [ -z "${SERVER_PID}" ]; then
|
|
193
|
-
|
|
181
|
+
echo "无法获取 server 后台进程 PID"
|
|
194
182
|
fi
|
|
195
|
-
|
|
183
|
+
echo "server 服务已启动,进程 ID:${SERVER_PID:-unknown}"
|
|
196
184
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
185
|
+
echo "==================== 启动 Expo 项目 ===================="
|
|
186
|
+
echo "开始启动 Expo 服务,端口 ${EXPO_PORT}"
|
|
187
|
+
start_expo 0
|
|
200
188
|
if detect_expo_fetch_failed 8; then
|
|
201
|
-
|
|
189
|
+
echo "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
|
|
202
190
|
if [ -n "${EXPO_PID}" ]; then kill -9 "$EXPO_PID" 2>/dev/null || true; fi
|
|
203
|
-
: > logs/
|
|
204
|
-
|
|
191
|
+
: > "$ROOT_DIR/logs/client.log"
|
|
192
|
+
start_expo 1
|
|
205
193
|
fi
|
|
206
194
|
# 输出以下环境变量,确保 Expo 项目能正确连接到 Server 服务
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
195
|
+
echo "Expo 环境变量配置:"
|
|
196
|
+
echo "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
|
|
197
|
+
echo "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
|
|
198
|
+
echo "EXPO_PUBLIC_COZE_PROJECT_ID=${EXPO_PUBLIC_COZE_PROJECT_ID}"
|
|
210
199
|
if [ -z "${EXPO_PID}" ]; then
|
|
211
|
-
|
|
200
|
+
echo "无法获取 Expo 后台进程 PID"
|
|
212
201
|
fi
|
|
213
202
|
|
|
214
|
-
|
|
203
|
+
echo "所有服务已启动。Server PID: ${SERVER_PID}, Expo PID: ${EXPO_PID}"
|
|
215
204
|
|
|
216
|
-
|
|
205
|
+
echo "检查 Server 服务端口:$SERVER_HOST:$SERVER_PORT"
|
|
217
206
|
if wait_port_connectable "$SERVER_HOST" "$SERVER_PORT" 10 2; then
|
|
218
|
-
|
|
207
|
+
echo "端口可连接:$SERVER_HOST:$SERVER_PORT"
|
|
219
208
|
else
|
|
220
|
-
|
|
209
|
+
echo "端口不可连接:$SERVER_HOST:$SERVER_PORT 10 次)"
|
|
221
210
|
fi
|
|
222
211
|
|
|
223
|
-
|
|
212
|
+
echo "检查 Expo 服务端口:$EXPO_HOST:$EXPO_PORT"
|
|
224
213
|
if wait_port_connectable "$EXPO_HOST" "$EXPO_PORT" 10 2; then
|
|
225
|
-
|
|
214
|
+
echo "端口可连接:$EXPO_HOST:$EXPO_PORT"
|
|
226
215
|
else
|
|
227
|
-
|
|
216
|
+
echo "端口不可连接:$EXPO_HOST:$EXPO_PORT(已尝试 10 次)"
|
|
228
217
|
fi
|
|
229
218
|
|
|
230
|
-
|
|
219
|
+
echo "服务端口检查完成"
|
|
231
220
|
|
|
232
|
-
|
|
221
|
+
echo "检查根目录 post_run.py"
|
|
233
222
|
if [ -f "$ROOT_DIR/post_run.py" ]; then
|
|
234
|
-
|
|
235
|
-
python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" ||
|
|
236
|
-
|
|
223
|
+
echo "启动检查中"
|
|
224
|
+
python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" || echo "post_run.py 执行失败"
|
|
225
|
+
echo "启动检查结束"
|
|
237
226
|
fi
|
|
238
227
|
|
|
239
|
-
|
|
228
|
+
echo "==================== 服务启动完成 ===================="
|
|
@@ -40,8 +40,8 @@ fi
|
|
|
40
40
|
info "==================== 依赖安装完成!====================\n"
|
|
41
41
|
|
|
42
42
|
info "==================== dist打包 ===================="
|
|
43
|
-
info "开始执行:
|
|
44
|
-
(
|
|
43
|
+
info "开始执行:pnpm run build (server)"
|
|
44
|
+
(pushd "$ROOT_DIR/server" > /dev/null && pnpm run build; popd > /dev/null) || error "dist打包失败"
|
|
45
45
|
info "==================== dist打包完成!====================\n"
|
|
46
46
|
|
|
47
47
|
info "下一步:执行 ./prod_run.sh 启动服务"
|
|
@@ -29,6 +29,6 @@ check_command() {
|
|
|
29
29
|
check_command "pnpm"
|
|
30
30
|
check_command "npm"
|
|
31
31
|
|
|
32
|
-
info "开始执行:
|
|
33
|
-
(
|
|
32
|
+
info "开始执行:pnpm run start (server)"
|
|
33
|
+
(pushd "$ROOT_DIR/server" > /dev/null && PORT="$PORT" pnpm run start; popd > /dev/null) || error "服务启动失败"
|
|
34
34
|
info "服务启动完成!\n"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
4
|
+
SERVER_DIR="$ROOT_DIR/server"
|
|
5
|
+
LOG_DIR="$ROOT_DIR/logs"
|
|
6
|
+
LOG_FILE="$LOG_DIR/server.log"
|
|
7
|
+
SERVER_PORT="${SERVER_PORT:-9091}"
|
|
8
|
+
|
|
9
|
+
mkdir -p "$LOG_DIR"
|
|
10
|
+
|
|
11
|
+
pipe_to_log() {
|
|
12
|
+
local source="${1:-SERVER}"
|
|
13
|
+
local raw_log="${2:-}"
|
|
14
|
+
local line
|
|
15
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
16
|
+
if [ -n "$raw_log" ]; then
|
|
17
|
+
echo "$line" >> "$raw_log"
|
|
18
|
+
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
|
+
done
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
kill_old_server() {
|
|
25
|
+
if command -v lsof &> /dev/null; then
|
|
26
|
+
local pids
|
|
27
|
+
pids=$(lsof -t -i tcp:"$SERVER_PORT" -sTCP:LISTEN 2>/dev/null || true)
|
|
28
|
+
if [ -n "$pids" ]; then
|
|
29
|
+
echo "正在关闭旧的 server 进程:$pids"
|
|
30
|
+
kill -9 $pids 2>/dev/null || echo "关闭进程失败:$pids"
|
|
31
|
+
sleep 1
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
echo "==================== Server Dev Run ===================="
|
|
37
|
+
echo "Server 目录:$SERVER_DIR"
|
|
38
|
+
echo "Server 端口:$SERVER_PORT"
|
|
39
|
+
echo "日志文件:$LOG_FILE"
|
|
40
|
+
|
|
41
|
+
kill_old_server
|
|
42
|
+
|
|
43
|
+
echo "启动 server 服务..."
|
|
44
|
+
cd "$SERVER_DIR"
|
|
45
|
+
NODE_ENV=development PORT="$SERVER_PORT" npx tsx ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_FILE"
|
|
@@ -1,13 +1,74 @@
|
|
|
1
|
-
# Expo App
|
|
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
|
+
|
|
2
37
|
## 安装依赖
|
|
38
|
+
|
|
39
|
+
### 命令
|
|
40
|
+
|
|
3
41
|
```bash
|
|
4
|
-
pnpm
|
|
42
|
+
pnpm i
|
|
5
43
|
```
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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';
|
|
9
66
|
```
|
|
10
|
-
|
|
67
|
+
|
|
68
|
+
## 本地开发
|
|
69
|
+
|
|
70
|
+
运行 coze dev 可以同时启动前端和后端服务,如果端口已占用,该命令会先杀掉占用端口的进程再启动,也可以用来重启前端和后端服务
|
|
71
|
+
|
|
11
72
|
```bash
|
|
12
|
-
|
|
73
|
+
coze dev
|
|
13
74
|
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
2
|
+
import { Link } from 'expo-router';
|
|
3
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
4
|
+
import { Spacing } from '@/constants/theme';
|
|
5
|
+
|
|
6
|
+
export default function NotFoundScreen() {
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<View style={[styles.container, { backgroundColor: theme.backgroundRoot }]}>
|
|
11
|
+
<Text>
|
|
12
|
+
页面不存在
|
|
13
|
+
</Text>
|
|
14
|
+
<Link href="/" style={[styles.gohome]}>
|
|
15
|
+
返回首页
|
|
16
|
+
</Link>
|
|
17
|
+
</View>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
flex: 1,
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
},
|
|
27
|
+
gohome: {
|
|
28
|
+
marginTop: Spacing['2xl'],
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -5,6 +5,7 @@ import { StatusBar } from 'expo-status-bar';
|
|
|
5
5
|
import { LogBox } from 'react-native';
|
|
6
6
|
import Toast from 'react-native-toast-message';
|
|
7
7
|
import { AuthProvider } from "@/contexts/AuthContext";
|
|
8
|
+
import { ColorSchemeProvider } from '@/hooks/useColorScheme';
|
|
8
9
|
|
|
9
10
|
LogBox.ignoreLogs([
|
|
10
11
|
"TurboModuleRegistry.getEnforcing(...): 'RNMapsAirModule' could not be found",
|
|
@@ -14,20 +15,22 @@ LogBox.ignoreLogs([
|
|
|
14
15
|
export default function RootLayout() {
|
|
15
16
|
return (
|
|
16
17
|
<AuthProvider>
|
|
18
|
+
<ColorSchemeProvider>
|
|
17
19
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
<StatusBar style="dark"></StatusBar>
|
|
21
|
+
<Stack screenOptions={{
|
|
22
|
+
// 设置所有页面的切换动画为从右侧滑入,适用于iOS 和 Android
|
|
23
|
+
animation: 'slide_from_right',
|
|
24
|
+
gestureEnabled: true,
|
|
25
|
+
gestureDirection: 'horizontal',
|
|
26
|
+
// 隐藏自带的头部
|
|
27
|
+
headerShown: false
|
|
28
|
+
}}>
|
|
29
|
+
<Stack.Screen name="index" options={{ title: "" }} />
|
|
30
|
+
</Stack>
|
|
31
|
+
<Toast />
|
|
30
32
|
</GestureHandlerRootView>
|
|
33
|
+
</ColorSchemeProvider>
|
|
31
34
|
</AuthProvider>
|
|
32
35
|
);
|
|
33
36
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@/screens/demo';
|