Files
ECShopX/docker-dev/web-entrypoint.sh
2026-07-20 13:46:08 +08:00

118 lines
3.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# ECShopX Web 前端Nuxt容器启动脚本
# 容器重启后自动启动已编译的 Nuxt 生产服务
APP_DIR="/data/httpd/ECShopX_web-frontend"
BUILD_FILE="$APP_DIR/.output/server/index.mjs"
LOG_FILE="/var/log/nuxt.log"
WAIT_INTERVAL="${NUXT_WAIT_INTERVAL:-10}"
PUBLIC_API_BASE="${NUXT_PUBLIC_API_BASE:-http://localhost:8080/api/h5app}"
INTERNAL_API_BASE="${NUXT_INTERNAL_API_BASE:-${NUXT_API_BASE:-http://ecshopx-dev:8080/api/h5app}}"
export TZ="${TZ:-Asia/Shanghai}"
export NITRO_HOST=0.0.0.0
export NITRO_PORT=3000
export HOST=0.0.0.0
export PORT=3000
cd "$APP_DIR" || {
echo "错误: 无法进入目录 $APP_DIR"
exit 1
}
start_local_api_proxy() {
node <<'NODE_PROXY' &
const http = require('http')
const https = require('https')
const publicBase = process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:8080/api/h5app'
const internalBase =
process.env.NUXT_INTERNAL_API_BASE ||
process.env.NUXT_API_BASE ||
'http://ecshopx-dev:8080/api/h5app'
let publicUrl
let internalUrl
try {
publicUrl = new URL(publicBase)
internalUrl = new URL(internalBase)
} catch (error) {
console.error(`[SSR API Proxy] API URL 解析失败: ${error.message}`)
process.exit(0)
}
const localHosts = new Set(['localhost', '127.0.0.1', '::1'])
if (!localHosts.has(publicUrl.hostname)) {
console.log(`[SSR API Proxy] NUXT_PUBLIC_API_BASE=${publicBase} 不是本机地址,跳过本地转发`)
process.exit(0)
}
const listenHost = publicUrl.hostname === '::1' ? '::1' : '127.0.0.1'
const listenPort = Number(publicUrl.port || (publicUrl.protocol === 'https:' ? 443 : 80))
const publicPath = publicUrl.pathname.replace(/\/+$/, '') || '/'
const internalPath = internalUrl.pathname.replace(/\/+$/, '') || '/'
const transport = internalUrl.protocol === 'https:' ? https : http
function joinTargetPath(requestPath) {
const suffix = requestPath.startsWith(publicPath) ? requestPath.slice(publicPath.length) : requestPath
const normalizedSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`
return `${internalPath}${normalizedSuffix}`.replace(/\/{2,}/g, '/')
}
const server = http.createServer((req, res) => {
const incomingUrl = new URL(req.url || '/', publicUrl)
const headers = { ...req.headers, host: internalUrl.host }
const targetPath = `${joinTargetPath(incomingUrl.pathname)}${incomingUrl.search}`
const proxyReq = transport.request(
{
protocol: internalUrl.protocol,
hostname: internalUrl.hostname,
port: internalUrl.port || (internalUrl.protocol === 'https:' ? 443 : 80),
method: req.method,
path: targetPath,
headers,
},
(proxyRes) => {
res.writeHead(proxyRes.statusCode || 502, proxyRes.headers)
proxyRes.pipe(res)
}
)
proxyReq.on('error', (error) => {
console.error(`[SSR API Proxy] ${req.method} ${targetPath} -> ${error.message}`)
if (!res.headersSent) {
res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' })
}
res.end('Bad Gateway')
})
req.pipe(proxyReq)
})
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
console.log(`[SSR API Proxy] ${listenHost}:${listenPort} 已被占用,跳过本地转发`)
return
}
console.error(`[SSR API Proxy] 启动失败: ${error.message}`)
})
server.listen(listenPort, listenHost, () => {
console.log(`[SSR API Proxy] http://${listenHost}:${listenPort}${publicPath} -> ${internalBase}`)
})
NODE_PROXY
}
export NUXT_PUBLIC_API_BASE="$PUBLIC_API_BASE"
export NUXT_INTERNAL_API_BASE="$INTERNAL_API_BASE"
start_local_api_proxy
echo "等待 Nuxt 生产构建产物: $BUILD_FILE"
while [ ! -f "$BUILD_FILE" ]; do
echo "未找到构建产物,${WAIT_INTERVAL} 秒后重试(可先运行 dev-setup.sh 完成编译)..."
sleep "$WAIT_INTERVAL"
done
echo "启动 Nuxt 服务 (0.0.0.0:3000)..."
exec node .output/server/index.mjs >> "$LOG_FILE" 2>&1