create-content-sdk-app 2.4.1 → 2.4.2

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.
Files changed (23) hide show
  1. package/dist/templates/angular/.agents/docs/AGENTS-angular-specifics.md +21 -10
  2. package/dist/templates/angular/.agents/docs/AGENTS-key-concepts.md +1 -1
  3. package/dist/templates/angular/.agents/docs/AGENTS-overview.md +1 -1
  4. package/dist/templates/angular/.agents/skills/content-sdk-sitemap-robots/SKILL.md +5 -4
  5. package/dist/templates/angular/.agents/skills/content-sdk-ssr-express-middleware/SKILL.md +1 -1
  6. package/dist/templates/angular/Skills.md +1 -1
  7. package/dist/templates/angular/src/app/shared/layout.component.ts +10 -14
  8. package/dist/templates/angular/src/server.ts +10 -0
  9. package/dist/templates/nextjs/next.config.js +14 -2
  10. package/dist/templates/nextjs/package.json +1 -0
  11. package/dist/templates/nextjs/src/Layout.tsx +3 -6
  12. package/dist/templates/nextjs/src/SitecoreHead.tsx +28 -0
  13. package/dist/templates/nextjs/src/proxy.ts +5 -2
  14. package/dist/templates/nextjs-app-router/src/Layout.tsx +9 -5
  15. package/dist/templates/nextjs-app-router/src/SitecoreHead.tsx +26 -0
  16. package/dist/templates/nextjs-app-router/src/proxy.ts +2 -2
  17. package/dist/templates/nextjs-app-router-cache-components/src/Layout.tsx +9 -5
  18. package/dist/templates/nextjs-app-router-cache-components/src/SitecoreHead.tsx +26 -0
  19. package/dist/templates/nextjs-app-router-cache-components/src/lib/cache/get-sitecore-dictionary.ts +6 -1
  20. package/dist/templates/nextjs-app-router-cache-components/src/lib/cache/get-sitecore-error-page.ts +9 -2
  21. package/dist/templates/nextjs-app-router-cache-components/src/lib/cache/get-sitecore-page.ts +6 -1
  22. package/dist/templates/nextjs-app-router-cache-components/src/proxy.ts +2 -2
  23. package/package.json +9 -5
@@ -35,16 +35,17 @@ Optional, on-demand detail. The compact guide is [AGENTS.md](../../AGENTS.md).
35
35
  2. `createSitecoreRevalidateMiddleware({ cache, defaultLocale, sites })` — `POST /api/revalidate`
36
36
  3. `createSitemapMiddleware({ client, sites })` — `/sitemap.xml`, `/sitemap-:id.xml`
37
37
  4. `createRobotsMiddleware({ client, sites })` — `/robots.txt`
38
- 5. `createEditingConfigMiddleware({ components, metadataImport })` — `/api/editing/config`
39
- 6. `createExperimentalFeaturesMiddleware()` — `/api/editing/experimental`
40
- 7. `createEditingRenderMiddleware()` — `/api/editing/render`
41
- 8. `createMultisiteMiddleware(...)` — resolves the site onto `req.scParams`
42
- 9. `createBotTrackingMiddleware(...)` — sets the `sc_bot` cookie **before** personalize decides to skip
43
- 10. `createRedirectsMiddleware(...)` — short-circuits before any CDP call
44
- 11. `createPersonalizeMiddleware(...)` — reads the site resolved in step 8
45
- 12. `createLoaderDataServiceMiddleware(config, { loaders: LOADERS, cache })` — `POST /_data`
46
- 13. `express.static(browserDistFolder, ...)`
47
- 14. `angularApp.handle(req, { cache: loaderCache, req, res })` — SSR
38
+ 5. `createLlmsTxtMiddleware({ client, sites })` — `/llms.txt`
39
+ 6. `createEditingConfigMiddleware({ components, metadataImport })` — `/api/editing/config`
40
+ 7. `createExperimentalFeaturesMiddleware()` — `/api/editing/experimental`
41
+ 8. `createEditingRenderMiddleware()` — `/api/editing/render`
42
+ 9. `createMultisiteMiddleware(...)` — resolves the site onto `req.scParams`
43
+ 10. `createBotTrackingMiddleware(...)` — sets the `sc_bot` cookie **before** personalize decides to skip
44
+ 11. `createRedirectsMiddleware(...)` — short-circuits before any CDP call
45
+ 12. `createPersonalizeMiddleware(...)` — reads the site resolved in step 9
46
+ 13. `createLoaderDataServiceMiddleware(config, { loaders: LOADERS, cache })` — `POST /_data`
47
+ 14. `express.static(browserDistFolder, ...)`
48
+ 15. `angularApp.handle(req, { cache: loaderCache, req, res })` — SSR
48
49
 
49
50
  Why it matters: multisite must precede personalize (personalize reads the resolved site); bot tracking must precede personalize (the cookie gates the skip); redirects must precede personalize (avoid a wasted CDP call); editing endpoints must precede static and SSR; `/_data` must precede the SSR catch-all handler.
50
51
 
@@ -118,6 +119,15 @@ Angular has no framework ISR. This app caches **loader results** instead:
118
119
  - **`angular.json`** — `@angular/build:application` builder, `outputMode: "server"`, SSR entry `src/server.ts`, environment `fileReplacements` per configuration, and `allowedCommonJsDependencies`. Lint covers `src/**/*.ts`, `src/**/*.html` and `sitecore.config.ts`.
119
120
  - **`tsconfig.json`** — path aliases `client/*`, `components/*`, `lib/*`, `.sitecore/*`; includes `sitecore.config.ts`, `sitecore.cli.config.ts` and `.sitecore/**/*.ts`.
120
121
 
122
+ ## Page metadata and structured data
123
+
124
+ `src/app/shared/layout.component.ts` renders two SDK components that write to `<head>` and render no DOM of their own:
125
+
126
+ - `<sc-page-meta-tags [route]="scRoute()" />` — `<title>` (from the route `Title` field, falling back to `'Page'`) plus metadata and Open Graph `<meta>` tags from the route's `baseMetadata*` / `baseOg*` fields (`RouteFields extends PageMetadataFields`). A field with no value omits only its own tag; tags left from the previous route are removed on navigation.
127
+ - `<sc-json-ld-schema [page]="page()" />` — one `<script type="application/ld+json">` with the Layout Service's `sitecore.context.schemas`. Rendered only in normal mode (not in editing or preview).
128
+
129
+ Both work during SSR and on client-side navigation and clean up when destroyed. For metadata outside a component template, inject `PageMetadataService` / `JsonLdSchemaService` and call `apply(...)` directly. Do not set `<title>` or these `<meta>` tags manually elsewhere — the services own them.
130
+
121
131
  ## Differences from the Next.js templates
122
132
 
123
133
  Useful when porting guidance or code from a Next.js head app:
@@ -132,3 +142,4 @@ Useful when porting guidance or code from a Next.js head app:
132
142
  | Component map | `SITECORE_COMPONENT_MAP` injection token | Props / `SitecoreProvider` |
133
143
  | Field rendering | Structural directives (`*scText`) | Components (`<Text>`) |
134
144
  | Locale | URL segment + `scLocaleMatcher` | `context.locale` from Next.js i18n |
145
+ | Page metadata / JSON-LD | `<sc-page-meta-tags>` / `<sc-json-ld-schema>` (Angular `Meta` / `Title` services) | `generateMetadata` + `getPageMetadata` or `<PageMetaTags>`; `<JsonLdSchema>` |
@@ -6,7 +6,7 @@ Optional, on-demand detail. The compact guide is [AGENTS.md](../../AGENTS.md).
6
6
 
7
7
  - **Where:** `src/content-sdk/client/sitecore-client.ts` exports `getClient()` — a **lazy singleton** that constructs `new SitecoreClient(scConfig)` on first use. It is lazy on purpose: build-time route extraction runs without credentials, and eager construction would throw.
8
8
  - **Use for:** `getPage`, `getDictionary`, `getPreview`, `getErrorPage`, `getPagePaths`, `getSiteMap`, `getHeadLinks`.
9
- - **Consumed by:** loaders (`getClient()` directly), `provideSitecoreAngular({ sitecoreClient: getClient() })` in `app.config.ts`, and the Express middleware in `server.ts` (sitemap, robots).
9
+ - **Consumed by:** loaders (`getClient()` directly), `provideSitecoreAngular({ sitecoreClient: getClient() })` in `app.config.ts`, and the Express middleware in `server.ts` (sitemap, robots, llms.txt).
10
10
  - **In components:** inject `SITECORE_CLIENT_TOKEN` (as `LayoutComponent` does for `getHeadLinks`). Do **not** call `new SitecoreClient(...)` anywhere else.
11
11
 
12
12
  ## Loaders
@@ -1,6 +1,6 @@
1
1
  # Project overview (Angular)
2
2
 
3
- This is a **Sitecore Content SDK** application built with **Angular** (standalone components, signals, Angular SSR) and **TypeScript**. AI agents work as developer assistants within this scaffolded head application. The app integrates with Sitecore AI / XM Cloud for content, supports i18n, multisite, personalization and analytics, and serves SSR through an Express server that also hosts the Content SDK middleware (sitemap, robots, editing, redirects, revalidation, loader data).
3
+ This is a **Sitecore Content SDK** application built with **Angular** (standalone components, signals, Angular SSR) and **TypeScript**. AI agents work as developer assistants within this scaffolded head application. The app integrates with Sitecore AI / XM Cloud for content, supports i18n, multisite, personalization and analytics, and serves SSR through an Express server that also hosts the Content SDK middleware (sitemap, robots, llms.txt, editing, redirects, revalidation, loader data).
4
4
 
5
5
  **Scope:** This file applies to **this application only** (a scaffolded head app). It is **not** the Content SDK monorepo — for SDK package development use that repo's `AGENTS.md`. Here we edit app code and config (`src/app/`, `src/content-sdk/`, `src/server.ts`, `sitecore.config.ts`); we do not modify SDK packages or CI.
6
6
 
@@ -1,20 +1,21 @@
1
1
  ---
2
2
  name: content-sdk-sitemap-robots
3
- description: Sitemap and robots Express middleware in src/server.ts with sites from .sitecore/sites.json.
3
+ description: Sitemap, robots and llms.txt Express middleware in src/server.ts with sites from .sitecore/sites.json.
4
4
  ---
5
5
 
6
- # Sitemap and robots (Angular)
6
+ # Sitemap, robots and llms.txt (Angular)
7
7
 
8
8
  **Detail:** [AGENTS-angular-specifics.md#express-server-and-middleware-order](../../docs/AGENTS-angular-specifics.md#express-server-and-middleware-order)
9
9
  **Read first:** `src/server.ts`
10
10
 
11
11
  ## When
12
12
 
13
- - Sitemap, robots.txt, or other SEO / well-known file handlers
13
+ - Sitemap, robots.txt, llms.txt, or other SEO / well-known file handlers
14
14
 
15
15
  ## Rules
16
16
 
17
- - Use `createSitemapMiddleware({ client: getClient(), sites })` mounted at `/sitemap.xml` and `/sitemap-:id.xml`, and `createRobotsMiddleware({ client: getClient(), sites })` at `/robots.txt`
17
+ - Use `createSitemapMiddleware({ client: getClient(), sites })` mounted at `/sitemap.xml` and `/sitemap-:id.xml`, `createRobotsMiddleware({ client: getClient(), sites })` at `/robots.txt`, and `createLlmsTxtMiddleware({ client: getClient(), sites })` at `/llms.txt`
18
+ - llms.txt content is managed via SitecoreAI configuration; Content SDK only consumes/serves it. A site without llms.txt content gets a `404` with a minimal default llms.txt
18
19
  - `sites` comes from `.sitecore/sites.json` — never hardcode the site list
19
20
  - Register these before `express.static` and the SSR handler
20
21
  - These are plain Express routes; there is no rewrite layer to keep in sync (unlike the Next.js templates)
@@ -16,7 +16,7 @@ description: Express middleware chain in src/server.ts; fixed order and the serv
16
16
 
17
17
  ## Rules
18
18
 
19
- - Order is fixed: `express.json()` → revalidate → sitemap → robots → editing (config, experimental, render) → multisite → bot tracking → redirects → personalize → `/_data` loader middleware → static → `angularApp.handle`
19
+ - Order is fixed: `express.json()` → revalidate → sitemap → robots → llms.txt → editing (config, experimental, render) → multisite → bot tracking → redirects → personalize → `/_data` loader middleware → static → `angularApp.handle`
20
20
  - Multisite before personalize; bot tracking before personalize; redirects before personalize; editing before static and SSR; `/_data` before the SSR handler
21
21
  - New endpoints register before `express.static`; add app-specific exemptions to `middlewareMatcher.excludePaths`
22
22
  - Pass the **same** `loaderCache` instance to the revalidate middleware, the `/_data` middleware, and `angularApp.handle(req, { cache, req, res })`
@@ -20,7 +20,7 @@ Angular head app: catch-all route behind `scLocaleMatcher`, Sitecore data throug
20
20
  | [content-sdk-multisite-management](.agents/skills/content-sdk-multisite-management/SKILL.md) | Site resolution and `.sitecore/sites.json` |
21
21
  | [content-sdk-personalization-and-analytics](.agents/skills/content-sdk-personalization-and-analytics/SKILL.md) | Variants, CDP, analytics events, bot tracking |
22
22
  | [content-sdk-site-setup-and-env](.agents/skills/content-sdk-site-setup-and-env/SKILL.md) | `sitecore.config.ts` and the `CSDK_PUBLIC_*` env split |
23
- | [content-sdk-sitemap-robots](.agents/skills/content-sdk-sitemap-robots/SKILL.md) | Sitemap and robots middleware |
23
+ | [content-sdk-sitemap-robots](.agents/skills/content-sdk-sitemap-robots/SKILL.md) | Sitemap, robots and llms.txt middleware |
24
24
  | [content-sdk-upgrade-assistant](.agents/skills/content-sdk-upgrade-assistant/SKILL.md) | Upgrading SDK or Angular packages |
25
25
 
26
26
  Do **not** load every skill at session start. Open [AGENTS.md](AGENTS.md) first; add one skill when the task matches a row above.
@@ -1,23 +1,27 @@
1
1
  import { Component, PLATFORM_ID, Renderer2, input, computed, effect, inject } from '@angular/core';
2
- import { Title } from '@angular/platform-browser';
3
2
  import { DOCUMENT, isPlatformBrowser } from '@angular/common';
4
3
  import {
5
4
  Page,
6
5
  Field,
6
+ PageMetadataFields,
7
7
  RouteData,
8
+ ScJsonLdSchemaComponent,
9
+ ScPageMetaTagsComponent,
8
10
  ScPlaceholderComponent,
9
11
  SITECORE_CLIENT_TOKEN,
10
12
  } from '@sitecore-content-sdk/angular';
11
13
 
12
- interface RouteFields {
14
+ export interface RouteFields extends PageMetadataFields {
13
15
  [key: string]: unknown;
14
16
  Title?: Field<string>;
15
17
  }
16
18
 
17
19
  @Component({
18
20
  selector: 'app-layout',
19
- imports: [ScPlaceholderComponent],
21
+ imports: [ScPlaceholderComponent, ScPageMetaTagsComponent, ScJsonLdSchemaComponent],
20
22
  template: `
23
+ <sc-page-meta-tags [route]="scRoute()" />
24
+ <sc-json-ld-schema [page]="page()" />
21
25
  <div [attr.class]="layoutClassAttr()">
22
26
  <header class="w-full">
23
27
  <div id="header">
@@ -51,7 +55,9 @@ interface RouteFields {
51
55
  export class LayoutComponent {
52
56
  readonly page = input.required<Page>();
53
57
 
54
- readonly scRoute = computed(() => this.page().layout?.sitecore?.route as RouteData | null);
58
+ readonly scRoute = computed(
59
+ () => this.page().layout?.sitecore?.route as RouteData<RouteFields> | null
60
+ );
55
61
 
56
62
  readonly layoutClassAttr = computed(() => {
57
63
  const editing = this.page().mode?.isEditing;
@@ -59,22 +65,12 @@ export class LayoutComponent {
59
65
  return editing ? `${base} editing-mode` : `${base} prod-mode`;
60
66
  });
61
67
 
62
- private readonly titleService = inject(Title);
63
68
  private readonly sitecoreClient = inject(SITECORE_CLIENT_TOKEN, { optional: true });
64
69
  private readonly document = inject(DOCUMENT);
65
70
  private readonly renderer = inject(Renderer2);
66
71
  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
67
72
 
68
73
  constructor() {
69
- effect(() => {
70
- const route = this.scRoute();
71
- if (route) {
72
- const fields = route.fields as RouteFields | undefined;
73
- const title = fields?.Title?.value ?? 'Content SDK Page';
74
- this.titleService.setTitle(title);
75
- }
76
- });
77
-
78
74
  effect(() => {
79
75
  if (this.isBrowser || !this.sitecoreClient) return;
80
76
  const layout = this.page().layout;
@@ -16,6 +16,7 @@ import {
16
16
  createLoaderCache,
17
17
  createLoaderDataServiceMiddleware,
18
18
  createRobotsMiddleware,
19
+ createLlmsTxtMiddleware,
19
20
  createMultisiteMiddleware,
20
21
  createPersonalizeMiddleware,
21
22
  createRedirectsMiddleware,
@@ -81,6 +82,15 @@ app.use(
81
82
  })
82
83
  );
83
84
 
85
+ /** llms.txt at `/llms.txt` */
86
+ app.use(
87
+ '/llms.txt',
88
+ createLlmsTxtMiddleware({
89
+ client: getClient(),
90
+ sites,
91
+ })
92
+ );
93
+
84
94
  /**
85
95
  * Editing config endpoint (`/api/editing/config`). Replies with the registered
86
96
  * component map keys and `editMode: 'metadata'` so Sitecore Pages can negotiate
@@ -13,6 +13,18 @@ const nextConfig = {
13
13
  turbopackFileSystemCacheForDev: true,
14
14
  },
15
15
 
16
+ turbopack: {
17
+ rules: {
18
+ // Strip out getComponentServerProps from components in the client bundle
19
+ '*.tsx': {
20
+ condition: {
21
+ all: ['browser', { not: 'foreign' }, { path: /(^|\/)src\/components\// }],
22
+ },
23
+ loaders: ['@sitecore-content-sdk/nextjs/component-props-loader'],
24
+ },
25
+ },
26
+ },
27
+
16
28
  i18n: {
17
29
  // These are all the locales you want to support in your application.
18
30
  // These should generally match (or at least be a subset of) those in Sitecore.
@@ -80,8 +92,8 @@ const nextConfig = {
80
92
  if (!options.isServer) {
81
93
  // Add a loader to strip out getComponentServerProps from components in the client bundle
82
94
  config.module.rules.unshift({
83
- test: /src\\components\\.*\.tsx$/,
84
- use: ['@sitecore-content-sdk\\nextjs\\component-props-loader'],
95
+ test: /[\\/]src[\\/]components[\\/].*\.tsx$/,
96
+ use: ['@sitecore-content-sdk/nextjs/component-props-loader'],
85
97
  });
86
98
  } else {
87
99
  // Force use of CommonJS on the server for FEAAS SDK since Content SDK also uses CommonJS entrypoint to FEAAS SDK.
@@ -17,6 +17,7 @@
17
17
  "license": "Apache-2.0",
18
18
  "dependencies": {
19
19
  "@sitecore-content-sdk/analytics-core": "<%- versions['@sitecore-content-sdk/analytics-core'] %>",
20
+ "@sitecore-content-sdk/personalize": "<%- versions['@sitecore-content-sdk/personalize'] %>",
20
21
  "@sitecore-content-sdk/events": "<%- versions['@sitecore-content-sdk/events'] %>",
21
22
  "@sitecore-content-sdk/nextjs": "<%- versions['@sitecore-content-sdk/nextjs'] %>",
22
23
  "@sitecore-feaas/clientside": "^0.6.0",
@@ -3,9 +3,8 @@
3
3
  */
4
4
  import { JSX } from 'react';
5
5
  import Head from 'next/head';
6
- import { Placeholder, DesignLibrary, Page, PageMetaTags } from '@sitecore-content-sdk/nextjs';
7
- import Scripts from 'src/Scripts';
8
- import SitecoreStyles from 'src/components/content-sdk/SitecoreStyles';
6
+ import { Placeholder, DesignLibrary, Page } from '@sitecore-content-sdk/nextjs';
7
+ import SitecoreHead from 'src/SitecoreHead';
9
8
 
10
9
  interface LayoutProps {
11
10
  page: Page;
@@ -18,9 +17,7 @@ const Layout = ({ page }: LayoutProps): JSX.Element => {
18
17
 
19
18
  return (
20
19
  <>
21
- <Scripts />
22
- <SitecoreStyles layoutData={layout} />
23
- <PageMetaTags route={route} />
20
+ <SitecoreHead page={page} />
24
21
  <Head>
25
22
  <link rel="icon" href="/favicon.ico" />
26
23
  </Head>
@@ -0,0 +1,28 @@
1
+ import { JSX } from 'react';
2
+ import { Page, PageMetaTags, JsonLdSchema } from '@sitecore-content-sdk/nextjs';
3
+ import Scripts from 'src/Scripts';
4
+ import SitecoreStyles from 'src/components/content-sdk/SitecoreStyles';
5
+
6
+ interface SitecoreHeadProps {
7
+ page: Page;
8
+ }
9
+
10
+ /**
11
+ * Groups the scripts, styles, meta tags, and structured data injected alongside the page layout.
12
+ */
13
+ const SitecoreHead = ({ page }: SitecoreHeadProps): JSX.Element => {
14
+ const { layout } = page;
15
+ const { route } = layout.sitecore;
16
+
17
+ return (
18
+ <>
19
+ <Scripts />
20
+ <SitecoreStyles layoutData={layout} />
21
+ <PageMetaTags route={route} />
22
+ <JsonLdSchema page={page} />
23
+ </>
24
+ );
25
+ };
26
+
27
+ export default SitecoreHead;
28
+
@@ -89,7 +89,10 @@ export const config = {
89
89
  * 3. /sitecore/api (Sitecore API routes)
90
90
  * 4. /- (Sitecore media)
91
91
  * 5. /healthz (Health check)
92
- * 7. all root files inside /public
92
+ * 6. static files inside /public (images, fonts, css, js, etc.)
93
93
  */
94
- matcher: ['/', '/((?!api/|_next/|healthz|sitecore/api/|-/|favicon.ico|sc_logo.svg).*)'],
94
+ matcher: [
95
+ '/',
96
+ '/((?!api/|_next/|healthz|sitecore/api/|-/|.*[.](?:svg|png|jpe?g|gif|webp|avif|ico|woff2?|ttf|otf|eot|css|js|map|webmanifest)$).*)',
97
+ ],
95
98
  };
@@ -1,7 +1,12 @@
1
1
  import { JSX } from 'react';
2
- import { AppPlaceholder, DesignLibraryApp, Field, PageMetadataFields, Page } from '@sitecore-content-sdk/nextjs';
3
- import Scripts from 'src/Scripts';
4
- import SitecoreStyles from 'components/content-sdk/SitecoreStyles';
2
+ import {
3
+ AppPlaceholder,
4
+ DesignLibraryApp,
5
+ Field,
6
+ PageMetadataFields,
7
+ Page,
8
+ } from '@sitecore-content-sdk/nextjs';
9
+ import SitecoreHead from 'src/SitecoreHead';
5
10
  import componentMap from '.sitecore/component-map';
6
11
 
7
12
  interface LayoutProps {
@@ -19,8 +24,7 @@ const Layout = ({ page }: LayoutProps): JSX.Element => {
19
24
  const mainClassPageEditing = mode.isEditing ? 'editing-mode' : 'prod-mode';
20
25
  return (
21
26
  <>
22
- <Scripts />
23
- <SitecoreStyles layoutData={layout} />
27
+ <SitecoreHead page={page} />
24
28
  {/* root placeholder for the app, which we add components to using route data */}
25
29
  <div className={mainClassPageEditing}>
26
30
  {mode.isDesignLibrary ? (
@@ -0,0 +1,26 @@
1
+ import { JSX } from 'react';
2
+ import { Page, JsonLdSchema } from '@sitecore-content-sdk/nextjs';
3
+ import Scripts from 'src/Scripts';
4
+ import SitecoreStyles from 'components/content-sdk/SitecoreStyles';
5
+
6
+ interface SitecoreHeadProps {
7
+ page: Page;
8
+ }
9
+
10
+ /**
11
+ * Groups the scripts, styles, and structured data injected alongside the page layout.
12
+ */
13
+ const SitecoreHead = ({ page }: SitecoreHeadProps): JSX.Element => {
14
+ const { layout } = page;
15
+
16
+ return (
17
+ <>
18
+ <Scripts />
19
+ <SitecoreStyles layoutData={layout} />
20
+ <JsonLdSchema page={page} />
21
+ </>
22
+ );
23
+ };
24
+
25
+ export default SitecoreHead;
26
+
@@ -113,10 +113,10 @@ export const config = {
113
113
  * 3. /sitecore/api (Sitecore API routes)
114
114
  * 4. /- (Sitecore media)
115
115
  * 5. /healthz (Health check)
116
- * 7. all root files inside /public
116
+ * 6. static files inside /public (images, fonts, css, js, etc.)
117
117
  */
118
118
  matcher: [
119
119
  '/',
120
- '/((?!api/|sitemap|robots|_next/|healthz|sitecore/api/|-/|favicon.ico|sc_logo.svg).*)',
120
+ '/((?!api/|sitemap|robots|_next/|healthz|sitecore/api/|-/|.*[.](?:svg|png|jpe?g|gif|webp|avif|ico|woff2?|ttf|otf|eot|css|js|map|webmanifest)$).*)',
121
121
  ],
122
122
  };
@@ -1,7 +1,12 @@
1
1
  import { JSX } from 'react';
2
- import { AppPlaceholder, DesignLibraryApp, Field, PageMetadataFields, Page } from '@sitecore-content-sdk/nextjs';
3
- import Scripts from 'src/Scripts';
4
- import SitecoreStyles from 'components/content-sdk/SitecoreStyles';
2
+ import {
3
+ AppPlaceholder,
4
+ DesignLibraryApp,
5
+ Field,
6
+ PageMetadataFields,
7
+ Page,
8
+ } from '@sitecore-content-sdk/nextjs';
9
+ import SitecoreHead from 'src/SitecoreHead';
5
10
  import componentMap from '.sitecore/component-map';
6
11
 
7
12
  interface LayoutProps {
@@ -19,8 +24,7 @@ const Layout = ({ page }: LayoutProps): JSX.Element => {
19
24
  const mainClassPageEditing = mode.isEditing ? 'editing-mode' : 'prod-mode';
20
25
  return (
21
26
  <>
22
- <Scripts />
23
- <SitecoreStyles layoutData={layout} />
27
+ <SitecoreHead page={page} />
24
28
  {/* root placeholder for the app, which we add components to using route data */}
25
29
  <div className={mainClassPageEditing}>
26
30
  {mode.isDesignLibrary ? (
@@ -0,0 +1,26 @@
1
+ import { JSX } from 'react';
2
+ import { Page, JsonLdSchema } from '@sitecore-content-sdk/nextjs';
3
+ import Scripts from 'src/Scripts';
4
+ import SitecoreStyles from 'components/content-sdk/SitecoreStyles';
5
+
6
+ interface SitecoreHeadProps {
7
+ page: Page;
8
+ }
9
+
10
+ /**
11
+ * Groups the scripts, styles, and structured data injected alongside the page layout.
12
+ */
13
+ const SitecoreHead = ({ page }: SitecoreHeadProps): JSX.Element => {
14
+ const { layout } = page;
15
+
16
+ return (
17
+ <>
18
+ <Scripts />
19
+ <SitecoreStyles layoutData={layout} />
20
+ <JsonLdSchema page={page} />
21
+ </>
22
+ );
23
+ };
24
+
25
+ export default SitecoreHead;
26
+
@@ -1,5 +1,5 @@
1
1
  import { buildSitecoreDictionaryCacheTag, DictionaryPhrases } from '@sitecore-content-sdk/nextjs';
2
- import { cacheTag } from 'next/cache';
2
+ import { cacheLife, cacheTag } from 'next/cache';
3
3
  import client from 'src/lib/sitecore-client';
4
4
 
5
5
  type GetSitecoreDictionaryParams = {
@@ -13,6 +13,11 @@ type GetSitecoreDictionaryParams = {
13
13
  export async function getSitecoreDictionary(params: GetSitecoreDictionaryParams): Promise<DictionaryPhrases> {
14
14
  'use cache';
15
15
 
16
+ // Update the cacheLife profile to control the lifespan of Cache Components.
17
+ // NextJS defaults to the 'default' profile if not called, we explicity call it to make the policy clear.
18
+ // https://nextjs.org/docs/app/api-reference/functions/cacheLife
19
+ cacheLife('default');
20
+
16
21
  const { site, locale } = params;
17
22
  cacheTag(buildSitecoreDictionaryCacheTag({ site, locale }));
18
23
 
@@ -1,5 +1,5 @@
1
1
  import { collectSitecorePageCacheTags, ErrorPage, type Page } from '@sitecore-content-sdk/nextjs';
2
- import { cacheTag } from 'next/cache';
2
+ import { cacheLife, cacheTag } from 'next/cache';
3
3
  import client from 'src/lib/sitecore-client';
4
4
 
5
5
  type GetSitecoreErrorPageParams = {
@@ -12,7 +12,9 @@ type GetSitecoreErrorPageParams = {
12
12
  * Loads Sitecore error pages with Next.js Cache Components and the same tag strategy as
13
13
  * {@link getSitecorePage}, so webhook / `revalidateTag` flows can invalidate updated error experiences.
14
14
  */
15
- export async function getSitecoreErrorPage(params: GetSitecoreErrorPageParams): Promise<Page | null> {
15
+ export async function getSitecoreErrorPage(
16
+ params: GetSitecoreErrorPageParams
17
+ ): Promise<Page | null> {
16
18
  'use cache';
17
19
 
18
20
  const { site, locale, code } = params;
@@ -21,6 +23,11 @@ export async function getSitecoreErrorPage(params: GetSitecoreErrorPageParams):
21
23
  const sitecore = page?.layout?.sitecore;
22
24
  const itemPath = sitecore?.context?.itemPath;
23
25
 
26
+ // Update the cacheLife profile to control the lifespan of Cache Components.
27
+ // NextJS defaults to the 'default' profile if not called, we explicity call it to make the policy clear.
28
+ // https://nextjs.org/docs/app/api-reference/functions/cacheLife
29
+ cacheLife('default');
30
+
24
31
  const tags = collectSitecorePageCacheTags({
25
32
  site,
26
33
  locale,
@@ -1,5 +1,5 @@
1
1
  import { collectSitecorePageCacheTags, Page } from '@sitecore-content-sdk/nextjs';
2
- import { cacheTag } from 'next/cache';
2
+ import { cacheLife, cacheTag } from 'next/cache';
3
3
  import client from 'src/lib/sitecore-client';
4
4
 
5
5
  type GetSitecorePageParams = {
@@ -17,6 +17,11 @@ export async function getSitecorePage(params: GetSitecorePageParams): Promise<Pa
17
17
  const { site, locale, path } = params;
18
18
  const page = await client.getPage(path, { site, locale });
19
19
 
20
+ // Update the cacheLife profile to control the lifespan of Cache Components.
21
+ // NextJS defaults to the 'default' profile if not called, we explicity call it to make the policy clear.
22
+ // https://nextjs.org/docs/app/api-reference/functions/cacheLife
23
+ cacheLife('default');
24
+
20
25
  const tags = collectSitecorePageCacheTags({
21
26
  site,
22
27
  locale,
@@ -113,10 +113,10 @@ export const config = {
113
113
  * 3. /sitecore/api (Sitecore API routes)
114
114
  * 4. /- (Sitecore media)
115
115
  * 5. /healthz (Health check)
116
- * 7. all root files inside /public
116
+ * 6. static files inside /public (images, fonts, css, js, etc.)
117
117
  */
118
118
  matcher: [
119
119
  '/',
120
- '/((?!api/|sitemap|robots|_next/|healthz|sitecore/api/|-/|favicon.ico|sc_logo.svg).*)',
120
+ '/((?!api/|sitemap|robots|_next/|healthz|sitecore/api/|-/|.*[.](?:svg|png|jpe?g|gif|webp|avif|ico|woff2?|ttf|otf|eot|css|js|map|webmanifest)$).*)',
121
121
  ],
122
122
  };
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "create-content-sdk-app",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Sitecore Content SDK initializer",
5
+ "publishConfig": {
6
+ "access": "public",
7
+ "registry": "https://registry.npmjs.org/"
8
+ },
5
9
  "bin": "./dist/index.js",
6
10
  "scripts": {
7
11
  "build": "npm run clean && tsc && ts-node ./scripts/build-templates.ts",
@@ -16,7 +20,7 @@
16
20
  },
17
21
  "repository": {
18
22
  "type": "git",
19
- "url": "https://github.com/Sitecore/content-sdk.git",
23
+ "url": "git+https://github.com/Sitecore/content-sdk.git",
20
24
  "directory": "packages/create-content-sdk-app"
21
25
  },
22
26
  "homepage": "https://doc.sitecore.com/xmc/en/developers/content-sdk/index.html",
@@ -39,10 +43,10 @@
39
43
  },
40
44
  "devDependencies": {
41
45
  "@sitecore-content-sdk/analytics-core": "^2.1.2",
42
- "@sitecore-content-sdk/angular": "~1.0.1",
43
- "@sitecore-content-sdk/cli": "^2.3.0",
46
+ "@sitecore-content-sdk/angular": "~1.1.0",
47
+ "@sitecore-content-sdk/cli": "^2.4.0",
44
48
  "@sitecore-content-sdk/events": "^2.1.2",
45
- "@sitecore-content-sdk/nextjs": "^2.4.1",
49
+ "@sitecore-content-sdk/nextjs": "^2.5.0",
46
50
  "@sitecore-content-sdk/personalize": "^2.1.0",
47
51
  "@stylistic/eslint-plugin": "^5.2.2",
48
52
  "@types/chai": "^5.2.2",