mirror of
https://github.com/kuaifan/dootask.git
synced 2026-10-29 22:10:42 +00:00
refactor(dev): 开发模式改由 nginx 同源反代 vite,移除 VSCODE_PROXY_URI 拼接
- vite 开发 base 改为 /__vite/,nginx 通过 host.docker.internal 反代(含 HMR websocket),任意访问地址/代理下均可用 - vite 端口默认 5173,被占用自动顺延,实际端口由 devProxyPlugin 写入 nginx 片段并 reload(先 nginx -t 校验,失败不保留片段) - HMR 客户端改连当前页面源;启动输出改为应用访问地址 - public/hot 只写 base/port,不再泄露整个 .env - cmd dev 移除随机 APP_DEV_PORT、VSCODE_PROXY_URI 与 index.html 跳转;docker-compose nginx 增加 extra_hosts
This commit is contained in:
parent
c64fb1d98f
commit
aca8fc6b24
@ -63,11 +63,8 @@ class IndexController extends InvokeController
|
||||
if (file_exists($hotFile)) {
|
||||
$array = Base::json2array(file_get_contents($hotFile));
|
||||
$style = null;
|
||||
$script = preg_replace("/^(\/\/(.*?))(:\d+)?\//i", "$1:" . $array['APP_DEV_PORT'] . "/", asset_main("resources/assets/js/app.js"));
|
||||
$proxyUri = Base::liveEnv('VSCODE_PROXY_URI');
|
||||
if (is_string($proxyUri) && preg_match('/^https?:\/\//i', $proxyUri)) {
|
||||
$script = preg_replace('/^(https?:\/\/|\/\/)[^\/]+/', rtrim($proxyUri, '/'), $script, 1);
|
||||
}
|
||||
// 开发模式:vite 经 nginx 反代在同源的 base 路径下(见 vite.config.js devProxyPlugin)
|
||||
$script = asset_main(trim($array['base'] ?? '/__vite/', '/') . "/resources/assets/js/app.js");
|
||||
} else {
|
||||
$array = Base::json2array(file_get_contents($manifestFile));
|
||||
$style = asset_main($array['resources/assets/js/app.js']['css'][0]);
|
||||
|
||||
12
cmd
12
cmd
@ -379,18 +379,6 @@ web_build() {
|
||||
if [ ! -d "./node_modules" ]; then
|
||||
npm install
|
||||
fi
|
||||
if [ "$type" = "dev" ]; then
|
||||
echo "<script>window.location.href=window.location.href.replace(/:\d+/, ':' + $(env_get APP_PORT))</script>" > ./index.html
|
||||
if [ -z "$(env_get APP_DEV_PORT)" ]; then
|
||||
env_set APP_DEV_PORT $(rand 20001 30000)
|
||||
fi
|
||||
if [ -n "${VSCODE_PROXY_URI:-}" ]; then
|
||||
APP_REAL_URI=$(TARGET_PORT="$(env_get APP_PORT)" node -p "process.env.VSCODE_PROXY_URI.replace(/\{\{port\}\}/g, process.env.TARGET_PORT || '')")
|
||||
VSCODE_PROXY_URI=$(APP_DEV_PORT="$(env_get APP_DEV_PORT)" node -p "process.env.VSCODE_PROXY_URI.replace(/\{\{port\}\}/g, process.env.APP_DEV_PORT || '')")
|
||||
echo "<script>window.location.href='${APP_REAL_URI}'</script>" > ./index.html
|
||||
fi
|
||||
env_set VSCODE_PROXY_URI "${VSCODE_PROXY_URI:-}"
|
||||
fi
|
||||
switch_debug "$type"
|
||||
#
|
||||
if [ "$type" = "prod" ]; then
|
||||
|
||||
@ -45,6 +45,8 @@ services:
|
||||
- "${APP_SSL_PORT:-0}:443"
|
||||
environment:
|
||||
APP_SCHEME: "${APP_SCHEME:-auto}"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./docker/nginx/default.conf:/etc/nginx/templates/default.conf.template
|
||||
- ./:/var/www
|
||||
|
||||
128
vite.config.js
vendored
128
vite.config.js
vendored
@ -18,28 +18,99 @@ if (!argv.includes('fromcmd')) {
|
||||
process.exit()
|
||||
}
|
||||
|
||||
/**
|
||||
* 开发模式:由 nginx 把 /__vite/ 反代到本机 vite,页面与 vite 同源,任意访问地址/代理下均可用
|
||||
* - 监听成功后写入 nginx 反代片段并 reload,同时写 public/hot 通知后端走开发资源
|
||||
* - 退出时清理并 reload
|
||||
*/
|
||||
function devProxyPlugin(env, devBase) {
|
||||
const hotFile = path.resolve(__dirname, 'public/hot')
|
||||
const confFile = path.resolve(__dirname, 'docker/nginx/site/vite-dev.conf')
|
||||
const nginxName = `dootask-nginx-${env['APP_ID']}`
|
||||
const reloadNginx = () => {
|
||||
try {
|
||||
// nginx -s reload 在配置有误时也返回成功,先 -t 校验
|
||||
execSync(`docker exec ${nginxName} sh -c "nginx -t -q && nginx -s reload"`, {stdio: 'pipe'})
|
||||
return true
|
||||
} catch (e) {
|
||||
console.warn(`[dev-proxy] reload ${nginxName} failed: ${String(e.stderr || e.message).trim()}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
const cleanup = () => {
|
||||
const exists = fs.existsSync(confFile)
|
||||
fs.rmSync(hotFile, {force: true})
|
||||
fs.rmSync(confFile, {force: true})
|
||||
exists && reloadNginx()
|
||||
}
|
||||
return {
|
||||
name: 'dootask-dev-proxy',
|
||||
configureServer(server) {
|
||||
// 浏览器经 nginx 访问应用,不直接访问 vite,替换 vite 默认打印的地址
|
||||
server.printUrls = () => {
|
||||
const {info, warn} = server.config.logger
|
||||
if (!fs.existsSync(hotFile)) {
|
||||
warn(` > Proxy unavailable`)
|
||||
return
|
||||
}
|
||||
// 与 vite 默认输出一致:地址青色、端口加粗
|
||||
const useColor = process.stdout.isTTY && !('NO_COLOR' in process.env)
|
||||
const ansi = (open, close) => text => useColor ? `\x1b[${open}m${text}\x1b[${close}m` : text
|
||||
const cyan = ansi(36, 39), bold = ansi(1, 22)
|
||||
const appPort = env['APP_PORT']
|
||||
info(` > Local: ${cyan(`http://localhost:${bold(appPort)}/`)}`)
|
||||
const proxyUri = process.env['VSCODE_PROXY_URI']
|
||||
if (proxyUri && proxyUri.includes('{{port}}')) {
|
||||
info(` > Network: ${cyan(proxyUri.replace(/\{\{port\}\}/g, bold(appPort)))}`)
|
||||
}
|
||||
}
|
||||
server.httpServer.once('listening', () => {
|
||||
const {port} = server.httpServer.address()
|
||||
fs.writeFileSync(confFile, [
|
||||
`location ^~ ${devBase} {`,
|
||||
` proxy_http_version 1.1;`,
|
||||
` proxy_set_header Host $host;`,
|
||||
` proxy_set_header Upgrade $http_upgrade;`,
|
||||
` proxy_set_header Connection $connection_upgrade;`,
|
||||
` proxy_read_timeout 1d;`,
|
||||
` proxy_buffering off;`,
|
||||
` proxy_pass http://host.docker.internal:${port};`,
|
||||
`}`,
|
||||
``,
|
||||
].join('\n'))
|
||||
if (reloadNginx()) {
|
||||
fs.writeFileSync(hotFile, JSON.stringify({base: devBase, port}))
|
||||
} else {
|
||||
// 不保留无效片段,否则 nginx 容器重启时会因配置错误起不来
|
||||
fs.rmSync(confFile, {force: true})
|
||||
}
|
||||
})
|
||||
// 修改配置后 vite 会重新加载本文件并重启服务,退出钩子挂在 globalThis 上只注册一次
|
||||
if (!globalThis.__dootaskDevProxyHooked) {
|
||||
globalThis.__dootaskDevProxyHooked = true
|
||||
process.on('exit', cleanup)
|
||||
for (const signal of ['SIGINT', 'SIGHUP', 'SIGTERM']) {
|
||||
process.on(signal, () => process.exit())
|
||||
}
|
||||
}
|
||||
},
|
||||
transform(code, id) {
|
||||
// vite 2 的 HMR 客户端固定连 location.hostname:端口,改为连当前页面的源(经 nginx 转发)
|
||||
if (id.includes('/vite/dist/client/client.mjs')) {
|
||||
return code.replace(
|
||||
/const socketHost = `\$\{__HMR_HOSTNAME__ \|\| location\.hostname\}:\$\{__HMR_PORT__\}`;/,
|
||||
`const socketHost = location.host + ${JSON.stringify(devBase)};`
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default defineConfig(({command, mode}) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const host = "0.0.0.0"
|
||||
const port = parseInt(env['APP_DEV_PORT'])
|
||||
const proxy_uri = env['VSCODE_PROXY_URI']
|
||||
|
||||
if (command === 'serve') {
|
||||
const hotFile = path.resolve(__dirname, 'public/hot')
|
||||
const hotClean = (exit) => {
|
||||
if (fs.existsSync(hotFile)) {
|
||||
fs.unlinkSync(hotFile);
|
||||
}
|
||||
if (exit) {
|
||||
process.exit()
|
||||
}
|
||||
}
|
||||
hotClean(false)
|
||||
fs.writeFileSync(hotFile, JSON.stringify(env));
|
||||
process.on('exit', () => hotClean(true));
|
||||
process.on('SIGINT', () => hotClean(true));
|
||||
process.on('SIGHUP', () => hotClean(true));
|
||||
}
|
||||
const port = parseInt(env['APP_DEV_PORT']) || 5173
|
||||
const devBase = '/__vite/'
|
||||
|
||||
const plugins = [
|
||||
createVuePlugin({
|
||||
@ -52,6 +123,9 @@ export default defineConfig(({command, mode}) => {
|
||||
vitePluginRequire(),
|
||||
vitePluginFileCopy([staticDir])
|
||||
]
|
||||
if (command === 'serve') {
|
||||
plugins.push(devProxyPlugin(env, devBase))
|
||||
}
|
||||
if (mode === "development") {
|
||||
plugins.push({
|
||||
name: 'watch-copy',
|
||||
@ -81,24 +155,13 @@ export default defineConfig(({command, mode}) => {
|
||||
})
|
||||
}
|
||||
|
||||
const serverHmr = {}
|
||||
if (/^https?:\/\//i.test(proxy_uri)) {
|
||||
const proxyUri = new URL(proxy_uri)
|
||||
if (proxyUri) {
|
||||
Object.assign(serverHmr, {
|
||||
host: proxyUri.host,
|
||||
clientPort: proxyUri.port || (/^https/.test(proxy_uri) ? 443 : 80)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
base: basePath,
|
||||
base: command === 'serve' ? devBase : basePath,
|
||||
publicDir: publicPath,
|
||||
server: {
|
||||
host,
|
||||
port,
|
||||
strictPort: false,
|
||||
strictPort: false, // 端口被占用时自动顺延,实际端口由 devProxyPlugin 同步给 nginx
|
||||
watch: {
|
||||
ignored: [
|
||||
'**/node_modules/**',
|
||||
@ -111,7 +174,6 @@ export default defineConfig(({command, mode}) => {
|
||||
'**/electron/**',
|
||||
]
|
||||
},
|
||||
hmr: serverHmr
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user