mirror of
https://github.com/kuaifan/dootask.git
synced 2026-11-03 16:30:32 +00:00
feat(app): 新增 ./cmd expo dev 同时启动前端与 Metro,appexpo 命令更名为 expo
- ./cmd expo [build|dev|npm],与 ./cmd electron 同规范;CI 同步改用 ./cmd expo build - expo dev:Metro 端口自动找空闲(指定 EXPO_PACKAGER_PROXY_URL 时固定并在占用时报错),地址按 VSCODE_PROXY_URI 推导或命令行传入 - vite 开发反代开启 gzip,减少手机经公网加载开发前端的体积 - resources/app:DooTask (dev) 变体
This commit is contained in:
parent
aca8fc6b24
commit
3192e43db3
2
.github/workflows/app-build.yml
vendored
2
.github/workflows/app-build.yml
vendored
@ -96,7 +96,7 @@ jobs:
|
||||
run: npm install --include=dev --no-package-lock --no-audit --no-fund
|
||||
|
||||
- name: Build and copy web assets
|
||||
run: ./cmd appexpo build
|
||||
run: ./cmd expo build
|
||||
|
||||
- name: Upload bundled web assets
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
39
cmd
39
cmd
@ -417,13 +417,14 @@ electron_operate() {
|
||||
env BUILD_FRONTEND=$BUILD_FRONTEND node ./electron/build.js $argv
|
||||
}
|
||||
|
||||
# Expo App 前端:同 electron 使用本机 Node,不依赖 Docker。
|
||||
appexpo_operate() {
|
||||
# Expo App:同 electron 使用本机 Node,不依赖 Docker。
|
||||
expo_operate() {
|
||||
local usage="用法: ./cmd expo [build] | ./cmd expo dev | ./cmd expo npm <参数...>"
|
||||
check_node
|
||||
case "${1:-build}" in
|
||||
"build")
|
||||
"build"|"dev")
|
||||
if [[ $# -gt 1 ]]; then
|
||||
error "用法: ./cmd appexpo [build] | ./cmd appexpo npm <参数...>"
|
||||
error "$usage"
|
||||
return 1
|
||||
fi
|
||||
if [ ! -d "./node_modules" ]; then
|
||||
@ -432,14 +433,22 @@ appexpo_operate() {
|
||||
if [ ! -d "./electron/node_modules" ]; then
|
||||
(cd electron && npm install --no-package-lock) || return $?
|
||||
fi
|
||||
node ./electron/build.js app-expo build
|
||||
if [ "$1" == "dev" ]; then
|
||||
if [ ! -d "./resources/app/node_modules" ]; then
|
||||
(cd resources/app && npm install --no-audit --no-fund) || return $?
|
||||
fi
|
||||
switch_debug dev
|
||||
node ./electron/build.js app-expo dev
|
||||
else
|
||||
node ./electron/build.js app-expo build
|
||||
fi
|
||||
;;
|
||||
"npm")
|
||||
shift
|
||||
(cd "${WORK_DIR}/resources/app" && npm "$@")
|
||||
;;
|
||||
*)
|
||||
error "用法: ./cmd appexpo [build] | ./cmd appexpo npm <参数...>"
|
||||
error "$usage"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
@ -699,8 +708,9 @@ DooTask 管理脚本
|
||||
serve, dev 启动开发模式
|
||||
build, prod 生产环境构建
|
||||
electron 构建桌面应用
|
||||
appexpo [build] 编译并同步 Expo App 前端
|
||||
appexpo npm <参数...> 在 Expo 子模块执行本机 npm
|
||||
expo [build] 编译并同步 Expo App 前端
|
||||
expo dev 启动 App 开发模式(Metro + 前端)
|
||||
expo npm <参数...> 在 Expo 子模块执行本机 npm
|
||||
|
||||
🔧 服务管理:
|
||||
up [服务名] 启动容器
|
||||
@ -752,8 +762,9 @@ Usage: ./cmd <command> [options]
|
||||
serve, dev Start dev mode
|
||||
build, prod Production build
|
||||
electron Build desktop app
|
||||
appexpo [build] Build and copy Expo App web assets
|
||||
appexpo npm <args...> Run local npm in the Expo submodule
|
||||
expo [build] Build and copy Expo App web assets
|
||||
expo dev Start App dev mode (Metro + web)
|
||||
expo npm <args...> Run local npm in the Expo submodule
|
||||
|
||||
🔧 Services:
|
||||
up [service] Start containers
|
||||
@ -1216,8 +1227,8 @@ if [[ "$1" == "help" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]] || [[ $#
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 非electron、appexpo和permission命令需要检查Docker环境
|
||||
if [[ "$1" != "electron" ]] && [[ "$1" != "appexpo" ]] && [[ "$1" != "permission" ]]; then
|
||||
# 非electron、expo和permission命令需要检查Docker环境
|
||||
if [[ "$1" != "electron" ]] && [[ "$1" != "expo" ]] && [[ "$1" != "permission" ]]; then
|
||||
check_docker
|
||||
env_init
|
||||
fi
|
||||
@ -1276,9 +1287,9 @@ case "$1" in
|
||||
shift 1
|
||||
web_build prod
|
||||
;;
|
||||
"appexpo")
|
||||
"expo")
|
||||
shift 1
|
||||
appexpo_operate "$@"
|
||||
expo_operate "$@"
|
||||
exit $?
|
||||
;;
|
||||
"electron")
|
||||
|
||||
87
electron/build.js
vendored
87
electron/build.js
vendored
@ -509,31 +509,78 @@ if (["dev"].includes(argv[2])) {
|
||||
child_process.spawn("npx", ["vite", "--", "fromcmd", "electronDev"], {stdio: "inherit"});
|
||||
child_process.spawn("npm", ["run", "start-quiet"], {stdio: "inherit", cwd: "electron"});
|
||||
} else if (argv[2] === 'app-expo') {
|
||||
if ((argv[3] && argv[3] !== 'build') || argv.length > 4) {
|
||||
console.error("用法: node ./electron/build.js app-expo [build]");
|
||||
if ((argv[3] && !['build', 'dev'].includes(argv[3])) || argv.length > 4) {
|
||||
console.error("用法: node ./electron/build.js app-expo [build|dev]");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!fs.existsSync(path.resolve(__dirname, "../resources/app/app.config.ts"))) {
|
||||
const appDir = path.resolve(__dirname, "../resources/app");
|
||||
if (!fs.existsSync(path.resolve(appDir, "app.config.ts"))) {
|
||||
console.error("resources/app 未找到,请先初始化 Expo 子模块");
|
||||
process.exit(1);
|
||||
}
|
||||
startBuild({
|
||||
name: 'App',
|
||||
id: 'app-expo',
|
||||
// public 是前端“尚未设置服务器”的占位域名,不是静态资源的 origin。
|
||||
// electronBuild 的 ./ 资源路径在 localhost:22223/ 下加载,路由自动使用 hash。
|
||||
url: 'http://public/',
|
||||
configure: {
|
||||
platform: '',
|
||||
archs: [],
|
||||
publish: false,
|
||||
release: true,
|
||||
notarize: false,
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error.message || error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
if (argv[3] === 'dev') {
|
||||
// 开发模式:前端 vite + Metro;键盘交给 Metro(r 重载等),任一退出则全部结束
|
||||
// 地址优先取命令行环境变量,其次按 VSCODE_PROXY_URI 端口模板推导,都没有则 Metro 由 Expo 自动取局域网地址、前端取本机局域网 IP
|
||||
// 手动指定 EXPO_PACKAGER_PROXY_URL 时端口固定(METRO_PORT,默认 2220),否则从 2220 起自动找空闲端口
|
||||
const appPort = env.parsed.APP_PORT;
|
||||
const proxyUri = process.env.VSCODE_PROXY_URI || '';
|
||||
const proxyUrl = port => proxyUri.includes('{{port}}') ? proxyUri.replace(/\{\{port\}\}/g, port).replace(/\/+$/, '') : '';
|
||||
const lanIp = Object.values(require('os').networkInterfaces()).flat().find(item => item.family === 'IPv4' && !item.internal)?.address;
|
||||
const webUrl = process.env.EXPO_PUBLIC_WEB_URL || proxyUrl(appPort) || (lanIp ? `http://${lanIp}:${appPort}` : '');
|
||||
const fixedPort = !!process.env.EXPO_PACKAGER_PROXY_URL;
|
||||
const isPortFree = port => new Promise(resolve => {
|
||||
const server = require('net').createServer();
|
||||
server.once('error', () => resolve(false));
|
||||
server.listen(port, () => server.close(() => resolve(true)));
|
||||
});
|
||||
(async () => {
|
||||
let metroPort = Number(process.env.METRO_PORT) || 2220;
|
||||
// 跳过前端端口 APP_PORT:nginx 未启动时它也是空闲的,被 Metro 占用会导致 nginx 起不来
|
||||
while (metroPort == appPort || !await isPortFree(metroPort)) {
|
||||
if (fixedPort || metroPort >= 2299) {
|
||||
console.error(`Metro 端口 ${metroPort} 已被占用,请先关闭旧的 Metro`);
|
||||
process.exit(1);
|
||||
}
|
||||
metroPort++;
|
||||
}
|
||||
const packagerUrl = process.env.EXPO_PACKAGER_PROXY_URL || proxyUrl(metroPort);
|
||||
console.log(`Metro 地址:${packagerUrl || '自动(局域网)'}`);
|
||||
console.log(`前端地址:${webUrl || '本地 Web 服务'}`);
|
||||
const appEnv = {...process.env, EXPO_PUBLIC_WEB_URL: webUrl};
|
||||
if (packagerUrl) appEnv.EXPO_PACKAGER_PROXY_URL = packagerUrl;
|
||||
const children = [
|
||||
child_process.spawn("npx", ["vite", "--", "fromcmd"], {stdio: ["ignore", "inherit", "inherit"]}),
|
||||
child_process.spawn("npx", ["expo", "start", "--dev-client", "--port", String(metroPort)], {stdio: "inherit", cwd: appDir, env: appEnv}),
|
||||
];
|
||||
let exiting = false;
|
||||
const stopAll = (code) => {
|
||||
if (exiting) return;
|
||||
exiting = true;
|
||||
process.exitCode = code;
|
||||
children.forEach(child => child.exitCode === null && child.kill('SIGTERM'));
|
||||
};
|
||||
children.forEach(child => child.on('exit', code => stopAll(code || 0)));
|
||||
['SIGINT', 'SIGTERM'].forEach(signal => process.on(signal, () => stopAll(0)));
|
||||
})();
|
||||
} else {
|
||||
startBuild({
|
||||
name: 'App',
|
||||
id: 'app-expo',
|
||||
// public 是前端“尚未设置服务器”的占位域名,不是静态资源的 origin。
|
||||
// electronBuild 的 ./ 资源路径在 localhost:22223/ 下加载,路由自动使用 hash。
|
||||
url: 'http://public/',
|
||||
configure: {
|
||||
platform: '',
|
||||
archs: [],
|
||||
publish: false,
|
||||
release: true,
|
||||
notarize: false,
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error.message || error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
} else if (["android-upload"].includes(argv[2])) {
|
||||
// 上传安卓文件到 R2 draft(GitHub Actions):参数为 APK 所在目录(app-build.yml 产出的 app-android)
|
||||
(async () => {
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit d2ff9a54a0cfc1ea9942531193cc8265d80b7135
|
||||
Subproject commit cc14a508968a299146091ac44c8f421acb3358a3
|
||||
5
vite.config.js
vendored
5
vite.config.js
vendored
@ -74,6 +74,11 @@ function devProxyPlugin(env, devBase) {
|
||||
` proxy_set_header Connection $connection_upgrade;`,
|
||||
` proxy_read_timeout 1d;`,
|
||||
` proxy_buffering off;`,
|
||||
// vite 开发服务不压缩,模块总量十几 MB,手机经公网加载时尤其慢
|
||||
` gzip on;`,
|
||||
` gzip_proxied any;`,
|
||||
` gzip_min_length 1024;`,
|
||||
` gzip_types application/javascript text/javascript text/css application/json;`,
|
||||
` proxy_pass http://host.docker.internal:${port};`,
|
||||
`}`,
|
||||
``,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user