Is it possible to create a Vite SSR app with Node.js native HTTP server? The guide from Vite documentation is using Express. But I prefer using Node.js native HTTP server as follows:
const port = 3000
const host = 'localhost'
const requestListener = async function (req, res) {
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom'
})
// Use vite's connect instance as middleware
vite.middlewares
// Serve index.html as follows:
const url = req.url
let template
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)
}
const server = createServer(requestListener)
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`)
})
My attemp has the following error on the terminal:
$ npm run dev
> dev
> node server
Server is running on http://localhost:3000
WebSocket server error: Port is already in use
Browser errors:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
entry-client.js:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
Any ideas?
If you add the Vite middleware and provide static files, it should work with Vite SSR and Node.js native HTTP server:
const { createServer } = require('http');
const { createViteServer } = require('vite');
const fs = require('fs');
const path = require('path');
const url = require('url');
const port = 3000;
const host = 'localhost';
async function createRequestListener() {
const vite = await createViteServer({
server: { middlewareMode: 'ssr' },
});
return async function (req, res) {
try {
const parsedUrl = new url.URL(req.url, `http://${host}:${port}`);
let serveUrl = parsedUrl.pathname;
if (vite.middlewares) {
await new Promise((resolve) =>
vite.middlewares(req, res, resolve)
);
}
if (req.method === 'GET' && serveUrl.endsWith('.js')) {
res.setHeader('Content-Type', 'application/javascript');
}
if (serveUrl === '/') {
serveUrl = '/index.html';
}
if (serveUrl.endsWith('.html')) {
const template = fs.readFileSync(
path.resolve(__dirname, './index.html'),
'utf-8'
);
const transformedTemplate = await vite.transformIndexHtml(
serveUrl,
template
);
const render = (await vite.ssrLoadModule('/src/entry-server.js')).render;
const { appHtml } = await render(parsedUrl);
const html = transformedTemplate.replace('{{ appHtml }}', appHtml);
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(html);
} else {
res.end();
}
} catch (err) {
console.error(err);
res.writeHead(500);
res.end(err.message);
}
};
}
createRequestListener().then((requestListener) => {
const server = createServer(requestListener);
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`);
});
});