@gracile/engine 0.0.4 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient.d.ts +6 -0
- package/dist/assertions.d.ts +1 -1
- package/dist/assertions.d.ts.map +1 -1
- package/dist/build/static.d.ts +12 -3
- package/dist/build/static.d.ts.map +1 -1
- package/dist/build/static.js +34 -19
- package/dist/dev/dev.d.ts +5 -2
- package/dist/dev/dev.d.ts.map +1 -1
- package/dist/dev/dev.js +14 -7
- package/dist/dev/server.d.ts +22 -2
- package/dist/dev/server.d.ts.map +1 -1
- package/dist/dev/server.js +51 -23
- package/dist/preview.d.ts +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +3 -0
- package/dist/render/route-template.d.ts +14 -3
- package/dist/render/route-template.d.ts.map +1 -1
- package/dist/render/route-template.js +42 -10
- package/dist/render/utils.d.ts.map +1 -0
- package/dist/routes/collect.d.ts +2 -3
- package/dist/routes/collect.d.ts.map +1 -1
- package/dist/routes/collect.js +5 -2
- package/dist/routes/load-module.d.ts +5 -1
- package/dist/routes/load-module.d.ts.map +1 -1
- package/dist/routes/load-module.js +15 -6
- package/dist/routes/match.d.ts +4 -2
- package/dist/routes/match.d.ts.map +1 -1
- package/dist/routes/match.js +9 -6
- package/dist/routes/route.d.ts +21 -3
- package/dist/routes/route.d.ts.map +1 -1
- package/dist/routes/route.js +23 -1
- package/dist/server/env.d.ts +5 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +6 -0
- package/dist/server/request.d.ts +21 -0
- package/dist/server/request.d.ts.map +1 -0
- package/dist/{dev → server}/request.js +64 -27
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +25 -0
- package/dist/server/utils.d.ts +4 -0
- package/dist/server/utils.d.ts.map +1 -0
- package/dist/server/utils.js +21 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/user-config.d.ts +11 -0
- package/dist/user-config.d.ts.map +1 -1
- package/dist/user-config.js +9 -0
- package/dist/vite/build.d.ts.map +1 -1
- package/dist/vite/build.js +82 -7
- package/dist/vite/config.d.ts +1 -0
- package/dist/vite/config.d.ts.map +1 -1
- package/dist/vite/config.js +6 -1
- package/dist/vite/plugins/build-routes.d.ts +28 -0
- package/dist/vite/plugins/build-routes.d.ts.map +1 -0
- package/dist/vite/plugins/build-routes.js +103 -0
- package/dist/vite/plugins/virtual-routes.d.ts +11 -0
- package/dist/vite/plugins/virtual-routes.d.ts.map +1 -0
- package/dist/vite/plugins/virtual-routes.js +51 -0
- package/dist/vite/server.d.ts +4 -1
- package/dist/vite/server.d.ts.map +1 -1
- package/dist/vite/server.js +5 -3
- package/package.json +11 -12
- package/dist/dev/request.d.ts +0 -4
- package/dist/dev/request.d.ts.map +0 -1
- package/dist/vite/plugins/html-static-pages.d.ts +0 -13
- package/dist/vite/plugins/html-static-pages.d.ts.map +0 -1
- package/dist/vite/plugins/html-static-pages.js +0 -58
- package/dist/vite/utils.d.ts.map +0 -1
- /package/dist/{vite → render}/utils.d.ts +0 -0
- /package/dist/{vite → render}/utils.js +0 -0
package/dist/routes/match.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { routes } from './collect.js';
|
|
2
1
|
import { loadForeignRouteObject } from './load-module.js';
|
|
3
|
-
|
|
4
|
-
function matchRouteFromUrl(url) {
|
|
2
|
+
// FIXME: proper DI for routes
|
|
3
|
+
function matchRouteFromUrl(url, routes) {
|
|
5
4
|
let match;
|
|
6
5
|
let foundRoute;
|
|
7
6
|
const pathname = new URL(url).pathname;
|
|
@@ -44,9 +43,13 @@ function extractStaticPaths(options) {
|
|
|
44
43
|
return { staticPaths, props };
|
|
45
44
|
}
|
|
46
45
|
export async function getRoute(options) {
|
|
47
|
-
const { foundRoute, pathname, params } = matchRouteFromUrl(options.url);
|
|
48
|
-
|
|
49
|
-
const routeModule = await loadForeignRouteObject(
|
|
46
|
+
const { foundRoute, pathname, params } = matchRouteFromUrl(options.url, options.routes);
|
|
47
|
+
// TODO: Simplify all the routes things
|
|
48
|
+
const routeModule = await loadForeignRouteObject({
|
|
49
|
+
vite: options.vite,
|
|
50
|
+
route: foundRoute,
|
|
51
|
+
routeImports: options.routeImports,
|
|
52
|
+
});
|
|
50
53
|
const staticPaths = extractStaticPaths({
|
|
51
54
|
routeModule,
|
|
52
55
|
foundRoute,
|
package/dist/routes/route.d.ts
CHANGED
|
@@ -3,22 +3,36 @@ import type { TemplateResult } from 'lit';
|
|
|
3
3
|
export type MethodHtml = 'GET' | 'POST';
|
|
4
4
|
export type MethodNonHtml = 'QUERY' | 'PUT' | 'PATCH' | 'DELETE';
|
|
5
5
|
export type Method = MethodHtml & MethodNonHtml;
|
|
6
|
+
export declare const RequestMethod: {
|
|
7
|
+
readonly GET: "GET";
|
|
8
|
+
readonly QUERY: "QUERY";
|
|
9
|
+
readonly HEAD: "HEAD";
|
|
10
|
+
readonly POST: "POST";
|
|
11
|
+
readonly PUT: "PUT";
|
|
12
|
+
readonly DELETE: "DELETE";
|
|
13
|
+
readonly OPTIONS: "OPTIONS";
|
|
14
|
+
readonly PATCH: "PATCH";
|
|
15
|
+
};
|
|
6
16
|
export type ModuleOptions = {
|
|
7
17
|
staticPaths?: StaticPathsGeneric;
|
|
18
|
+
locals?: (locals: any) => any;
|
|
8
19
|
handler?: HandlerGeneric;
|
|
9
|
-
|
|
20
|
+
prerender?: boolean | undefined;
|
|
10
21
|
document?: DocumentTemplate<RouteContextGeneric>;
|
|
22
|
+
template?: (context: RouteContextGeneric) => RouteTemplateResult;
|
|
11
23
|
};
|
|
12
24
|
export declare class RouteModule {
|
|
13
25
|
#private;
|
|
14
26
|
get staticPaths(): StaticPathsGeneric | undefined;
|
|
15
|
-
get
|
|
27
|
+
get locals(): ((locals: any) => any) | undefined;
|
|
28
|
+
get handler(): Handler<object | Response | undefined, any> | Partial<Record<MethodHtml, Handler<object | Response | undefined, any>> & Record<MethodNonHtml, Handler<Response, any>>> | undefined;
|
|
16
29
|
get document(): DocumentTemplate<RouteContextGeneric> | undefined;
|
|
30
|
+
get prerender(): boolean | undefined;
|
|
17
31
|
get template(): ((context: RouteContextGeneric) => RouteTemplateResult) | undefined;
|
|
18
32
|
constructor(options: ModuleOptions);
|
|
19
33
|
}
|
|
20
34
|
export type Params = Record<string, string | undefined>;
|
|
21
|
-
export type Handler<Data extends HandlerData | HandlerDataHtml = never> = (context: {
|
|
35
|
+
export type Handler<Data extends HandlerData | HandlerDataHtml = never, Locals = any> = (context: {
|
|
22
36
|
url: URL;
|
|
23
37
|
/**
|
|
24
38
|
* Parameters from dynamic route.
|
|
@@ -27,6 +41,7 @@ export type Handler<Data extends HandlerData | HandlerDataHtml = never> = (conte
|
|
|
27
41
|
*/
|
|
28
42
|
params: Params;
|
|
29
43
|
request: Request;
|
|
44
|
+
locals?: Locals;
|
|
30
45
|
/**
|
|
31
46
|
* Let you mutate the downstream **page** response.
|
|
32
47
|
*
|
|
@@ -60,4 +75,7 @@ export interface Route {
|
|
|
60
75
|
hasParams: boolean;
|
|
61
76
|
pageAssets: string[];
|
|
62
77
|
}
|
|
78
|
+
export type RoutesManifest = Map<string, Route>;
|
|
79
|
+
export type RoutesImports = Map<string, () => Record<string, unknown>>;
|
|
80
|
+
export type RoutesAssets = Map<string, string>;
|
|
63
81
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/routes/route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/routes/route.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/route.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
// export type KnownMethod = typeof knownMethods[number];
|
|
3
|
+
export const RequestMethod = {
|
|
4
|
+
GET: 'GET',
|
|
5
|
+
QUERY: 'QUERY',
|
|
6
|
+
HEAD: 'HEAD',
|
|
7
|
+
POST: 'POST',
|
|
8
|
+
PUT: 'PUT',
|
|
9
|
+
DELETE: 'DELETE',
|
|
10
|
+
OPTIONS: 'OPTIONS',
|
|
11
|
+
PATCH: 'PATCH',
|
|
12
|
+
};
|
|
1
13
|
// TODO: put in engine
|
|
2
14
|
export class RouteModule {
|
|
3
15
|
#staticPaths;
|
|
4
16
|
get staticPaths() {
|
|
5
17
|
return this.#staticPaths;
|
|
6
18
|
}
|
|
19
|
+
#locals;
|
|
20
|
+
get locals() {
|
|
21
|
+
return this.#locals;
|
|
22
|
+
}
|
|
7
23
|
#handler;
|
|
8
24
|
get handler() {
|
|
9
25
|
return this.#handler;
|
|
@@ -12,6 +28,10 @@ export class RouteModule {
|
|
|
12
28
|
get document() {
|
|
13
29
|
return this.#document;
|
|
14
30
|
}
|
|
31
|
+
#prerender;
|
|
32
|
+
get prerender() {
|
|
33
|
+
return this.#prerender;
|
|
34
|
+
}
|
|
15
35
|
#template;
|
|
16
36
|
get template() {
|
|
17
37
|
return this.#template;
|
|
@@ -23,10 +43,12 @@ export class RouteModule {
|
|
|
23
43
|
typeof options.handler === 'function') &&
|
|
24
44
|
options.handler)
|
|
25
45
|
this.#handler = options.handler;
|
|
26
|
-
|
|
46
|
+
this.#locals = options.locals;
|
|
27
47
|
if (typeof options.template === 'function')
|
|
28
48
|
this.#template = options.template;
|
|
29
49
|
if (typeof options.document === 'function')
|
|
30
50
|
this.#document = options.document;
|
|
51
|
+
if (typeof options.prerender === 'boolean')
|
|
52
|
+
this.#prerender = options.prerender;
|
|
31
53
|
}
|
|
32
54
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/server/env.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,eAAO,MAAM,UAAU,4BAEM,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { ViteDevServer } from 'vite';
|
|
3
|
+
import type * as R from '../routes/route.js';
|
|
4
|
+
type NextFunction = (error?: unknown) => void | Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* This is fully compatible with Express or bare Node HTTP
|
|
7
|
+
* What it adds on top of Connect-style middleware:
|
|
8
|
+
* 1. Async.
|
|
9
|
+
* 2. Can return a `ServerResponse`
|
|
10
|
+
*/
|
|
11
|
+
export type ConnectLikeAsyncMiddleware = (req: IncomingMessage, res: ServerResponse, next: NextFunction) => Promise<void | NextFunction | ServerResponse> | (void | NextFunction | ServerResponse);
|
|
12
|
+
export declare function createGracileMiddleware({ vite, routes, routeImports, routeAssets, root, serverMode, }: {
|
|
13
|
+
vite?: ViteDevServer | undefined;
|
|
14
|
+
routes: R.RoutesManifest;
|
|
15
|
+
routeImports?: R.RoutesImports | undefined;
|
|
16
|
+
routeAssets?: R.RoutesAssets;
|
|
17
|
+
root: string;
|
|
18
|
+
serverMode?: boolean | undefined;
|
|
19
|
+
}): ConnectLikeAsyncMiddleware;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/server/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAS1C,OAAO,KAAK,KAAK,CAAC,MAAM,oBAAoB,CAAC;AAE7C,KAAK,YAAY,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,CACxC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,YAAY,KAEjB,OAAO,CAAC,IAAI,GAAG,YAAY,GAAG,cAAc,CAAC,GAE5C,CAAC,IAAI,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC;AAM1C,wBAAgB,uBAAuB,CAAC,EACvC,IAAI,EACJ,MAAM,EACN,YAAY,EACZ,WAAW,EACX,IAAI,EACJ,UAAU,GACV,EAAE;IACF,IAAI,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,CAAC,CAAC,cAAc,CAAC;IACzB,YAAY,CAAC,EAAE,CAAC,CAAC,aAAa,GAAG,SAAS,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC,8BAsOA"}
|
|
@@ -1,41 +1,60 @@
|
|
|
1
|
-
import { Writable } from 'node:stream';
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
import { logger } from '@gracile/internal-utils/logger';
|
|
3
3
|
import { createServerAdapter } from '@whatwg-node/server';
|
|
4
4
|
import c from 'picocolors';
|
|
5
5
|
import { /* errorInline, */ errorPage } from '../errors/templates.js';
|
|
6
6
|
import { renderRouteTemplate, } from '../render/route-template.js';
|
|
7
|
+
import { renderSsrTemplate } from '../render/utils.js';
|
|
7
8
|
import { getRoute } from '../routes/match.js';
|
|
8
|
-
import { renderSsrTemplate } from '../vite/utils.js';
|
|
9
9
|
// NOTE: Find a more canonical way to ponyfill the Node HTTP request to standard Request
|
|
10
10
|
// @ts-expect-error Abusing this feature!
|
|
11
11
|
const adapter = createServerAdapter((request) => request);
|
|
12
|
-
export function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
export function createGracileMiddleware({ vite, routes, routeImports, routeAssets, root, serverMode, }) {
|
|
13
|
+
const middleware = async (req, res, next) => {
|
|
14
|
+
// Typing workaround
|
|
15
|
+
if (!req.url)
|
|
16
|
+
throw Error('Incorrect url');
|
|
17
|
+
if (!req.method)
|
|
18
|
+
throw Error('Incorrect method');
|
|
19
|
+
logger.info(`[${c.yellow(req.method)}] ${c.yellow(req.url)}`, {
|
|
16
20
|
timestamp: true,
|
|
17
21
|
});
|
|
18
22
|
// MARK: Skip unwanted requests
|
|
19
23
|
if (
|
|
20
24
|
//
|
|
21
|
-
url.endsWith('favicon.ico') ||
|
|
22
|
-
url.endsWith('favicon.svg'))
|
|
25
|
+
req.url.endsWith('favicon.ico') ||
|
|
26
|
+
req.url.endsWith('favicon.svg'))
|
|
23
27
|
return next();
|
|
24
28
|
const requestPonyfilled = (await Promise.resolve(adapter.handleNodeRequest(req)));
|
|
25
29
|
async function renderPageFn(handlerInfos, routeInfos) {
|
|
26
|
-
const { output } = await renderRouteTemplate(
|
|
27
|
-
|
|
30
|
+
const { output } = await renderRouteTemplate({
|
|
31
|
+
request: requestPonyfilled,
|
|
32
|
+
vite,
|
|
33
|
+
mode: 'dev',
|
|
34
|
+
routeInfos,
|
|
35
|
+
handlerInfos,
|
|
36
|
+
routeAssets,
|
|
37
|
+
root,
|
|
38
|
+
serverMode,
|
|
39
|
+
});
|
|
40
|
+
return output || undefined;
|
|
28
41
|
}
|
|
29
42
|
try {
|
|
30
43
|
// MARK: Get route infos
|
|
31
44
|
const moduleInfos = await getRoute({
|
|
32
45
|
url: requestPonyfilled.url,
|
|
33
46
|
vite,
|
|
47
|
+
routes,
|
|
48
|
+
routeImports,
|
|
34
49
|
});
|
|
35
50
|
let output;
|
|
36
51
|
// TODO: should move this to `special-file` so we don't recalculate on each request
|
|
37
52
|
// + we would be able to do some route codegen.
|
|
38
53
|
const response = {};
|
|
54
|
+
// NOTE: Only for Express for now.
|
|
55
|
+
let locals = null;
|
|
56
|
+
if ('locals' in res)
|
|
57
|
+
locals = moduleInfos.routeModule.locals?.(res.locals);
|
|
39
58
|
// MARK: Server handler
|
|
40
59
|
const handler = moduleInfos.routeModule.handler;
|
|
41
60
|
if ('handler' in moduleInfos.routeModule &&
|
|
@@ -45,6 +64,7 @@ export function createDevRequestHandler(vite) {
|
|
|
45
64
|
url: new URL(requestPonyfilled.url),
|
|
46
65
|
response,
|
|
47
66
|
params: moduleInfos.params,
|
|
67
|
+
locals,
|
|
48
68
|
};
|
|
49
69
|
// MARK: Top level handler
|
|
50
70
|
if (typeof handler === 'function') {
|
|
@@ -52,13 +72,13 @@ export function createDevRequestHandler(vite) {
|
|
|
52
72
|
if (handlerOutput instanceof Response)
|
|
53
73
|
output = handlerOutput;
|
|
54
74
|
else
|
|
55
|
-
throw new
|
|
75
|
+
throw new TypeError('Catch-all handler must return a Response object.');
|
|
56
76
|
// MARK: Handler with method
|
|
57
77
|
}
|
|
58
78
|
else if (requestPonyfilled.method in handler) {
|
|
59
79
|
const handlerWithMethod = handler[requestPonyfilled.method];
|
|
60
80
|
if (typeof handlerWithMethod !== 'function')
|
|
61
|
-
throw
|
|
81
|
+
throw TypeError('Handler must be a function.');
|
|
62
82
|
const handlerOutput = await Promise.resolve(handlerWithMethod(options));
|
|
63
83
|
if (handlerOutput instanceof Response)
|
|
64
84
|
output = handlerOutput;
|
|
@@ -85,10 +105,14 @@ export function createDevRequestHandler(vite) {
|
|
|
85
105
|
if (output instanceof Response) {
|
|
86
106
|
if (output.status >= 300 && output.status <= 303) {
|
|
87
107
|
const location = output.headers.get('location');
|
|
88
|
-
if (location)
|
|
89
|
-
|
|
108
|
+
// if (location) return res.redirect(location);
|
|
109
|
+
if (location) {
|
|
110
|
+
res.statusCode = output.status;
|
|
111
|
+
res.setHeader('location', location);
|
|
112
|
+
return res.end(`Found. Redirecting to ${location}`);
|
|
113
|
+
}
|
|
90
114
|
}
|
|
91
|
-
output.headers?.forEach((content, header) => res.
|
|
115
|
+
output.headers?.forEach((content, header) => res.setHeader(header, content));
|
|
92
116
|
if (output.status)
|
|
93
117
|
res.statusCode = output.status;
|
|
94
118
|
if (output.statusText)
|
|
@@ -100,17 +124,18 @@ export function createDevRequestHandler(vite) {
|
|
|
100
124
|
output.body
|
|
101
125
|
.pipeTo(Writable.toWeb(res))
|
|
102
126
|
.catch((e) => logger.error(String(e)));
|
|
127
|
+
// else throw new Error('Missing body.');
|
|
103
128
|
else
|
|
104
|
-
|
|
129
|
+
return res.end(output);
|
|
105
130
|
// MARK: Stream page render
|
|
106
131
|
}
|
|
107
132
|
else {
|
|
108
|
-
new Headers(response.headers)?.forEach((content, header) => res.
|
|
133
|
+
new Headers(response.headers)?.forEach((content, header) => res.setHeader(header, content));
|
|
109
134
|
if (response.status)
|
|
110
135
|
res.statusCode = response.status;
|
|
111
136
|
if (response.statusText)
|
|
112
137
|
res.statusMessage = response.statusText;
|
|
113
|
-
res.
|
|
138
|
+
res.setHeader('Content-Type', 'text/html');
|
|
114
139
|
// MARK: Page stream error
|
|
115
140
|
output
|
|
116
141
|
?.on('error', (error) => {
|
|
@@ -124,11 +149,12 @@ export function createDevRequestHandler(vite) {
|
|
|
124
149
|
// Maybe just returning nothing is better to not break the page?
|
|
125
150
|
// Should send a overlay message anyway via WebSocket
|
|
126
151
|
// vite.ws.send()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
152
|
+
if (vite)
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
vite.hot.send('gracile:ssr-error', {
|
|
155
|
+
message: errorMessage,
|
|
156
|
+
});
|
|
157
|
+
}, 500);
|
|
132
158
|
res.end('' /* errorInline(error) */);
|
|
133
159
|
})
|
|
134
160
|
.pipe(res);
|
|
@@ -137,15 +163,26 @@ export function createDevRequestHandler(vite) {
|
|
|
137
163
|
}
|
|
138
164
|
catch (e) {
|
|
139
165
|
const error = e;
|
|
140
|
-
vite
|
|
166
|
+
if (vite)
|
|
167
|
+
vite.ssrFixStacktrace(error);
|
|
168
|
+
// else
|
|
169
|
+
logger.error(error.message);
|
|
141
170
|
if (error.cause === 404) {
|
|
142
|
-
|
|
171
|
+
// TODO: Handle 404 with dedicated page
|
|
172
|
+
if (!vite)
|
|
173
|
+
return next();
|
|
174
|
+
res.statusCode = 404;
|
|
175
|
+
return res.end('404');
|
|
143
176
|
// TODO: use a nice framework service page
|
|
144
177
|
// .redirect(new URL('/__404/', requestPonyfilled.url).href)
|
|
145
178
|
}
|
|
146
|
-
|
|
147
|
-
|
|
179
|
+
let errorTemplate = await renderSsrTemplate(errorPage(error));
|
|
180
|
+
if (vite)
|
|
181
|
+
errorTemplate = await vite.transformIndexHtml(req.url, errorTemplate);
|
|
182
|
+
res.statusCode = 500;
|
|
183
|
+
return res.end(errorTemplate);
|
|
148
184
|
}
|
|
149
185
|
return next();
|
|
150
186
|
};
|
|
187
|
+
return middleware;
|
|
151
188
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAUzD,eAAO,MAAM,cAAc,EAAE,gBAiB5B,CAAC;AAEF,OAAO,EAAE,+BAA+B,IAAI,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { setCurrentWorkingDirectory } from '@gracile/internal-utils/paths';
|
|
2
|
+
import { routeAssets, routeImports, routes } from 'gracile:routes';
|
|
3
|
+
import { createGracileMiddleware } from './request.js';
|
|
4
|
+
routes.forEach((route, pattern) => {
|
|
5
|
+
routes.set(pattern, {
|
|
6
|
+
...route,
|
|
7
|
+
pattern: new URLPattern(pattern, 'http://gracile'),
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
export const createHandlers = async ({ root = process.cwd(),
|
|
11
|
+
// hmrPort,
|
|
12
|
+
// NOTE: We need type parity with the dev. version of this function
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
14
|
+
} = {}) => {
|
|
15
|
+
setCurrentWorkingDirectory(root);
|
|
16
|
+
const gracileHandler = createGracileMiddleware({
|
|
17
|
+
root,
|
|
18
|
+
routes,
|
|
19
|
+
routeImports,
|
|
20
|
+
routeAssets,
|
|
21
|
+
serverMode: true,
|
|
22
|
+
});
|
|
23
|
+
return { handlers: [gracileHandler /* as RequestHandler */], vite: null };
|
|
24
|
+
};
|
|
25
|
+
export { printNodeHttpServerAddressInfos as printAddressInfos } from './utils.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/server/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAKvC,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAsB7E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// NOTE: Util. to pretty print for user provided server.
|
|
2
|
+
import { logger } from '@gracile/internal-utils/logger';
|
|
3
|
+
import { DEV } from 'esm-env';
|
|
4
|
+
import c from 'picocolors';
|
|
5
|
+
import { IP_EXPOSED } from './env.js';
|
|
6
|
+
export function printNodeHttpServerAddressInfos(instance) {
|
|
7
|
+
const infos = instance.address();
|
|
8
|
+
logger.info(c.green(`${DEV ? 'development' : 'production'} server started`), {
|
|
9
|
+
timestamp: true,
|
|
10
|
+
});
|
|
11
|
+
if (typeof infos === 'object' && infos && infos.port && infos.address) {
|
|
12
|
+
logger.info(`
|
|
13
|
+
${c.dim('┃')} Local ${c.cyan(`http://localhost:${infos.port}/`)}` +
|
|
14
|
+
`${infos.address === IP_EXPOSED
|
|
15
|
+
? `${c.dim('┃')} Network ${c.cyan(`http://${infos.address}:${infos.port}/`)}`
|
|
16
|
+
: ''}
|
|
17
|
+
`);
|
|
18
|
+
return infos;
|
|
19
|
+
}
|
|
20
|
+
throw Error('Invalid address/port.');
|
|
21
|
+
}
|