create-sitecore-jss 22.1.0-canary.9 → 22.2.0-canary.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.
Files changed (27) hide show
  1. package/dist/templates/angular/package.json +40 -40
  2. package/dist/templates/angular/server.bundle.ts +1 -1
  3. package/dist/templates/angular/src/polyfills.ts +2 -6
  4. package/dist/templates/angular/src/test.ts +1 -6
  5. package/dist/templates/nextjs/next.config.js +5 -0
  6. package/dist/templates/nextjs/package.json +7 -6
  7. package/dist/templates/nextjs/src/lib/next-config/plugins/cors-header.js +0 -9
  8. package/dist/templates/nextjs/src/pages/[[...path]].tsx +1 -13
  9. package/dist/templates/nextjs-styleguide/package.json +1 -1
  10. package/dist/templates/nextjs-sxa/src/assets/sass/components/title/_component-title.scss +19 -13
  11. package/dist/templates/nextjs-sxa/src/components/Image.tsx +22 -12
  12. package/dist/templates/nextjs-sxa/src/components/Promo.tsx +1 -1
  13. package/dist/templates/nextjs-sxa/src/components/Title.tsx +10 -13
  14. package/dist/templates/nextjs-xmcloud/package.json +1 -1
  15. package/dist/templates/nextjs-xmcloud/src/Scripts.tsx +2 -0
  16. package/dist/templates/nextjs-xmcloud/src/lib/dictionary-service-factory.ts +46 -0
  17. package/dist/templates/nextjs-xmcloud/src/lib/graphql-editing-service.ts +9 -0
  18. package/dist/templates/nextjs-xmcloud/src/lib/middleware/plugins/personalize.ts +6 -5
  19. package/dist/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/personalize.ts +7 -3
  20. package/dist/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/preview-mode.ts +72 -0
  21. package/dist/templates/nextjs-xmcloud/src/pages/api/editing/render.ts +46 -0
  22. package/dist/templates/node-headless-ssr-experience-edge/package.json +2 -2
  23. package/dist/templates/node-headless-ssr-proxy/package.json +4 -4
  24. package/dist/templates/react/package.json +5 -5
  25. package/dist/templates/react-native/package.json +4 -4
  26. package/dist/templates/vue/package.json +4 -4
  27. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%- appName %>",
3
- "version": "22.1.0-canary",
3
+ "version": "22.2.0-canary",
4
4
  "description": "Application utilizing Sitecore JavaScript Services and Angular (angular-cli).",
5
5
  "config": {
6
6
  "appName": "<%- appName %>",
@@ -48,50 +48,50 @@
48
48
  "homepage": "https://jss.sitecore.com",
49
49
  "license": "Apache-2.0",
50
50
  "dependencies": {
51
- "@angular/animations": "~16.2.10",
52
- "@angular/common": "~16.2.10",
53
- "@angular/compiler": "~16.2.10",
54
- "@angular/core": "~16.2.10",
55
- "@angular/forms": "~16.2.10",
56
- "@angular/platform-browser": "~16.2.10",
57
- "@angular/platform-browser-dynamic": "~16.2.10",
58
- "@angular/platform-server": "~16.2.10",
59
- "@angular/router": "~16.2.10",
51
+ "@angular/animations": "~17.3.11",
52
+ "@angular/common": "~17.3.11",
53
+ "@angular/compiler": "~17.3.11",
54
+ "@angular/core": "~17.3.11",
55
+ "@angular/forms": "~17.3.11",
56
+ "@angular/platform-browser": "~17.3.11",
57
+ "@angular/platform-browser-dynamic": "~17.3.11",
58
+ "@angular/platform-server": "~17.3.11",
59
+ "@angular/router": "~17.3.11",
60
60
  "@apollo/client": "^3.3.12",
61
- "@ngx-translate/core": "~14.0.0",
62
- "@ngx-translate/http-loader": "~7.0.0",
63
- "@sitecore-jss/sitecore-jss-angular": "~22.1.0-canary",
64
- "apollo-angular": "~5.0.2",
65
- "bootstrap": "^5.3.1",
66
- "core-js": "~3.32.1",
61
+ "@ngx-translate/core": "~15.0.0",
62
+ "@ngx-translate/http-loader": "~8.0.0",
63
+ "@sitecore-jss/sitecore-jss-angular": "~22.2.0-canary",
64
+ "apollo-angular": "~6.0.0",
65
+ "bootstrap": "^5.3.3",
66
+ "core-js": "~3.37.1",
67
67
  "graphql": "15.5.0",
68
68
  "graphql-tag": "~2.11.0",
69
69
  "lodash": "^4.17.21",
70
70
  "rxjs": "~7.8.1",
71
- "tslib": "^2.1.0",
72
- "zone.js": "~0.13.1"
71
+ "tslib": "^2.6.3",
72
+ "zone.js": "~0.14.7"
73
73
  },
74
74
  "devDependencies": {
75
- "@angular-builders/custom-webpack": "^16.0.1",
76
- "@angular-devkit/build-angular": "^16.2.10",
77
- "@angular-eslint/builder": "^16.3.1",
78
- "@angular-eslint/eslint-plugin": "^16.3.1",
79
- "@angular-eslint/eslint-plugin-template": "^16.3.1",
80
- "@angular-eslint/schematics": "^16.3.1",
81
- "@angular-eslint/template-parser": "^16.3.1",
82
- "@angular/cli": "~16.2.10",
83
- "@angular/compiler-cli": "~16.2.10",
84
- "@angular/language-service": "~16.2.10",
85
- "@sitecore-jss/sitecore-jss-angular-schematics": "~22.1.0-canary",
86
- "@sitecore-jss/sitecore-jss-cli": "~22.1.0-canary",
87
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
75
+ "@angular-builders/custom-webpack": "^17.0.2",
76
+ "@angular-devkit/build-angular": "^17.3.8",
77
+ "@angular-eslint/builder": "^17.5.2",
78
+ "@angular-eslint/eslint-plugin": "^17.5.2",
79
+ "@angular-eslint/eslint-plugin-template": "^17.5.2",
80
+ "@angular-eslint/schematics": "^17.5.2",
81
+ "@angular-eslint/template-parser": "^17.5.2",
82
+ "@angular/cli": "~17.3.8",
83
+ "@angular/compiler-cli": "~17.3.11",
84
+ "@angular/language-service": "~17.3.11",
85
+ "@sitecore-jss/sitecore-jss-angular-schematics": "~22.2.0-canary",
86
+ "@sitecore-jss/sitecore-jss-cli": "~22.2.0-canary",
87
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
88
88
  "@types/isomorphic-fetch": "0.0.35",
89
89
  "@types/jasmine": "~3.6.7",
90
90
  "@types/jasminewd2": "~2.0.8",
91
- "@types/node": "~12.7.9",
92
- "@typescript-eslint/eslint-plugin": "^6.14.0",
93
- "@typescript-eslint/parser": "^6.14.0",
94
- "body-parser": "~1.19.0",
91
+ "@types/node": "~20.14.10",
92
+ "@typescript-eslint/eslint-plugin": "^7.16.0",
93
+ "@typescript-eslint/parser": "^7.16.0",
94
+ "body-parser": "~1.20.2",
95
95
  "chalk": "~4.1.0",
96
96
  "chokidar": "^3.5.2",
97
97
  "codelyzer": "~6.0.1",
@@ -102,9 +102,9 @@
102
102
  "dotenv": "^16.0.0",
103
103
  "dotenv-webpack": "^7.1.0",
104
104
  "enhanced-resolve": "5.7.0",
105
- "eslint": "^7.22.0",
106
- "eslint-plugin-import": "2.22.1",
107
- "eslint-plugin-jsdoc": "32.3.0",
105
+ "eslint": "^8.56.0",
106
+ "eslint-plugin-import": "2.29.1",
107
+ "eslint-plugin-jsdoc": "48.7.0",
108
108
  "eslint-plugin-prefer-arrow": "1.2.3",
109
109
  "express": "~4.17.1",
110
110
  "fs-extra": "~9.1.0",
@@ -120,8 +120,8 @@
120
120
  "move-cli": "^2.0.0",
121
121
  "npm-run-all": "~4.1.5",
122
122
  "protractor": "^7.0.0",
123
- "ts-node": "~10.9.0",
124
- "typescript": "~4.9.5",
123
+ "ts-node": "~10.9.2",
124
+ "typescript": "~5.2.2",
125
125
  "yaml-lint": "^1.2.4"
126
126
  }
127
127
  }
@@ -2,7 +2,7 @@
2
2
  import { readFileSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import 'reflect-metadata';
5
- import 'zone.js/dist/zone-node';
5
+ import 'zone.js';
6
6
  import { JssRouteBuilderService } from './src/app/routing/jss-route-builder.service';
7
7
  import { environment } from './src/environments/environment';
8
8
  import { AppServerModule, renderModule } from './src/main.server';
@@ -47,16 +47,12 @@ import 'core-js/es/reflect';
47
47
  // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
48
48
 
49
49
  /** Polyfill for node.js process **/
50
- (window as any).process = { env: { DEBUG: undefined }, };
51
-
52
-
50
+ (window as any).process = { env: { DEBUG: undefined } };
53
51
 
54
52
  /***************************************************************************************************
55
53
  * Zone JS is required by Angular itself.
56
54
  */
57
- import 'zone.js/dist/zone'; // Included with Angular CLI.
58
-
59
-
55
+ import 'zone.js'; // Included with Angular CLI.
60
56
 
61
57
  /***************************************************************************************************
62
58
  * APPLICATION IMPORTS
@@ -1,11 +1,6 @@
1
1
  // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2
2
 
3
- import 'zone.js/dist/long-stack-trace-zone';
4
- import 'zone.js/dist/proxy.js';
5
- import 'zone.js/dist/sync-test';
6
- import 'zone.js/dist/jasmine-patch';
7
- import 'zone.js/dist/async-test';
8
- import 'zone.js/dist/fake-async-test';
3
+ import 'zone.js/testing';
9
4
  import { getTestBed } from '@angular/core/testing';
10
5
  import {
11
6
  BrowserDynamicTestingModule,
@@ -40,6 +40,11 @@ const nextConfig = {
40
40
  hostname: 'edge*.**',
41
41
  port: '',
42
42
  },
43
+ {
44
+ protocol: 'https',
45
+ hostname: 'xmc-*.**',
46
+ port: '',
47
+ },
43
48
  {
44
49
  protocol: 'https',
45
50
  hostname: 'feaas*.blob.core.windows.net',
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "<%- appName %>",
3
3
  "description": "Application utilizing Sitecore JavaScript Services and Next.js",
4
- "version": "22.1.0-canary",
4
+ "version": "22.2.0-canary",
5
5
  "private": true,
6
6
  "config": {
7
7
  "appName": "<%- appName %>",
@@ -25,13 +25,14 @@
25
25
  },
26
26
  "license": "Apache-2.0",
27
27
  "dependencies": {
28
- "@sitecore-jss/sitecore-jss-nextjs": "~22.1.0-canary",
28
+ "@sitecore-jss/sitecore-jss-nextjs": "~22.2.0-canary",
29
29
  "graphql": "~15.8.0",
30
30
  "graphql-tag": "^2.12.6",
31
31
  "next": "^14.1.0",
32
32
  "next-localization": "^0.12.0",
33
33
  "react": "^18.2.0",
34
- "react-dom": "^18.2.0"
34
+ "react-dom": "^18.2.0",
35
+ "sharp": "0.32.6"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@graphql-codegen/cli": "^5.0.0",
@@ -42,9 +43,9 @@
42
43
  "@graphql-codegen/typescript-operations": "^4.0.1",
43
44
  "@graphql-codegen/typescript-resolvers": "^4.0.1",
44
45
  "@graphql-typed-document-node/core": "^3.2.0",
45
- "@sitecore-jss/sitecore-jss-cli": "~22.1.0-canary",
46
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
47
- "@types/node": "^18.11.18",
46
+ "@sitecore-jss/sitecore-jss-cli": "~22.2.0-canary",
47
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
48
+ "@types/node": "^20.14.2",
48
49
  "@types/react": "^18.2.22",
49
50
  "@types/react-dom": "^18.0.5",
50
51
  "@typescript-eslint/eslint-plugin": "^5.49.0",
@@ -22,15 +22,6 @@ const corsHeaderPlugin = (nextConfig = {}) => {
22
22
  },
23
23
  ],
24
24
  },
25
- {
26
- source: '/api/:path*',
27
- headers: [
28
- {
29
- key: 'Access-Control-Allow-Origin',
30
- value: config.sitecoreApiHost.replace(/\/$/, ''),
31
- },
32
- ],
33
- },
34
25
  ];
35
26
  },
36
27
  });
@@ -7,10 +7,8 @@ import { GetServerSideProps } from 'next';
7
7
  import NotFound from 'src/NotFound';
8
8
  import Layout from 'src/Layout';
9
9
  import {
10
- RenderingType,
11
10
  SitecoreContext,
12
11
  ComponentPropsContext,
13
- EditingComponentPlaceholder,
14
12
  <% if (prerender === 'SSG') { -%>
15
13
  StaticPath,
16
14
  <% } -%>
@@ -36,8 +34,6 @@ const SitecorePage = ({ notFound, componentProps, layoutData, headLinks }: Sitec
36
34
  }
37
35
 
38
36
  const isEditing = layoutData.sitecore.context.pageEditing;
39
- const isComponentRendering =
40
- layoutData.sitecore.context.renderingType === RenderingType.Component;
41
37
 
42
38
  return (
43
39
  <ComponentPropsContext value={componentProps}>
@@ -45,15 +41,7 @@ const SitecorePage = ({ notFound, componentProps, layoutData, headLinks }: Sitec
45
41
  componentFactory={componentBuilder.getComponentFactory({ isEditing })}
46
42
  layoutData={layoutData}
47
43
  >
48
- {/*
49
- Sitecore Pages supports component rendering to avoid refreshing the entire page during component editing.
50
- If you are using Experience Editor only, this logic can be removed, Layout can be left.
51
- */}
52
- {isComponentRendering ? (
53
- <EditingComponentPlaceholder rendering={layoutData.sitecore.route} />
54
- ) : (
55
- <Layout layoutData={layoutData} headLinks={headLinks} />
56
- )}
44
+ <Layout layoutData={layoutData} headLinks={headLinks} />
57
45
  </SitecoreContext>
58
46
  </ComponentPropsContext>
59
47
  );
@@ -4,7 +4,7 @@
4
4
  "nprogress": "~0.2.0"
5
5
  },
6
6
  "devDependencies": {
7
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
7
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
8
8
  "@types/nprogress": "^0.2.0"
9
9
  },
10
10
  "scripts": {
@@ -3,22 +3,28 @@
3
3
 
4
4
  .title {
5
5
  background: $title-bg;
6
+
6
7
  h1,
7
8
  .field-title {
8
- >a, >span {
9
- @include border-basic(bottom, $border-basic-color);
10
- font-size: $font-extrabig;
11
- margin-bottom: $small-margin;
12
- color: $title-color;
13
- line-height: normal;
14
- padding-bottom: 10px;
15
- display: block;
9
+ @include border-basic(bottom, $border-basic-color);
10
+ font-size: $font-extrabig;
11
+ margin-bottom: $small-margin;
12
+ color: $title-color;
13
+ line-height: normal;
14
+ padding-bottom: 10px;
15
+ display: block;
16
+ text-decoration: none;
17
+ cursor: pointer;
18
+
19
+ &:hover {
20
+ color: $title-color-active;
21
+ }
22
+
23
+ > a,
24
+ > span {
16
25
  text-decoration: none;
17
- cursor: pointer;
18
- &:hover {
19
- color: $title-color-active;
20
- }
26
+ }
21
27
  }
22
- }
28
+
23
29
  @import '@sass/variants/title';
24
30
  }
@@ -1,16 +1,17 @@
1
- import React, { CSSProperties } from 'react';
2
1
  import {
3
- Image as JssImage,
4
- Link as JssLink,
5
- ImageField,
2
+ EditMode,
6
3
  Field,
4
+ ImageField,
5
+ NextImage as JssImage,
6
+ Link as JssLink,
7
7
  LinkField,
8
8
  Text,
9
9
  useSitecoreContext,
10
10
  } from '@sitecore-jss/sitecore-jss-nextjs';
11
+ import React, { CSSProperties } from 'react';
11
12
 
12
13
  interface Fields {
13
- Image: ImageField;
14
+ Image: ImageField & { metadata?: { [key: string]: unknown } };
14
15
  ImageCaption: Field<string>;
15
16
  TargetUrl: LinkField;
16
17
  }
@@ -29,8 +30,10 @@ const ImageDefault = (props: ImageProps): JSX.Element => (
29
30
  );
30
31
 
31
32
  export const Banner = (props: ImageProps): JSX.Element => {
33
+ const id = props.params.RenderingIdentifier;
32
34
  const { sitecoreContext } = useSitecoreContext();
33
35
  const isPageEditing = sitecoreContext.pageEditing;
36
+ const isMetadataMode = sitecoreContext?.editMode === EditMode.Metadata;
34
37
  const classHeroBannerEmpty =
35
38
  isPageEditing && props.fields?.Image?.value?.class === 'scEmptyImage'
36
39
  ? 'hero-banner-empty'
@@ -38,13 +41,20 @@ export const Banner = (props: ImageProps): JSX.Element => {
38
41
  const backgroundStyle = (props?.fields?.Image?.value?.src && {
39
42
  backgroundImage: `url('${props.fields.Image.value.src}')`,
40
43
  }) as CSSProperties;
41
- const modifyImageProps = {
42
- ...props.fields.Image,
43
- editable: props?.fields?.Image?.editable
44
- ?.replace(`width="${props?.fields?.Image?.value?.width}"`, 'width="100%"')
45
- .replace(`height="${props?.fields?.Image?.value?.height}"`, 'height="100%"'),
46
- };
47
- const id = props.params.RenderingIdentifier;
44
+ const modifyImageProps = !isMetadataMode
45
+ ? {
46
+ ...props.fields.Image,
47
+ editable: props?.fields?.Image?.editable
48
+ ?.replace(`width="${props?.fields?.Image?.value?.width}"`, 'width="100%"')
49
+ .replace(`height="${props?.fields?.Image?.value?.height}"`, 'height="100%"'),
50
+ }
51
+ : {
52
+ ...props.fields.Image,
53
+ value: {
54
+ ...props.fields.Image.value,
55
+ style: { width: '100%', height: '100%' },
56
+ },
57
+ };
48
58
 
49
59
  return (
50
60
  <div
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import {
3
- Image as JssImage,
3
+ NextImage as JssImage,
4
4
  Link as JssLink,
5
5
  RichText as JssRichText,
6
6
  ImageField,
@@ -1,11 +1,11 @@
1
- import React from 'react';
2
1
  import {
3
2
  Link,
4
- Text,
5
- useSitecoreContext,
6
3
  LinkField,
4
+ Text,
7
5
  TextField,
6
+ useSitecoreContext,
8
7
  } from '@sitecore-jss/sitecore-jss-nextjs';
8
+ import React from 'react';
9
9
 
10
10
  interface Fields {
11
11
  data: {
@@ -17,7 +17,8 @@ interface Fields {
17
17
  field: {
18
18
  jsonValue: {
19
19
  value: string;
20
- editable: string;
20
+ editable?: string;
21
+ metadata?: { [key: string]: unknown };
21
22
  };
22
23
  };
23
24
  };
@@ -29,7 +30,8 @@ interface Fields {
29
30
  field: {
30
31
  jsonValue: {
31
32
  value: string;
32
- editable: string;
33
+ editable?: string;
34
+ metadata?: { [key: string]: unknown };
33
35
  };
34
36
  };
35
37
  };
@@ -61,21 +63,16 @@ const ComponentContent = (props: ComponentContentProps) => {
61
63
  export const Default = (props: TitleProps): JSX.Element => {
62
64
  const datasource = props.fields?.data?.datasource || props.fields?.data?.contextItem;
63
65
  const { sitecoreContext } = useSitecoreContext();
64
-
65
- const text: TextField = {
66
- value: datasource?.field?.jsonValue?.value,
67
- editable: datasource?.field?.jsonValue?.editable,
68
- };
66
+ const text: TextField = datasource?.field?.jsonValue || {};
69
67
  const link: LinkField = {
70
68
  value: {
71
69
  href: datasource?.url?.path,
72
70
  title: datasource?.field?.jsonValue?.value,
73
- editable: true,
74
71
  },
75
72
  };
76
73
  if (sitecoreContext.pageState !== 'normal') {
77
74
  link.value.querystring = `sc_site=${datasource?.url?.siteName}`;
78
- if (!text.value) {
75
+ if (!text?.value) {
79
76
  text.value = 'Title field';
80
77
  link.value.href = '#';
81
78
  }
@@ -84,7 +81,7 @@ export const Default = (props: TitleProps): JSX.Element => {
84
81
  return (
85
82
  <ComponentContent styles={props.params.styles} id={props.params.RenderingIdentifier}>
86
83
  <>
87
- {sitecoreContext.pageState === 'edit' ? (
84
+ {sitecoreContext.pageEditing ? (
88
85
  <Text field={text} />
89
86
  ) : (
90
87
  <Link field={link}>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "dependencies": {
3
3
  "@sitecore/components": "^1.1.10",
4
- "@sitecore-cloudsdk/events": "^0.3.0",
4
+ "@sitecore-cloudsdk/events": "^0.3.1",
5
5
  "@sitecore-feaas/clientside": "^0.5.17"
6
6
  }
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { EditingScripts } from '@sitecore-jss/sitecore-jss-nextjs';
1
2
  // The BYOC bundle imports external (BYOC) components into the app and makes sure they are ready to be used
2
3
  import BYOC from 'src/byoc';
3
4
  import CdpPageView from 'components/CdpPageView';
@@ -9,6 +10,7 @@ const Scripts = (): JSX.Element => {
9
10
  <BYOC />
10
11
  <CdpPageView />
11
12
  <FEAASScripts />
13
+ <EditingScripts />
12
14
  </>
13
15
  );
14
16
  };
@@ -0,0 +1,46 @@
1
+ import {
2
+ DictionaryService,
3
+ RestDictionaryService,
4
+ GraphQLDictionaryService,
5
+ constants,
6
+ } from '@sitecore-jss/sitecore-jss-nextjs';
7
+ import config from 'temp/config';
8
+ import clientFactory from 'lib/graphql-client-factory';
9
+
10
+ /**
11
+ * Factory responsible for creating a DictionaryService instance
12
+ */
13
+ export class DictionaryServiceFactory {
14
+ /**
15
+ * @param {string} siteName site name
16
+ * @returns {DictionaryService} service instance
17
+ */
18
+ create(siteName: string): DictionaryService {
19
+ return process.env.FETCH_WITH === constants.FETCH_WITH.GRAPHQL
20
+ ? new GraphQLDictionaryService({
21
+ siteName,
22
+ clientFactory,
23
+ /*
24
+ GraphQL endpoint may reach its rate limit with the amount of requests it receives and throw a rate limit error.
25
+ GraphQL Dictionary and Layout Services can handle rate limit errors from server and attempt a retry on requests.
26
+ For this, specify the number of 'retries' the GraphQL client will attempt.
27
+ By default it is set to 3. You can disable it by configuring it to 0 for this service.
28
+
29
+ Additionally, you have the flexibility to customize the retry strategy by passing a 'retryStrategy'.
30
+ By default it uses the `DefaultRetryStrategy` with exponential back-off factor of 2 and handles error codes 429,
31
+ 502, 503, 504, 520, 521, 522, 523, 524, 'ECONNRESET', 'ETIMEDOUT' and 'EPROTO' . You can use this class or your own implementation of `RetryStrategy`.
32
+ */
33
+ retries: (process.env.GRAPH_QL_SERVICE_RETRIES &&
34
+ parseInt(process.env.GRAPH_QL_SERVICE_RETRIES, 10)) as number,
35
+ useSiteQuery: true,
36
+ })
37
+ : new RestDictionaryService({
38
+ apiHost: config.sitecoreApiHost,
39
+ apiKey: config.sitecoreApiKey,
40
+ siteName,
41
+ });
42
+ }
43
+ }
44
+
45
+ /** DictionaryServiceFactory singleton */
46
+ export const dictionaryServiceFactory = new DictionaryServiceFactory();
@@ -0,0 +1,9 @@
1
+ import { GraphQLEditingService } from '@sitecore-jss/sitecore-jss-nextjs/editing';
2
+ import clientFactory from 'lib/graphql-client-factory';
3
+
4
+ /**
5
+ * GraphQL Editing Service instance. Used to fetch editing data in Pages preview (editing) Metadata Edit Mode.
6
+ */
7
+ export const graphQLEditingService = new GraphQLEditingService({
8
+ clientFactory,
9
+ });
@@ -7,12 +7,12 @@ import { siteResolver } from 'lib/site-resolver';
7
7
 
8
8
  /**
9
9
  * This is the personalize middleware plugin for Next.js.
10
- * It is used to enable Sitecore personalization of pages in Next.js.
10
+ * It is used to enable Sitecore personalization and A/B testing of pages in Next.js.
11
11
  *
12
12
  * The `PersonalizeMiddleware` will
13
- * 1. Make a call to the Sitecore Experience Edge to get the personalization information about the page.
14
- * 2. Based on the response, make a call to the Sitecore CDP (with request/user context) to determine the page variant.
15
- * 3. Rewrite the response to the specific page variant.
13
+ * 1. Call Sitecore Experience Edge to get the personalization information about the page.
14
+ * 2. Based on the response, call Sitecore Personalize (with request/user context) to determine the page / component variant(s).
15
+ * 3. Rewrite the response to the specific page / component variant(s).
16
16
  */
17
17
  class PersonalizePlugin implements MiddlewarePlugin {
18
18
  private personalizeMiddleware: PersonalizeMiddleware;
@@ -30,7 +30,6 @@ class PersonalizePlugin implements MiddlewarePlugin {
30
30
  (process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT &&
31
31
  parseInt(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT)) ||
32
32
  400,
33
- scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
34
33
  },
35
34
  // Configuration for your Sitecore CDP endpoint
36
35
  cdpConfig: {
@@ -41,6 +40,8 @@ class PersonalizePlugin implements MiddlewarePlugin {
41
40
  parseInt(process.env.PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT)) ||
42
41
  400,
43
42
  },
43
+ // Optional Sitecore Personalize scope identifier.
44
+ scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
44
45
  // This function determines if the middleware should be turned off.
45
46
  // IMPORTANT: You should implement based on your cookie consent management solution of choice.
46
47
  // You may wish to keep it disabled while in development mode.
@@ -16,12 +16,16 @@ class PersonalizePlugin implements Plugin {
16
16
  ? context.params.path.join('/')
17
17
  : context.params.path ?? '/';
18
18
 
19
- // Get variant for personalization (from path)
19
+ // Get variant(s) for personalization (from path)
20
20
  const personalizeData = getPersonalizedRewriteData(path);
21
21
 
22
- // Modify layoutData to use specific variant instead of default
22
+ // Modify layoutData to use specific variant(s) instead of default
23
23
  // This will also set the variantId on the Sitecore context so that it is accessible here
24
- personalizeLayout(props.layoutData, personalizeData.variantId);
24
+ personalizeLayout(
25
+ props.layoutData,
26
+ personalizeData.variantId,
27
+ personalizeData.componentVariantIds
28
+ );
25
29
 
26
30
  return props;
27
31
  }
@@ -0,0 +1,72 @@
1
+ import { GetServerSidePropsContext, GetStaticPropsContext } from 'next';
2
+ import {
3
+ SiteInfo,
4
+ personalizeLayout,
5
+ getGroomedVariantIds,
6
+ } from '@sitecore-jss/sitecore-jss-nextjs';
7
+ import {
8
+ editingDataService,
9
+ isEditingMetadataPreviewData,
10
+ } from '@sitecore-jss/sitecore-jss-nextjs/editing';
11
+ import { SitecorePageProps } from 'lib/page-props';
12
+ import { graphQLEditingService } from 'lib/graphql-editing-service';
13
+ import { Plugin } from '..';
14
+
15
+ class PreviewModePlugin implements Plugin {
16
+ order = 1;
17
+
18
+ async exec(props: SitecorePageProps, context: GetServerSidePropsContext | GetStaticPropsContext) {
19
+ if (!context.preview) return props;
20
+
21
+ // If we're in Pages preview (editing) Metadata Edit Mode, prefetch the editing data
22
+ if (isEditingMetadataPreviewData(context.previewData)) {
23
+ const { site, itemId, language, version, variantIds } = context.previewData;
24
+
25
+ const data = await graphQLEditingService.fetchEditingData({
26
+ siteName: site,
27
+ itemId,
28
+ language,
29
+ version,
30
+ });
31
+
32
+ if (!data) {
33
+ throw new Error(
34
+ `Unable to fetch editing data for preview ${JSON.stringify(context.previewData)}`
35
+ );
36
+ }
37
+
38
+ props.site = data.layoutData.sitecore.context.site as SiteInfo;
39
+ props.locale = context.previewData.language;
40
+ props.layoutData = data.layoutData;
41
+ props.dictionary = data.dictionary;
42
+ props.headLinks = [];
43
+ const personalizeData = getGroomedVariantIds(variantIds);
44
+ personalizeLayout(
45
+ props.layoutData,
46
+ personalizeData.variantId,
47
+ personalizeData.componentVariantIds
48
+ );
49
+
50
+ return props;
51
+ }
52
+
53
+ // If we're in preview (editing) Chromes Edit Mode, use data already sent along with the editing request
54
+ // This mode is used by the Experience Editor.
55
+ // In Pages it's treated as a legacy mode but still supported for backward compatibility.
56
+ const data = await editingDataService.getEditingData(context.previewData);
57
+ if (!data) {
58
+ throw new Error(
59
+ `Unable to get editing data for preview ${JSON.stringify(context.previewData)}`
60
+ );
61
+ }
62
+ props.site = data.layoutData.sitecore.context.site as SiteInfo;
63
+ props.locale = data.language;
64
+ props.layoutData = data.layoutData;
65
+ props.dictionary = data.dictionary;
66
+ props.headLinks = [];
67
+
68
+ return props;
69
+ }
70
+ }
71
+
72
+ export const previewModePlugin = new PreviewModePlugin();
@@ -0,0 +1,46 @@
1
+ import { EditingRenderMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/editing';
2
+
3
+ /**
4
+ * This Next.js API route is used to handle GET and POST requests from Sitecore editors.
5
+ * GET requests are used with Metadata editing mode while POST ones are used with Chromes(legacy) mode.
6
+ * This route should match the `serverSideRenderingEngineEndpointUrl` in your Sitecore configuration,
7
+ * which is set to "http://<rendering_host>/api/editing/render" by default (see the settings item under /sitecore/content/<your/site/path>/Settings/Site Grouping).
8
+ *
9
+ * For Metadata mode, the `EditingRenderMiddleware` will
10
+ * 1. Extract data about the route we need to rendr from the Sitecore editor GET request
11
+ * 2. Enable Next.js Preview Mode, passing the route data as preview data
12
+ * 3. Redirect the request to the route, passing along the Preview Mode cookies.
13
+ * This allows retrieval of the editing data in preview context (via an `EditingDataService`) - see `SitecorePagePropsFactory`
14
+ * 4. The redirected request will render the page with editing markup in place
15
+ *
16
+ * For Chromes(legacy) mode, the `EditingRenderMiddleware` will
17
+ * 1. Extract editing data from the Sitecore editor POST request
18
+ * 2. Stash this data (for later use in the page render request) via an `EditingDataService`, which returns a key for retrieval
19
+ * 3. Enable Next.js Preview Mode, passing our stashed editing data key as preview data
20
+ * 4. Invoke the actual page render request, passing along the Preview Mode cookies.
21
+ * This allows retrieval of the editing data in preview context (via an `EditingDataService`) - see `SitecorePagePropsFactory`
22
+ * 5. Return the rendered page HTML to the Sitecore editor
23
+ *
24
+ */
25
+
26
+ /**
27
+ * [Chromes mode only] For Vercel deployments:
28
+ * if you experience crashes in editing, you may need to use VercelEditingDataCache or a custom Redis data cache implementation with EditingRenderMiddleware
29
+ * Please refer to documentation for a detailed guide.
30
+ */
31
+
32
+ // [Chromes mode only] Bump body size limit (1mb by default) and disable response limit for Sitecore editor payloads
33
+ // See https://nextjs.org/docs/api-routes/request-helpers#custom-config
34
+ export const config = {
35
+ api: {
36
+ bodyParser: {
37
+ sizeLimit: '2mb',
38
+ },
39
+ responseLimit: false,
40
+ },
41
+ };
42
+
43
+ // Wire up the EditingRenderMiddleware handler
44
+ const handler = new EditingRenderMiddleware().getHandler();
45
+
46
+ export default handler;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-headless-ssr-experience-edge-sample",
3
- "version": "22.1.0-canary",
3
+ "version": "22.2.0-canary",
4
4
  "description": "Node server-side-rendering sample for running JSS apps under Node hosting using Experience Edge",
5
5
  "scripts": {
6
6
  "start": "ts-node ./src/index.ts"
@@ -19,7 +19,7 @@
19
19
  "homepage": "https://jss.sitecore.com",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@sitecore-jss/sitecore-jss": "~22.1.0-canary",
22
+ "@sitecore-jss/sitecore-jss": "~22.2.0-canary",
23
23
  "compression": "^1.7.4",
24
24
  "express": "^4.18.2",
25
25
  "dotenv": "^16.0.3"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-headless-ssr-proxy-sample",
3
- "version": "22.1.0-canary",
3
+ "version": "22.2.0-canary",
4
4
  "description": "Node server-side-rendering proxy sample for running JSS apps under Node hosting",
5
5
  "scripts": {
6
6
  "start": "ts-node ./src/index.ts"
@@ -19,8 +19,8 @@
19
19
  "homepage": "https://jss.sitecore.com",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@sitecore-jss/sitecore-jss": "~22.1.0-canary",
23
- "@sitecore-jss/sitecore-jss-proxy": "~22.1.0-canary",
22
+ "@sitecore-jss/sitecore-jss": "~22.2.0-canary",
23
+ "@sitecore-jss/sitecore-jss-proxy": "~22.2.0-canary",
24
24
  "agentkeepalive": "^4.2.1",
25
25
  "compression": "~1.7.4",
26
26
  "express": "~4.19.2",
@@ -31,7 +31,7 @@
31
31
  "@types/compression": "^1.7.2",
32
32
  "@types/express": "^4.17.17",
33
33
  "@types/memory-cache": "^0.2.2",
34
- "@types/node": "^18.14.0",
34
+ "@types/node": "^20.14.2",
35
35
  "ts-node": "^10.9.1",
36
36
  "typescript": "~4.9.5"
37
37
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "<%- appName %>",
3
3
  "description": "Application utilizing Sitecore JavaScript Services and React (create-react-app).",
4
- "version": "22.1.0-canary",
4
+ "version": "22.2.0-canary",
5
5
  "private": true,
6
6
  "config": {
7
7
  "appName": "<%- appName %>",
@@ -28,7 +28,7 @@
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
30
  "@apollo/client": "^3.7.1",
31
- "@sitecore-jss/sitecore-jss-react": "~22.1.0-canary",
31
+ "@sitecore-jss/sitecore-jss-react": "~22.2.0-canary",
32
32
  "axios": "^1.2.0",
33
33
  "bootstrap": "^5.2.3",
34
34
  "cross-fetch": "^3.1.5",
@@ -53,9 +53,9 @@
53
53
  "@babel/preset-env": "^7.20.2",
54
54
  "@babel/preset-react": "^7.18.6",
55
55
  "@babel/register": "~7.18.9",
56
- "@sitecore-jss/sitecore-jss-cli": "~22.1.0-canary",
57
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
58
- "@sitecore-jss/sitecore-jss-rendering-host": "~22.1.0-canary",
56
+ "@sitecore-jss/sitecore-jss-cli": "~22.2.0-canary",
57
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
58
+ "@sitecore-jss/sitecore-jss-rendering-host": "~22.2.0-canary",
59
59
  "babel-loader": "~9.1.0",
60
60
  "babel-preset-react-app": "~10.0.1",
61
61
  "chalk": "~4.1.2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%- appName %>",
3
- "version": "22.1.0-canary",
3
+ "version": "22.2.0-canary",
4
4
  "description": "A basic React Native app utilizing Sitecore JavaScript Services",
5
5
  "config": {
6
6
  "appName": "<%- appName %>",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@react-native-community/masked-view": "^0.1.10",
26
- "@sitecore-jss/sitecore-jss-react-native": "~22.1.0-canary",
26
+ "@sitecore-jss/sitecore-jss-react-native": "~22.2.0-canary",
27
27
  "prop-types": "^15.6.0",
28
28
  "react": "16.13.1",
29
29
  "react-native": "^0.63.4",
@@ -37,8 +37,8 @@
37
37
  },
38
38
  "private": true,
39
39
  "devDependencies": {
40
- "@sitecore-jss/sitecore-jss-cli": "~22.1.0-canary",
41
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
40
+ "@sitecore-jss/sitecore-jss-cli": "~22.2.0-canary",
41
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
42
42
  "babel-core": "^6.26.0",
43
43
  "babel-eslint": "^8.2.1",
44
44
  "babel-plugin-inline-replace-variables": "^1.3.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%- appName %>",
3
- "version": "22.1.0-canary",
3
+ "version": "22.2.0-canary",
4
4
  "description": "Application utilizing Sitecore JavaScript Services and Vue (vue-cli).",
5
5
  "private": true,
6
6
  "config": {
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "@apollo/client": "^3.7.4",
47
47
  "@panter/vue-i18next": "~0.15.2",
48
- "@sitecore-jss/sitecore-jss-vue": "~22.1.0-canary",
48
+ "@sitecore-jss/sitecore-jss-vue": "~22.2.0-canary",
49
49
  "@vue/apollo-composable": "4.0.0-beta.2",
50
50
  "@vue/apollo-option": "^4.0.0-alpha.20",
51
51
  "@vue/apollo-ssr": "^4.0.0-alpha.18",
@@ -64,8 +64,8 @@
64
64
  "devDependencies": {
65
65
  "@babel/eslint-parser": "^7.19.1",
66
66
  "@babel/register": "7.18.9",
67
- "@sitecore-jss/sitecore-jss-cli": "~22.1.0-canary",
68
- "@sitecore-jss/sitecore-jss-dev-tools": "~22.1.0-canary",
67
+ "@sitecore-jss/sitecore-jss-cli": "~22.2.0-canary",
68
+ "@sitecore-jss/sitecore-jss-dev-tools": "~22.2.0-canary",
69
69
  "@vue/cli-plugin-babel": "~5.0.8",
70
70
  "@vue/cli-plugin-eslint": "~5.0.8",
71
71
  "@vue/cli-service": "~5.0.8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sitecore-jss",
3
- "version": "22.1.0-canary.9",
3
+ "version": "22.2.0-canary.1",
4
4
  "description": "Sitecore JSS initializer",
5
5
  "bin": "./dist/index.js",
6
6
  "scripts": {
@@ -12,7 +12,7 @@
12
12
  "coverage": "nyc npm test"
13
13
  },
14
14
  "engines": {
15
- "node": ">=18"
15
+ "node": ">=20"
16
16
  },
17
17
  "repository": {
18
18
  "type": "git",
@@ -49,7 +49,7 @@
49
49
  "@types/inquirer": "^9.0.3",
50
50
  "@types/minimist": "^1.2.2",
51
51
  "@types/mocha": "^10.0.1",
52
- "@types/node": "^18.11.18",
52
+ "@types/node": "^20.14.2",
53
53
  "@types/sinon": "10.0.6",
54
54
  "@types/sinon-chai": "^3.2.9",
55
55
  "chai": "^4.3.7",
@@ -63,5 +63,5 @@
63
63
  "ts-node": "^10.9.1",
64
64
  "typescript": "~4.9.5"
65
65
  },
66
- "gitHead": "9b249f8d03fb9d74e74f74f3040fc2668137bdcc"
66
+ "gitHead": "7dd64ce5a019e4579596beae31315db262a4700f"
67
67
  }