Socket
Socket
Sign inDemoInstall

@gracile/engine

Package Overview
Dependencies
Maintainers
0
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gracile/engine - npm Package Compare versions

Comparing version 0.6.0 to 0.7.0-next.0

dist/render/markers.d.ts

10

dist/build/static.d.ts
import type { ViteDevServer } from 'vite';
import type { RoutesManifest } from '../routes/route.js';
import type { GracileConfig } from '../user-config.js';

@@ -8,5 +9,10 @@ export interface RenderedRouteDefinition {

handlerAssets?: string;
static: {
props: unknown;
document: string | null;
};
savePrerender: boolean | null;
}
export declare function renderRoutes({ vite, serverMode, root, gracileConfig, }: {
export declare function renderRoutes({ routes, vite, serverMode, root, gracileConfig, }: {
routes: RoutesManifest;
vite: ViteDevServer;

@@ -17,5 +23,5 @@ serverMode: boolean;

}): Promise<{
routes: import("../routes/route.js").RoutesManifest;
routes: RoutesManifest;
renderedRoutes: RenderedRouteDefinition[];
}>;
//# sourceMappingURL=static.d.ts.map

39

dist/build/static.js

@@ -20,6 +20,6 @@ import { Buffer } from 'node:buffer';

}
export async function renderRoutes({ vite, serverMode, root = process.cwd(), gracileConfig, }) {
export async function renderRoutes({ routes, vite, serverMode, root = process.cwd(), gracileConfig, }) {
logger.info(c.green('Rendering routes…'), { timestamp: true });
// MARK: Collect
const routes = await collectRoutes(root, gracileConfig.routes?.exclude);
await collectRoutes(routes, root, gracileConfig.routes?.exclude);
const renderedRoutes = [];

@@ -35,11 +35,34 @@ // MARK: Iterate modules

return;
const routeStaticPaths = routeModule.staticPaths?.();
const routeStaticPaths = await Promise.resolve(routeModule.staticPaths?.());
// MARK: Extract data
await Promise.all((routeStaticPaths ?? [patternString]).map(async (staticPathOptions) => {
await Promise.all(
/* Single route */
(routeStaticPaths ?? [patternString]).map(async (staticPathOptions) => {
let pathnameWithParams = patternString;
let params = {};
let props;
// MARK: Handler data (for single route only, NOT dynamic)
if (routeModule.handler) {
const url = new URL(pathnameWithParams, 'http://gracile-static');
const context = {
url,
params: {},
// NOTE: STUB, maybe it should be better to remove them from typings?
// But that will make more mismatches between static and server.
request: new Request(url),
locals: {},
responseInit: {},
};
if (typeof routeModule.handler === 'function') {
props = await Promise.resolve(routeModule.handler(context));
}
else if ('GET' in routeModule.handler) {
props = {
GET: await Promise.resolve(routeModule.handler.GET(context)),
};
}
}
// MARK: Convert pattern
// to real route with static parameters + get props. for after
if (typeof staticPathOptions === 'object') {
else if (typeof staticPathOptions === 'object') {
params = staticPathOptions.params;

@@ -67,5 +90,6 @@ props = staticPathOptions.props;

// MARK: Render
const { output } = await renderRouteTemplate({
const { output, document } = await renderRouteTemplate({
//
request: { url: url.href },
// request: { url: url.href },
url: url.href,
vite,

@@ -96,2 +120,3 @@ mode: 'build',

savePrerender,
static: { props, document },
};

@@ -98,0 +123,0 @@ renderedRoutes.push(rendered);

import { type ViteDevServer } from 'vite';
import type { RoutesManifest } from '../routes/route.js';
import { type GracileHandler } from '../server/request.js';
import type { GracileConfig } from '../user-config.js';
export declare function createDevHandler({ vite, gracileConfig, }: {
export declare function createDevHandler({ routes, vite, gracileConfig, }: {
routes: RoutesManifest;
vite: ViteDevServer;

@@ -9,3 +11,4 @@ gracileConfig: GracileConfig;

handler: GracileHandler;
routes: RoutesManifest;
}>;
//# sourceMappingURL=dev.d.ts.map

@@ -7,6 +7,6 @@ import { logger } from '@gracile/internal-utils/logger';

import { generateRoutesTypings } from './route-typings.js';
export async function createDevHandler({ vite, gracileConfig, }) {
export async function createDevHandler({ routes, vite, gracileConfig, }) {
const root = vite.config.root;
logger.info(c.dim('\nCreating handler…'), { timestamp: true });
const routes = await collectRoutes(root, gracileConfig.routes?.exclude);
await collectRoutes(routes, root, gracileConfig.routes?.exclude);
if (gracileConfig.experimental?.generateRoutesTypings)

@@ -16,5 +16,5 @@ generateRoutesTypings(root, routes).catch((error) => logger.error(String(error)));

// console.log({ event });
if (file.match(/\/src\/routes\/(.*)\.(ts|js)$/) &&
if (file.match(/\/src\/routes\/(.*)\.(ts|js|css|scss|sass|less|styl|stylus)$/) &&
['add', 'unlink'].includes(event))
collectRoutes(root, gracileConfig.routes?.exclude)
collectRoutes(routes, root, gracileConfig.routes?.exclude)
.then(() => {

@@ -30,4 +30,10 @@ vite.hot.send('vite:invalidate');

const serverMode = false;
const gracile = createGracileHandler({ vite, root, serverMode, routes });
return { handler: gracile };
const gracile = createGracileHandler({
vite,
root,
serverMode,
routes,
gracileConfig,
});
return { handler: gracile, routes };
}

@@ -10,3 +10,3 @@ import { join } from 'node:path';

import { buildRoutes } from './vite/plugins/build-routes.js';
import { virtualRoutes } from './vite/plugins/virtual-routes.js';
import { virtualRoutes, virtualRoutesClient, } from './vite/plugins/virtual-routes.js';
let isClientBuilt = false;

@@ -31,3 +31,4 @@ /**

*/
// Return as `any` to avoid Plugin type mismatches when there are multiple Vite versions installed
// NOTE: for Vite versions mismatches with `exactOptionalPropertyTypes`?
// This `any[]` AND with a plugin -array- makes ESLint and TS shut up.
// eslint-disable-next-line @typescript-eslint/no-explicit-any

@@ -37,3 +38,3 @@ export const gracile = (config) => {

const clientAssets = {};
let routes = null;
const routes = new Map();
let renderedRoutes = null;

@@ -45,29 +46,38 @@ let root = null;

isClientBuilt = true;
const virtualRoutesForClient = virtualRoutesClient({
mode: outputMode,
routes,
// NOTE: This will be a dedicated setting when it will not be experimental
// anymore.
gracileConfig,
// enabled: gracileConfig?.pages?.premises?.expose || false,
});
return [
// {
// name: 'gracile-routes-codegen',
// // watchChange(change) {
// // console.log({ change });
// // },
// resolveId(id) {
// const virtualModuleId = 'gracile:route';
// const resolvedVirtualModuleId = `\0${virtualModuleId}`;
// if (id === virtualModuleId) {
// return resolvedVirtualModuleId;
// }
// return null;
// },
// load(id) {
// const virtualModuleId = 'gracile:route';
// const resolvedVirtualModuleId = `\0${virtualModuleId}`;
// if (id === resolvedVirtualModuleId) {
// return `
// export function route(input){
// return input;
// }`;
// }
// return null;
// },
// },
virtualRoutesForClient,
{
name: 'gracile-routes-codegen',
// watchChange(change) {
// console.log({ change });
// },
resolveId(id) {
const virtualModuleId = 'gracile:route';
const resolvedVirtualModuleId = `\0${virtualModuleId}`;
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
return null;
},
load(id) {
const virtualModuleId = 'gracile:route';
const resolvedVirtualModuleId = `\0${virtualModuleId}`;
if (id === resolvedVirtualModuleId) {
return `
export function route(input){
return input;
}`;
}
return null;
},
},
{
name: 'vite-plugin-gracile-serve-middleware',

@@ -79,2 +89,5 @@ apply: 'serve',

optimizeDeps: { include: [] },
// resolve: {
// conditions: ['development'],
// },
};

@@ -98,6 +111,7 @@ },

const version = process.env['__GRACILE_VERSION__'];
logger.info(`${c.cyan(c.italic(c.underline('🧚 Gracile ')))}` +
` ${c.green(` v${version ?? 'X'}`)}`);
logger.info(`${c.cyan(c.italic(c.underline('🧚 Gracile')))}` +
` ${c.dim(`~`)} ${c.green(`v${version ?? 'X'}`)}`);
// ---
const { handler } = await createDevHandler({
routes,
vite: server,

@@ -124,2 +138,3 @@ gracileConfig,

optimizeDeps: { include: [] },
plugins: [virtualRoutesForClient],
});

@@ -131,4 +146,4 @@ const htmlPages = await buildRoutes({

serverMode: outputMode === 'server',
routes,
});
routes = htmlPages.routes;
renderedRoutes = htmlPages.renderedRoutes;

@@ -191,3 +206,2 @@ await viteServerForClientHtmlBuild.close();

if (chunkInfo.name) {
// (chunkInfo);
const fileName = clientAssets[chunkInfo.name];

@@ -207,6 +221,4 @@ if (fileName)

plugins: [
virtualRoutes({
routes,
renderedRoutes,
}),
virtualRoutesForClient,
virtualRoutes({ routes, renderedRoutes }),
{

@@ -224,7 +236,5 @@ name: 'vite-plugin-gracile-entry',

import { routeAssets, routeImports, routes } from 'gracile:routes';
import { createGracileMiddleware } from '@gracile/gracile/_internals/server-runtime';
import { createGracileHandler } from '@gracile/gracile/_internals/server-runtime';
// ({ routeAssets, routeImports, routes })
export const handler = createGracileMiddleware({
export const handler = createGracileHandler({
root: process.cwd(),

@@ -235,2 +245,3 @@ routes,

serverMode: true,
gracileConfig: ${JSON.stringify(gracileConfig, null, 2)}
});

@@ -237,0 +248,0 @@ `;

@@ -1,25 +0,20 @@

import { Readable } from 'stream';
import { Readable } from 'node:stream';
import type { ViteDevServer } from 'vite';
import type { RouteInfos } from '../routes/match.js';
import type * as R from '../routes/route.js';
export declare const SSR_OUTLET_MARKER = "<route-template-outlet></route-template-outlet>";
export declare const PAGE_ASSETS_MARKER = "<!--__GRACILE_PAGE_ASSETS__-->";
export declare const REGEX_TAG_SCRIPT: RegExp;
export declare const REGEX_TAG_LINK: RegExp;
export type HandlerInfos = {
data: unknown;
method: string;
};
export declare function renderRouteTemplate({ request, vite, mode, routeInfos, handlerInfos, routeAssets, serverMode, }: {
request: Request | R.StaticRequest;
export declare function renderRouteTemplate({ url, vite, mode, routeInfos, routeAssets, serverMode, docOnly, }: {
url: string;
vite?: ViteDevServer | undefined;
mode: 'dev' | 'build';
routeInfos: RouteInfos;
handlerInfos?: HandlerInfos | undefined;
routeAssets?: R.RoutesAssets | undefined;
root: string;
serverMode?: boolean | undefined;
docOnly?: boolean | undefined;
}): Promise<{
output: null | Readable;
document: null | string;
}>;
//# sourceMappingURL=route-template.d.ts.map

@@ -0,6 +1,7 @@

import { Readable } from 'node:stream';
import { html } from '@gracile/internal-utils/dummy-literals';
import { render as renderLitSsr } from '@lit-labs/ssr';
import { collectResult } from '@lit-labs/ssr/lib/render-result.js';
import { Readable } from 'stream';
import { isLitServerTemplate, isLitTemplate } from '../assertions.js';
import { PAGE_ASSETS_MARKER, SSR_OUTLET_MARKER } from './markers.js';
async function* concatStreams(...readables) {

@@ -15,22 +16,12 @@ // eslint-disable-next-line no-restricted-syntax

}
// export const SSR_OUTLET_MARKER = '________SSR_OUTLET________';
export const SSR_OUTLET_MARKER = '<route-template-outlet></route-template-outlet>';
// const SSR_OUTLET = unsafeHTML(SSR_OUTLET_MARKER);
export const PAGE_ASSETS_MARKER = '<!--__GRACILE_PAGE_ASSETS__-->';
export const REGEX_TAG_SCRIPT = /\s?<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script\s*>\s?/gi;
export const REGEX_TAG_LINK = /\s?<link\b[^>]*?>\s?/gi;
export async function renderRouteTemplate({ request, vite, mode, routeInfos, handlerInfos, routeAssets,
// root,
serverMode, }) {
export async function renderRouteTemplate({ url, vite, mode, routeInfos, routeAssets, serverMode, docOnly, }) {
if (!routeInfos.routeModule.document && !routeInfos.routeModule.template)
return { output: null };
return { output: null, document: null };
// MARK: Context
const context = {
url: new URL(request.url),
url: new URL(url),
params: routeInfos.params,
props: handlerInfos?.data
? {
[handlerInfos.method]: handlerInfos.data,
}
: routeInfos.props,
props: routeInfos.props,
};

@@ -44,3 +35,3 @@ // MARK: Fragment

const output = Readable.from(fragmentRender);
return { output };
return { output, document: null };
}

@@ -59,25 +50,24 @@ // MARK: Document

baseDocRenderedWithAssets = baseDocRenderedWithAssets
.replace('</head>', `${PAGE_ASSETS_MARKER}</head>`)
.replace('</head>', `\n${PAGE_ASSETS_MARKER}</head>`)
.replace(PAGE_ASSETS_MARKER,
// eslint-disable-next-line prefer-template
html `
<!-- PAGE ASSETS -->
${routeInfos.foundRoute.pageAssets.map((path) => {
//
if (/\.(js|ts)$/.test(path)) {
return html `
<script type="module" src="/${path}"></script>
<!-- -->
`;
}
if (/\.(css|scss|sass|less|styl|stylus)$/.test(path)) {
return html `
<link rel="stylesheet" href="/${path}" />
<!-- -->
`;
}
throw new Error('Unknown asset.');
})}
<!-- /PAGE ASSETS -->
`);
routeInfos.foundRoute.pageAssets.length
? // eslint-disable-next-line prefer-template
html `<!-- PAGE ASSETS -->` +
`${routeInfos.foundRoute.pageAssets
.map((path) => {
//
if (/\.(js|ts)$/.test(path)) {
// prettier-ignore
return html ` <script type="module" src="/${path}"></script>`;
}
if (/\.(css|scss|sass|less|styl|stylus)$/.test(path)) {
// prettier-ignore
return html ` <link rel="stylesheet" href="/${path}" />`;
}
throw new Error('Unknown asset.');
})
.join('\n')}` +
`<!-- /PAGE ASSETS -->\n `
: '');
// MARK: Dev. overlay

@@ -124,2 +114,4 @@ // TODO: Need more testing and refinement (refreshes kills its usefulness)

: baseDocRenderedWithAssets;
if (docOnly)
return { document: baseDocHtml, output: null };
const index = baseDocHtml.indexOf(SSR_OUTLET_MARKER);

@@ -141,3 +133,3 @@ const baseDocRenderStreamPre = Readable.from(baseDocHtml.substring(0, index));

// );
// return { output };
// return { output, document: null };
// }

@@ -148,7 +140,7 @@ if (isLitTemplate(routeOutput) === false)

const output = Readable.from(concatStreams(baseDocRenderStreamPre, renderStream, baseDocRenderStreamPost));
return { output };
return { output, document: baseDocHtml };
}
// MARK: Just the document
const output = Readable.from(baseDocHtml);
return { output };
return { output, document: baseDocHtml };
}
import { type ServerRenderedTemplate } from '@lit-labs/ssr';
export declare function renderSsrTemplate(template: ServerRenderedTemplate): Promise<string>;
import type { TemplateResult } from 'lit';
/**
* Just a tiny wrapper for `render` and `collectResult` from `@lit-labs/ssr`.
*
* Useful for testing server only partials.
*
* @example
* ```js
* import assert from 'node:assert';
* import {
* html,
* type ServerRenderedTemplate,
* } from '@gracile/gracile/server-html';
*
* const myServerTemplate1 = (): ServerRenderedTemplate => html`
* <div>Hello</div>
* `;
*
* const result = await renderLitTemplate(myServerTemplate1());
*
* assert.match(result, /Hello/);
* ```
*/
export declare function renderLitTemplate(template: ServerRenderedTemplate | TemplateResult<1>): Promise<string>;
//# sourceMappingURL=utils.d.ts.map
import { render as renderLitSsr, } from '@lit-labs/ssr';
import { collectResult } from '@lit-labs/ssr/lib/render-result.js';
export async function renderSsrTemplate(template) {
/**
* Just a tiny wrapper for `render` and `collectResult` from `@lit-labs/ssr`.
*
* Useful for testing server only partials.
*
* @example
* ```js
* import assert from 'node:assert';
* import {
* html,
* type ServerRenderedTemplate,
* } from '@gracile/gracile/server-html';
*
* const myServerTemplate1 = (): ServerRenderedTemplate => html`
* <div>Hello</div>
* `;
*
* const result = await renderLitTemplate(myServerTemplate1());
*
* assert.match(result, /Hello/);
* ```
*/
export async function renderLitTemplate(template) {
return collectResult(renderLitSsr(template));
}
import type * as R from './route.js';
export declare function collectRoutes(root: string, excludePatterns?: string[]): Promise<R.RoutesManifest>;
export declare function collectRoutes(routes: R.RoutesManifest, root: string, excludePatterns?: string[]): Promise<R.RoutesManifest>;
//# sourceMappingURL=collect.d.ts.map

@@ -51,4 +51,4 @@ import { join } from 'node:path';

}
const routes = new Map();
export async function collectRoutes(root /* vite: ViteDevServer */, excludePatterns = []) {
// const routes: R.RoutesManifest = new Map<string, R.Route>();
export async function collectRoutes(routes, root /* vite: ViteDevServer */, excludePatterns = []) {
routes.clear();

@@ -55,0 +55,0 @@ const routesFolder = 'src/routes';

@@ -22,3 +22,3 @@ import { loadForeignRouteObject } from './load-module.js';

}
function extractStaticPaths(options) {
async function extractStaticPaths(options) {
if (!options.foundRoute.hasParams)

@@ -30,3 +30,3 @@ return null;

let props;
const staticPaths = routeStaticPaths();
const staticPaths = await Promise.resolve(routeStaticPaths());
let hasCorrectParams = false;

@@ -55,3 +55,3 @@ staticPaths.forEach((providedRouteOptions) => {

});
const staticPaths = extractStaticPaths({
const staticPaths = await extractStaticPaths({
routeModule,

@@ -58,0 +58,0 @@ foundRoute,

@@ -53,3 +53,3 @@ import type { ServerRenderedTemplate } from '@lit-labs/ssr';

export type HandlerGeneric = Handler<HandlerData | HandlerDataHtml> | Partial<Record<MethodHtml, Handler<HandlerData | HandlerDataHtml>> & Record<MethodNonHtml, Handler<Response>>>;
export type StaticPathsGeneric = () => StaticPathOptionsGeneric[];
export type StaticPathsGeneric = () => MaybePromise<StaticPathOptionsGeneric[]>;
export type HandlerData = Response | undefined;

@@ -56,0 +56,0 @@ export type HandlerDataHtml = HandlerData | object;

@@ -5,3 +5,3 @@ // import { logger } from '@gracile/internal-utils/logger';

import { fileURLToPath } from 'node:url';
import { server } from '../constants.js';
import { constants } from '../constants.js';
/**

@@ -28,3 +28,3 @@ * @param handler - Takes a pre-built Gracile handler from `./dist/server/entrypoint.js`.

const result = await handler(context.req.raw, context.var);
// TODO: Hhandle stream abortion as gracefully as with Express.
// TODO: Handle stream abortion as gracefully as with Express.
if (result?.body) {

@@ -55,4 +55,4 @@ // NOTE: Typings mismatches

export function getClientDistPath(root) {
return relative(process.cwd(), fileURLToPath(new URL(server.CLIENT_DIST_DIR, root)));
return relative(process.cwd(), fileURLToPath(new URL(constants.CLIENT_DIST_DIR, root)));
}
export { printUrls } from '../utils.js';

@@ -0,1 +1,2 @@

import { Writable } from 'node:stream';
import { fileURLToPath } from 'node:url';

@@ -5,4 +6,3 @@ import { env } from '@gracile/internal-utils/env';

import { createServerAdapter } from '@whatwg-node/server';
import { Writable } from 'stream';
import { server } from '../constants.js';
import { constants } from '../constants.js';
import { isRedirect } from '../request.js';

@@ -93,4 +93,4 @@ // NOTE: Find a more canonical way to ponyfill the Node HTTP request to standard Request

export function getClientDistPath(root) {
return fileURLToPath(new URL(server.CLIENT_DIST_DIR, root));
return fileURLToPath(new URL(constants.CLIENT_DIST_DIR, root));
}
export { printUrls } from '../utils.js';

@@ -19,3 +19,3 @@ /**

*/
export declare const server: Readonly<{
export declare const constants: Readonly<{
LOCALHOST: "localhost";

@@ -22,0 +22,0 @@ IP_LOCALHOST: "127.0.0.1";

@@ -19,3 +19,3 @@ /**

*/
export const server = Object.freeze({
export const constants = Object.freeze({
LOCALHOST: 'localhost',

@@ -22,0 +22,0 @@ IP_LOCALHOST: '127.0.0.1',

import { Readable } from 'node:stream';
import type { ViteDevServer } from 'vite';
import type * as R from '../routes/route.js';
import type { GracileConfig } from '../user-config.js';
type StandardResponse = {

@@ -21,3 +22,3 @@ response: Response;

} | null;
export declare function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, }: {
export declare function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, gracileConfig, }: {
vite?: ViteDevServer | undefined;

@@ -29,4 +30,5 @@ routes: R.RoutesManifest;

serverMode?: boolean | undefined;
gracileConfig: GracileConfig;
}): GracileHandler;
export {};
//# sourceMappingURL=request.d.ts.map
import { Readable } from 'node:stream';
import { logger } from '@gracile/internal-utils/logger';
// import { logger } from '@gracile/internal-utils/logger/vite-logger';
import c from 'picocolors';

@@ -7,3 +8,3 @@ import * as assert from '../assertions.js';

import { renderRouteTemplate } from '../render/route-template.js';
import { renderSsrTemplate } from '../render/utils.js';
import { renderLitTemplate } from '../render/utils.js';
import { getRoute } from '../routes/match.js';

@@ -18,6 +19,6 @@ const CONTENT_TYPE_HTML = { 'Content-Type': 'text/html' };

}
export function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, }) {
export function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, gracileConfig, }) {
async function createErrorPage(urlPath, e) {
logger.error(e.message);
let errorPageHtml = await renderSsrTemplate(errorPage(e));
let errorPageHtml = await renderLitTemplate(errorPage(e));
if (vite)

@@ -29,5 +30,12 @@ errorPageHtml = await vite.transformIndexHtml(urlPath, errorPageHtml);

try {
// NOTE: Maybe it should be constructed from `req`
const { url: fullUrl, method } = request;
const { url: requestedUrl, method } = request;
// MARK: Rewrite hidden route siblings
const fullUrl = requestedUrl.replace(/\/__(.*)$/, '/');
// MARK: Get route infos
const exposePremises = gracileConfig.pages?.premises?.expose
? {
propsOnly: /\/__(.*?)\.props\.json$/.test(requestedUrl),
docOnly: /\/__(.*?)\.doc\.html$/.test(requestedUrl),
}
: null;
const routeOptions = {

@@ -40,3 +48,3 @@ url: fullUrl,

const routeInfos = await getRoute(routeOptions).catch(async (error) => {
// MARK: User defined Gracile 404
// MARK: User defined Gracile 404 rewriting
logger.error(String(error));

@@ -61,3 +69,3 @@ const url = new URL('/404/', fullUrl).href;

const routeTemplateOptions = {
request,
url: fullUrl,
vite,

@@ -69,2 +77,3 @@ mode: 'dev', // vite && vite.config.mode === 'dev' ? 'dev' : 'build',

routeInfos,
docOnly: exposePremises?.docOnly,
};

@@ -81,6 +90,5 @@ logger.info(`[${c.yellow(method)}] ${c.yellow(fullUrl)}`, {

const responseInit = {};
// TODO: should move this to `special-file` so we don't recalculate on each request
// + we would be able to do some route codegen.
if (('handler' in routeInfos.routeModule &&
typeof handler !== 'undefined') ||
// TODO: Explain this condition
(handler && 'GET' in handler === false && method !== 'GET')) {

@@ -115,13 +123,8 @@ const routeContext = Object.freeze({

//
// MARK: Top level handler
if (typeof handler === 'function') {
const handlerOutput = (await Promise.resolve(handler(routeContext)));
if (assert.isResponseOrPatchedResponse(handlerOutput))
output = handlerOutput;
else
throw new TypeError('Catch-all handler must return a Response object.');
// MARK: Handler with method
}
else if (method in handler) {
const handlerWithMethod = handler[method];
// MARK: Handler(s)
const hasTopLevelHandler = typeof handler === 'function';
if (hasTopLevelHandler || method in handler) {
const handlerWithMethod = hasTopLevelHandler
? handler
: handler[method];
if (typeof handlerWithMethod !== 'function')

@@ -133,7 +136,18 @@ throw TypeError('Handler must be a function.');

else {
output = await renderRouteTemplate({
...routeTemplateOptions,
handlerInfos: { data: handlerOutput, method },
routeInfos,
}).then((r) => r.output);
routeTemplateOptions.routeInfos.props = hasTopLevelHandler
? handlerOutput
: { [method]: handlerOutput };
if (exposePremises?.docOnly) {
const { document } = await renderRouteTemplate(routeTemplateOptions);
return {
response: new Response(document, {
headers: { ...CONTENT_TYPE_HTML },
}),
};
}
if (exposePremises?.propsOnly)
return {
response: Response.json(routeTemplateOptions.routeInfos.props),
};
output = await renderRouteTemplate(routeTemplateOptions).then((r) => r.output);
}

@@ -150,7 +164,15 @@ // MARK: No GET, render page

else {
output = await renderRouteTemplate({
...routeTemplateOptions,
handlerInfos: { data: null, method: 'GET' },
routeInfos,
}).then((r) => r.output);
if (exposePremises?.docOnly) {
const { document } = await renderRouteTemplate(routeTemplateOptions);
return {
response: new Response(document, {
headers: { ...CONTENT_TYPE_HTML },
}),
};
}
if (exposePremises?.propsOnly)
return {
response: Response.json(routeTemplateOptions.routeInfos.props || {}),
};
output = await renderRouteTemplate(routeTemplateOptions).then((r) => r.output);
}

@@ -196,3 +218,5 @@ // MARK: Return response

}
logger.error(errorMessage);
else {
logger.error(errorMessage);
}
}),

@@ -199,0 +223,0 @@ init: responseInit,

@@ -5,3 +5,3 @@ // NOTE: Util. to pretty print for user provided server.

import c from 'picocolors';
import { server as serverConstants } from './constants.js';
import { constants } from './constants.js';
// setTimeout(() => {

@@ -56,4 +56,4 @@ // logger.info('HY');

});
if (address.includes(serverConstants.IP_EXPOSED))
logger.info(`${address.includes(serverConstants.IP_EXPOSED)
if (address.includes(constants.IP_EXPOSED))
logger.info(`${address.includes(constants.IP_EXPOSED)
? `\n${c.dim('┃')} Network ${c.cyan(address)}\n`

@@ -60,0 +60,0 @@ : ''}`);

@@ -64,2 +64,35 @@ import type { Connect } from 'vite';

/**
* Settings for pages in `/src/routes`.
*/
pages?: {
/**
* Premises are the document and the properties necessary for page template
* rendering.
*
* You can access them via:
*
* - `.../_my-route/__index.props.json`
* - `.../_my-route/__index.doc.html`
*
* They are accessible with the dev/server handler and are outputted as
* static files for the static output or for server pre-rendered pages.
*
* They can be use for implementing client-side routing.
*/
premises?: {
/**
* @defaultValue false
*/
expose?: boolean;
/**
* Include routes with a glob filter array.
*/
include?: string[];
/**
* Exclude routes with a glob filter array.
*/
exclude?: string[];
};
};
/**
* Future, unstable features flags.

@@ -69,3 +102,4 @@ */

/**
* Exclude routes with an array of patterns. Useful for debugging.
* Automatically typed route paths.
* @experimental
*/

@@ -72,0 +106,0 @@ generateRoutesTypings?: boolean;

import { type ViteDevServer } from 'vite';
import type { RoutesManifest } from '../../routes/route.js';
import type { GracileConfig } from '../../user-config.js';
export declare const buildRoutes: ({ viteServerForBuild, root, gracileConfig, serverMode, }: {
export declare const buildRoutes: ({ routes, viteServerForBuild, root, gracileConfig, serverMode, }: {
routes: RoutesManifest;
viteServerForBuild: ViteDevServer;

@@ -9,3 +11,3 @@ root: string;

}) => Promise<{
routes: import("../../routes/route.js").RoutesManifest;
routes: RoutesManifest;
renderedRoutes: import("../../build/static.js").RenderedRouteDefinition[];

@@ -19,2 +21,3 @@ inputList: string[];

load(this: import("rollup").PluginContext, id: string): string | null;
buildStart?: never;
generateBundle?: never;

@@ -24,2 +27,3 @@ } | {

enforce: "post";
buildStart(this: import("rollup").PluginContext): void;
generateBundle(this: import("rollup").PluginContext, _: import("rollup").NormalizedOutputOptions, bundle: import("rollup").OutputBundle): void;

@@ -26,0 +30,0 @@ apply?: never;

@@ -1,7 +0,8 @@

import {} from 'vite';
import { basename, extname, join } from 'node:path';
import { createFilter } from 'vite';
import { renderRoutes } from '../../build/static.js';
import { REGEX_TAG_LINK, REGEX_TAG_SCRIPT, } from '../../render/route-template.js';
export const buildRoutes = async ({ viteServerForBuild, root, gracileConfig, serverMode = false, }) => {
export const buildRoutes = async ({ routes, viteServerForBuild, root, gracileConfig, serverMode = false, }) => {
// TODO: extract upstream, return just the plugins
const { renderedRoutes, routes } = await renderRoutes({
const { renderedRoutes } = await renderRoutes({
vite: viteServerForBuild,

@@ -11,2 +12,3 @@ serverMode,

gracileConfig,
routes,
});

@@ -16,2 +18,14 @@ const inputList = renderedRoutes

.map((input) => input.name);
const premisesFilter = gracileConfig.pages?.premises?.expose
? createFilter(gracileConfig.pages.premises.include, gracileConfig.pages.premises.exclude)
: null;
if (gracileConfig.pages?.premises?.expose && premisesFilter) {
inputList.forEach((input) => {
if (premisesFilter(input) === false)
return;
inputList.push(input
.replace(/index\.html$/, '__index.doc.html')
.replace(/404\.html$/, '__404.doc.html'));
});
}
return {

@@ -26,31 +40,6 @@ routes,

enforce: 'pre',
// config() {
// return {
// build: { rollupOptions: { input: inputList } },
// };
// },
// NOTE: NOT WORKING. Must be done in the config, before.
// config: {
// order: 'pre',
// handler(config) {
// if (config.build?.rollupOptions) {
// // eslint-disable-next-line no-param-reassign
// }
// // eslint-disable-next-line no-param-reassign
// config.build ||= {};
// // eslint-disable-next-line no-param-reassign
// config.build.rollupOptions ||= {};
// // eslint-disable-next-line no-param-reassign
// config.build.rollupOptions.input = inputList;
// return {
// build: { rollupOptions: { input: inputList } },
// };
// // return
// },
// },
resolveId(id) {
if (id.endsWith('.html')) {
const input = renderedRoutes.find((i) => i.name === id);
if (input)
return input.absoluteId;
if (extname(id) === '.html') {
if (inputList.find((i) => i === id))
return join(root, id);
}

@@ -60,6 +49,23 @@ return null;

load(id) {
if (id.endsWith('.html')) {
const content = renderedRoutes.find((i) => i.absoluteId === id)?.html;
if (content)
return content;
if (extname(id) === '.html') {
if (['index.html', '404.html'].includes(basename(id))) {
const content = renderedRoutes.find((i) => i.absoluteId === id)?.html;
if (content)
return content;
}
if (gracileConfig.pages?.premises?.expose) {
if (basename(id).endsWith('doc.html')) {
const content = renderedRoutes.find((i) => {
return (i.absoluteId
.replace(/index\.html$/, '__index.doc.html')
.replace(/404\.html$/, '__404.doc.html') === id);
})?.static.document;
if (content)
return content;
}
const content = renderedRoutes.find((i) => i.name === basename(id))?.html;
if (content)
return content;
// return '';}
}
}

@@ -72,2 +78,24 @@ return null;

enforce: 'post',
buildStart() {
if (!gracileConfig.pages?.premises?.expose || !premisesFilter)
return;
renderedRoutes.forEach((route) => {
if (premisesFilter(route.name) === false)
return;
if (serverMode && route.savePrerender !== true)
return;
const fileNameParts = route.name.split('/');
const last = fileNameParts.pop();
const newName = last?.replace(/(.*)\.html$/, (_, r) => `__${r}.props.json`);
if (!newName)
throw new Error();
fileNameParts.push(newName);
const fileName = fileNameParts.join('/');
this.emitFile({
fileName,
type: 'asset',
source: JSON.stringify(route.static.props ?? {}),
});
});
},
generateBundle(_, bundle) {

@@ -94,2 +122,5 @@ if (serverMode === false)

const route = renderedRoutes.find((r) => {
if (gracileConfig.pages?.premises?.expose)
return (`/${r.name}` ===
`/${fileKey}`.replace(/(.*?)\/__(.*?)\.doc\.html$/, (a, b, c) => `${b}/${c}.html`));
return r.name === fileKey;

@@ -102,2 +133,3 @@ });

delete bundle[fileKey];
// NOTE: Not sure if it's useful
if (route?.html)

@@ -104,0 +136,0 @@ route.html = null;

import type { RenderedRouteDefinition } from '../../build/static.js';
import type { RoutesManifest } from '../../routes/route.js';
import type { GracileConfig } from '../../user-config.js';
export declare function virtualRoutes({ routes, renderedRoutes, }: {

@@ -11,2 +12,11 @@ routes: RoutesManifest;

}[];
export declare function virtualRoutesClient({ routes: routesMap, mode, gracileConfig, }: {
routes: RoutesManifest;
mode: 'static' | 'server';
gracileConfig: GracileConfig;
}): {
name: string;
resolveId(this: import("rollup").PluginContext, id: string): "\0gracile:client:routes" | null;
load(this: import("rollup").PluginContext, id: string): string | null;
}[];
//# sourceMappingURL=virtual-routes.d.ts.map

@@ -0,1 +1,2 @@

import { createFilter } from 'vite';
export function virtualRoutes({

@@ -29,3 +30,7 @@ // root,

const routes = new Map(${JSON.stringify(routesWithoutPrerender, null, 2)})
const routes = new Map(${
//
JSON.stringify(routesWithoutPrerender, null, 2).replaceAll(
// NOTE: Not strictly necessary, but just in case.
'"pattern": {}', '"pattern": null')})
routes.forEach((route, pattern) => {

@@ -37,5 +42,5 @@ route.pattern = new URLPattern(pattern, 'http://gracile');

[
${routesWithoutPrerender
${routesWithoutPrerender
.map(([pattern, route]) => `['${pattern}', () => import('/${route.filePath}')],`)
.join('\n')}
.join('\n ')}
]

@@ -62,1 +67,47 @@ );

}
// TODO: move to CSR package?
// It's very tiny and can act as a stub.
// Could be documented for user, too? For allowing custom implementations.
export function virtualRoutesClient({ routes: routesMap, mode = 'server', gracileConfig, }) {
const virtualModuleId = 'gracile:client:routes';
const resolvedVirtualModuleId = `\0${virtualModuleId}`;
const enabled = gracileConfig.pages?.premises?.expose;
const premisesFilter = createFilter(gracileConfig.pages?.premises?.include, gracileConfig.pages?.premises?.exclude);
return [
{
name: 'gracile-client-routes',
// TODO: Proper invalidation!
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
return null;
},
load(id) {
if (id === resolvedVirtualModuleId) {
if (!routesMap || routesMap.size < 1)
return '';
const routes = [...routesMap].filter((r) => premisesFilter(r[1].filePath));
return `
const routeImports = new Map(
[
${enabled
? routes
.map(([pattern, route]) => `['${pattern}', () => import('/${route.filePath}')],`)
.join('\n ')
: '/* DISABLED */'}
]
);
export const enabled = ${enabled};
export const mode = '${mode}';
export { routeImports };
`;
}
return null;
},
},
];
}
{
"name": "@gracile/engine",
"version": "0.6.0",
"version": "0.7.0-next.0",
"description": "A thin, full-stack, web framework",

@@ -32,9 +32,7 @@ "keywords": [

"./*": "./dist/*.js",
"./ambient": {
"types": "./ambient.d.ts"
},
"./server": {
"types": "./dist/dev/server.js",
"development": "./dist/dev/server.js",
"default": "./dist/server/server.js"
"./ambient": "./ambient.d.ts",
"./server/*": {
"types": "./dist/server/*.js",
"development": "./dist/server/*.js",
"default": "./dist/server/*.js"
}

@@ -79,3 +77,3 @@ },

},
"gitHead": "970e457d0382b48beb531a1803393373cae38dcb"
"gitHead": "ed69f4d4d482a43fdb12bc0a02f12093337d91c7"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc