feat(0.2.1): 单端口生产架构 —— /sync 同域反代 (去掉 13002 独立同步端口), 新增 deploy/prod 生产编排

This commit is contained in:
jif2.zhang
2026-10-26 21:57:40 +08:00
parent 4b19d1d929
commit 30bc489b5c
10 changed files with 301 additions and 0 deletions
+3
View File
@@ -17,12 +17,15 @@ import checklistsRouter from './routes/checklists.js'
import projectsRouter, { columnRouter } from './routes/projects.js'
import tasksRouter from './routes/tasks.js'
import powersyncRouter from './routes/powersync.js'
import { powersyncProxy } from './powersync-proxy.js'
const PORT = Number(process.env.PORT) || 3001
const DIST_DIR = path.join(process.cwd(), 'dist')
const HAS_DIST = fs.existsSync(DIST_DIR)
const app = express()
// 同步服务同域反代必须最先挂载 (流式长连接, 不能经过 json/cors 中间件)
app.use(powersyncProxy())
app.use(cors())
app.use(express.json())
+54
View File
@@ -0,0 +1,54 @@
// PowerSync 同域反代 (0.2.1): 把 /sync、/socket 转发到内网同步服务,
// 对外只暴露应用本身一个端口 (无需单独的 powersync 端口)。
// - 未配置 POWERSYNC_UPSTREAM 时直接跳过 (本地开发/无同步服务时行为不变)
// - 必须挂在 express.json()/cors 之前: 同步走长连接流式响应, 不能被 body 解析打断
import http from 'node:http'
import https from 'node:https'
const PREFIXES = ['/sync', '/socket']
export function powersyncProxy() {
const upstream = process.env.POWERSYNC_UPSTREAM
if (!upstream) return (_req, _res, next) => next()
let target
try {
target = new URL(upstream)
} catch {
console.error('[powersync-proxy] POWERSYNC_UPSTREAM 非法:', upstream)
return (_req, _res, next) => next()
}
const transport = target.protocol === 'https:' ? https : http
const basePort = Number(target.port) || (target.protocol === 'https:' ? 443 : 80)
console.log('[powersync-proxy] 同步请求转发到', target.origin)
return (req, res, next) => {
if (!PREFIXES.some((p) => req.url === p || req.url.startsWith(p + '/') || req.url.startsWith(p + '?'))) {
return next()
}
const headers = { ...req.headers, host: target.host }
const upstreamReq = transport.request(
{
protocol: target.protocol,
hostname: target.hostname,
port: basePort,
method: req.method,
path: req.url,
headers,
},
(upstreamRes) => {
res.writeHead(upstreamRes.statusCode || 502, upstreamRes.headers)
upstreamRes.pipe(res)
},
)
upstreamReq.on('error', (e) => {
console.error('[powersync-proxy] 转发失败:', e.message)
if (!res.headersSent) res.writeHead(502, { 'content-type': 'text/plain' })
res.end('powersync upstream error')
})
// 长连接: 客户端断开时同步断开上游
req.on('aborted', () => upstreamReq.destroy())
res.on('close', () => upstreamReq.destroy())
req.pipe(upstreamReq)
}
}