-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/519338 redirect nextjs (#969)
* #519338: implement redirect service and middleware * #519338 refactoring redirects service. added unit tests * #519338 moved redirects service into sitecore-jss * #519338 fixed graphql-request for nextJs middleware and tests * #519338 modified yarn.lock * #519338 fixed test for sitecore-jss-nextjs * #519338 refactoring: moved constants * #519338 refactoring and fixed comments * #519338 update yarn.lock * #519338 fixed lint * #519338 fixed comments and added unit-test * #519338 added unit test for middleware redirects * #519338 fixed lint error and yarn.lock * #519338 fixed yarn.lock * #519338 removed unit-test of redirects middleware and fixed yarn.lock * #519338 added isomorphic-fetch for run pipline * #519338 removed unused package * #519338 removed test(override fetch)
- Loading branch information
1 parent
214a396
commit b963d40
Showing
21 changed files
with
364 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/create-sitecore-jss/src/templates/nextjs/scripts/templates/component-factory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
packages/create-sitecore-jss/src/templates/nextjs/src/lib/middleware/plugins/redirects.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import { RedirectsMiddleware } from '@sitecore-jss/sitecore-jss-nextjs'; | ||
import config from 'temp/config'; | ||
import { MiddlewarePlugin } from '..'; | ||
|
||
class RedirectsPlugin implements MiddlewarePlugin { | ||
private redirectsMiddleware: RedirectsMiddleware; | ||
order = 0; | ||
|
||
constructor() { | ||
this.redirectsMiddleware = new RedirectsMiddleware({ | ||
endpoint: config.graphQLEndpoint, | ||
apiKey: config.sitecoreApiKey, | ||
siteName: config.jssAppName, | ||
}); | ||
} | ||
|
||
/** | ||
* exec async method - to find coincidence in url.pathname and redirects of site | ||
* @param req<NextRequest> | ||
* @returns Promise<NextResponse> | ||
*/ | ||
async exec(req: NextRequest): Promise<NextResponse> { | ||
return this.redirectsMiddleware.getHandler(req); | ||
} | ||
} | ||
|
||
export const redirectsPlugin = new RedirectsPlugin(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
packages/sitecore-jss-nextjs/src/middleware/redirects-middleware.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import regexParser from 'regex-parser'; | ||
import { NextResponse, NextRequest } from 'next/server'; | ||
import { | ||
RedirectInfo, | ||
GraphQLRedirectsService, | ||
GraphQLRedirectsServiceConfig, | ||
REDIRECT_TYPE_301, | ||
REDIRECT_TYPE_302, | ||
REDIRECT_TYPE_SERVER_TRANSFER, | ||
} from '@sitecore-jss/sitecore-jss/site'; | ||
|
||
/** | ||
* extended RedirectsMiddlewareConfig config type for RedirectsMiddleware | ||
*/ | ||
export type RedirectsMiddlewareConfig = Omit<GraphQLRedirectsServiceConfig, 'fetch'>; | ||
|
||
/** | ||
* Middleware / handler fetches all redirects from Sitecore instance by grapqhl service | ||
* compares with current url and redirects to target url | ||
*/ | ||
export class RedirectsMiddleware { | ||
private redirectsService: GraphQLRedirectsService; | ||
|
||
/** | ||
* NOTE: we provide native fetch for compatibility on Next.js Edge Runtime | ||
* (underlying default 'cross-fetch' is not currently compatible: https://github.com/lquixada/cross-fetch/issues/78) | ||
* @param {RedirectsMiddlewareConfig} [config] redirects middleware config | ||
*/ | ||
constructor(config: RedirectsMiddlewareConfig) { | ||
this.redirectsService = new GraphQLRedirectsService({ ...config, fetch: fetch }); | ||
} | ||
|
||
/** | ||
* Gets the Next.js API route handler | ||
* @returns route handler | ||
*/ | ||
public getHandler(): (req: NextRequest) => Promise<NextResponse> { | ||
return this.handler; | ||
} | ||
|
||
private handler = async (req: NextRequest): Promise<NextResponse> => { | ||
const url = req.nextUrl.clone(); | ||
// Find the redirect from result of RedirectService | ||
|
||
const existsRedirect = await this.getExistsRedirect(url); | ||
|
||
if (!existsRedirect) { | ||
return NextResponse.next(); | ||
} | ||
|
||
url.search = existsRedirect.isQueryStringPreserved ? url.search : ''; | ||
url.pathname = existsRedirect.target; | ||
|
||
/** return Response redirect with http code of redirect type **/ | ||
switch (existsRedirect.redirectType) { | ||
case REDIRECT_TYPE_301: | ||
return NextResponse.redirect(url, 301); | ||
case REDIRECT_TYPE_302: | ||
return NextResponse.redirect(url, 302); | ||
case REDIRECT_TYPE_SERVER_TRANSFER: | ||
return NextResponse.rewrite(url); | ||
default: | ||
return NextResponse.next(); | ||
} | ||
}; | ||
|
||
/** | ||
* Method returns RedirectInfo when matches | ||
* @param url | ||
* @return Promise<RedirectInfo> | ||
* @private | ||
*/ | ||
private async getExistsRedirect(url: URL): Promise<RedirectInfo | undefined> { | ||
const redirects = await this.redirectsService.fetchRedirects(); | ||
|
||
return redirects.find((redirect: RedirectInfo) => | ||
regexParser(redirect.pattern).test(url.pathname) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
require('ts-node/register/transpile-only'); | ||
require('../src/tests/shim.ts'); | ||
require('../src/tests/jsdom-setup.ts'); | ||
require('../src/tests/enzyme-setup.ts'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
packages/sitecore-jss/src/site/graphql-redirects-service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { expect } from 'chai'; | ||
import nock from 'nock'; | ||
import { GraphQLRedirectsService, RedirectsQueryResult } from './graphql-redirects-service'; | ||
import { siteNameError } from '../constants'; | ||
|
||
const redirectsQueryResultNull = { | ||
site: { | ||
siteInfo: { | ||
redirects: [], | ||
}, | ||
}, | ||
} as RedirectsQueryResult; | ||
|
||
const redirectsQueryResult = { | ||
site: { | ||
siteInfo: { | ||
redirects: [ | ||
{ | ||
pattern: '/notfound', | ||
target: '/404', | ||
redirectType: 'REDIRECT_301', | ||
isQueryStringPreserved: true, | ||
}, | ||
], | ||
}, | ||
}, | ||
} as RedirectsQueryResult; | ||
|
||
describe('GraphQLRedirectsService', () => { | ||
const endpoint = 'http://site'; | ||
const apiKey = 'some-api-key'; | ||
const siteName = 'site-name'; | ||
|
||
afterEach(() => { | ||
nock.cleanAll(); | ||
}); | ||
|
||
const mockRedirectsRequest = (siteName?: string) => { | ||
nock(endpoint) | ||
.post('/') | ||
.reply( | ||
200, | ||
siteName | ||
? { | ||
data: redirectsQueryResult, | ||
} | ||
: { | ||
data: redirectsQueryResultNull, | ||
} | ||
); | ||
}; | ||
|
||
describe('fetch redirects from site by graphql', () => { | ||
it('should get error if redirects has empty siteName', async () => { | ||
mockRedirectsRequest(); | ||
|
||
const service = new GraphQLRedirectsService({ endpoint, apiKey, siteName: '' }); | ||
await service.fetchRedirects().catch((error: Error) => { | ||
expect(error.message).to.equal(siteNameError); | ||
}); | ||
|
||
return expect(nock.isDone()).to.be.false; | ||
}); | ||
|
||
it('should get redirects', async () => { | ||
mockRedirectsRequest(siteName); | ||
|
||
const service = new GraphQLRedirectsService({ endpoint, apiKey, siteName }); | ||
const result = await service.fetchRedirects(); | ||
|
||
expect(result).to.deep.equal(redirectsQueryResult.site.siteInfo.redirects); | ||
|
||
return expect(nock.isDone()).to.be.true; | ||
}); | ||
|
||
it('should get no redirects', async () => { | ||
mockRedirectsRequest(); | ||
|
||
const service = new GraphQLRedirectsService({ endpoint, apiKey, siteName }); | ||
const result = await service.fetchRedirects(); | ||
|
||
expect(result).to.deep.equal(redirectsQueryResultNull.site.siteInfo.redirects); | ||
|
||
return expect(nock.isDone()).to.be.true; | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.