quasqui
Version:
The meta-framework suite designed from scratch for frontend-focused modern web development.
92 lines (82 loc) • 2.51 kB
text/typescript
import url from 'url';
import { createDebugger } from '@modern-js/utils';
import { Middleware } from 'koa';
import { IAppContext, NormalizedConfig } from '@modern-js/core';
const debug = createDebugger('esm:history-api-fallback');
export const historyApiFallbackMiddleware = (
userConfig: NormalizedConfig,
appContext: IAppContext,
): Middleware => {
const { serverRoutes } = appContext;
return (ctx, next) => {
const { headers, method } = ctx;
const reqUrl = ctx.url;
// eslint-disable-next-line node/no-deprecated-api
const { pathname } = url.parse(reqUrl);
if (method !== 'GET') {
debug('Not rewriting', method, url, 'because the method is not GET.');
return next();
} else if (!headers || typeof headers.accept !== 'string') {
debug(
'Not rewriting',
method,
reqUrl,
'because the client did not send an HTTP accept header.',
);
return next();
} else if (headers.accept.startsWith('application/json')) {
debug(
'Not rewriting',
method,
reqUrl,
'because the client prefers JSON.',
);
return next();
} else if (!acceptsHtml(headers.accept)) {
debug(
'Not rewriting',
method,
reqUrl,
'because the client does not accept HTML.',
);
return next();
} else if (pathname!.lastIndexOf('.') > pathname!.lastIndexOf('/')) {
debug(
'Not rewriting',
method,
reqUrl,
'because the path includes a dot (.) character.',
);
return next();
}
const sortedRoutes = serverRoutes.sort(
(a, b) => b.urlPath.length - a.urlPath.length,
);
for (const { entryName, urlPath, isApi } of sortedRoutes) {
if (pathname?.startsWith(urlPath)) {
// should ignore api request
if (isApi) {
break;
}
if (entryName) {
const rewriteTarget = appContext.htmlTemplates[entryName];
debug('Rewriting', method, reqUrl, 'to', rewriteTarget);
ctx.url = rewriteTarget;
return next();
}
}
}
return next();
};
};
/* eslint-disable @typescript-eslint/prefer-for-of */
function acceptsHtml(header: any) {
const htmlAcceptHeaders = ['text/html', '*/*'];
for (let i = 0; i < htmlAcceptHeaders.length; i++) {
if (header.indexOf(htmlAcceptHeaders[i]) !== -1) {
return true;
}
}
return false;
}
/* eslint-enable @typescript-eslint/prefer-for-of */