96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import type { Plugin } from 'vite';
|
|
|
|
function normalizeBasePath(base: string) {
|
|
const baseSegment = base.trim().replaceAll(/^\/+|\/+$/g, '');
|
|
return baseSegment ? `/${baseSegment}/` : '/';
|
|
}
|
|
|
|
/**
|
|
* 解析开发服务器入口地址的规范化跳转目标。
|
|
*
|
|
* @param requestUrl 当前请求地址
|
|
* @param base Vite 应用基路径
|
|
* @returns 需要跳转时返回目标地址,否则返回 null
|
|
*/
|
|
export function resolveBasePathRedirect(
|
|
requestUrl: string | undefined,
|
|
base: string,
|
|
): null | string {
|
|
if (!requestUrl) {
|
|
return null;
|
|
}
|
|
const normalizedBase = normalizeBasePath(base);
|
|
if (normalizedBase === '/') {
|
|
return null;
|
|
}
|
|
|
|
const request = new URL(requestUrl, 'http://easyflow.local');
|
|
const baseWithoutTrailingSlash = normalizedBase.slice(0, -1);
|
|
if (
|
|
request.pathname !== '/' &&
|
|
request.pathname !== baseWithoutTrailingSlash
|
|
) {
|
|
return null;
|
|
}
|
|
return `${normalizedBase}${request.search}`;
|
|
}
|
|
|
|
/**
|
|
* 创建开发入口规范化脚本,确保 HTML 回退先于前端路由执行跳转。
|
|
*
|
|
* @param base Vite 应用基路径
|
|
* @returns 可注入 HTML 头部的同步脚本
|
|
*/
|
|
export function buildBasePathRedirectScript(base: string): string {
|
|
const normalizedBase = normalizeBasePath(base);
|
|
const baseWithoutTrailingSlash = normalizedBase.slice(0, -1);
|
|
return `(()=>{const l=window.location;if(${JSON.stringify(normalizedBase)}!=="/"&&(l.pathname==="/"||l.pathname===${JSON.stringify(baseWithoutTrailingSlash)})){l.replace(${JSON.stringify(normalizedBase)}+l.search+l.hash)}})();`;
|
|
}
|
|
|
|
/**
|
|
* 创建开发服务器入口规范化插件。
|
|
*
|
|
* Vite 会对浏览器导航请求提前执行 HTML 回退,因此同时使用服务端跳转
|
|
* 与同步头部脚本,保证 `/`、`/flow` 均在路由初始化前进入 `/flow/`。
|
|
*
|
|
* @returns Vite 开发服务器插件
|
|
*/
|
|
export function createBasePathRedirectPlugin(): Plugin {
|
|
let resolvedBase = '/';
|
|
return {
|
|
apply: 'serve',
|
|
configResolved(config) {
|
|
resolvedBase = config.base;
|
|
},
|
|
configureServer(server) {
|
|
server.middlewares.use((request, response, next) => {
|
|
const redirectTarget = resolveBasePathRedirect(
|
|
request.url,
|
|
server.config.base,
|
|
);
|
|
if (!redirectTarget) {
|
|
next();
|
|
return;
|
|
}
|
|
response.statusCode = 302;
|
|
response.setHeader('Location', redirectTarget);
|
|
response.end();
|
|
});
|
|
},
|
|
enforce: 'pre',
|
|
name: 'easyflow-base-path-redirect',
|
|
transformIndexHtml: {
|
|
handler() {
|
|
return [
|
|
{
|
|
children: buildBasePathRedirectScript(resolvedBase),
|
|
injectTo: 'head-prepend',
|
|
tag: 'script',
|
|
},
|
|
];
|
|
},
|
|
order: 'pre',
|
|
},
|
|
};
|
|
}
|