Server side rendering support
See original GitHub issueEdit: Summarized everything in one message
Hi there.
I just began learning server side rendering and I tried to set up css-vars-ponyfill
to do everything on the back before HTML is visible to user. I’ve managed to get it to work by passing a document DOM imitation as rootElement
:
cssVars({
rootElement: documentRef,
onlyLegacy: false,
include: `link[rel=stylesheet], style[${POLYFILL_MARK}], style[${THEME}]`,
onlyVars: true,
updateDOM: false,
onComplete: cssText => {
this.onPolyfillComplete(cssText);
},
});
Where documentRef
is like document, but in Node emulation. I use onlyLegacy: false
because I check browser myself — old Edge pretends to support CSS vars but does it very poorly so I ponyfill for it too. Also on the back CSS
object does not exist so cssVars
internal check would fail even on Chrome (in Server side rendering you have to determine browser from the user-agent sent in the HTTP request). POLYFILL_MARK
and THEME
are attributes that I mark <style>
tags with if I need to process them, never mind that, just my particular implementation.
So I was getting an error: ERROR RangeError: Maximum call stack size exceeded
.
Since documentRef
is not really document but rather an imitation it is considered an Object by mergeDeep
function inside css-vars-ponyfill
. So it goes over everything inside it 😃 I’ve added early return to that function which solved the issue for me:
if (Object.assign) {
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
args.unshift({});
return Object.assign.apply(this, args);
}
Also had to make that document dummy pretend it’s loaded, Domino (DOM in Node) sets readyState to “loading” by default.
With that I’ve managed to get it to work. Everything is ponyfilled before user gets it, so no flickering on IE, looks awesome. I know Object.assign is a shallow copy but from the options of the ponyfill it doesn’t look like you need a deep merge, the only object is variables map which is a map and is only read and never written to. If you could make the change above to your ponyfill or maybe come up with another way to allow for DOM imitation to take place — you could add Angular Universal / Server Side Rendering / Domino support to you library 😃
You could also make a change to this line:
if (document.readyState !== "loading") {
to something like this:
// if document is an object — we're in a backend DOM
// imitation and we do not need to wait for page load
if (document.constructor === Object || document.readyState !== "loading") {
It would eliminate the need to pretend to be loaded.
Issue Analytics
- State:
- Created 5 years ago
- Comments:10 (6 by maintainers)
Top GitHub Comments
No worries, @waterplea. Just wanted to make sure we addressed the issue before publishing.
New version (1.16.3) has been published to NPM.
Thx!
Right, sorry @jhildenbiddle, forgot to give it a shot. Works fine with my setup, pretty sure it should work with other SSR frameworks. Thank you!