这是一种不尝试检查磁盘上的内容的方法(这对我来说产生了不正确的行为)。
相反,这种方法:
- 移除 Vite 的 SPA 后备中间件
- 它使用 Vite 的内置 HTML 转换并返回
/dir/index.html
(如果存在)/dir
或/dir/
请求
- 404 其他一切
// express not necessary, but its API does simplify things
const express = require("express");
const { join } = require("path");
const { readFile } = require("fs/promises");
// ADJUST THIS FOR YOUR PROJECT
const PROJECT_ROOT = join(__dirname, "..");
function removeHistoryFallback() {
return {
name: "remove-history-fallback",
configureServer(server) {
// returned function runs AFTER Vite's middleware is built
return function () {
removeViteSpaFallbackMiddleware(server.middlewares);
server.middlewares.use(transformHtmlMiddleware(server));
server.middlewares.use(notFoundMiddleware());
};
},
};
}
function removeViteSpaFallbackMiddleware(middlewares) {
const { stack } = middlewares;
const index = stack.findIndex(function (layer) {
const { handle: fn } = layer;
return fn.name === "viteSpaFallbackMiddleware";
});
if (index > -1) {
stack.splice(index, 1);
} else {
throw Error("viteSpaFallbackMiddleware() not found in server middleware");
}
}
function transformHtmlMiddleware(server) {
const middleware = express();
middleware.use(async (req, res, next) => {
try {
const rawHtml = await getIndexHtml(req.path);
const transformedHtml = await server.transformIndexHtml(
req.url, rawHtml, req.originalUrl
);
res.set(server.config.server.headers);
res.send(transformedHtml);
} catch (error) {
return next(error);
}
});
// named function for easier debugging
return function customViteHtmlTransformMiddleware(req, res, next) {
middleware(req, res, next);
};
}
async function getIndexHtml(path) {
const indexPath = join(PROJECT_ROOT, path, "index.html");
return readFile(indexPath, "utf-8");
}
function notFoundMiddleware() {
const middleware = express();
middleware.use((req, res) => {
const { method, path } = req;
res.status(404);
res.type("html");
res.send(`<pre>Cannot ${method} ${path}</pre>`);
});
return function customNotFoundMiddleware(req, res, next) {
middleware(req, res, next);
};
}
module.exports = {
removeHistoryFallback,
};
有趣的是,Vite 似乎采取的立场是:
- 它只是一个开发和构建工具,不能用于生产
- 构建的文件是静态服务的,因此,它不附带生产服务器
但是,对于静态文件服务器:
- 当请求目录时,静态文件服务器的某些配置将返回索引文件
- 当找不到文件时,它们通常不会回退到服务
index.html
,而是在这些情况下返回 404
因此,当 Vite 的开发服务器针对没有它的生产环境时,它具有这种回退行为并没有多大意义。如果有一种“正确”的方式来关闭历史回退,同时保持其余的服务行为(HTML 转换等),那就太好了。