fix: sort routes into route records and lazily import
This commit is contained in:
parent
1928bfcb5e
commit
d917b69753
8 changed files with 33 additions and 37 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@andyburke/serverus",
|
||||
"description": "A flexible HTTP server for mixed content. Throw static files, markdown, Typescript and (hopefully, eventually) more into a directory and serverus can serve it up a bit more like old-school CGI.",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": "./serverus.ts",
|
||||
|
|
|
@ -32,7 +32,13 @@ export interface ROUTE_HANDLER {
|
|||
default?: ROUTE_HANDLER_METHOD;
|
||||
}
|
||||
|
||||
const routes: Map<URLPattern, ROUTE_HANDLER> = new Map<URLPattern, ROUTE_HANDLER>();
|
||||
type ROUTE_HANDLER_RECORD = {
|
||||
route_path: string;
|
||||
route_pattern: URLPattern;
|
||||
import_path: string;
|
||||
module?: ROUTE_HANDLER;
|
||||
};
|
||||
const routes: ROUTE_HANDLER_RECORD[] = [];
|
||||
let loading: boolean = false;
|
||||
let all_routes_loaded: boolean = false;
|
||||
|
||||
|
@ -53,11 +59,7 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
|
||||
const root_directory = path.resolve(Deno.cwd());
|
||||
|
||||
type import_record = {
|
||||
route_path: string;
|
||||
import_path: string;
|
||||
};
|
||||
const imports: import_record[] = [];
|
||||
const imports: ROUTE_HANDLER_RECORD[] = [];
|
||||
for await (
|
||||
const entry of walk(root_directory, {
|
||||
exts: ['.ts'],
|
||||
|
@ -73,10 +75,13 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
.replace(/___/g, ':') || // required for windows, uncivilized OS that it is
|
||||
'/';
|
||||
|
||||
const route_pattern = new URLPattern({ pathname: route_path });
|
||||
|
||||
const import_path = new URL('file://' + entry.path, import.meta.url).toString();
|
||||
|
||||
imports.push({
|
||||
route_path,
|
||||
route_pattern,
|
||||
import_path
|
||||
});
|
||||
}
|
||||
|
@ -84,26 +89,11 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
|
||||
// try to sort imports such that they're registered like:
|
||||
// /permissions/test
|
||||
// /echo/hi
|
||||
// /echo/:input
|
||||
// /api/echo/hi
|
||||
// /api/echo/:input
|
||||
//
|
||||
// we want paths with parameters to sort later than paths without
|
||||
const sorted_imports = imports.sort((lhs, rhs) => rhs.route_path.localeCompare(lhs.route_path));
|
||||
for (const import_info of sorted_imports) {
|
||||
try {
|
||||
const module: ROUTE_HANDLER = await import(import_info.import_path) as ROUTE_HANDLER;
|
||||
|
||||
const pattern = new URLPattern({ pathname: import_info.route_path });
|
||||
|
||||
if (Deno.env.get('SERVERUS_TYPESCRIPT_IMPORT_LOGGING')) {
|
||||
console.log(`${import_info.route_path} : imported: ${import_info.import_path}`);
|
||||
}
|
||||
|
||||
routes.set(pattern, module);
|
||||
} catch (error) {
|
||||
console.error(`Error mounting module ${import_info.import_path} at ${import_info.route_path}\n\n${error}\n`);
|
||||
}
|
||||
}
|
||||
routes.push(...imports.sort((lhs, rhs) => rhs.route_path.localeCompare(lhs.route_path)));
|
||||
|
||||
all_routes_loaded = true;
|
||||
loading = false;
|
||||
|
@ -114,11 +104,21 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
} while (!all_routes_loaded);
|
||||
}
|
||||
|
||||
for (const [pattern, handler_module] of routes) {
|
||||
const match = pattern.exec(request.url.replace(/\/$/, ''));
|
||||
for (const route_record of routes) {
|
||||
const match = route_record.route_pattern.exec(request.url.replace(/\/$/, ''));
|
||||
if (match) {
|
||||
const method = request.method as keyof ROUTE_HANDLER;
|
||||
const method_handler: ROUTE_HANDLER_METHOD = (handler_module[method] ?? handler_module.default) as ROUTE_HANDLER_METHOD;
|
||||
|
||||
if (!route_record.module) {
|
||||
if (Deno.env.get('SERVERUS_TYPESCRIPT_IMPORT_LOGGING')) {
|
||||
console.log(`${route_record.route_path} : imported: ${route_record.import_path}`);
|
||||
}
|
||||
}
|
||||
|
||||
route_record.module = route_record.module ?? await import(route_record.import_path) as ROUTE_HANDLER;
|
||||
|
||||
const method_handler: ROUTE_HANDLER_METHOD =
|
||||
(route_record.module[method] ?? route_record.module.default) as ROUTE_HANDLER_METHOD;
|
||||
if (!method_handler) {
|
||||
return;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
query
|
||||
};
|
||||
|
||||
const prechecks: PRECHECK[] | undefined = handler_module.PRECHECKS?.[request.method as keyof PRECHECKS_TABLE];
|
||||
const prechecks: PRECHECK[] | undefined = route_record.module.PRECHECKS?.[request.method as keyof PRECHECKS_TABLE];
|
||||
if (Array.isArray(prechecks)) {
|
||||
for (const precheck of prechecks) {
|
||||
const result = await precheck(request, metadata);
|
||||
|
@ -149,6 +149,6 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
|||
|
||||
export function unload(): void {
|
||||
loading = false;
|
||||
routes.clear();
|
||||
routes.splice(0, routes.length);
|
||||
all_routes_loaded = false;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ Deno.test({
|
|||
Deno.chdir('./tests/www');
|
||||
test_server_info = await get_ephemeral_listen_server();
|
||||
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/hello_world`, {
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/api/echo/hello_world`, {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Deno.test({
|
|||
Deno.chdir('./tests/www');
|
||||
test_server_info = await get_ephemeral_listen_server();
|
||||
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/hello_world.foo`, {
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/api/echo/hello_world.foo`, {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ Deno.test({
|
|||
};
|
||||
|
||||
for await (const key of Object.keys(echoes)) {
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/${key}`, {
|
||||
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/api/echo/${key}`, {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
|
@ -32,10 +32,6 @@ Deno.test({
|
|||
|
||||
asserts.assert(response.ok);
|
||||
asserts.assert(body);
|
||||
console.dir({
|
||||
body,
|
||||
key
|
||||
});
|
||||
asserts.assertEquals(body, echoes[key]);
|
||||
}
|
||||
} finally {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue