Skip to content

Commit

Permalink
[Next.js] Personalize Middleware updates to handle Component A/B Test…
Browse files Browse the repository at this point in the history
…ing (#1848)

* updates to personalize middleware and supporting utilities / services for component A/B testing

* upgrade to @sitecore-cloudsdk/personalize / events 0.3.1 and add passing of variantIds to personalize call from middleware

* update CHANGELOG and upgrade docs

* Updates per PR feedback

* adjusted test based on PR feedback

* remove only
  • Loading branch information
ambrauer authored Jul 23, 2024
1 parent 855f04c commit bd5ebb3
Show file tree
Hide file tree
Showing 17 changed files with 546 additions and 142 deletions.
9 changes: 3 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Our versioning strategy is as follows:
### 🐛 Bug Fixes

* `[templates/nextjs]` `[templates/react]` `[templates/vue]` `[templates/angular]` Changed formatting in temp/config to prevent parse issues in Unix systems ([#1787](https://github.com/Sitecore/jss/pull/1787))([#1791](https://github.com/Sitecore/jss/pull/1791))
* `[sitecore-jss]` `GraphQLRequestClientFactory` type is updated and `config` parameter is now optional. Since it should match `GraphQLRequestClient.createClientFactory` method return type ([#1806](https://github.com/Sitecore/jss/pull/1806))
* `[templates/nextjs-sxa]` The banner variant of image component is fixed with supporting metadata mode. ([#1826](https://github.com/Sitecore/jss/pull/1826))
* `[sitecore-jss]` `[sitecore-jss-react]` DateField empty value is not treated as empty ([#1836](https://github.com/Sitecore/jss/pull/1836))
* `[templates/nextjs-sxa]` Fix styles of title component in metadata mode. ([#1839](https://github.com/Sitecore/jss/pull/1839))
Expand All @@ -26,7 +27,7 @@ Our versioning strategy is as follows:
* `[sitecore-jss]` _GraphQLRequestClient_ now can accept custom 'headers' in the constructor or via _createClientFactory_ ([#1806](https://github.com/Sitecore/jss/pull/1806))
* `[templates/nextjs]` Removed cors header for API endpoints from _lib/next-config/plugins/cors-header_ plugin since cors is handled by API handlers / middlewares ([#1806](https://github.com/Sitecore/jss/pull/1806))
* `[sitecore-jss-nextjs]` Updates to Next.js editing integration to further support secure hosting scenarios (on XM Cloud & Vercel) ([#1832](https://github.com/Sitecore/jss/pull/1832))
* `[templates/nextjs-xmcloud]` `[sitecore-jss]` AB testing and componente level personalization support. ([#1844](https://github.com/Sitecore/jss/pull/1844))([1847](https://github.com/Sitecore/jss/pull/1847))
* `[templates/nextjs-xmcloud]` `[sitecore-jss]` A/B testing and component-level personalization support. ([#1844](https://github.com/Sitecore/jss/pull/1844))([#1847](https://github.com/Sitecore/jss/pull/1847))([#1848](https://github.com/Sitecore/jss/pull/1848))
* `[sitecore-jss]` `[nextjs-xmcloud]` DictionaryService can now use a `site` GraphQL query instead of `search` one to improve performance. This is currently only available for XMCloud deployments and is enabled with `nextjs-xmcloud` add-on by default ([#1804](https://github.com/Sitecore/jss/pull/1804))([#1846](https://github.com/Sitecore/jss/pull/1846))([commit](https://github.com/Sitecore/jss/commit/5813a2df8ad6a9ee63dd74d5f206ed4b4f758753))([commit](https://github.com/Sitecore/jss/commit/d0ea3ac02c78343b5dd60277dbf7403410794a49))([commit](https://github.com/Sitecore/jss/commit/307b905ed60d7fff44b2dc799fd78c0842af6fbd))([commit](https://github.com/Sitecore/jss/commit/66164a42263aac8b55f0c5e47eda4bd4d7a72e87))
* `[templates/nextjs-sxa]` nextjs-sxa components now use the NextImage component instead of the react Image component from JSS lib for image optimization ([#1843](https://github.com/Sitecore/jss/pull/1843))

Expand All @@ -52,11 +53,7 @@ Our versioning strategy is as follows:
* Updated Angular and core dependencies to ~17.3.11
* Updated Typescript to ~5.2.2
* Updated import statements from zone.js/dist/zone-node to zone.js

### 🐛 Bug Fixes

* `[sitecore-jss]` `GraphQLRequestClientFactory` type is updated and `config` parameter is now optional. Since it should match `GraphQLRequestClient.createClientFactory` method return type ([#1806](https://github.com/Sitecore/jss/pull/1806))

* `[sitecore-jss/personalize]` `[sitecore-jss-nextjs]` `CdpHelper.getPersonalizedRewrite` signature changed to accept `variantIds: string[]` as second parameter. `CdpHelper.getContentId` was renamed to `CdpHelper.getPageFriendlyId`. ([#1848](https://github.com/Sitecore/jss/pull/1848))

### 🧹 Chores

Expand Down
13 changes: 13 additions & 0 deletions docs/upgrades/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,17 @@
personalizeData.componentVariantIds
);
```
* Update _lib/middleware/plugins/personalize.ts_ `PersonalizeMiddleware` constructor signature, moving `scope` from `cdpConfig` to the root. For now this option will continue working but is marked as deprecated. It will be removed in the next major version release.
```ts
this.personalizeMiddleware = new PersonalizeMiddleware({
...
cdpConfig: {
...
scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE, // REMOVE
},
scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE, // ADD
});
```
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"@sitecore/components": "^1.1.10",
"@sitecore-cloudsdk/events": "^0.3.0",
"@sitecore-cloudsdk/events": "^0.3.1",
"@sitecore-feaas/clientside": "^0.5.17"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { siteResolver } from 'lib/site-resolver';

/**
* This is the personalize middleware plugin for Next.js.
* It is used to enable Sitecore personalization of pages in Next.js.
* It is used to enable Sitecore personalization and A/B testing of pages in Next.js.
*
* The `PersonalizeMiddleware` will
* 1. Make a call to the Sitecore Experience Edge to get the personalization information about the page.
* 2. Based on the response, make a call to the Sitecore CDP (with request/user context) to determine the page variant.
* 3. Rewrite the response to the specific page variant.
* 1. Call Sitecore Experience Edge to get the personalization information about the page.
* 2. Based on the response, call Sitecore Personalize (with request/user context) to determine the page / component variant(s).
* 3. Rewrite the response to the specific page / component variant(s).
*/
class PersonalizePlugin implements MiddlewarePlugin {
private personalizeMiddleware: PersonalizeMiddleware;
Expand All @@ -30,7 +30,6 @@ class PersonalizePlugin implements MiddlewarePlugin {
(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT &&
parseInt(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT)) ||
400,
scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
},
// Configuration for your Sitecore CDP endpoint
cdpConfig: {
Expand All @@ -41,6 +40,8 @@ class PersonalizePlugin implements MiddlewarePlugin {
parseInt(process.env.PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT)) ||
400,
},
// Optional Sitecore Personalize scope identifier.
scope: process.env.NEXT_PUBLIC_PERSONALIZE_SCOPE,
// This function determines if the middleware should be turned off.
// IMPORTANT: You should implement based on your cookie consent management solution of choice.
// You may wish to keep it disabled while in development mode.
Expand Down
6 changes: 3 additions & 3 deletions packages/sitecore-jss-nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"url": "https://github.com/sitecore/jss/issues"
},
"devDependencies": {
"@sitecore-cloudsdk/personalize": "^0.3.0",
"@sitecore-cloudsdk/personalize": "^0.3.1",
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/chai-string": "^1.4.2",
Expand Down Expand Up @@ -65,8 +65,8 @@
"typescript": "~4.9.4"
},
"peerDependencies": {
"@sitecore-cloudsdk/events": "^0.3.0",
"@sitecore-cloudsdk/personalize": "^0.3.0",
"@sitecore-cloudsdk/events": "^0.3.1",
"@sitecore-cloudsdk/personalize": "^0.3.1",
"next": "^14.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
Expand Down
31 changes: 31 additions & 0 deletions packages/sitecore-jss-nextjs/src/middleware/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,37 @@ describe('MiddlewareBase', () => {
});
});

describe('isPrefetch', () => {
it('should return true when purpose header is prefetch', () => {
const middleware = new SampleMiddleware({ siteResolver: new MockSiteResolver([]) });
const req = createReq({
headerValues: {
purpose: 'prefetch',
},
});

expect(middleware['isPrefetch'](req)).to.equal(true);
});

it('should return true when Next-Router-Prefetch header is 1', () => {
const middleware = new SampleMiddleware({ siteResolver: new MockSiteResolver([]) });
const req = createReq({
headerValues: {
'Next-Router-Prefetch': '1',
},
});

expect(middleware['isPrefetch'](req)).to.equal(true);
});

it('should return false when required header is not provided', () => {
const middleware = new SampleMiddleware({ siteResolver: new MockSiteResolver([]) });
const req = createReq();

expect(middleware['isPrefetch'](req)).to.equal(false);
});
});

describe('excludeRoute', () => {
it('default', () => {
const middleware = new SampleMiddleware({ siteResolver: new MockSiteResolver([]) });
Expand Down
13 changes: 13 additions & 0 deletions packages/sitecore-jss-nextjs/src/middleware/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ export abstract class MiddlewareBase {
);
}

/**
* Determines if the request is a Next.js (next/link) prefetch request
* @param {NextRequest} req request
* @returns {boolean} is prefetch
*/
protected isPrefetch(req: NextRequest): boolean {
return (
// eslint-disable-next-line prettier/prettier
req.headers.get('purpose') === 'prefetch' || // Pages Router
req.headers.get('Next-Router-Prefetch') === '1' // App Router
);
}

protected excludeRoute(pathname: string) {
return (
pathname.startsWith('/api/') || // Ignore Next.js API calls
Expand Down
Loading

0 comments on commit bd5ebb3

Please sign in to comment.