import 'dotenv/config' import fs from 'node:fs/promises'; import { URL } from 'node:url'; import { Transform } from 'node:stream'; import { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; import { Hono } from 'hono'; import { cors } from 'hono/cors' import { logger } from 'hono/logger'; import { createServer as createNodeServer } from 'node:http'; import process from 'node:process'; import { createAdaptorServer } from '@hono/node-server' // 新增:导入 Socket.IO import { Server } from 'socket.io'; // 创建 Hono 应用 const app = new Hono(); // 全局使用 Hono 日志中间件(记录所有请求) app.use('*', logger()); app.use('*', cors( // { // origin: ['http://localhost:3000'], // allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // credentials: true // } )) // 常量定义 const isProduction = process.env.NODE_ENV === 'production'; const port = process.env.PORT || 8080; const base = process.env.BASE || '/'; const ABORT_DELAY = 10000; console.log('========================================'); console.log('开始初始化服务器...'); console.log(`环境: ${isProduction ? '生产环境' : '开发环境'}`); console.log(`端口: ${port}`); console.log(`基础路径: ${base}`); console.log('========================================'); // 解析基础路径为 URL 对象 const baseUrl = new URL(base, `http://localhost:${port}`); console.log(`基础URL解析完成: ${baseUrl.href}`); // 创建服务器实例 console.log('正在创建服务器实例...'); const parentServer = createAdaptorServer({ fetch: app.fetch, createServer: createNodeServer, port: port, }) console.log('服务器实例创建成功'); // 新增:初始化 Socket.IO 服务器 console.log('正在初始化 Socket.IO 服务器...'); const io = new Server(parentServer, { // // 配置 CORS,根据实际需求调整 // cors: { // origin: isProduction ? process.env.FRONTEND_URL || false : "http://localhost:8080", // methods: ["GET", "POST"], // credentials: true // }, // // 路径配置,避免与其他路由冲突 // path: `${base}socket.io` }); console.log('Socket.IO 服务器初始化完成'); // 生产环境中间件 let compressionMiddleware; let sirvMiddleware; if (isProduction) { console.log('生产环境: 加载压缩和静态文件中间件...'); compressionMiddleware = (await import('compression')).default(); sirvMiddleware = (await import('sirv')).default('./dist/client', { extensions: [], baseUrl: base }); console.log('生产环境中间件加载完成'); } // Vite 开发服务器 /** @type {import('vite').ViteDevServer | undefined} */ let vite; if (!isProduction) { console.log('开发环境: 初始化 Vite 开发服务器...'); const { createServer } = await import('vite'); vite = await createServer({ server: { middlewareMode: { server: parentServer }, hmr: { port: 8081, clientPort: 443, path: 'vite-hmr' }, proxy: { '/vite-hmr': { target: 'ws://localhost:8081', ws: true, }, }, }, appType: 'custom', base, }); console.log('Vite 开发服务器初始化完成'); } // 开发环境模板处理函数 - 仅处理模板转换 const processDevTemplate = async (template) => { if (!isProduction && vite) { console.log('开发环境: 处理模板...'); const processedTemplate = await vite.transformIndexHtml('/', template); console.log('开发环境模板处理完成'); return processedTemplate; } return template; }; // 新增:加载 Socket.IO 中间件和路由 if (!isProduction) { console.log('开发环境: 从 Vite 加载 Socket.IO 路由和中间件...'); try { const apiModule = await vite.ssrLoadModule('./src/server/index.tsx'); // 应用认证中间件 if (apiModule.socketAuthMiddleware) { console.log('应用 Socket.IO 认证中间件'); io.use(apiModule.socketAuthMiddleware); } // 应用路由 if (apiModule.socketHandler) { console.log('注册 Socket.IO 路由处理'); apiModule.socketHandler(io); } console.log('Socket.IO 路由和中间件加载完成'); } catch (err) { console.error('开发环境加载 Socket.IO 模块失败:', err); } } else { console.log('生产环境: 加载编译后的 Socket.IO 路由和中间件...'); try { const apiModule = (await import('./dist/server/index.js')); // 应用认证中间件 if (apiModule.socketAuthMiddleware) { console.log('应用 Socket.IO 认证中间件'); io.use(apiModule.socketAuthMiddleware); } // 应用路由 if (apiModule.socketHandler) { console.log('注册 Socket.IO 路由处理'); apiModule.socketHandler(io); } console.log('Socket.IO 路由和中间件加载完成'); } catch (err) { console.error('加载 Socket.IO 模块失败:', err); } } // 生产环境模板处理函数 - 仅处理资源路径替换 const processProdTemplate = async (template) => { console.log('生产环境: 处理模板资源路径...'); try { // 读取 manifest const manifestPath = new URL('./dist/client/.vite/manifest.json', import.meta.url); const manifestContent = await fs.readFile(manifestPath, 'utf-8'); const manifest = JSON.parse(manifestContent); console.log('生产环境: 成功读取 manifest.json'); // 获取 src/client/index.tsx 对应的资源信息 const indexManifest = manifest['src/client/index.tsx']; if (!indexManifest) { throw new Error('manifest 中未找到 src/client/index.tsx 入口配置'); } // 获取 src/style.css 对应的资源信息 const styleManifest = manifest['src/style.css']; if (!styleManifest) { throw new Error('manifest 中未找到 src/style.css 入口配置'); } const cssPath = new URL(styleManifest.file, baseUrl).pathname; const cssLinks = ``; // 替换入口脚本 const jsEntryPath = new URL(indexManifest.file, baseUrl).pathname; const entryScript = ``; // 执行替换 const processedTemplate = template .replace(//, cssLinks) .replace(/