Skip to content

Commit

Permalink
[Next.js] Introduce nextjs-xmcloud Initializer Template (#1653)
Browse files Browse the repository at this point in the history
* 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 <BYOC/> from sxa Layout.tsx

* fix for PR comment

(cherry picked from commit 19f5c22)
  • Loading branch information
ambrauer authored and art-alexeyenko committed Nov 8, 2023
1 parent f0f14fc commit 9aa7d80
Show file tree
Hide file tree
Showing 38 changed files with 253 additions and 143 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,29 @@ import {
incompatibleAddonsMsg,
} from '../../common';

export default class NextjsPersonalizeInitializer implements Initializer {
export default class NextjsXMCloudInitializer implements Initializer {
get isBase(): boolean {
return false;
}

async init(args: ClientAppArgs) {
const pkg = openPackageJson(`${args.destination}${sep}package.json`);

// TODO: prompts for Personalize and argument types
// const answers = await prompt<StyleguideAnswer>(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);

if (
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 = {
Expand Down
71 changes: 44 additions & 27 deletions packages/create-sitecore-jss/src/initializers/nextjs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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 (
Expand Down
19 changes: 10 additions & 9 deletions packages/create-sitecore-jss/src/initializers/nextjs/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum Prerender {

export type NextjsAnswer = ClientAppAnswer & {
prerender: Prerender;
xmcloud: boolean;
};

const DEFAULT_PRERENDER = Prerender.SSG;
Expand All @@ -29,6 +30,15 @@ export const prompts: QuestionCollection<NextjsAnswer> = [
return !answers.prerender;
},
},
{
type: 'confirm',
name: 'xmcloud',
message: 'Are you building for Sitecore XM Cloud?',
default: false,
when: (answers: NextjsAnswer): boolean => {
return !answers.yes;
},
},
];

/**
Expand All @@ -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');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -37,7 +35,6 @@ const Layout = ({ layoutData, headLinks }: LayoutProps): JSX.Element => {
return (
<>
<Scripts />
<BYOC />
<Head>
<title>{fields?.Title?.value?.toString() || 'Page'}</title>
<link rel="icon" href={`${publicUrl}/favicon.ico`} />
Expand Down
Original file line number Diff line number Diff line change
@@ -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=
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"dependencies": {
"@sitecore/components": "~1.0.19",
"@sitecore/engage": "^1.4.1",
"@sitecore-feaas/clientside": "^0.4.12"
}
}
Original file line number Diff line number Diff line change
@@ -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();
Original file line number Diff line number Diff line change
@@ -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 (
<>
<BYOC />
<CdpPageView />
</>
);
Expand Down
Loading

0 comments on commit 9aa7d80

Please sign in to comment.