-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Warn when implementing apis twice #3889
Merged
KyleAMathews
merged 17 commits into
gatsbyjs:master
from
m-allanson:topics/warn-duplicate-apis
Feb 27, 2018
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
acfe558
Warn when replaceRenderer is implemented multiple times
m-allanson 66af1b9
Remove unused import
m-allanson 959d7f4
Add tests
m-allanson 5dae156
Back out 'named arguments' change from apiRunner
m-allanson c577de6
Re-add required import
m-allanson 881f066
Add first draft of docs page
m-allanson e9de6c4
Simplify language based on results from Hemingway App
m-allanson 6298c41
Implement docs feedback
m-allanson 44c30a4
Capitalisation
m-allanson 3913207
Copy tweaks
m-allanson 00f39e7
More concise 'add internal plugins'
m-allanson 55b7d3f
Use work from previous PR's to improve this
m-allanson 360677b
Remove unused import
m-allanson 57375ee
Use the reporter for nicer error formatting
m-allanson 68cfa35
Exit on error during build
m-allanson a4807ee
Split code out into smaller functions and add tests
m-allanson db3e56d
Update comments
m-allanson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
--- | ||
title: Debugging replaceRenderer API | ||
--- | ||
|
||
## What is the `replaceRenderer` API? | ||
|
||
The `replaceRenderer` API is one of [Gatsby's Server Side Rendering (SSR) extension APIs](/docs/ssr-apis/#replaceRenderer). This API is called when you run `gatsby build` and is used to customise how Gatsby renders your static content. It can be implemented by any Gatsby plugin or your `gatsby-ssr.js` file - adding support for Redux, CSS-in-JS libraries or any code that needs to change Gatsby's default HTML output. | ||
|
||
## Why does it cause build errors? | ||
|
||
If multiple plugins implement `replaceRenderer` in your project, only the last plugin implementing the API can be called - which will break your site builds. | ||
|
||
Note that `replaceRenderer` is only used during `gatsby build`. It won't cause problems as you work on your site with `gatsby develop`. | ||
|
||
If multiple plugins implement `replaceRenderer`, `gatsby build` will warn you: | ||
|
||
``` | ||
The "replaceRenderer" API is implemented by several enabled plugins. | ||
This could be an error, see https://gatsbyjs.org/docs/debugging-replace-renderer-api for workarounds. | ||
Check the following plugins for "replaceRenderer" implementations: | ||
/path/to/my/site/node_modules/gatsby-plugin-styled-components/gatsby-ssr.js | ||
/path/to/my/site/gatsby-ssr.js | ||
``` | ||
|
||
## Fixing `replaceRenderer` build errors | ||
|
||
If you see errors during your build, you can fix them with the following steps. | ||
|
||
### 1. Identify the plugins using `replaceRenderer` | ||
|
||
Your error message should list the files that use `replaceRenderer` | ||
|
||
```shell | ||
Check the following files for "replaceRenderer" implementations: | ||
/path/to/my/site/node_modules/gatsby-plugin-styled-components/gatsby-ssr.js | ||
/path/to/my/site/gatsby-ssr.js | ||
``` | ||
|
||
In this example, your `gatsby-ssr.js` file and `gatsby-plugin-styled-components` are both using `replaceRenderer`. | ||
|
||
### 2. Copy the plugins' `replaceRenderer` functionality to your site's `gatsby-ssr.js` file | ||
|
||
You'll need to override your plugins' `replaceRenderer` code in your `gatsby-ssr.js` file. This step will be different for each project, keep reading to see an example. | ||
|
||
## Example | ||
|
||
### Initial setup | ||
|
||
In this example project we're using [`redux`](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-redux) and [Gatsby's Styled Components plugin](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-styled-components). | ||
|
||
`gatsby-config.js` | ||
|
||
```js | ||
module.exports = { | ||
plugins: [`gatsby-plugin-styled-components`], | ||
} | ||
``` | ||
|
||
`gatsby-ssr.js` (based on the [using Redux example](https://github.com/gatsbyjs/gatsby/blob/master/examples/using-redux/gatsby-ssr.js)) | ||
|
||
```js | ||
import React from "react" | ||
import { Provider } from "react-redux" | ||
import { renderToString } from "react-dom/server" | ||
|
||
import createStore from "./src/state/createStore" | ||
|
||
exports.replaceRenderer = ({ bodyComponent, replaceBodyHTMLString }) => { | ||
const store = createStore() | ||
|
||
const ConnectedBody = () => <Provider store={store}>{bodyComponent}</Provider> | ||
replaceBodyHTMLString(renderToString(<ConnectedBody />)) | ||
} | ||
``` | ||
|
||
Note that the Styled Components plugin uses `replaceRenderer`, and the code in `gatsby-ssr.js` also uses `replaceRenderer`. | ||
|
||
### Fixing the `replaceRenderer` error | ||
|
||
Our `gatsby-config.js` file will remain unchanged. However, oour `gatsby-ssr.js` file will update to include the [`replaceRenderer` functionality from the Styled Components plugin](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-plugin-styled-components/src/gatsby-ssr.js) | ||
|
||
`gatsby-ssr.js` | ||
|
||
```js | ||
import React from "react" | ||
import { Provider } from "react-redux" | ||
import { renderToString } from "react-dom/server" | ||
import { ServerStyleSheet, StyleSheetManager } from "styled-components" | ||
import createStore from "./src/state/createStore" | ||
|
||
exports.replaceRenderer = ({ | ||
bodyComponent, | ||
replaceBodyHTMLString, | ||
setHeadComponents, | ||
}) => { | ||
const sheet = new ServerStyleSheet() | ||
const store = createStore() | ||
|
||
const app = () => ( | ||
<Provider store={store}> | ||
<StyleSheetManager sheet={sheet.instance}> | ||
{bodyComponent} | ||
</StyleSheetManager> | ||
</Provider> | ||
) | ||
replaceBodyHTMLString(renderToString(<app />)) | ||
setHeadComponents([sheet.getStyleElement()]) | ||
} | ||
``` | ||
|
||
Now `gatsby-ssr.js` implements the Styled Components and Redux functionality using one `replaceRenderer` instance. Run `gatsby build` and the site will build without errors. | ||
|
||
All the code from this example is [available on GitHub](https://github.com/m-allanson/gatsby-replace-renderer-example/commits/master). |
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
19 changes: 19 additions & 0 deletions
19
packages/gatsby/src/bootstrap/__mocks__/resolve-module-exports.js
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,19 @@ | ||
'use strict' | ||
|
||
let mockResults = {} | ||
|
||
module.exports = input => { | ||
// return a mocked result | ||
if (typeof input === `string`) { | ||
return mockResults[input] | ||
} | ||
|
||
// return default result | ||
if (typeof input !== `object`) { | ||
return [] | ||
} | ||
|
||
// set mock results | ||
mockResults = Object.assign({}, input) | ||
return undefined | ||
} |
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we disable plugins for individual APIs not all SSR APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I implemented disabling individual APIs on my checkout, but then had a thought - is there any reason for a plugin to implement
replaceRenderer
andonRenderBody
? I can't find any official or community plugins that do this.Disabling all SSR APIs keeps things simpler as it means
api-runner-ssr.js
doesn't have to check whether it should run an API or not. I'd be tempted to roll with this implementation and then review if it causes problems.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does seem unlikely. If we add more APIs in the future, this could potentially become not true — that a plugin would implement multiple ssr APIs. I did a query (this one was fun
ag -l replaceRenderer | xargs -L 1 ag onRenderBody -l
) and there isn't any plugin currently that implements both. So let's go with it and see what happens. It'd be easy to change later.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good. Nice querying :)