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

[Next.js] Prevent extraneous router.replace in Experience Editor when using SSG #736

Merged
merged 2 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
77 changes: 76 additions & 1 deletion docs/data/routes/docs/nextjs/graphql/sample-app/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
# 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();
```
8 changes: 4 additions & 4 deletions docs/src/app/components/Navigation/nextjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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
Expand Down