如何用Node.js原生HTTP服务器搭建Vite SSR应用?求解报错问题
用Node.js原生HTTP服务器搭建Vite SSR的问题修复方案
Node.js原生HTTP服务器完全可以用于构建Vite SSR应用,你遇到的两个错误都是代码逻辑问题导致的,以下是具体修复步骤:
1. 解决WebSocket端口占用错误
问题原因
你把createViteServer放在了请求监听器requestListener内部,每次收到HTTP请求都会重新创建一个Vite服务器实例,重复启动HMR所需的WebSocket服务,导致端口被重复占用。
修复代码
将Vite服务器的初始化逻辑移到请求监听器外部,确保只初始化一次:
import { createServer } from 'http' import { createViteServer } from 'vite' import fs from 'fs' import path from 'path' const port = 3000 const host = 'localhost' // 全局初始化Vite服务器,仅执行一次 const vite = await createViteServer({ server: { middlewareMode: true }, appType: 'custom' }) const requestListener = async function (req, res) { // 后续处理逻辑... } const server = createServer(requestListener) server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`) })
2. 解决模块脚本MIME类型错误
问题原因
当前代码对所有请求一律返回HTML内容,包括JS模块、静态资源等请求。浏览器请求entry-client.js时,服务器返回的是text/html类型的响应,不符合JS模块的MIME类型要求,因此触发报错。
修复代码
优先让Vite的中间件处理开发环境下的资源请求(如模块编译、HMR、静态资源),只有当Vite中间件无法处理时,才执行SSR渲染逻辑。由于原生HTTP服务器不直接支持connect风格中间件,需要用vite.middlewares.handle方法适配:
const requestListener = async function (req, res) { try { // 先用Vite中间件处理开发相关请求 await new Promise((resolve, reject) => { vite.middlewares(req, res, (err) => { if (err) reject(err) resolve() }) }) // 处理SSR渲染 const url = req.url let template = fs.readFileSync( path.resolve(__dirname, 'index.html'), 'utf-8' ) template = await vite.transformIndexHtml(url, template) const render = (await vite.ssrLoadModule('/src/entry-server.js')).render const { appHtml } = await render(url) const html = template.replace(`{{ appHtml }}`, appHtml) res.setHeader('Content-Type', 'text/html') res.writeHead(200) res.end(html) } catch (e) { vite.ssrFixStacktrace(e) console.error(e) res.writeHead(500) res.end(e.message) } }
完整修复后的代码
import { createServer } from 'http' import { createViteServer } from 'vite' import fs from 'fs' import path from 'path' const port = 3000 const host = 'localhost' // 全局初始化Vite服务器,避免重复创建实例 const vite = await createViteServer({ server: { middlewareMode: true }, appType: 'custom' }) const requestListener = async function (req, res) { try { // 优先处理Vite负责的开发请求 await new Promise((resolve, reject) => { vite.middlewares(req, res, (err) => { if (err) reject(err) resolve() }) }) // SSR渲染逻辑 const url = req.url let template = fs.readFileSync( path.resolve(__dirname, 'index.html'), 'utf-8' ) template = await vite.transformIndexHtml(url, template) const render = (await vite.ssrLoadModule('/src/entry-server.js')).render const { appHtml } = await render(url) const html = template.replace(`{{ appHtml }}`, appHtml) res.setHeader('Content-Type', 'text/html') res.writeHead(200) res.end(html) } catch (e) { vite.ssrFixStacktrace(e) console.error(e) res.writeHead(500) res.end(e.message) } } const server = createServer(requestListener) server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`) })
内容的提问来源于stack exchange,提问作者Run
相关产品推荐
相关产品推荐

