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",
|
"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.",
|
"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",
|
"license": "MIT",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./serverus.ts",
|
".": "./serverus.ts",
|
||||||
|
|
|
@ -32,7 +32,13 @@ export interface ROUTE_HANDLER {
|
||||||
default?: ROUTE_HANDLER_METHOD;
|
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 loading: boolean = false;
|
||||||
let all_routes_loaded: 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());
|
const root_directory = path.resolve(Deno.cwd());
|
||||||
|
|
||||||
type import_record = {
|
const imports: ROUTE_HANDLER_RECORD[] = [];
|
||||||
route_path: string;
|
|
||||||
import_path: string;
|
|
||||||
};
|
|
||||||
const imports: import_record[] = [];
|
|
||||||
for await (
|
for await (
|
||||||
const entry of walk(root_directory, {
|
const entry of walk(root_directory, {
|
||||||
exts: ['.ts'],
|
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
|
.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();
|
const import_path = new URL('file://' + entry.path, import.meta.url).toString();
|
||||||
|
|
||||||
imports.push({
|
imports.push({
|
||||||
route_path,
|
route_path,
|
||||||
|
route_pattern,
|
||||||
import_path
|
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:
|
// try to sort imports such that they're registered like:
|
||||||
// /permissions/test
|
// /permissions/test
|
||||||
// /echo/hi
|
// /api/echo/hi
|
||||||
// /echo/:input
|
// /api/echo/:input
|
||||||
//
|
//
|
||||||
// we want paths with parameters to sort later than paths without
|
// 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));
|
routes.push(...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`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
all_routes_loaded = true;
|
all_routes_loaded = true;
|
||||||
loading = false;
|
loading = false;
|
||||||
|
@ -114,11 +104,21 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
||||||
} while (!all_routes_loaded);
|
} while (!all_routes_loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [pattern, handler_module] of routes) {
|
for (const route_record of routes) {
|
||||||
const match = pattern.exec(request.url.replace(/\/$/, ''));
|
const match = route_record.route_pattern.exec(request.url.replace(/\/$/, ''));
|
||||||
if (match) {
|
if (match) {
|
||||||
const method = request.method as keyof ROUTE_HANDLER;
|
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) {
|
if (!method_handler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
||||||
query
|
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)) {
|
if (Array.isArray(prechecks)) {
|
||||||
for (const precheck of prechecks) {
|
for (const precheck of prechecks) {
|
||||||
const result = await precheck(request, metadata);
|
const result = await precheck(request, metadata);
|
||||||
|
@ -149,6 +149,6 @@ export default async function handle_typescript(request: Request): Promise<Respo
|
||||||
|
|
||||||
export function unload(): void {
|
export function unload(): void {
|
||||||
loading = false;
|
loading = false;
|
||||||
routes.clear();
|
routes.splice(0, routes.length);
|
||||||
all_routes_loaded = false;
|
all_routes_loaded = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ Deno.test({
|
||||||
Deno.chdir('./tests/www');
|
Deno.chdir('./tests/www');
|
||||||
test_server_info = await get_ephemeral_listen_server();
|
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'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ Deno.test({
|
||||||
Deno.chdir('./tests/www');
|
Deno.chdir('./tests/www');
|
||||||
test_server_info = await get_ephemeral_listen_server();
|
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'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ Deno.test({
|
||||||
};
|
};
|
||||||
|
|
||||||
for await (const key of Object.keys(echoes)) {
|
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'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -32,10 +32,6 @@ Deno.test({
|
||||||
|
|
||||||
asserts.assert(response.ok);
|
asserts.assert(response.ok);
|
||||||
asserts.assert(body);
|
asserts.assert(body);
|
||||||
console.dir({
|
|
||||||
body,
|
|
||||||
key
|
|
||||||
});
|
|
||||||
asserts.assertEquals(body, echoes[key]);
|
asserts.assertEquals(body, echoes[key]);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue