From 9aa7d801ba6133a2effe48a8381b27bb4a04901e Mon Sep 17 00:00:00 2001 From: Adam Brauer <400763+ambrauer@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:06:36 -0600 Subject: [PATCH] [Next.js] Introduce `nextjs-xmcloud` Initializer Template (#1653) * rename nextjs-personalize -> nextjs-xmcloud. move feaas and BYOC here. * Move Sitecore Edge Platform / conext related items to nextjs-xmcloud * Repurpose nextjs-personalize -> nextjs-xmcloud initializer "system" template (driven by prompt / --xmcloud CLI option) * Moved skipping of site information fetch on XM Cloud to base package (GraphQLSiteInfoService) * CHANGELOG update * fix scaffold samples * removed from sxa Layout.tsx * fix for PR comment (cherry picked from commit 19f5c22ac9ad857b7d401398672250e68bdfbcbe) --- CHANGELOG.md | 7 +- .../nextjs-styleguide-tracking/index.ts | 6 +- .../index.ts | 9 +-- .../src/initializers/nextjs/index.ts | 71 ++++++++++++------- .../src/initializers/nextjs/prompts.ts | 19 ++--- .../scripts/config/plugins/multisite.ts | 32 +++------ .../templates/nextjs-personalize/package.json | 5 -- .../src/templates/nextjs-sxa/src/Layout.tsx | 3 - .../.env | 49 +++++++------ .../src/templates/nextjs-xmcloud/package.json | 7 ++ .../scripts/config/plugins/edge-platform.ts | 32 +++++++++ .../plugins/feaas.ts | 0 .../scaffold-component/plugins/byoc.ts | 0 .../plugins/next-steps-byoc.ts | 0 .../scripts/templates/byoc-component-src.ts | 0 .../src/Scripts.tsx | 3 + .../src/byoc/index.client.tsx | 0 .../src/byoc/index.hybrid.ts | 0 .../src/byoc/index.ts | 0 .../src/components/CdpPageView.tsx | 0 .../lib/extract-path/plugins/personalize.ts | 0 .../src/lib/graphql-client-factory/create.ts | 32 +++++++++ .../src/lib/middleware/plugins/personalize.ts | 0 .../src/lib/next-config/plugins/feaas.js | 0 .../src/lib/next-config/plugins/monorepo.js | 30 ++++++++ .../plugins/feaas-themes.ts | 0 .../page-props-factory/plugins/personalize.ts | 0 .../src/lib/site-resolver/plugins/default.ts | 0 .../src/templates/nextjs/.env | 10 +-- .../nextjs/scripts/config/plugins/fallback.ts | 10 --- .../nextjs/scripts/generate-config.ts | 2 - .../src/templates/nextjs/src/Layout.tsx | 3 - .../src/templates/nextjs/src/lib/config.ts | 2 - .../src/lib/graphql-client-factory/create.ts | 11 +-- .../src/lib/next-config/plugins/monorepo.js | 9 --- .../src/site/graphql-siteinfo-service.test.ts | 36 +++++++++- .../src/site/graphql-siteinfo-service.ts | 4 ++ scripts/samples.json | 4 +- 38 files changed, 253 insertions(+), 143 deletions(-) rename packages/create-sitecore-jss/src/initializers/{nextjs-personalize => nextjs-xmcloud}/index.ts (73%) delete mode 100644 packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/.env (78%) create mode 100644 packages/create-sitecore-jss/src/templates/nextjs-xmcloud/package.json create mode 100644 packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/config/plugins/edge-platform.ts rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/scripts/generate-component-builder/plugins/feaas.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/scripts/scaffold-component/plugins/byoc.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/scripts/scaffold-component/plugins/next-steps-byoc.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/scripts/templates/byoc-component-src.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/Scripts.tsx (52%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/src/byoc/index.client.tsx (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/src/byoc/index.hybrid.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/src/byoc/index.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/components/CdpPageView.tsx (100%) rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/lib/extract-path/plugins/personalize.ts (100%) create mode 100644 packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/graphql-client-factory/create.ts rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/lib/middleware/plugins/personalize.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/src/lib/next-config/plugins/feaas.js (100%) create mode 100644 packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/monorepo.js rename packages/create-sitecore-jss/src/templates/{nextjs => nextjs-xmcloud}/src/lib/page-props-factory/plugins/feaas-themes.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/lib/page-props-factory/plugins/personalize.ts (100%) rename packages/create-sitecore-jss/src/templates/{nextjs-personalize => nextjs-xmcloud}/src/lib/site-resolver/plugins/default.ts (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed240dbd25..b2d098f41d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Our versioning strategy is as follows: * `[sitecore-jss-nextjs]` (Vercel/Sitecore) Deployment Protection Bypass support for editing integration. ([#1634](https://github.com/Sitecore/jss/pull/1634)) * `[sitecore-jss]` `[templates/nextjs]` Load environment-specific FEAAS theme stylesheets based on Sitecore Edge Platform URL ([#1645](https://github.com/Sitecore/jss/pull/1645)) * `[sitecore-jss-nextjs]` The _GraphQLRequestClient_ import from _@sitecore-jss/sitecore-jss-nextjs_ is deprecated, use import from _@sitecore-jss/sitecore-jss-nextjs/graphql_ submodule instead ([#1650](https://github.com/Sitecore/jss/pull/1650) [#1648](https://github.com/Sitecore/jss/pull/1648)) +* `[create-sitecore-jss]` Introduced `nextjs-xmcloud` initializer template. This will include all base XM Cloud features, including Personalize, FEaaS, BYOC, Sitecore Edge Platform and Context support. ([#1653](https://github.com/Sitecore/jss/pull/1653)) ### 🐛 Bug Fixes @@ -32,7 +33,11 @@ Our versioning strategy is as follows: * `[sitecore-jss-nextjs]` Fix issue when redirects works each every other times. ([#1629](https://github.com/Sitecore/jss/pull/1629)) * `[templates/nextjs]` Fix custom headers. Now in cors-header plugin extends custom headers from next.config.js file. ([#1637](https://github.com/Sitecore/jss/pull/1637)) * `[sitecore-jss-react]` Fix PlaceholderCommon with using two and more dynamic placeholders. ([#1641](https://github.com/Sitecore/jss/pull/1641)) -* `[templates/nextjs-multisite]` Fix site info fetch errors (now skipped) on XM Cloud rendering/editing host builds. ([#1649](https://github.com/Sitecore/jss/pull/1649)) +* `[templates/nextjs-multisite]` Fix site info fetch errors (now skipped) on XM Cloud rendering/editing host builds. ([#1649](https://github.com/Sitecore/jss/pull/1649)), ([#1653](https://github.com/Sitecore/jss/pull/1653)) + +### 🛠 Breaking Changes + +* `[create-sitecore-jss]` The `nextjs-personalize` initializer add-on template has been removed and is replaced by the `nextjs-xmcloud` initializer template. You can use the interactive prompts or the `--xmcloud` argument to include this template. ([#1653](https://github.com/Sitecore/jss/pull/1653)) ## 21.5.0 diff --git a/packages/create-sitecore-jss/src/initializers/nextjs-styleguide-tracking/index.ts b/packages/create-sitecore-jss/src/initializers/nextjs-styleguide-tracking/index.ts index 05a4163a18..81fe0dd663 100644 --- a/packages/create-sitecore-jss/src/initializers/nextjs-styleguide-tracking/index.ts +++ b/packages/create-sitecore-jss/src/initializers/nextjs-styleguide-tracking/index.ts @@ -35,10 +35,10 @@ export default class NextjsStyleguideInitializer implements Initializer { } if ( - args.templates.includes('nextjs-personalize') || - pkg.config?.templates?.includes('nextjs-personalize') + args.templates.includes('nextjs-xmcloud') || + pkg.config?.templates?.includes('nextjs-xmcloud') ) { - console.log(incompatibleAddonsMsg('nextjs-styleguide-tracking', 'nextjs-personalize')); + console.log(incompatibleAddonsMsg('nextjs-styleguide-tracking', 'nextjs-xmcloud')); } const response = { diff --git a/packages/create-sitecore-jss/src/initializers/nextjs-personalize/index.ts b/packages/create-sitecore-jss/src/initializers/nextjs-xmcloud/index.ts similarity index 73% rename from packages/create-sitecore-jss/src/initializers/nextjs-personalize/index.ts rename to packages/create-sitecore-jss/src/initializers/nextjs-xmcloud/index.ts index 6439b7b8e1..16813e229a 100644 --- a/packages/create-sitecore-jss/src/initializers/nextjs-personalize/index.ts +++ b/packages/create-sitecore-jss/src/initializers/nextjs-xmcloud/index.ts @@ -8,7 +8,7 @@ import { incompatibleAddonsMsg, } from '../../common'; -export default class NextjsPersonalizeInitializer implements Initializer { +export default class NextjsXMCloudInitializer implements Initializer { get isBase(): boolean { return false; } @@ -16,16 +16,13 @@ export default class NextjsPersonalizeInitializer implements Initializer { async init(args: ClientAppArgs) { const pkg = openPackageJson(`${args.destination}${sep}package.json`); - // TODO: prompts for Personalize and argument types - // const answers = await prompt(styleguidePrompts, args); - const mergedArgs = { ...args, appName: args.appName || pkg?.config?.appName || DEFAULT_APPNAME, appPrefix: args.appPrefix || pkg?.config?.prefix || false, }; - const templatePath = path.resolve(__dirname, '../../templates/nextjs-personalize'); + const templatePath = path.resolve(__dirname, '../../templates/nextjs-xmcloud'); await transform(templatePath, mergedArgs); @@ -33,7 +30,7 @@ export default class NextjsPersonalizeInitializer implements Initializer { args.templates.includes('nextjs-styleguide-tracking') || pkg.config?.templates?.includes('nextjs-styleguide-tracking') ) { - console.log(incompatibleAddonsMsg('nextjs-personalize', 'nextjs-styleguide-tracking')); + console.log(incompatibleAddonsMsg('nextjs-xmcloud', 'nextjs-styleguide-tracking')); } const response = { diff --git a/packages/create-sitecore-jss/src/initializers/nextjs/index.ts b/packages/create-sitecore-jss/src/initializers/nextjs/index.ts index 843dec78a6..ad9fe98826 100644 --- a/packages/create-sitecore-jss/src/initializers/nextjs/index.ts +++ b/packages/create-sitecore-jss/src/initializers/nextjs/index.ts @@ -14,6 +14,36 @@ import { NextjsArgs } from './args'; inquirer.registerPrompt('nextjs-checkbox', NextjsCheckbox); +enum PlatformCompatibility { + SXP, + XMC, + Both, +} + +const addOnChoices = [ + { + name: 'nextjs-styleguide - Includes example components and setup for working disconnected', + value: 'nextjs-styleguide', + platform: PlatformCompatibility.Both, + }, + { + name: 'nextjs-styleguide-tracking - Includes example (Sitecore XP) tracking component', + value: 'nextjs-styleguide-tracking', + platform: PlatformCompatibility.SXP, + }, + { + name: 'nextjs-sxa - Includes example components and setup for Headless SXA projects', + value: 'nextjs-sxa', + platform: PlatformCompatibility.Both, + }, + { + name: + 'nextjs-multisite - Includes example setup for hosting multiple sites in a single NextJS application', + value: 'nextjs-multisite', + platform: PlatformCompatibility.Both, + }, +]; + export default class NextjsInitializer implements Initializer { get isBase(): boolean { return true; @@ -31,7 +61,12 @@ export default class NextjsInitializer implements Initializer { removeDevDependencies(args.destination); } - let addInitializers: string[] = []; + const addInitializers: string[] = []; + + if (answers.xmcloud && !args.templates.includes('nextjs-xmcloud')) { + // add the "system" nextjs-xmcloud template if needed + addInitializers.push('nextjs-xmcloud'); + } // don't prompt for add-on initializers if --yes or they've already specified // multiple via --templates (assume they know what they're doing) @@ -40,33 +75,15 @@ export default class NextjsInitializer implements Initializer { type: 'nextjs-checkbox' as 'checkbox', name: 'addInitializers', message: 'Would you like to include any add-on initializers?', - choices: [ - { - name: - 'nextjs-styleguide - Includes example components and setup for working disconnected', - value: 'nextjs-styleguide', - }, - { - name: 'nextjs-styleguide-tracking - Includes example (Sitecore XP) tracking component', - value: 'nextjs-styleguide-tracking', - }, - { - name: 'nextjs-sxa - Includes example components and setup for Headless SXA projects', - value: 'nextjs-sxa', - }, - { - name: - 'nextjs-personalize - Includes example setup for projects using XM Cloud Embedded Personalization', - value: 'nextjs-personalize', - }, - { - name: - 'nextjs-multisite - Includes example setup for hosting multiple sites in a single NextJS application', - value: 'nextjs-multisite', - }, - ], + choices: addOnChoices.filter((choice) => { + return ( + choice.platform === PlatformCompatibility.Both || + (answers.xmcloud && choice.platform === PlatformCompatibility.XMC) || + (!answers.xmcloud && choice.platform === PlatformCompatibility.SXP) + ); + }), }); - addInitializers = addInitAnswer.addInitializers; + addInitializers.push(...addInitAnswer.addInitializers); } if ( diff --git a/packages/create-sitecore-jss/src/initializers/nextjs/prompts.ts b/packages/create-sitecore-jss/src/initializers/nextjs/prompts.ts index e501ed1d91..1c04472e20 100644 --- a/packages/create-sitecore-jss/src/initializers/nextjs/prompts.ts +++ b/packages/create-sitecore-jss/src/initializers/nextjs/prompts.ts @@ -10,6 +10,7 @@ export enum Prerender { export type NextjsAnswer = ClientAppAnswer & { prerender: Prerender; + xmcloud: boolean; }; const DEFAULT_PRERENDER = Prerender.SSG; @@ -29,6 +30,15 @@ export const prompts: QuestionCollection = [ return !answers.prerender; }, }, + { + type: 'confirm', + name: 'xmcloud', + message: 'Are you building for Sitecore XM Cloud?', + default: false, + when: (answers: NextjsAnswer): boolean => { + return !answers.yes; + }, + }, ]; /** @@ -45,15 +55,6 @@ export class NextjsCheckbox extends CheckboxPrompt { return value === initializer && checked; }); - const isPersonalizeSelected = isSelected('nextjs-personalize'); - const isTrackingSelected = isSelected('nextjs-styleguide-tracking'); - - if (isPersonalizeSelected && isTrackingSelected) { - this.onError({ - isValid: incompatibleAddonsMsg('nextjs-styleguide-tracking', 'nextjs-personalize'), - }); - } - const isSxaSelected = isSelected('nextjs-sxa'); const isStyleguideSelected = isSelected('nextjs-styleguide'); diff --git a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts index 754717a41f..56f7581f1c 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts @@ -14,29 +14,15 @@ class MultisitePlugin implements ConfigPlugin { async exec(config: JssConfig) { let sites: SiteInfo[] = []; - - const endpoint = config.sitecoreEdgeContextId ? config.sitecoreEdgeUrl : config.graphQLEndpoint; - - if (!endpoint || process.env.SITECORE) { - console.warn( - chalk.yellow( - `Skipping site information fetch (${ - !endpoint ? 'missing GraphQL endpoint' : 'building on XM Cloud' - })` - ) - ); - } else { - console.log(`Fetching site information from ${endpoint}`); - - try { - const siteInfoService = new GraphQLSiteInfoService({ - clientFactory: createGraphQLClientFactory(config), - }); - sites = await siteInfoService.fetchSiteInfo(); - } catch (error) { - console.error(chalk.red('Error fetching site information')); - console.error(error); - } + console.log('Fetching site information'); + try { + const siteInfoService = new GraphQLSiteInfoService({ + clientFactory: createGraphQLClientFactory(config), + }); + sites = await siteInfoService.fetchSiteInfo(); + } catch (error) { + console.error(chalk.red('Error fetching site information')); + console.error(error); } return Object.assign({}, config, { diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json b/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json deleted file mode 100644 index 6653194865..0000000000 --- a/packages/create-sitecore-jss/src/templates/nextjs-personalize/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "@sitecore/engage": "^1.4.1" - } -} diff --git a/packages/create-sitecore-jss/src/templates/nextjs-sxa/src/Layout.tsx b/packages/create-sitecore-jss/src/templates/nextjs-sxa/src/Layout.tsx index 17122e889d..3d4800e3d3 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-sxa/src/Layout.tsx +++ b/packages/create-sitecore-jss/src/templates/nextjs-sxa/src/Layout.tsx @@ -11,8 +11,6 @@ import { } from '@sitecore-jss/sitecore-jss-nextjs'; import { getPublicUrl } from '@sitecore-jss/sitecore-jss-nextjs/utils'; import Scripts from 'src/Scripts'; -// The bundle imports external (BYOC) components into the app and makes sure they are ready to be used. -import BYOC from 'src/byoc'; // Prefix public assets with a public URL to enable compatibility with Sitecore Experience Editor. // If you're not supporting the Experience Editor, you can remove this. @@ -37,7 +35,6 @@ const Layout = ({ layoutData, headLinks }: LayoutProps): JSX.Element => { return ( <> - {fields?.Title?.value?.toString() || 'Page'} diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/.env b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/.env similarity index 78% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/.env rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/.env index a508d9edfb..45ccca7ccc 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-personalize/.env +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/.env @@ -1,20 +1,29 @@ -# Your Sitecore CDP API target (specific to your data center region) -NEXT_PUBLIC_CDP_TARGET_URL= - -# Your Sitecore CDP client key -NEXT_PUBLIC_CDP_CLIENT_KEY= - -# An optional Sitecore Personalize scope identifier. -# This can be used to isolate personalization data when multiple XM Cloud Environments share a Personalize tenant. -# This should match the PAGES_PERSONALIZE_SCOPE environment variable for your connected XM Cloud Environment. -NEXT_PUBLIC_PERSONALIZE_SCOPE= - -# Your Sitecore CDP point(s) of sale -# Can be provided as a single value (mypoint.com) or a multi-value JSON with locales ({"en":"en.mypoint.com","fr":"fr.mypoint.com"} etc) -NEXT_PUBLIC_CDP_POINTOFSALE= - -# Timeout (ms) for Sitecore CDP requests to respond within. Default is 400. -PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT= - -# Timeout (ms) for Sitecore Experience Edge requests to respond within. Default is 400. -PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT= + +# ========== Sitecore Edge Platform =========== + +# Your unified Sitecore Edge Context Id. +# This will be used over any Sitecore Preview / Delivery Edge variables (above). +SITECORE_EDGE_CONTEXT_ID= + +# ============================================== + +# Your Sitecore CDP API target (specific to your data center region) +NEXT_PUBLIC_CDP_TARGET_URL= + +# Your Sitecore CDP client key +NEXT_PUBLIC_CDP_CLIENT_KEY= + +# An optional Sitecore Personalize scope identifier. +# This can be used to isolate personalization data when multiple XM Cloud Environments share a Personalize tenant. +# This should match the PAGES_PERSONALIZE_SCOPE environment variable for your connected XM Cloud Environment. +NEXT_PUBLIC_PERSONALIZE_SCOPE= + +# Your Sitecore CDP point(s) of sale +# Can be provided as a single value (mypoint.com) or a multi-value JSON with locales ({"en":"en.mypoint.com","fr":"fr.mypoint.com"} etc) +NEXT_PUBLIC_CDP_POINTOFSALE= + +# Timeout (ms) for Sitecore CDP requests to respond within. Default is 400. +PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT= + +# Timeout (ms) for Sitecore Experience Edge requests to respond within. Default is 400. +PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT= diff --git a/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/package.json b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/package.json new file mode 100644 index 0000000000..33d06644d2 --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "@sitecore/components": "~1.0.19", + "@sitecore/engage": "^1.4.1", + "@sitecore-feaas/clientside": "^0.4.12" + } +} diff --git a/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/config/plugins/edge-platform.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/config/plugins/edge-platform.ts new file mode 100644 index 0000000000..d8779ff0bb --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/config/plugins/edge-platform.ts @@ -0,0 +1,32 @@ +import 'dotenv/config'; +import chalk from 'chalk'; +import { constantCase } from 'constant-case'; +import { JssConfig } from 'lib/config'; +import { ConfigPlugin } from '..'; + +/** + * This plugin will set config props used by the Sitecore Edge Platform. + */ +class EdgePlatformPlugin implements ConfigPlugin { + order = 2; + + async exec(config: JssConfig) { + const sitecoreEdgeUrl = process.env[`${constantCase('sitecoreEdgeUrl')}`] || 'https://edge-platform.sitecorecloud.io'; + const sitecoreEdgeContextId = process.env[`${constantCase('sitecoreEdgeContextId')}`]; + + if (config.sitecoreApiKey && sitecoreEdgeContextId) { + console.log( + chalk.yellow( + "You have configured both 'sitecoreApiKey' and 'sitecoreEdgeContextId' values. The 'sitecoreEdgeContextId' is used instead." + ) + ); + } + + return Object.assign({}, config, { + sitecoreEdgeUrl, + sitecoreEdgeContextId, + }); + } +} + +export const edgePlatformPlugin = new EdgePlatformPlugin(); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-component-builder/plugins/feaas.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/generate-component-builder/plugins/feaas.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-component-builder/plugins/feaas.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/generate-component-builder/plugins/feaas.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/scaffold-component/plugins/byoc.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/scaffold-component/plugins/byoc.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/scripts/scaffold-component/plugins/byoc.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/scaffold-component/plugins/byoc.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/scaffold-component/plugins/next-steps-byoc.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/scaffold-component/plugins/next-steps-byoc.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/scripts/scaffold-component/plugins/next-steps-byoc.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/scaffold-component/plugins/next-steps-byoc.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/templates/byoc-component-src.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/templates/byoc-component-src.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/scripts/templates/byoc-component-src.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/scripts/templates/byoc-component-src.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/Scripts.tsx b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/Scripts.tsx similarity index 52% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/Scripts.tsx rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/Scripts.tsx index 52ecf0b89a..8f7e0602a0 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/Scripts.tsx +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/Scripts.tsx @@ -1,8 +1,11 @@ +// The BYOC bundle imports external (BYOC) components into the app and makes sure they are ready to be used +import BYOC from 'src/byoc'; import CdpPageView from 'components/CdpPageView'; const Scripts = (): JSX.Element => { return ( <> + ); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.client.tsx b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.client.tsx similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.client.tsx rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.client.tsx diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.hybrid.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.hybrid.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.hybrid.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.hybrid.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/src/byoc/index.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/byoc/index.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/components/CdpPageView.tsx b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/components/CdpPageView.tsx similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/components/CdpPageView.tsx rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/components/CdpPageView.tsx diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/extract-path/plugins/personalize.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/extract-path/plugins/personalize.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/extract-path/plugins/personalize.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/extract-path/plugins/personalize.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/graphql-client-factory/create.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/graphql-client-factory/create.ts new file mode 100644 index 0000000000..bc76efc74f --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/graphql-client-factory/create.ts @@ -0,0 +1,32 @@ +import { + GraphQLRequestClientFactoryConfig, + GraphQLRequestClient, + getEdgeProxyContentUrl +} from '@sitecore-jss/sitecore-jss-nextjs/graphql'; +import { JssConfig } from 'lib/config'; + +/** + * Creates a new GraphQLRequestClientFactory instance + * @param config jss config + * @returns GraphQLRequestClientFactory instance + */ +export const createGraphQLClientFactory = (config: JssConfig) => { + let clientConfig: GraphQLRequestClientFactoryConfig; + + if (config.sitecoreEdgeContextId) { + clientConfig = { + endpoint: getEdgeProxyContentUrl(config.sitecoreEdgeContextId, config.sitecoreEdgeUrl), + }; + } else if (config.graphQLEndpoint && config.sitecoreApiKey) { + clientConfig = { + endpoint: config.graphQLEndpoint, + apiKey: config.sitecoreApiKey, + }; + } else { + throw new Error( + 'Please configure either your sitecoreEdgeContextId, or your graphQLEndpoint and sitecoreApiKey.' + ); + } + + return GraphQLRequestClient.createClientFactory(clientConfig); +}; diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/middleware/plugins/personalize.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/middleware/plugins/personalize.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/middleware/plugins/personalize.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/middleware/plugins/personalize.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/feaas.js b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/feaas.js similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/feaas.js rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/feaas.js diff --git a/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/monorepo.js b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/monorepo.js new file mode 100644 index 0000000000..f1ce7c9a26 --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/next-config/plugins/monorepo.js @@ -0,0 +1,30 @@ +const path = require('path'); +const CWD = process.cwd(); + +/** + * @param {import('next').NextConfig} nextConfig + */ +const monorepoPlugin = (nextConfig = {}) => { + return Object.assign({}, nextConfig, { + webpack: (config, options) => { + if (options.isServer) { + config.externals = ['react', 'vertx', ...config.externals]; + } + // Monorepo support for @sitecore-feaas/clientside/react + config.resolve.alias['@sitecore-feaas/clientside/react'] = path.resolve( + CWD, options.isServer ? + './node_modules/@sitecore-feaas/clientside/dist/node/react.cjs' : + './node_modules/@sitecore-feaas/clientside/dist/browser/react.esm.js' + ); + + // Overload the Webpack config if it was already overloaded + if (typeof nextConfig.webpack === 'function') { + return nextConfig.webpack(config, options); + } + + return config; + } + }); +}; + +module.exports = monorepoPlugin; diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/page-props-factory/plugins/feaas-themes.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/feaas-themes.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs/src/lib/page-props-factory/plugins/feaas-themes.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/feaas-themes.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/page-props-factory/plugins/personalize.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/personalize.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/page-props-factory/plugins/personalize.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/personalize.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/site-resolver/plugins/default.ts b/packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/site-resolver/plugins/default.ts similarity index 100% rename from packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/site-resolver/plugins/default.ts rename to packages/create-sitecore-jss/src/templates/nextjs-xmcloud/src/lib/site-resolver/plugins/default.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs/.env b/packages/create-sitecore-jss/src/templates/nextjs/.env index 3975c535d6..9f2db19a61 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/.env +++ b/packages/create-sitecore-jss/src/templates/nextjs/.env @@ -17,15 +17,7 @@ PUBLIC_URL=http://localhost:3000 # We recommend an alphanumeric value of at least 16 characters. JSS_EDITING_SECRET= -# ===== Sitecore Edge Platform ====== - -# Your unified Sitecore Edge Context Id. -SITECORE_EDGE_CONTEXT_ID= - -# ================================ - # ====== Sitecore Preview / Delivery Edge ====== -# (Sitecore Edge Proxy environment variables should be set empty, otherwise they will be prioritized and applied) # Your Sitecore API key is needed to build the app. Typically, the API key is # defined in `scjssconfig.json` (as `sitecore.apiKey`). This file may not exist @@ -46,7 +38,7 @@ SITECORE_API_HOST= # the resolved Sitecore API hostname + the `graphQLEndpointPath` defined in your `package.json`. GRAPH_QL_ENDPOINT= -# ================================ +# ============================================== # Your Sitecore site name. # Uses your `package.json` config `appName` if empty. diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts index ba3b08c00a..535847cf59 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts @@ -1,4 +1,3 @@ -import chalk from 'chalk'; import { JssConfig } from 'lib/config'; import { ConfigPlugin } from '..'; @@ -11,19 +10,10 @@ class FallbackPlugin implements ConfigPlugin { order = 100; async exec(config: JssConfig) { - if (config.sitecoreApiKey && config.sitecoreEdgeContextId) { - console.log( - chalk.yellow( - "You have configured both 'sitecoreApiKey' and 'sitecoreEdgeContextId' values. The 'sitecoreEdgeContextId' is used instead." - ) - ); - } - return Object.assign({}, config, { defaultLanguage: config.defaultLanguage || 'en', sitecoreApiKey: config.sitecoreApiKey || 'no-api-key-set', layoutServiceConfigurationName: config.layoutServiceConfigurationName || 'default', - sitecoreEdgeUrl: config.sitecoreEdgeUrl || 'https://edge-platform.sitecorecloud.io', }); } } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts index 2369bc8f87..beca398a20 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts @@ -14,8 +14,6 @@ import { jssConfigFactory } from './config'; const defaultConfig: JssConfig = { sitecoreApiKey: process.env[`${constantCase('sitecoreApiKey')}`], sitecoreApiHost: process.env[`${constantCase('sitecoreApiHost')}`], - sitecoreEdgeUrl: process.env[`${constantCase('sitecoreEdgeUrl')}`], - sitecoreEdgeContextId: process.env[`${constantCase('sitecoreEdgeContextId')}`], siteName: process.env[`${constantCase('siteName')}`] || process.env[`${constantCase('jssAppName')}`], graphQLEndpointPath: process.env[`${constantCase('graphQLEndpointPath')}`], diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/Layout.tsx b/packages/create-sitecore-jss/src/templates/nextjs/src/Layout.tsx index 80f6c90924..c3679bd1b0 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/src/Layout.tsx +++ b/packages/create-sitecore-jss/src/templates/nextjs/src/Layout.tsx @@ -9,8 +9,6 @@ import { import { getPublicUrl } from '@sitecore-jss/sitecore-jss-nextjs/utils'; import Navigation from 'src/Navigation'; import Scripts from 'src/Scripts'; -// The bundle imports external (BYOC) components into the app and makes sure they are ready to be used. -import BYOC from 'src/byoc'; // Prefix public assets with a public URL to enable compatibility with Sitecore editors. // If you're not supporting Sitecore editors, you can remove this. @@ -34,7 +32,6 @@ const Layout = ({ layoutData, headLinks }: LayoutProps): JSX.Element => { return ( <> - {fields.pageTitle.value.toString() || 'Page'} diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/config.ts b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/config.ts index 88ec0aaa07..83a2596423 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/config.ts @@ -4,8 +4,6 @@ export interface JssConfig extends Record { sitecoreApiKey?: string; sitecoreApiHost?: string; - sitecoreEdgeUrl?: string; - sitecoreEdgeContextId?: string; siteName?: string; graphQLEndpointPath?: string; defaultLanguage?: string; diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/graphql-client-factory/create.ts b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/graphql-client-factory/create.ts index bc76efc74f..b3bf7017bb 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/graphql-client-factory/create.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/graphql-client-factory/create.ts @@ -1,7 +1,6 @@ import { GraphQLRequestClientFactoryConfig, - GraphQLRequestClient, - getEdgeProxyContentUrl + GraphQLRequestClient } from '@sitecore-jss/sitecore-jss-nextjs/graphql'; import { JssConfig } from 'lib/config'; @@ -13,18 +12,14 @@ import { JssConfig } from 'lib/config'; export const createGraphQLClientFactory = (config: JssConfig) => { let clientConfig: GraphQLRequestClientFactoryConfig; - if (config.sitecoreEdgeContextId) { - clientConfig = { - endpoint: getEdgeProxyContentUrl(config.sitecoreEdgeContextId, config.sitecoreEdgeUrl), - }; - } else if (config.graphQLEndpoint && config.sitecoreApiKey) { + if (config.graphQLEndpoint && config.sitecoreApiKey) { clientConfig = { endpoint: config.graphQLEndpoint, apiKey: config.sitecoreApiKey, }; } else { throw new Error( - 'Please configure either your sitecoreEdgeContextId, or your graphQLEndpoint and sitecoreApiKey.' + 'Please configure your graphQLEndpoint and sitecoreApiKey.' ); } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/monorepo.js b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/monorepo.js index f1ce7c9a26..f6f54147ea 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/monorepo.js +++ b/packages/create-sitecore-jss/src/templates/nextjs/src/lib/next-config/plugins/monorepo.js @@ -1,6 +1,3 @@ -const path = require('path'); -const CWD = process.cwd(); - /** * @param {import('next').NextConfig} nextConfig */ @@ -10,12 +7,6 @@ const monorepoPlugin = (nextConfig = {}) => { if (options.isServer) { config.externals = ['react', 'vertx', ...config.externals]; } - // Monorepo support for @sitecore-feaas/clientside/react - config.resolve.alias['@sitecore-feaas/clientside/react'] = path.resolve( - CWD, options.isServer ? - './node_modules/@sitecore-feaas/clientside/dist/node/react.cjs' : - './node_modules/@sitecore-feaas/clientside/dist/browser/react.esm.js' - ); // Overload the Webpack config if it was already overloaded if (typeof nextConfig.webpack === 'function') { diff --git a/packages/sitecore-jss/src/site/graphql-siteinfo-service.test.ts b/packages/sitecore-jss/src/site/graphql-siteinfo-service.test.ts index d9c95db7d4..53f61b98a5 100644 --- a/packages/sitecore-jss/src/site/graphql-siteinfo-service.test.ts +++ b/packages/sitecore-jss/src/site/graphql-siteinfo-service.test.ts @@ -1,10 +1,17 @@ +/* eslint-disable no-unused-expressions */ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { expect } from 'chai'; +import { expect, spy, use } from 'chai'; +import spies from 'chai-spies'; import nock from 'nock'; import { GraphQLSiteInfoService, GraphQLSiteInfoResult } from './graphql-siteinfo-service'; import { GraphQLRequestClient, PageInfo } from '../graphql'; +import debugApi from 'debug'; +import debug from '../debug'; + +use(spies); describe('GraphQLSiteInfoService', () => { + let debugNamespaces: string; const endpoint = 'http://site'; const apiKey = 'some-api-key'; @@ -63,8 +70,23 @@ describe('GraphQLSiteInfoService', () => { }, }; + before(() => { + debugNamespaces = debugApi.disable(); + debugApi.enable(debug.multisite.namespace); + }); + + beforeEach(() => { + spy.on(debug.multisite, 'log', () => true); + }); + afterEach(() => { nock.cleanAll(); + spy.restore(debug.multisite); + delete process.env.SITECORE; + }); + + after(() => { + debugApi.enable(debugNamespaces); }); const mockSiteInfoRequest = (response: { [key: string]: unknown }) => { @@ -269,4 +291,16 @@ describe('GraphQLSiteInfoService', () => { const resultCached = await service.fetchSiteInfo(); expect(resultCached).to.deep.equal([]); }); + + it('should skip on XM Cloud', async () => { + process.env.SITECORE = 'true'; + nock(endpoint) + .post('/') + .reply(200, emptyResponse); + const service = new GraphQLSiteInfoService({ apiKey: apiKey, endpoint: endpoint }); + const result = await service.fetchSiteInfo(); + expect(result).to.deep.equal([]); + expect(debug.multisite.log, 'log debug message').to.be.called.once; + expect(nock.isDone(), 'skip request').to.be.false; + }); }); diff --git a/packages/sitecore-jss/src/site/graphql-siteinfo-service.ts b/packages/sitecore-jss/src/site/graphql-siteinfo-service.ts index 8c57ca256c..c0b87758f4 100644 --- a/packages/sitecore-jss/src/site/graphql-siteinfo-service.ts +++ b/packages/sitecore-jss/src/site/graphql-siteinfo-service.ts @@ -134,6 +134,10 @@ export class GraphQLSiteInfoService { if (cachedResult) { return cachedResult; } + if (process.env.SITECORE) { + debug.multisite('Skipping site information fetch (building on XM Cloud)'); + return []; + } const results: SiteInfo[] = []; let hasNext = true; diff --git a/scripts/samples.json b/scripts/samples.json index 2f647ccfa7..b0eb76be3a 100644 --- a/scripts/samples.json +++ b/scripts/samples.json @@ -22,10 +22,10 @@ }, { "initializers": [ - "nextjs", "nextjs-styleguide", "nextjs-personalize" + "nextjs", "nextjs-styleguide", "nextjs-xmcloud" ], "args": { - "appName": "nextjs-styleguide-personalize", + "appName": "nextjs-styleguide-xmcloud", "fetchWith": "GraphQL", "prerender": "SSG" }