@emberkit/cli 0.6.9 → 0.7.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.
@@ -59,7 +59,7 @@ export async function build(_args) {
59
59
  log("info", "Building client bundle...");
60
60
  await buildClient(root, outDir, viteConfig, customLogger);
61
61
  log("info", "Building SSR bundle...");
62
- await buildSSR(root, outDir, viteConfig, customLogger);
62
+ await buildSSR(root, outDir, viteConfig, customLogger, emberkitConfig);
63
63
  log("info", "Generating SSR manifest...");
64
64
  await generateManifest(root, outDir, mode);
65
65
  if (mode === "hybrid") {
@@ -72,7 +72,7 @@ export async function build(_args) {
72
72
  log("info", "Building static site...");
73
73
  await buildClient(root, outDir, viteConfig, customLogger);
74
74
  log("info", "Building SSR bundle for pre-rendering...");
75
- await buildSSR(root, outDir, viteConfig, customLogger);
75
+ await buildSSR(root, outDir, viteConfig, customLogger, emberkitConfig);
76
76
  log("info", "Generating manifest...");
77
77
  await generateManifest(root, outDir, mode);
78
78
  log("info", "Pre-rendering all routes...");
@@ -113,13 +113,48 @@ async function buildClient(root, outDir, viteConfig, customLogger) {
113
113
  };
114
114
  await viteBuild(clientConfig);
115
115
  }
116
- function getServerEntryShim() {
117
- return `import { routes, notFoundRoute, errorRoute } from 'virtual:emberkit-routes';
118
- import { createElement } from '@emberkit/core';
116
+ function siteConfigToHeadOptions(site) {
117
+ const config = site;
118
+ if (!config?.url) {
119
+ return "null";
120
+ }
121
+ return JSON.stringify({
122
+ siteUrl: config.url,
123
+ siteName: config.name,
124
+ titleSuffix: config.titleSuffix,
125
+ defaultDescription: config.description,
126
+ defaultOgImage: config.ogImage,
127
+ twitterSite: config.twitterSite,
128
+ });
129
+ }
130
+ function getServerEntryShim(site) {
131
+ const siteHeadOptions = siteConfigToHeadOptions(site);
132
+ return `import { routes, rootLayout, notFoundRoute, errorRoute } from 'virtual:emberkit-routes';
133
+ import {
134
+ createElement,
135
+ buildRouteHeadFromMetadata,
136
+ drainHeadContent,
137
+ clearHeadContent,
138
+ } from '@emberkit/core';
119
139
  import { readFileSync } from 'node:fs';
120
140
  import { join, dirname } from 'node:path';
121
141
  import { fileURLToPath } from 'node:url';
122
142
 
143
+ const siteHeadOptions = ${siteHeadOptions};
144
+
145
+ const wrapWithRootLayout = async (RouteComponent) => {
146
+ if (!rootLayout) {
147
+ return RouteComponent;
148
+ }
149
+ const layoutMod = await rootLayout();
150
+ const Layout = layoutMod.default || layoutMod;
151
+ return (routeProps) =>
152
+ createElement(Layout, {
153
+ pathname: routeProps?.pathname,
154
+ children: createElement(RouteComponent, routeProps),
155
+ });
156
+ };
157
+
123
158
  const __dirname = dirname(fileURLToPath(import.meta.url));
124
159
 
125
160
  const routeToRegex = (routePath) => {
@@ -247,19 +282,18 @@ export async function render(url) {
247
282
  if (match) {
248
283
  try {
249
284
  const mod = await match.route.component();
250
- const Component = mod.default || mod;
251
-
285
+ const Route = mod.default || mod;
286
+ clearHeadContent();
287
+ const Page = await wrapWithRootLayout(Route);
288
+ const element = createElement(Page, { params: match.params, pathname });
289
+ appHtml = renderToString(element);
290
+ const drained = drainHeadContent();
252
291
  if (mod.metadata) {
253
- if (mod.metadata.title) {
254
- headContent += '<title>' + escapeHtml(mod.metadata.title) + '</title>\\n';
255
- }
256
- if (mod.metadata.description) {
257
- headContent += '<meta name="description" content="' + escapeHtml(mod.metadata.description) + '">\\n';
258
- }
292
+ headContent =
293
+ buildRouteHeadFromMetadata(mod.metadata, pathname, siteHeadOptions ?? undefined) + '\\n';
294
+ } else if (drained) {
295
+ headContent = drained + '\\n';
259
296
  }
260
-
261
- const element = createElement(Component, { params: match.params });
262
- appHtml = renderToString(element);
263
297
  } catch (e) {
264
298
  console.error('[SSR] Failed to render route:', pathname, e);
265
299
  if (errorRoute) {
@@ -288,9 +322,18 @@ export async function render(url) {
288
322
  if (notFoundRoute) {
289
323
  try {
290
324
  const mod = await notFoundRoute();
291
- const Component = mod.default || mod;
292
- const element = createElement(Component, {});
325
+ const Route = mod.default || mod;
326
+ clearHeadContent();
327
+ const Page = await wrapWithRootLayout(Route);
328
+ const element = createElement(Page, {});
293
329
  appHtml = renderToString(element);
330
+ const drained = drainHeadContent();
331
+ if (drained) {
332
+ headContent = drained + '\\n';
333
+ } else if (mod.metadata) {
334
+ headContent =
335
+ buildRouteHeadFromMetadata(mod.metadata, pathname, siteHeadOptions ?? undefined) + '\\n';
336
+ }
294
337
  } catch (e) {
295
338
  console.error('[SSR] Failed to render 404 page:', e);
296
339
  appHtml = '<div style="padding: 20px;">404 - Page not found</div>';
@@ -319,7 +362,7 @@ export async function render(url) {
319
362
  }
320
363
  `;
321
364
  }
322
- async function resolveSSREntry(root) {
365
+ async function resolveSSREntry(root, emberkitConfig) {
323
366
  const userEntryTs = join(root, "src", "entry-server.ts");
324
367
  const userEntryTsx = join(root, "src", "entry-server.tsx");
325
368
  if (existsSync(userEntryTs)) {
@@ -331,11 +374,12 @@ async function resolveSSREntry(root) {
331
374
  const cacheDir = join(root, "node_modules", ".cache", "emberkit");
332
375
  mkdirSync(cacheDir, { recursive: true });
333
376
  const shimPath = join(cacheDir, "server-entry.js");
334
- writeFileSync(shimPath, getServerEntryShim(), "utf-8");
377
+ const site = emberkitConfig?.site;
378
+ writeFileSync(shimPath, getServerEntryShim(site), "utf-8");
335
379
  return shimPath;
336
380
  }
337
- async function buildSSR(root, outDir, viteConfig, customLogger) {
338
- const ssrEntry = await resolveSSREntry(root);
381
+ async function buildSSR(root, outDir, viteConfig, customLogger, emberkitConfig) {
382
+ const ssrEntry = await resolveSSREntry(root, emberkitConfig);
339
383
  const ssrConfig = {
340
384
  ...viteConfig,
341
385
  root,
@@ -1,10 +1,10 @@
1
1
  // Semver ranges for @emberkit/* packages written into generated projects.
2
2
  // When releasing libraries, bump these to match packages/*/package.json "version".
3
3
  export const EMBERKIT_PACKAGE_VERSIONS = {
4
- core: "^0.4.0",
5
- ui: "^2.0.0",
6
- icons: "^2.0.0",
7
- cli: "^0.6.9",
4
+ core: "^0.6.1",
5
+ ui: "^4.0.0",
6
+ icons: "^4.0.1",
7
+ cli: "^0.7.1",
8
8
  edge: "^0.2.4",
9
9
  tsconfig: "^0.2.1",
10
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emberkit/cli",
3
- "version": "0.6.9",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "CLI tool for EmberKit projects",