@gracile/engine
Advanced tools
Comparing version 0.0.4-next.3 to 0.0.4-next.34
/// <reference types="vite/client" /> | ||
declare module 'gracile:routes' { | ||
export const routes: import('./src/routes/route.js').RoutesManifest; | ||
export const routeImports: import('./src/routes/route.js').RoutesImports; | ||
export const routeAssets: import('./src/routes/route.js').RoutesAssets; | ||
} |
@@ -9,5 +9,5 @@ import { type ServerRenderedTemplate } from '@lit-labs/ssr'; | ||
export declare function isUnknownObject(input: unknown): input is UnknownObject; | ||
export declare function isLitTemplate(input: unknown): input is TemplateResult<1>; | ||
export declare function isLitTemplate(input: unknown): input is TemplateResult<1> | ServerRenderedTemplate; | ||
export declare function isLitNormalTemplate(input: unknown): input is TemplateResult<1>; | ||
export declare function isLitServerTemplate(input: unknown): input is ServerRenderedTemplate; | ||
//# sourceMappingURL=assertions.d.ts.map |
import type { ViteDevServer } from 'vite'; | ||
export interface RouteDefinition { | ||
export interface RenderedRouteDefinition { | ||
absoluteId: string; | ||
name: string; | ||
html: string; | ||
handlerAssets?: string; | ||
savePrerender: boolean | null; | ||
} | ||
export declare function renderRoutes(vite: ViteDevServer, root?: string): Promise<RouteDefinition[]>; | ||
export declare function renderRoutes({ vite, serverMode, root, }: { | ||
vite: ViteDevServer; | ||
serverMode: boolean; | ||
root?: string; | ||
}): Promise<{ | ||
routes: import("../routes/route.js").RoutesManifest; | ||
renderedRoutes: RenderedRouteDefinition[]; | ||
}>; | ||
//# sourceMappingURL=static.d.ts.map |
@@ -6,3 +6,3 @@ import { Buffer } from 'node:buffer'; | ||
import { renderRouteTemplate } from '../render/route-template.js'; | ||
import { collectRoutes, routes } from '../routes/collect.js'; | ||
import { collectRoutes } from '../routes/collect.js'; | ||
import { loadForeignRouteObject } from '../routes/load-module.js'; | ||
@@ -21,11 +21,13 @@ async function streamToString(stream) { | ||
} | ||
export async function renderRoutes(vite, root = process.cwd()) { | ||
export async function renderRoutes({ vite, serverMode, root = process.cwd(), }) { | ||
logger.info(c.green('Rendering routes…'), { timestamp: true }); | ||
// MARK: Collect | ||
await collectRoutes(root /* vite */); | ||
logger.info(c.green('Rendering routes finished'), { timestamp: true }); | ||
const routes = await collectRoutes(root /* vite */); | ||
const renderedRoutes = []; | ||
// MARK: Iterate modules | ||
await Promise.all([...routes].map(async ([patternString, options]) => { | ||
const routeModule = await loadForeignRouteObject(vite, options.filePath); | ||
await Promise.all([...routes].map(async ([patternString, route]) => { | ||
const routeModule = await loadForeignRouteObject({ | ||
vite, | ||
route, | ||
}); | ||
const routeStaticPaths = routeModule.staticPaths?.(); | ||
@@ -60,10 +62,16 @@ // MARK: Extract data | ||
// MARK: Render | ||
const { output } = await renderRouteTemplate( | ||
// | ||
{ url: url.href }, vite, 'build', { | ||
routeModule, | ||
params, | ||
foundRoute: options, | ||
pathname: pathnameWithParams, | ||
props, | ||
const { output } = await renderRouteTemplate({ | ||
// | ||
request: { url: url.href }, | ||
vite, | ||
mode: 'build', | ||
routeInfos: { | ||
routeModule, | ||
params, | ||
foundRoute: route, | ||
pathname: pathnameWithParams, | ||
props, | ||
}, | ||
root, | ||
serverMode, | ||
}); | ||
@@ -81,6 +89,11 @@ const htmlString = await streamToString(output); | ||
html: htmlString, | ||
savePrerender: route.prerender, | ||
}); | ||
})); | ||
})); | ||
return renderedRoutes; | ||
logger.info(c.green('Rendering routes finished'), { timestamp: true }); | ||
return { | ||
routes, | ||
renderedRoutes: renderedRoutes.sort((a, b) => a.absoluteId < b.absoluteId ? -1 : 1), | ||
}; | ||
} |
export declare function dev(options: { | ||
port?: number | undefined; | ||
root?: string; | ||
root?: string | undefined; | ||
expose?: boolean | undefined; | ||
}): Promise<void>; | ||
}): Promise<void | { | ||
port: number; | ||
instance: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>; | ||
}>; | ||
//# sourceMappingURL=dev.d.ts.map |
import { logger } from '@gracile/internal-utils/logger'; | ||
import { setCurrentWorkingDirectory } from '@gracile/internal-utils/paths'; | ||
import c from 'picocolors'; | ||
import { getConfigs } from '../vite/config.js'; | ||
import { startServer } from './server.js'; | ||
const DEFAULT_DEV_SERVER_PORT = 9090; | ||
import { createStandaloneDevServer, DEFAULT_DEV_SERVER_PORT, DEFAULT_USER_SERVER_MODULE_ENTRYPOINT, startUserProvidedServer, } from './server.js'; | ||
export async function dev(options) { | ||
logger.info(c.gray('\n— Development mode —\n')); | ||
const { userConfigGracile } = await getConfigs(options.root ?? process.cwd(), 'dev'); | ||
const root = setCurrentWorkingDirectory(options.root); | ||
const { userConfigGracile } = await getConfigs(root, 'dev'); | ||
const port = options.port ?? userConfigGracile?.port ?? DEFAULT_DEV_SERVER_PORT; | ||
startServer({ | ||
...options, | ||
port, | ||
}).catch((e) => logger.error(String(e))); | ||
const entrypoint = userConfigGracile?.server?.entrypoint ?? | ||
DEFAULT_USER_SERVER_MODULE_ENTRYPOINT; | ||
if (userConfigGracile?.output === 'server') { | ||
logger.info(c.gray(`\n— User provided ${c.cyan('server')} mode —\n`)); | ||
return startUserProvidedServer({ | ||
root, | ||
entrypoint, | ||
}); | ||
} | ||
return createStandaloneDevServer({ root, port }); | ||
} |
import type { Server } from 'node:http'; | ||
export declare function startServer(options: { | ||
port?: number | undefined; | ||
import { type RequestHandler } from 'express'; | ||
import { type ViteDevServer } from 'vite'; | ||
export type CreateHandler = typeof createHandler; | ||
export declare function createHandler({ root, isStandalone, }?: { | ||
isStandalone?: boolean; | ||
hmrPort?: number; | ||
root?: string; | ||
}): Promise<{ | ||
vite: ViteDevServer | null; | ||
handlers: RequestHandler[]; | ||
}>; | ||
export declare const DEFAULT_DEV_SERVER_PORT = 9090; | ||
export declare const DEV_SERVER_EXPOSED_HOST = "0.0.0.0"; | ||
export declare const DEV_SERVER_HOST = "127.0.0.1"; | ||
export declare function createStandaloneDevServer(options: { | ||
port: number; | ||
root: string; | ||
expose?: boolean | undefined; | ||
@@ -10,2 +24,8 @@ }): Promise<{ | ||
}>; | ||
export declare const DEFAULT_USER_SERVER_MODULE_ENTRYPOINT = "/src/server"; | ||
export declare function startUserProvidedServer(options: { | ||
root: string; | ||
entrypoint: string; | ||
}): Promise<void>; | ||
export { printNodeHttpServerAddressInfos as printAddressInfos } from '../server/utils.js'; | ||
//# sourceMappingURL=server.d.ts.map |
@@ -5,17 +5,22 @@ import { logger } from '@gracile/internal-utils/logger'; | ||
import c from 'picocolors'; | ||
import { collectRoutes, routes } from '../routes/collect.js'; | ||
import { createViteRuntime } from 'vite'; | ||
import { collectRoutes } from '../routes/collect.js'; | ||
import { IP_EXPOSED, IP_LOCALHOST } from '../server/env.js'; | ||
import { createRequestHandler } from '../server/request.js'; | ||
import { createViteServer } from '../vite/server.js'; | ||
import { createDevRequestHandler } from './request.js'; | ||
async function createServer(_hmrPort, root = process.cwd()) { | ||
logger.info(c.green('starting engine…'), { | ||
export async function createHandler({ root = process.cwd(), | ||
// hmrPort, | ||
isStandalone, } = {}) { | ||
if (isStandalone !== true) | ||
setCurrentWorkingDirectory(root); | ||
logger.info(c.green('creating handler…'), { | ||
timestamp: true, | ||
}); | ||
setCurrentWorkingDirectory(root); | ||
const app = express(); | ||
const vite = await createViteServer(root, 'dev'); | ||
app.use(vite.middlewares); | ||
app.get('/__routes', (req, res) => { | ||
return res.json([...routes]); | ||
}); | ||
await collectRoutes(root /* vite */); | ||
const { vite, gracileConfig } = await createViteServer(root, 'dev'); | ||
const routes = await collectRoutes(root /* vite */); | ||
const debugRoutes = (req, res, next) => { | ||
if (req.url === '__routes') | ||
return res.json([...routes]); | ||
return next(); | ||
}; | ||
vite.watcher.on('all', (event, _file) => { | ||
@@ -25,16 +30,25 @@ if (['add', 'unlink'].includes(event)) | ||
}); | ||
const handler = createDevRequestHandler(vite); | ||
/* NOTE: Types are wrong! Should accept an async request handler. */ | ||
app.use('*', handler); | ||
return { app, vite }; | ||
const serverMode = gracileConfig?.output === 'server'; | ||
const handler = createRequestHandler({ vite, root, serverMode, routes }); | ||
return { handlers: [debugRoutes, vite.middlewares, handler], vite }; | ||
} | ||
export async function startServer(options) { | ||
const port = options.port ?? 9090; | ||
const server = await createServer(port + 1, options.root); | ||
export const DEFAULT_DEV_SERVER_PORT = 9090; | ||
export const DEV_SERVER_EXPOSED_HOST = IP_EXPOSED; | ||
export const DEV_SERVER_HOST = IP_LOCALHOST; | ||
export async function createStandaloneDevServer(options) { | ||
const { handlers: handler } = await createHandler({ | ||
// hmrPort: options.port + 1, | ||
root: options.root, | ||
}); | ||
// NOTE: `0` will auto-alocate a random available port. | ||
let resultingPort = port; | ||
let resultingPort = options.port; | ||
let resultingHost; | ||
const expressApp = express(); | ||
expressApp.use(handler); | ||
const instance = await new Promise((resolve) => { | ||
const inst = server.app.listen(port, options.expose ? '0.0.0.0' : '127.0.0.1', () => { | ||
logger.info(c.green('development server started'), { timestamp: true }); | ||
const inst = expressApp.listen(options.port, options.expose ? DEV_SERVER_EXPOSED_HOST : DEV_SERVER_HOST, () => { | ||
logger.info(c.green('development server started'), { | ||
timestamp: true, | ||
}); | ||
logger.info(c.dim(`CWD: ${process.env['__GRACILE_PROJECT_CWD']}`)); | ||
resolve(inst); | ||
@@ -57,1 +71,14 @@ const addressInfo = inst.address(); | ||
} | ||
export const DEFAULT_USER_SERVER_MODULE_ENTRYPOINT = '/src/server'; | ||
export async function startUserProvidedServer(options) { | ||
const { vite: runtimeServer } = await createViteServer(options.root, 'dev'); | ||
const runtime = await createViteRuntime(runtimeServer); | ||
await runtime.executeEntrypoint(options.entrypoint); | ||
// return { | ||
// close: async () => { | ||
// await runtime.destroy(); | ||
// await runtimeServer.close(); | ||
// }, | ||
// }; | ||
} | ||
export { printNodeHttpServerAddressInfos as printAddressInfos } from '../server/utils.js'; |
export declare function preview({ port, expose, root, }: { | ||
port?: number | undefined; | ||
expose?: boolean | undefined; | ||
root?: string; | ||
root?: string | undefined; | ||
}): Promise<void>; | ||
//# sourceMappingURL=preview.d.ts.map |
@@ -8,3 +8,6 @@ import { logger } from '@gracile/internal-utils/logger'; | ||
const { userConfigGracile } = await getConfigs(root ?? process.cwd(), 'build'); | ||
if (userConfigGracile?.output === 'server') | ||
throw new Error(c.red(`Vite preview is unnecessary when using the ${c.yellow('server mode')}.\n\n`) + | ||
c.yellow(`You can use a \`preview\` script with this command:\n\n${c.white('node --env-file=.env --watch dist/server/server.js')}\n`)); | ||
await vitePreview(port ?? userConfigGracile?.port ?? 9797, expose); | ||
} |
@@ -1,8 +0,10 @@ | ||
import type { Readable } from 'stream'; | ||
import { Readable } from 'stream'; | ||
import type { ViteDevServer } from 'vite'; | ||
import type { RouteInfos } from '../routes/match.js'; | ||
import type { StaticRequest } from '../routes/route.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 pageAssets: import("@lit-labs/ssr").ServerRenderedTemplate; | ||
export declare const REGEX_TAG_SCRIPT: RegExp; | ||
export declare const REGEX_TAG_LINK: RegExp; | ||
export type HandlerInfos = { | ||
@@ -12,5 +14,14 @@ data: unknown; | ||
}; | ||
export declare function renderRouteTemplate(request: Request | StaticRequest, vite: ViteDevServer, mode: 'dev' | 'build', routeInfos: RouteInfos, handlerInfos?: HandlerInfos): Promise<{ | ||
export declare function renderRouteTemplate({ request, vite, mode, routeInfos, handlerInfos, routeAssets, serverMode, }: { | ||
request: Request | R.StaticRequest; | ||
vite?: ViteDevServer | undefined; | ||
mode: 'dev' | 'build'; | ||
routeInfos: RouteInfos; | ||
handlerInfos?: HandlerInfos | undefined; | ||
routeAssets?: R.RoutesAssets | undefined; | ||
root: string; | ||
serverMode?: boolean | undefined; | ||
}): Promise<{ | ||
output: Readable; | ||
}>; | ||
//# sourceMappingURL=route-template.d.ts.map |
import { html } from '@gracile/internal-utils/dummy-literals'; | ||
import { html as LitSsrHtml, render as renderLitSsr } from '@lit-labs/ssr'; | ||
import { collectResult } from '@lit-labs/ssr/lib/render-result.js'; | ||
import { RenderResultReadable as LitReadable } from '@lit-labs/ssr/lib/render-result-readable.js'; | ||
import { Readable } from 'stream'; | ||
import { isLitServerTemplate, isLitTemplate } from '../assertions.js'; | ||
@@ -21,3 +21,7 @@ async function* concatStreams(...readables) { | ||
export const pageAssets = LitSsrHtml `<!--__GRACILE_PAGE_ASSETS__-->`; | ||
export async function renderRouteTemplate(request, vite, mode, routeInfos, handlerInfos) { | ||
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, }) { | ||
// MARK: Context | ||
@@ -39,3 +43,3 @@ const context = { | ||
const fragmentRender = renderLitSsr(fragmentOutput); | ||
const output = LitReadable.from(fragmentRender); | ||
const output = Readable.from(fragmentRender); | ||
return { output }; | ||
@@ -52,3 +56,3 @@ } | ||
// MARK: Sibling assets | ||
const baseDocRenderedWithAssets = baseDocRendered.replace(PAGE_ASSETS_MARKER, html ` | ||
let baseDocRenderedWithAssets = baseDocRendered.replace(PAGE_ASSETS_MARKER, html ` | ||
<!-- PAGE ASSETS --> | ||
@@ -58,6 +62,12 @@ ${routeInfos.foundRoute.pageAssets.map((path) => { | ||
if (/\.(js|ts)$/.test(path)) { | ||
return html `<script type="module" src="/${path}"></script>`; | ||
return html ` | ||
<script type="module" src="/${path}"></script> | ||
<!-- --> | ||
`; | ||
} | ||
if (/\.(scss|css)$/.test(path)) { | ||
return html `<link rel="stylesheet" href="/${path}" />`; | ||
return html ` | ||
<link rel="stylesheet" href="/${path}" /> | ||
<!-- --> | ||
`; | ||
} | ||
@@ -68,20 +78,38 @@ throw new Error('Unknown asset.'); | ||
`); | ||
const routeAssetsString = routeAssets?.get?.(routeInfos.foundRoute.pattern.pathname); | ||
if (routeAssetsString) | ||
baseDocRenderedWithAssets = baseDocRenderedWithAssets | ||
.replace(REGEX_TAG_SCRIPT, (s) => { | ||
if (s.includes(`type="module"`)) | ||
return ''; | ||
return s; | ||
}) | ||
.replace(REGEX_TAG_LINK, (s) => { | ||
if (s.includes(`rel="stylesheet"`)) | ||
return ''; | ||
return s; | ||
}) | ||
.replace('</head>', `${routeAssetsString}\n</head>`); | ||
// MARK: Base document | ||
const baseDocHtml = mode === 'dev' | ||
const baseDocHtml = vite && mode === 'dev' | ||
? await vite.transformIndexHtml(routeInfos.pathname, baseDocRenderedWithAssets) | ||
: baseDocRenderedWithAssets; | ||
const index = baseDocHtml.indexOf(SSR_OUTLET_MARKER); | ||
const baseDocRenderStreamPre = LitReadable.from(baseDocHtml.substring(0, index)); | ||
const baseDocRenderStreamPost = LitReadable.from(baseDocHtml.substring(index + SSR_OUTLET_MARKER.length + 1)); | ||
const baseDocRenderStreamPre = Readable.from(baseDocHtml.substring(0, index)); | ||
const baseDocRenderStreamPost = Readable.from(baseDocHtml.substring(index + SSR_OUTLET_MARKER.length + 1)); | ||
// MARK: Page | ||
if (routeInfos.routeModule.template) { | ||
const routeOutput = (await Promise.resolve(routeInfos.routeModule.template(context))); | ||
// Skipped with server mode in production build | ||
if ((serverMode === false && routeInfos.routeModule.template) || | ||
// | ||
(serverMode && routeInfos.routeModule.template && mode !== 'build')) { | ||
const routeOutput = await Promise.resolve(routeInfos.routeModule.template?.(context)); | ||
if (isLitTemplate(routeOutput) === false) | ||
throw Error(`Wrong template result for page template ${routeInfos.foundRoute.filePath}.`); | ||
const renderStream = LitReadable.from(renderLitSsr(routeOutput)); | ||
const output = LitReadable.from(concatStreams(baseDocRenderStreamPre, renderStream, baseDocRenderStreamPost)); | ||
const renderStream = Readable.from(renderLitSsr(routeOutput)); | ||
const output = Readable.from(concatStreams(baseDocRenderStreamPre, renderStream, baseDocRenderStreamPost)); | ||
return { output }; | ||
} | ||
const output = LitReadable.from(baseDocHtml); | ||
// MARK: Just the document | ||
const output = Readable.from(baseDocHtml); | ||
return { output }; | ||
} |
@@ -1,4 +0,3 @@ | ||
import type { Route } from './route.js'; | ||
export declare const routes: Map<string, Route>; | ||
export declare function collectRoutes(root: string): Promise<void>; | ||
import type * as R from './route.js'; | ||
export declare function collectRoutes(root: string): Promise<R.RoutesManifest>; | ||
//# sourceMappingURL=collect.d.ts.map |
@@ -10,3 +10,2 @@ import path, { join, relative } from 'node:path'; | ||
import { REGEXES } from './load-module.js'; | ||
export const routes = new Map(); | ||
function extractRoutePatterns(absoluteFilePath) { | ||
@@ -53,2 +52,3 @@ const routePathname = path | ||
} | ||
const routes = new Map(); | ||
export async function collectRoutes(root /* vite: ViteDevServer */) { | ||
@@ -99,2 +99,4 @@ routes.clear(); | ||
pageAssets: [], | ||
// NOTE: Not implemented! | ||
prerender: null, | ||
}); | ||
@@ -114,2 +116,3 @@ }); | ||
}); | ||
return routes; | ||
} |
@@ -10,3 +10,7 @@ import type { ViteDevServer } from 'vite'; | ||
}; | ||
export declare function loadForeignRouteObject(vite: ViteDevServer, routePath: string): Promise<R.RouteModule>; | ||
export declare function loadForeignRouteObject({ vite, route, routeImports, }: { | ||
vite?: ViteDevServer | undefined; | ||
route: R.Route; | ||
routeImports?: R.RoutesImports | undefined; | ||
}): Promise<R.RouteModule>; | ||
//# sourceMappingURL=load-module.d.ts.map |
@@ -12,7 +12,16 @@ import * as R from './route.js'; | ||
}; | ||
export async function loadForeignRouteObject(vite, routePath) { | ||
export async function loadForeignRouteObject({ vite, route, routeImports, }) { | ||
// NOTE: Check and assert unknown userland module to correct RouteModule instance (in the engine's realm) | ||
const rm = await vite.ssrLoadModule(routePath); | ||
const routeModuleFactory = rm['default']; | ||
const errorBase = `Incorrect route module ${routePath}!`; | ||
let unknownRouteModule = null; | ||
if (vite) | ||
unknownRouteModule = await vite.ssrLoadModule(route.filePath); | ||
else if (routeImports) { | ||
const ri = routeImports.get(route.pattern.pathname); | ||
if (ri) | ||
unknownRouteModule = await Promise.resolve(ri()); | ||
} | ||
if (unknownRouteModule === null) | ||
throw new Error('Cannot find route module.'); | ||
const routeModuleFactory = unknownRouteModule['default']; | ||
const errorBase = `Incorrect route module ${route.filePath}!`; | ||
if (typeof routeModuleFactory !== 'function') | ||
@@ -19,0 +28,0 @@ throw new Error(`${errorBase} Not a function.`); |
import type { ViteDevServer } from 'vite'; | ||
import * as R from './route.js'; | ||
import type * as R from './route.js'; | ||
type Params = Record<string, string | undefined>; | ||
@@ -13,5 +13,7 @@ export type RouteInfos = { | ||
url: string; | ||
vite: ViteDevServer; | ||
vite?: ViteDevServer | undefined; | ||
routes: R.RoutesManifest; | ||
routeImports?: R.RoutesImports | undefined; | ||
}): Promise<RouteInfos>; | ||
export {}; | ||
//# sourceMappingURL=match.d.ts.map |
@@ -1,5 +0,4 @@ | ||
import { routes } from './collect.js'; | ||
import { loadForeignRouteObject } from './load-module.js'; | ||
import * as R from './route.js'; | ||
function matchRouteFromUrl(url) { | ||
// FIXME: proper DI for routes | ||
function matchRouteFromUrl(url, routes) { | ||
let match; | ||
@@ -47,5 +46,9 @@ let foundRoute; | ||
export async function getRoute(options) { | ||
const { foundRoute, pathname, params } = matchRouteFromUrl(options.url); | ||
const routePath = foundRoute.filePath; | ||
const routeModule = await loadForeignRouteObject(options.vite, routePath); | ||
const { foundRoute, pathname, params } = matchRouteFromUrl(options.url, options.routes); | ||
// TODO: Simplify all the routes things | ||
const routeModule = await loadForeignRouteObject({ | ||
vite: options.vite, | ||
route: foundRoute, | ||
routeImports: options.routeImports, | ||
}); | ||
const staticPaths = extractStaticPaths({ | ||
@@ -52,0 +55,0 @@ routeModule, |
@@ -9,4 +9,5 @@ import type { ServerRenderedTemplate } from '@lit-labs/ssr'; | ||
handler?: HandlerGeneric; | ||
prerender?: boolean | undefined; | ||
document?: DocumentTemplate<RouteContextGeneric>; | ||
template?: (context: RouteContextGeneric) => RouteTemplateResult; | ||
document?: DocumentTemplate<RouteContextGeneric>; | ||
}; | ||
@@ -18,2 +19,3 @@ export declare class RouteModule { | ||
get document(): DocumentTemplate<RouteContextGeneric> | undefined; | ||
get prerender(): boolean | undefined; | ||
get template(): ((context: RouteContextGeneric) => RouteTemplateResult) | undefined; | ||
@@ -64,3 +66,7 @@ constructor(options: ModuleOptions); | ||
pageAssets: string[]; | ||
prerender: boolean | null; | ||
} | ||
export type RoutesManifest = Map<string, Route>; | ||
export type RoutesImports = Map<string, () => Record<string, unknown>>; | ||
export type RoutesAssets = Map<string, string>; | ||
//# sourceMappingURL=route.d.ts.map |
@@ -15,2 +15,6 @@ // TODO: put in engine | ||
} | ||
#prerender; | ||
get prerender() { | ||
return this.#prerender; | ||
} | ||
#template; | ||
@@ -27,3 +31,2 @@ get template() { | ||
this.#handler = options.handler; | ||
// if (options.fragment) this.#fragment = options.fragment; | ||
if (typeof options.template === 'function') | ||
@@ -33,3 +36,5 @@ this.#template = options.template; | ||
this.#document = options.document; | ||
if (typeof options.prerender === 'boolean') | ||
this.#prerender = options.prerender; | ||
} | ||
} |
import type { UserConfig } from 'vite'; | ||
export declare class GracileConfig { | ||
port?: number; | ||
/** | ||
* Root directory for the project | ||
*/ | ||
root?: string; | ||
/** | ||
* @defaultValue 'static' | ||
*/ | ||
output?: 'static' | 'server'; | ||
vite?: UserConfig; | ||
server?: { | ||
entrypoint?: string; | ||
}; | ||
constructor(options: GracileConfig); | ||
@@ -6,0 +17,0 @@ } |
export class GracileConfig { | ||
port; | ||
/** | ||
* Root directory for the project | ||
*/ | ||
root; | ||
/** | ||
* @defaultValue 'static' | ||
*/ | ||
output; | ||
vite; | ||
server; | ||
constructor(options) { | ||
@@ -5,0 +14,0 @@ Object.assign(this, options); |
@@ -5,4 +5,6 @@ import { logger } from '@gracile/internal-utils/logger'; | ||
import { build, mergeConfig } from 'vite'; | ||
import { DEFAULT_USER_SERVER_MODULE_ENTRYPOINT } from '../dev/server.js'; | ||
import { getConfigs } from './config.js'; | ||
import { htmlStaticPages } from './plugins/html-static-pages.js'; | ||
import { buildRoutes } from './plugins/build-routes.js'; | ||
import { virtualRoutes } from './plugins/virtual-routes.js'; | ||
import { createViteServer } from './server.js'; | ||
@@ -13,7 +15,13 @@ export async function viteBuild(root = process.cwd()) { | ||
// SHOULD BE Vite for SSR? | ||
const viteServerForBuild = await createViteServer(root, 'build'); | ||
const { vite: viteServerForBuild } = await createViteServer(root, 'build'); | ||
const { userConfigGracile, finalCommonConfigVite } = await getConfigs(root, 'build'); | ||
const htmlPages = await htmlStaticPages(viteServerForBuild, root, userConfigGracile || {}); | ||
const buildConfig = { | ||
const serverMode = userConfigGracile?.output === 'server'; | ||
const htmlPages = await buildRoutes({ | ||
viteServerForBuild, | ||
root, | ||
_config: userConfigGracile || {}, | ||
serverMode, | ||
}); | ||
const baseBuildConfig = { | ||
root, | ||
optimizeDeps: { include: [] }, | ||
@@ -27,2 +35,7 @@ css: { | ||
sourcemap: true, | ||
}, | ||
}; | ||
const finalConfig = mergeConfig(finalCommonConfigVite, baseBuildConfig); | ||
const clientConfig = mergeConfig(finalConfig, { | ||
build: { | ||
rollupOptions: { | ||
@@ -32,7 +45,69 @@ // NOTE: Cannot be set in a plugin | ||
plugins: [htmlPages.plugin], | ||
// input: { | ||
// server: | ||
// 'src/server.ts' /* DEFAULT_USER_SERVER_MODULE_ENTRYPOINT + '.ts' */, | ||
// }, | ||
output: { | ||
...(serverMode ? { dir: `${root}/dist/client` } : {}), | ||
}, | ||
}, | ||
}, | ||
}; | ||
const finalConfig = mergeConfig(finalCommonConfigVite, buildConfig); | ||
await build(finalConfig); | ||
// resolve: { | ||
// preserveSymlinks: true, | ||
// conditions: ['development'], | ||
// }, | ||
}); | ||
await build(clientConfig); | ||
if (serverMode) { | ||
const serverConfig = mergeConfig(finalConfig, { | ||
publicDir: false, | ||
ssr: { | ||
// external: ['*node_modules*'], | ||
// noExternal | ||
}, | ||
resolve: { | ||
// preserveSymlinks: true, | ||
// conditions: ['development'], | ||
// conditions: ['production'], | ||
}, | ||
build: { | ||
ssr: true, | ||
rollupOptions: { | ||
external: [ | ||
// '*', | ||
// '!*', | ||
// '*node_modules*', | ||
// 'node_modules/@gracile/gracile', | ||
// 'fsevents', | ||
// 'express', | ||
// 'vite', | ||
// '@whatwg-node/server', | ||
// '@lit/*', | ||
// '@lit-labs/*', | ||
// 'lit', | ||
// 'lit-html', | ||
// 'cheerio', | ||
// 'parse5', | ||
], | ||
plugins: [ | ||
virtualRoutes({ | ||
// root, | ||
routes: htmlPages.routes, | ||
renderedRoutes: htmlPages.renderedRoutes, | ||
}), | ||
], | ||
input: { | ||
server: DEFAULT_USER_SERVER_MODULE_ENTRYPOINT, | ||
}, | ||
output: { | ||
dir: `${root}/dist/server`, | ||
entryFileNames: '[name].js', | ||
assetFileNames: 'assets/[name].js', | ||
chunkFileNames: 'chunk/[name].js', | ||
}, | ||
}, | ||
}, | ||
}); | ||
await build(serverConfig); | ||
} | ||
await viteServerForBuild.close().catch((e) => logger.error(String(e))); | ||
@@ -39,0 +114,0 @@ logger.warn('Exiting'); |
@@ -7,2 +7,3 @@ import { type UserConfig } from 'vite'; | ||
root: string; | ||
mode: string; | ||
server: { | ||
@@ -15,2 +16,3 @@ middlewareMode: true; | ||
appType: "custom"; | ||
envPrefix: string; | ||
css: { | ||
@@ -17,0 +19,0 @@ devSourcemap: true; |
@@ -16,3 +16,5 @@ import path from 'node:path'; | ||
// Also, beware with absolute paths with Windows. They need the `file://` protocol. | ||
const userConfigGracile = await import(pathToFileURL(path.join(root, 'gracile.config')).href) | ||
const userConfigGracile = await import( | ||
/* @vite-ignore */ | ||
pathToFileURL(path.join(root, 'gracile.config')).href) | ||
.then((module) => { | ||
@@ -31,4 +33,9 @@ if (isUnknownObject(module) && typeof module['default'] === 'function') { | ||
}); | ||
// NOTE: Harmonize `import.meta.env.(MODE|DEV|PROD)` | ||
// See https://vitejs.dev/guide/api-javascript#createserver | ||
if (mode === 'build') | ||
process.env['NODE_ENV'] = 'production'; | ||
const baseConfigVite = { | ||
root, | ||
mode: mode === 'dev' ? 'development' : 'production', | ||
server: mode === 'dev' | ||
@@ -45,2 +52,3 @@ ? // NOTE: Same (for now) | ||
appType: 'custom', | ||
envPrefix: 'GRACILE', | ||
css: { | ||
@@ -57,2 +65,4 @@ devSourcemap: true, | ||
// conditions: mode === 'dev' ? ['development'] : ['production'], | ||
// preserveSymlinks: true, | ||
// conditions: ['development', 'default'], | ||
}, | ||
@@ -59,0 +69,0 @@ }; |
@@ -1,3 +0,6 @@ | ||
export declare function createViteServer(root: string, mode: 'dev' | 'build'): Promise<import("vite").ViteDevServer>; | ||
export declare function createViteServer(root: string, mode: 'dev' | 'build'): Promise<{ | ||
vite: import("vite").ViteDevServer; | ||
gracileConfig: import("../user-config.js").GracileConfig | null; | ||
}>; | ||
export declare function vitePreview(port?: number, expose?: boolean | undefined): Promise<void>; | ||
//# sourceMappingURL=server.d.ts.map |
@@ -5,10 +5,12 @@ import { createServer, preview } from 'vite'; | ||
export async function createViteServer(root, mode) { | ||
const { finalCommonConfigVite } = await getConfigs(root, mode); | ||
const { finalCommonConfigVite, userConfigGracile } = await getConfigs(root, mode); | ||
const vite = await createServer(finalCommonConfigVite); | ||
// TODO: print url even if in middleware mode | ||
// if (mode === 'dev') vite.printUrls(); | ||
return vite; | ||
return { vite, gracileConfig: userConfigGracile }; | ||
} | ||
export async function vitePreview( | ||
/* _root: string, */ port = 9091, expose) { | ||
/* _root: string, */ | ||
// | ||
port = 9091, expose) { | ||
const previewer = await preview({ | ||
@@ -15,0 +17,0 @@ appType: 'mpa', |
{ | ||
"name": "@gracile/engine", | ||
"version": "0.0.4-next.3+de03482", | ||
"description": "A thin, full-stack, web framework", | ||
"version": "0.0.4-next.34+b2b6452", | ||
"description": "A thin, full-stack, web framework.\nPowered by Vite and Lit SSR.", | ||
"keywords": [ | ||
@@ -34,2 +34,7 @@ "full-stack", | ||
"types": "./ambient.d.ts" | ||
}, | ||
"./server": { | ||
"types": "./dist/dev/server.js", | ||
"development": "./dist/dev/server.js", | ||
"default": "./dist/server/server.js" | ||
} | ||
@@ -43,6 +48,6 @@ }, | ||
"@gracile/client": "^0.0.3", | ||
"@gracile/internal-utils": "^0.0.4-next.3+de03482", | ||
"@gracile/internal-utils": "^0.0.3", | ||
"@whatwg-node/server": "^0.9.25", | ||
"esm-env": "^1.0.0", | ||
"express": "^4.19.2", | ||
"express": "4.x.x", | ||
"fast-glob": "^3.3.2", | ||
@@ -56,4 +61,3 @@ "picocolors": "^1.0.0", | ||
"@lit-labs/ssr-client": "1.x", | ||
"lit": "3.x", | ||
"sass": "^1.x.x" | ||
"lit": "3.x" | ||
}, | ||
@@ -64,7 +68,2 @@ "publishConfig": { | ||
}, | ||
"peerDependenciesMeta": { | ||
"sass": { | ||
"optional": true | ||
} | ||
}, | ||
"// disabledDeps": { | ||
@@ -87,3 +86,3 @@ "rollup-plugin-typescript2": "^0.36.0", | ||
}, | ||
"gitHead": "de03482a22df4d131c7baa2c2f439c9a92597629" | ||
"gitHead": "b2b645252bbaf46a657d7e6002e0a6a54af00f81" | ||
} |
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
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
147089
12
77
1736
3
+ Added@gracile/internal-utils@0.0.3(transitive)
- Removed@gracile/internal-utils@0.0.4(transitive)
- Removed@parcel/watcher@2.5.0(transitive)
- Removed@parcel/watcher-android-arm64@2.5.0(transitive)
- Removed@parcel/watcher-darwin-arm64@2.5.0(transitive)
- Removed@parcel/watcher-darwin-x64@2.5.0(transitive)
- Removed@parcel/watcher-freebsd-x64@2.5.0(transitive)
- Removed@parcel/watcher-linux-arm-glibc@2.5.0(transitive)
- Removed@parcel/watcher-linux-arm-musl@2.5.0(transitive)
- Removed@parcel/watcher-linux-arm64-glibc@2.5.0(transitive)
- Removed@parcel/watcher-linux-arm64-musl@2.5.0(transitive)
- Removed@parcel/watcher-linux-x64-glibc@2.5.0(transitive)
- Removed@parcel/watcher-linux-x64-musl@2.5.0(transitive)
- Removed@parcel/watcher-win32-arm64@2.5.0(transitive)
- Removed@parcel/watcher-win32-ia32@2.5.0(transitive)
- Removed@parcel/watcher-win32-x64@2.5.0(transitive)
- Removedchokidar@4.0.1(transitive)
- Removeddetect-libc@1.0.3(transitive)
- Removedimmutable@4.3.7(transitive)
- Removednode-addon-api@7.1.1(transitive)
- Removedreaddirp@4.0.2(transitive)
- Removedsass@1.80.6(transitive)
Updatedexpress@4.x.x