Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

 #534241: [sitecore-jss-nextjs][middleware-redirect]added handling with token $siteLang #1454

Merged
merged 5 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Our versioning strategy is as follows:
* `[sitecore-jss-react]` `[sitecore-jss-nextjs]` FEaaS component will render 'staged' variant for editing and preview and 'published' variant for live site by default, unless variant is overriden via rendering parameters. ([#1433](https://github.com/Sitecore/jss/pull/1433))
* `[templates/nextjs]` `[templates/angular]` `[templates/react]` `[templates/vue]` Pre-push hook for lint check ([#1427](https://github.com/Sitecore/jss/pull/1427))
([#1442](https://github.com/Sitecore/jss/pull/1442)) ([#1444](https://github.com/Sitecore/jss/pull/1444))
* `[sitecore-jss-nextjs] Add a new handling for token $siteLang(context site language) in middleware redirect ([#1454](https://github.com/Sitecore/jss/pull/1454))

### 🧹 Chores

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs/site';
import config from 'temp/config';
import { SiteResolverPlugin } from '..';

class DefaultPlugin implements SiteResolverPlugin {
exec(sites: SiteInfo[]): SiteInfo[] {
/**
* remove default logic. it breaks for getting site info about context site language
sc-ruslanmatkovskyi marked this conversation as resolved.
Show resolved Hide resolved
*/
return sites;
}
}

export const defaultPlugin = new DefaultPlugin();
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('RedirectsMiddleware', () => {
const referrer = 'http://localhost:3000';
const hostname = 'foo.net';
const siteName = 'nextjs-app';
const sitesFromConfigFile = [{"name":"basicSite","hostName":"*","language":"en"},{"name":"nextjs-app","hostName":"*","language":"da"}];

const createRequest = (props: any = {}) => {
const req = {
Expand Down Expand Up @@ -668,6 +669,66 @@ describe('RedirectsMiddleware', () => {
nextRedirectStub.restore();
});

it('should redirect uses token $siteLang in target url', async () => {
const setCookies = () => {};
const res = createResponse({
url: 'http://localhost:3000/da/found',
status: 301,
setCookies,
});
const nextRedirectStub = sinon.stub(NextResponse, 'redirect').callsFake((url, status) => {
return ({
url,
status,
cookies: { set: setCookies },
headers: res.headers,
} as unknown) as NextResponse;
});
const req = createRequest({
nextUrl: {
pathname: '/not-found',
search: 'abc=def',
href: 'http://localhost:3000/found',
sc-ruslanmatkovskyi marked this conversation as resolved.
Show resolved Hide resolved
locale: 'en',
clone() {
return Object.assign({}, req.nextUrl);
},
},
});

const { middleware, fetchRedirects, siteResolver } = createMiddleware({
pattern: '/not-found/',
target: 'http://localhost:3000/$siteLang/found',
redirectType: REDIRECT_TYPE_301,
isQueryStringPreserved: false,
locale: 'en',
sites: sitesFromConfigFile,
});

const finalRes = await middleware.getHandler()(req);

validateDebugLog('redirects middleware start: %o', {
hostname: 'foo.net',
language: 'en',
pathname: '/not-found',
});

validateDebugLog('redirects middleware end: %o', {
headers: {},
redirected: undefined,
status: 301,
url: 'http://localhost:3000/da/found',
});

expect(siteResolver.getByHost).to.be.calledWith(hostname);
// eslint-disable-next-line no-unused-expressions
expect(fetchRedirects.called).to.be.true;
expect(finalRes).to.deep.equal(res);
expect(finalRes.status).to.equal(res.status);

nextRedirectStub.restore();
});

it('should return default response if no redirect type defined', async () => {
const setCookies = () => {};
const res = createResponse({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
import { debug } from '@sitecore-jss/sitecore-jss';
import { MiddlewareBase, MiddlewareBaseConfig } from './middleware';

const REGEXP_CONTEXT_SITE_LANG = new RegExp(/\$siteLang/, 'gi');

/**
* extended RedirectsMiddlewareConfig config type for RedirectsMiddleware
*/
Expand Down Expand Up @@ -44,11 +46,19 @@ export class RedirectsMiddleware extends MiddlewareBase {
}

/**
* Gets the Next.js API route handler
* Gets the Next.js middleware handler with error handling
* @returns route handler
*/
public getHandler(): (req: NextRequest, res?: NextResponse) => Promise<NextResponse> {
return this.handler;
return async (req, res) => {
try {
return await this.handler(req, res);
} catch (error) {
console.log('Redirect middleware failed:');
console.log(error);
return res || NextResponse.next();
}
};
}

private handler = async (req: NextRequest, res?: NextResponse): Promise<NextResponse> => {
Expand Down Expand Up @@ -86,6 +96,14 @@ export class RedirectsMiddleware extends MiddlewareBase {
return res || NextResponse.next();
}

// Find context site language and replace token
if (REGEXP_CONTEXT_SITE_LANG.test(existsRedirect.target)) {
existsRedirect.target = existsRedirect.target.replace(
REGEXP_CONTEXT_SITE_LANG,
site.language
);
}

sc-ruslanmatkovskyi marked this conversation as resolved.
Show resolved Hide resolved
const url = req.nextUrl.clone();
const absoluteUrlRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
if (absoluteUrlRegex.test(existsRedirect.target)) {
Expand Down Expand Up @@ -145,15 +163,14 @@ export class RedirectsMiddleware extends MiddlewareBase {
siteName: string
): Promise<RedirectInfo | undefined> {
const redirects = await this.redirectsService.fetchRedirects(siteName);
const tragetURL = `${req.nextUrl.pathname}`.toLowerCase();
const targetQS = `?${req.nextUrl.search || ''}`.toLowerCase();
const tragetURL = req.nextUrl.pathname;
const targetQS = `?${req.nextUrl.search || ''}`;

return redirects.length
? redirects.find((redirect: RedirectInfo) => {
const pattern = `/^/${redirect.pattern
.toLowerCase()
.replace(/^\/|\/$/g, '')
.replace(/^\^|\$$/g, '')}$/`;
.replace(/^\^|\$$/g, '')}$/gi`;

return (
(regexParser(pattern).test(tragetURL) ||
Expand Down