Skip to content

Commit

Permalink
[Next.js][Multi-site] Multi-site middleware plugin (#1279)
Browse files Browse the repository at this point in the history
* jss-cli unit test coverage: first batch

* jss-cli unit test coverage: second batch

* jss-cli unit tests: second batch

* fix expected output for test not to fail across environments

* lint

* dev-tools unit test coverage first batch

* dev-tools unit test coverage: second batch

* resolve-scjssconfig test placeholder (for the future!)

* exclude index file from jss-vue test coverage (#1266)

* version v21.1.0-canary.58 [skip ci]

* fix test for scjssconfig resolving

* Update packages/sitecore-jss-dev-tools/src/manifest/manifest-manager.test.ts

Co-authored-by: Adam Brauer <400763+ambrauer@users.noreply.github.com>

* Update packages/sitecore-jss-dev-tools/src/manifest/manifest-manager.test.ts

Co-authored-by: Adam Brauer <400763+ambrauer@users.noreply.github.com>

* lint

* adding test data for scjssconfig

* some improvements to reject logic in resolve scjssconfig

* lint numero 2

* version v21.1.0-canary.59 [skip ci]

* #556667: fixed urls for sitemap

* version v21.1.0-canary.60 [skip ci]

* final batch

* re-gen yarn.lock

* yarn.lock re-update

* version v21.1.0-canary.61 [skip ci]

* #552985: fixed header styles

* version v21.1.0-canary.62 [skip ci]

* #546298: fixed style for showing hidden components

* version v21.1.0-canary.63 [skip ci]

* SiteResolver.resolve updates: removed 'language' from site resolution logic, return SiteInfo instead of site name

* [Next.js][Multi-site] Multi-site middleware plugin

* #559044: fixed rendering dynamic placeholder (#1278)

* version v21.1.0-canary.64 [skip ci]

* Adjust with latest site resolver changes

* adjust

* Add latest changes

* Extra comment

* extra fix

* Extend unit tests

* Revert cookie set change

* Use response cookies instead of request

* Adjust changes according to review

* Adjust changes according to review

* lint fix

Co-authored-by: Artem Alexeyenko <ala@sitecore.net>
Co-authored-by: Automated Build <builds@sitecore.com>
Co-authored-by: Adam Brauer <400763+ambrauer@users.noreply.github.com>
Co-authored-by: Ruslan Matkovskyi <rusm@sitecore.net>
Co-authored-by: Ruslan Matkovskyi <100142572+matkovskyi@users.noreply.github.com>
  • Loading branch information
6 people authored Jan 10, 2023
1 parent 5c2d3c0 commit bc26952
Show file tree
Hide file tree
Showing 70 changed files with 3,018 additions and 228 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"packages/*",
"samples/*"
],
"version": "21.1.0-canary.57",
"version": "21.1.0-canary.64",
"npmClient": "yarn",
"useWorkspaces": true
}
2 changes: 1 addition & 1 deletion packages/create-sitecore-jss/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-sitecore-jss",
"version": "21.1.0-canary.57",
"version": "21.1.0-canary.64",
"description": "Sitecore JSS initializer",
"bin": "./dist/index.js",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { NextRequest, NextResponse } from 'next/server';
import { MultisiteMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import { siteResolver } from 'lib/site-resolver';
import { MiddlewarePlugin } from '..';

/**
* This is the multisite middleware plugin for Next.js.
* It is used to enable Sitecore multisite in Next.js.
*
* The `MultisiteMiddleware` will
* 1. Based on provided hostname and sites information, resolve site.
* 2. Rewrite the response to the specific site.
* 3. Set `sc_site` cookie with site name and `x-sc-rewrite` header with rewritten path to be reused in following middlewares.
*/
class MultisitePlugin implements MiddlewarePlugin {
private multisiteMiddleware: MultisiteMiddleware;

// Multisite middleware has to be executed first
order = -1;

constructor() {
this.multisiteMiddleware = new MultisiteMiddleware({
// This function determines if a route should be excluded from site resolution.
// Certain paths are ignored by default (e.g. files and Next.js API routes), but you may wish to exclude more.
// This is an important performance consideration since Next.js Edge middleware runs on every request.
excludeRoute: () => false,
// This function resolves site based on hostname
getSite: siteResolver.getByHost,
});
}

async exec(req: NextRequest, res?: NextResponse): Promise<NextResponse> {
return this.multisiteMiddleware.getHandler()(req, res);
}
}

export const multisitePlugin = new MultisitePlugin();
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SiteResolver, SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs';
import { SiteResolver, SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import config from 'temp/config';

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PersonalizeMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/middlew
import { MiddlewarePlugin } from '..';
import config from 'temp/config';
import { PosResolver } from 'lib/pos-resolver';
import { siteResolver } from 'lib/site-resolver';

/**
* This is the personalize middleware plugin for Next.js.
Expand All @@ -26,7 +27,6 @@ class PersonalizePlugin implements MiddlewarePlugin {
edgeConfig: {
endpoint: config.graphQLEndpoint,
apiKey: config.sitecoreApiKey,
siteName: config.jssAppName,
timeout:
(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT &&
parseInt(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT)) ||
Expand All @@ -52,6 +52,8 @@ class PersonalizePlugin implements MiddlewarePlugin {
// This function resolves point of sale for cdp calls.
// Point of sale may differ by locale and middleware will use request language to get the correct value every time it's invoked
getPointOfSale: PosResolver.resolve,
// This function resolves site based on hostname
getSite: siteResolver.getByHost,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
.prod-mode {
#header {
display: flex;
flex-direction: column;

@include respond-to(mobile-large) {
padding-bottom: 0;
Expand Down Expand Up @@ -33,7 +32,7 @@ header {
padding-top: 0;
flex-direction: column-reverse;

.title {
.bs-title {
padding-left: 0;
text-align: center;
margin-top: -5px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
width: 100%;
}

.component {
position: relative;
}

.container {
padding: 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from 'next/server';
import { RedirectsMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import config from 'temp/config';
import { MiddlewarePlugin } from '..';
import { siteResolver } from 'lib/site-resolver';

class RedirectsPlugin implements MiddlewarePlugin {
private redirectsMiddleware: RedirectsMiddleware;
Expand All @@ -11,7 +12,6 @@ class RedirectsPlugin implements MiddlewarePlugin {
this.redirectsMiddleware = new RedirectsMiddleware({
endpoint: config.graphQLEndpoint,
apiKey: config.sitecoreApiKey,
siteName: config.jssAppName,
// These are all the locales you support in your application.
// These should match those in your next.config.js (i18n.locales).
locales: ['en'],
Expand All @@ -22,6 +22,8 @@ class RedirectsPlugin implements MiddlewarePlugin {
// This function determines if the middleware should be turned off.
// By default it is disabled while in development mode.
disabled: () => process.env.NODE_ENV === 'development',
// This function resolves site based on hostname
getSite: siteResolver.getByHost,
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AxiosResponse } from 'axios';
import type { NextApiRequest, NextApiResponse } from 'next';
import { AxiosDataFetcher, GraphQLSitemapXmlService } from '@sitecore-jss/sitecore-jss-nextjs';
import { AxiosDataFetcher, GraphQLSitemapXmlService, getPublicUrl } from '@sitecore-jss/sitecore-jss-nextjs';
import { siteResolver } from 'lib/site-resolver';
import config from 'temp/config';

Expand Down Expand Up @@ -53,13 +53,14 @@ const sitemapApi = async (
}

const SitemapLinks = sitemaps
.map(
(item) =>
`<sitemap>
<loc>${item}</loc>
</sitemap>
`
)
.map((item) => {
const parseUrl = item.split('/');
const lastSegment = parseUrl[parseUrl.length - 1];

return `<sitemap>
<loc>${getPublicUrl()}/${lastSegment}</loc>
</sitemap>`;
})
.join('');

res.setHeader('Content-Type', 'text/xml;charset=utf-8');
Expand Down
2 changes: 1 addition & 1 deletion packages/sitecore-jss-angular-schematics/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sitecore-jss/sitecore-jss-angular-schematics",
"version": "21.1.0-canary.57",
"version": "21.1.0-canary.64",
"description": "Scaffolding schematics for Sitecore JSS Angular apps",
"scripts": {
"build": "tsc -p tsconfig.json",
Expand Down
4 changes: 2 additions & 2 deletions packages/sitecore-jss-angular/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sitecore-jss/sitecore-jss-angular",
"version": "21.1.0-canary.57",
"version": "21.1.0-canary.64",
"description": "",
"scripts": {
"build": "ng-packagr -p ng-package.json",
Expand Down Expand Up @@ -58,7 +58,7 @@
"rxjs": "~6.6.6"
},
"dependencies": {
"@sitecore-jss/sitecore-jss": "^21.1.0-canary.57"
"@sitecore-jss/sitecore-jss": "^21.1.0-canary.64"
},
"main": "dist/bundles/sitecore-jss-sitecore-jss-angular.umd.js",
"module": "dist/fesm2015/sitecore-jss-sitecore-jss-angular.js",
Expand Down
7 changes: 6 additions & 1 deletion packages/sitecore-jss-cli/.nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"**/*.test.ts",
"src/test-data",
"dist",
"src/test.ts"
"src/test.ts",
"**/create.ts",
"**/deploy.package.ts",
"**/index.global.ts",
"**/index.ts",
"**/cli.global.ts"
],
"all": true,
"reporter": [
Expand Down
8 changes: 4 additions & 4 deletions packages/sitecore-jss-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sitecore-jss/sitecore-jss-cli",
"version": "21.1.0-canary.57",
"version": "21.1.0-canary.64",
"description": "Sitecore JSS command-line",
"main": "dist/cjs/cli.js",
"module": "dist/esm/cli.js",
Expand All @@ -12,8 +12,8 @@
"lint": "eslint ./src/**/*.ts",
"prepublishOnly": "npm run build",
"jss": "node ./dist/cjs/bin/jss.js",
"test": "mocha --require ts-node/register \"./src/**/*.test.ts\"",
"coverage": "nyc npm test"
"test": "mocha --require ts-node/register/transpile-only \"./src/**/*.test.ts\"",
"coverage": "nyc --require ts-node/register/transpile-only npm test"
},
"engines": {
"node": ">=12",
Expand All @@ -33,7 +33,7 @@
"url": "https://github.com/sitecore/jss/issues"
},
"dependencies": {
"@sitecore-jss/sitecore-jss-dev-tools": "^21.1.0-canary.57",
"@sitecore-jss/sitecore-jss-dev-tools": "^21.1.0-canary.64",
"chalk": "^2.4.2",
"cross-spawn": "^7.0.0",
"dotenv": "^16.0.1",
Expand Down
73 changes: 73 additions & 0 deletions packages/sitecore-jss-cli/src/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* eslint-disable no-unused-expressions */
import { expect } from 'chai';
import sinon from 'sinon';
import { getPackageScriptCommands, makeCommand } from './cli';
import * as resolvePkg from './resolve-package';
import * as packageScript from './run-package-script';
import { Arguments } from 'yargs';

describe('cli', () => {
describe('getPackageScriptCommands', async () => {
afterEach(() => {
sinon.restore();
});
const packageJson = {
scripts: {
first: 'do --this',
second: 'do --that',
third: 'do --all',
},
};

it('should read scripts from package.json and return result with handlers', async () => {
sinon.stub(resolvePkg, 'default').resolves(packageJson);

const result = await getPackageScriptCommands();
const runScriptStub = sinon.stub(packageScript, 'default');
const mockArgs: Arguments = {
_: ['arg1', 'arg2'],
$0: '',
};

expect(Object.keys(packageJson.scripts)).to.be.deep.equal(Object.keys(result));
for (const key of Object.keys(result)) {
const expectedCommand = makeCommand(key);
for (const field of Object.keys(expectedCommand)) {
if (typeof expectedCommand[field] === 'function') {
expectedCommand[field](mockArgs);
expect(runScriptStub.called).to.be.true;
} else {
expect(result[key][field]).to.deep.equal(expectedCommand[field]);
}
}
}
});

it('should return empty result when package.json contents are empty', async () => {
const emptyPackage = {};

sinon.stub(resolvePkg, 'default').resolves(emptyPackage);

const result = await getPackageScriptCommands();

expect(result).to.deep.equal(emptyPackage);
});

it('should ignore jss script entry', async () => {
const packageJson = {
scripts: {
jss: 'do --this',
second: 'do --that',
third: 'do --all',
},
};
const { jss: _, ...expectedScripts } = packageJson.scripts;

sinon.stub(resolvePkg, 'default').resolves(packageJson);

const result = await getPackageScriptCommands();

expect(Object.keys(expectedScripts)).to.be.deep.equal(Object.keys(result));
});
});
});
33 changes: 20 additions & 13 deletions packages/sitecore-jss-cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as commands from './scripts';
/**
* Get package script commands
*/
async function getPackageScriptCommands() {
export async function getPackageScriptCommands() {
const packageJson = await resolvePackage();
const result: { [key: string]: CommandModule } = {};

Expand All @@ -20,25 +20,32 @@ async function getPackageScriptCommands() {
return;
}

const command = {
command: script,
describe: 'package.json script',
builder: {},
disableStrictArgs: true,
handler: (argv: Arguments) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((argv as any)._[0]) {
runPackageScript(process.argv.slice(2));
}
},
};
const command = makeCommand(script);

result[script] = command;
});

return result;
}

/**
* @param script
*/
export function makeCommand(script: string) {
return {
command: script,
describe: 'package.json script',
builder: {},
disableStrictArgs: true,
handler: (argv: Arguments) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((argv as any)._[0]) {
runPackageScript(process.argv.slice(2));
}
},
};
}

/**
* implements CLI commands when executed from a local node_modules folder
*/
Expand Down
Loading

0 comments on commit bc26952

Please sign in to comment.