-
Notifications
You must be signed in to change notification settings - Fork 27.4k
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
[Discussion] Using Rapscallion with NextJS #2279
Closed
Closed
Conversation
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 adds support for, and an example of, using Rapscallion (or potentially other alternate React renderers) with Next. This has been discussed in vercel#1334 and vercel#1209. I'm submitting this as a proof of concept for discussion, though the changes are fairly minimal. I'm hoping with some bit of feedback we can add this for real! The issue as mentioned by @arunoda elsewhere is that `document.js` uses `renderToString()` directly, which makes it difficult to inject an alternate renderer method. **What I did here:** 1. creating a `renderToParts()` method, which in turn calls doRender with added configuration to allow for the replacement of `renderToString`, and keeping `renderToString` as the default. 2. Jettison `document.js`, and in the example `server.js` use [Rapscallion templating](https://github.com/FormidableLabs/rapscallion#template) to effectively do the same thing. 3. 🎉🎉🎉! **The main issue this raised:** * The subcomponents of `Document` (`Head`, `NextScript`) rely on context, and thus are difficult to interface with except through `Document`. I got around this by falling back to props when context was not defined. Hacky of course, and probably is the main thing we'd need to refactor to do this "right". **Results:** The test I created for examples was to generate a MD5 hash for the first 3000 integers. Since this is deterministic, I cached it with Rapscallion. `renderToString` continued to render it as normal on baseline. The test run was with apache benchmark, `ab -n 500 -c 10`. Baseline: ``` Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 0.4 0 4 Processing: 239 1293 246.1 1253 2099 Waiting: 238 1291 245.8 1251 2099 Total: 240 1293 246.1 1254 2100 Percentage of the requests served within a certain time (ms) 50% 1254 66% 1337 75% 1425 80% 1444 90% 1588 95% 1886 98% 1981 99% 1981 100% 2100 (longest request) ``` With Rapscallion: ``` Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 0.3 0 4 Processing: 97 204 39.6 190 318 Waiting: 97 202 38.6 189 318 Total: 98 205 39.6 191 319 Percentage of the requests served within a certain time (ms) 50% 191 66% 205 75% 224 80% 235 90% 269 95% 307 98% 315 99% 315 100% 319 (longest request) ``` ... or a roughly 6-7x improvement. Not super-surprising, since caching, but for us a larger portion of each page is static — being able to cache that, while leaving other areas to be dynamic, is a huge win. I played around with Rapscallion's streaming rendering as well, but I think that'll be most useful with something a little more real-world. Streaming seemed to have a small perf hit that gradually lessens the larger the CPU effort / payload becomes. If you were adding a bunch of CSS output in your header, for example, I think streaming would greatly improve load time. So yeah, open to suggestions here. I think this is a good stab at a general interface for getting "parts" for a more atomic Next render, but the API of that could certainly be better. Looking forward to hearing what you think! Love, @gcpantazis + @thumbtack ❤️
This was referenced Jun 15, 2017
This is pretty great. |
Does React 16's improvements to SSR change the approach here?
|
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
This adds support for, and an example of, using Rapscallion (or
potentially other alternate React renderers) with Next. This has been
discussed in #1334 and #1209. I'm submitting this as a proof of
concept for discussion, though the changes are fairly minimal. I'm
hoping with some bit of feedback we can add this for real!
The issue as mentioned by @arunoda elsewhere is that
document.js
uses
renderToString()
directly, which makes it difficult to inject analternate renderer method.
What I did here:
creating a
renderToParts()
method, which in turn calls doRender withadded configuration to allow for the replacement of
renderToString
,and keeping
renderToString
as the default.Jettison
document.js
, and in the exampleserver.js
useRapscallion templating to effectively do the same thing.
🎉🎉🎉!
The main issue this raised:
Document
(Head
,NextScript
) rely oncontext, and thus are difficult to interface with except through
Document
. I got around this by falling back to props when context wasnot defined. Hacky of course, and probably is the main thing we'd need
to refactor to do this "right".
Results:
The test I created for examples was to generate a MD5 hash for the first
3000 integers. Since this is deterministic, I cached it with
Rapscallion.
renderToString
continued to render it as normal onbaseline. The test run was with apache benchmark,
ab -n 500 -c 10
.Baseline:
With Rapscallion:
... or a roughly 6-7x improvement. Not super-surprising, since caching,
but for us a larger portion of each page is static, or at least made up of
pure components with predictable I/O — being able to cache those,
while leaving other areas to be completely dynamic, is a huge win.
I played around with Rapscallion's streaming rendering as well, but I
think that'll be most useful with something a little more real-world.
Streaming seemed to have a small perf hit that gradually lessens the
larger the CPU effort / payload becomes. If you were adding a bunch
of CSS output in your header, for example, I think streaming would
greatly improve load time.
So yeah, open to suggestions here. I think this is a good stab at a
general interface for getting "parts" for a more atomic Next render,
but the API of that could certainly be better. Looking forward to
hearing what you think!
Love,
@gcpantazis + @thumbtack ❤️