From aa028809634ecdf71f2c3e1d55cddd9e1ee3f17c Mon Sep 17 00:00:00 2001 From: Illia Kovalenko <23364749+illiakovalenko@users.noreply.github.com> Date: Fri, 11 Jun 2021 15:33:57 +0300 Subject: [PATCH 1/2] [Doc] [NextJS] GraphQL + Disconnected mode compatibility (#717) * [Doc] [NextJS] GraphQL + Disconnected mode compatibility * Add route * Review language and style * Remove duplicate export Co-authored-by: Anca Emcken --- .../docs/nextjs/graphql/sample-app/en.md | 77 ++++++++++++++++++- docs/src/app/components/Navigation/nextjs.js | 8 +- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/docs/data/routes/docs/nextjs/graphql/sample-app/en.md b/docs/data/routes/docs/nextjs/graphql/sample-app/en.md index 72d5094367..fc4ef5cb4a 100644 --- a/docs/data/routes/docs/nextjs/graphql/sample-app/en.md +++ b/docs/data/routes/docs/nextjs/graphql/sample-app/en.md @@ -3,4 +3,79 @@ name: sample-app routeTemplate: ./data/component-templates/article.yml title: Sitecore GraphQL in the sample app --- -# Sitecore GraphQL in the sample app \ No newline at end of file +# Sitecore GraphQL in the sample app + +## Disconnected mode + +If you created the app using `jss create my-app nextjs --fetchWith GraphQL`, your services will use the Sitecore GraphQL endpoint. + +Sitecore GraphQL does not come with a disconnected mock service, so it can only operate with a Next.js app in Connected mode. The disconnected server emulates the REST services only. + +Therefore, your service factories must return a REST service if you need to work in disconnected mode. + +To return a REST service for disconnected development from your service factories, leverage the `JSS_MODE` environment variable, as follows: + +1. Edit `src/lib/layout-service-factory.ts`: + +```js +import { + LayoutService, + GraphQLLayoutService, + RestLayoutService, + JSS_MODE_DISCONNECTED, +} from '@sitecore-jss/sitecore-jss-nextjs'; +import config from 'temp/config'; + +export class LayoutServiceFactory { + create(): LayoutService { + // Switch to REST endpoint if we are in disconnected mode + if (process.env.JSS_MODE === JSS_MODE_DISCONNECTED) { + return new RestLayoutService({ + apiHost: `http://localhost:${process.env.PROXY_PORT || 3042}`, + apiKey: config.sitecoreApiKey, + siteName: config.jssAppName, + }); + } + + return new GraphQLLayoutService({ + endpoint: config.graphQLEndpoint, + apiKey: config.sitecoreApiKey, + siteName: config.jssAppName, + }); + } +} + +export const layoutServiceFactory = new LayoutServiceFactory(); +``` + +2. Edit `src/lib/dictionary-service-factory.ts`: +```js +import { + DictionaryService, + RestDictionaryService, + GraphQLDictionaryService, + JSS_MODE_DISCONNECTED, +} from '@sitecore-jss/sitecore-jss-nextjs'; +import config from 'temp/config'; + +export class DictionaryServiceFactory { + create(): DictionaryService { + // Switch to REST endpoint if we are in disconnected mode + if (process.env.JSS_MODE === JSS_MODE_DISCONNECTED) { + return new RestDictionaryService({ + apiHost: `http://localhost:${process.env.PROXY_PORT || 3042}`, + apiKey: config.sitecoreApiKey, + siteName: config.jssAppName, + }); + } + + return new GraphQLDictionaryService({ + endpoint: config.graphQLEndpoint, + apiKey: config.sitecoreApiKey, + siteName: config.jssAppName, + }); + } +} + +export const dictionaryServiceFactory = new DictionaryServiceFactory(); +``` diff --git a/docs/src/app/components/Navigation/nextjs.js b/docs/src/app/components/Navigation/nextjs.js index c355ad94e6..1eabab2b32 100644 --- a/docs/src/app/components/Navigation/nextjs.js +++ b/docs/src/app/components/Navigation/nextjs.js @@ -128,10 +128,10 @@ export default { // url: 'edge-schema-introduction', // displayName: 'Introduction to the Edge Schema', //}, - //{ - // url: 'sample-app', - // displayName: 'Sitecore GraphQL in the sample app', - //}, + { + url: 'sample-app', + displayName: 'Sitecore GraphQL in the sample app', + }, { url: 'introspection', displayName: 'Introspecting the GraphQL schema' From d74e4cc8614bd445505d5c40eeb87b6a49e413ea Mon Sep 17 00:00:00 2001 From: Adam Brauer <400763+ambrauer@users.noreply.github.com> Date: Mon, 28 Jun 2021 07:51:10 -0500 Subject: [PATCH 2/2] Prevent extraneous router.replace (and resulting 404 in certain route configurations) in Experience Editor when using SSG --- .../src/middleware/editing-render-middleware.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/sitecore-jss-nextjs/src/middleware/editing-render-middleware.ts b/packages/sitecore-jss-nextjs/src/middleware/editing-render-middleware.ts index 4d62b1c3cd..f92bb9edd4 100644 --- a/packages/sitecore-jss-nextjs/src/middleware/editing-render-middleware.ts +++ b/packages/sitecore-jss-nextjs/src/middleware/editing-render-middleware.ts @@ -1,4 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next'; +import { STATIC_PROPS_ID, SERVER_PROPS_ID } from 'next/constants'; import { AxiosDataFetcher, debug } from '@sitecore-jss/sitecore-jss'; import { EditingData } from '../sharedTypes/editing-data'; import { EditingDataService, editingDataService } from '../services/editing-data-service'; @@ -137,6 +138,14 @@ export class EditingRenderMiddleware { // show correct placeholders, so save and refresh won't be needed after adding each rendering html = html.replace(new RegExp('phkey', 'g'), 'key'); + // When SSG, Next will attempt to perform a router.replace on the client-side to inject the query string parms + // to the router state. See https://github.com/vercel/next.js/blob/v10.0.3/packages/next/client/index.tsx#L169. + // However, this doesn't really work since at this point we're in the editor and the location.search has nothing + // to do with the Next route/page we've rendered. Beyond the extraneous request, this can result in a 404 with + // certain route configurations (e.g. multiple catch-all routes). + // The following line will trick it into thinking we're SSR, thus avoiding any router.replace. + html = html.replace(STATIC_PROPS_ID, SERVER_PROPS_ID); + const body = { html }; // Return expected JSON result