@emberkit/core 0.6.0 → 0.6.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/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export { compileMDX, compileSync, useMDX } from './mdx/index.js';
13
13
  export { DataCache, createCache, getCached, setCache, prefetch } from './cache/index.js';
14
14
  export { LazyInView, hydrateLazyInView, clearLazyRegistry } from './viewport/index.js';
15
15
  export { renderToHTMLString } from './ssr/helpers/render-html.js';
16
- export { drainHeadContent } from './meta/head-registry.js';
16
+ export { drainHeadContent, clearHeadContent } from './meta/head-registry.js';
17
17
  export { Head } from './meta/index.js';
18
18
  export type { HeadProps } from './meta/index.js';
19
19
  export { generateMeta, buildRouteHeadFromMetadata, generateBreadcrumbs, generateArticleSchema, generateProductSchema, } from './meta/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,QAAsB,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnF,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjG,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,QAAsB,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnF,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjG,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErF"}
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ export { compileMDX, compileSync, useMDX } from './mdx/index.js';
12
12
  export { DataCache, createCache, getCached, setCache, prefetch } from './cache/index.js';
13
13
  export { LazyInView, hydrateLazyInView, clearLazyRegistry } from './viewport/index.js';
14
14
  export { renderToHTMLString } from './ssr/helpers/render-html.js';
15
- export { drainHeadContent } from './meta/head-registry.js';
15
+ export { drainHeadContent, clearHeadContent } from './meta/head-registry.js';
16
16
  export { Head } from './meta/index.js';
17
17
  export { generateMeta, buildRouteHeadFromMetadata, generateBreadcrumbs, generateArticleSchema, generateProductSchema, } from './meta/index.js';
18
18
  export function defineConfig(config) {
@@ -1145,11 +1145,29 @@ function siteConfigToHeadOptions(site) {
1145
1145
  function generateSSREntry(site) {
1146
1146
  const siteHeadOptions = siteConfigToHeadOptions(site);
1147
1147
  return `
1148
- import { routes, notFoundRoute, errorRoute } from 'virtual:emberkit-routes';
1149
- import { createElement, buildRouteHeadFromMetadata } from '@emberkit/core';
1148
+ import { routes, rootLayout, notFoundRoute, errorRoute } from 'virtual:emberkit-routes';
1149
+ import {
1150
+ createElement,
1151
+ buildRouteHeadFromMetadata,
1152
+ drainHeadContent,
1153
+ clearHeadContent,
1154
+ } from '@emberkit/core';
1150
1155
 
1151
1156
  const siteHeadOptions = ${siteHeadOptions};
1152
1157
 
1158
+ const wrapWithRootLayout = async (RouteComponent) => {
1159
+ if (!rootLayout) {
1160
+ return RouteComponent;
1161
+ }
1162
+ const layoutMod = await rootLayout();
1163
+ const Layout = layoutMod.default || layoutMod;
1164
+ return (routeProps) =>
1165
+ createElement(Layout, {
1166
+ pathname: routeProps?.pathname,
1167
+ children: createElement(RouteComponent, routeProps),
1168
+ });
1169
+ };
1170
+
1153
1171
  const matchRoute = (routes, pathname) => {
1154
1172
  const normalizedPath = pathname.replace(/\\/+$/, '') || '/';
1155
1173
 
@@ -1282,14 +1300,18 @@ export async function render(url, server) {
1282
1300
  if (match) {
1283
1301
  try {
1284
1302
  const mod = await match.route.component();
1285
- const Component = mod.default || mod;
1286
-
1303
+ const Route = mod.default || mod;
1304
+ clearHeadContent();
1305
+ const Page = await wrapWithRootLayout(Route);
1306
+ const element = createElement(Page, { params: match.params, pathname });
1307
+ appHtml = renderToString(element);
1308
+ const drained = drainHeadContent();
1287
1309
  if (mod.metadata) {
1288
- headContent += buildRouteHeadFromMetadata(mod.metadata, pathname, siteHeadOptions ?? undefined) + '\\n';
1310
+ headContent =
1311
+ buildRouteHeadFromMetadata(mod.metadata, pathname, siteHeadOptions ?? undefined) + '\\n';
1312
+ } else if (drained) {
1313
+ headContent = drained + '\\n';
1289
1314
  }
1290
-
1291
- const element = createElement(Component, { params: match.params });
1292
- appHtml = renderToString(element);
1293
1315
  } catch (e) {
1294
1316
  console.error('[SSR] Failed to render route:', pathname, e);
1295
1317
  if (errorRoute) {
@@ -1318,9 +1340,18 @@ export async function render(url, server) {
1318
1340
  if (notFoundRoute) {
1319
1341
  try {
1320
1342
  const mod = await notFoundRoute();
1321
- const Component = mod.default || mod;
1322
- const element = createElement(Component, { });
1343
+ const Route = mod.default || mod;
1344
+ clearHeadContent();
1345
+ const Page = await wrapWithRootLayout(Route);
1346
+ const element = createElement(Page, { });
1323
1347
  appHtml = renderToString(element);
1348
+ const drained = drainHeadContent();
1349
+ if (drained) {
1350
+ headContent = drained + '\\n';
1351
+ } else if (mod.metadata) {
1352
+ headContent =
1353
+ buildRouteHeadFromMetadata(mod.metadata, pathname, siteHeadOptions ?? undefined) + '\\n';
1354
+ }
1324
1355
  } catch (e) {
1325
1356
  console.error('[SSR] Failed to render 404 page:', e);
1326
1357
  appHtml = '<div style="padding: 20px;">404 - Page not found</div>';
@@ -1405,10 +1436,19 @@ function generateRoutesCode(files, routeDir) {
1405
1436
  const routeEntries = [];
1406
1437
  let notFoundRoute = 'null';
1407
1438
  let errorRoute = 'null';
1439
+ let rootLayout = 'null';
1408
1440
  for (const file of files) {
1409
1441
  const relativePath = relative(routeDir, file).replace(/\\/g, '/');
1410
1442
  const ext = file.split('.').pop() ?? '';
1411
1443
  const isMarkdown = ext === 'md' || ext === 'mdx';
1444
+ const importPath = file.replace(/\\/g, '/');
1445
+ if (relativePath === '_layout.tsx' ||
1446
+ relativePath === '_layout.ts' ||
1447
+ relativePath === '_layout.jsx' ||
1448
+ relativePath === '_layout.js') {
1449
+ rootLayout = `() => import(${JSON.stringify(importPath)})`;
1450
+ continue;
1451
+ }
1412
1452
  // Check for special error pages
1413
1453
  if (relativePath === '404.tsx' || relativePath === '404.ts' || relativePath === '404.jsx' || relativePath === '404.js') {
1414
1454
  const importPath = file.replace(/\\/g, '/');
@@ -1441,7 +1481,6 @@ function generateRoutesCode(files, routeDir) {
1441
1481
  else {
1442
1482
  routePath = '/' + routePath;
1443
1483
  }
1444
- const importPath = file.replace(/\\/g, '/');
1445
1484
  const entry = isMarkdown
1446
1485
  ? ` { path: ${JSON.stringify(routePath)}, component: () => import(${JSON.stringify(importPath)}), isMarkdown: true }`
1447
1486
  : ` { path: ${JSON.stringify(routePath)}, component: () => import(${JSON.stringify(importPath)}) }`;
@@ -1451,6 +1490,7 @@ function generateRoutesCode(files, routeDir) {
1451
1490
  // the correct priority order (defense-in-depth alongside runtime scoring).
1452
1491
  routeEntries.sort((a, b) => scoreRoutePath(b.path) - scoreRoutePath(a.path));
1453
1492
  return `export const routes = [\n${routeEntries.map((r) => r.entry).join(',\n')}\n];
1493
+ export const rootLayout = ${rootLayout};
1454
1494
  export const notFoundRoute = ${notFoundRoute};
1455
1495
  export const errorRoute = ${errorRoute};`;
1456
1496
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emberkit/core",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Lightweight TypeScript-first JSX framework core",