-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
SSR with blueprint #131
Comments
interesting! we've never used blueprint in an SSR app so this has never come up before. as a result, SSR support is low priority for the team because we don't build apps like this. @RobAWilkinson are you having trouble getting dom4 to work on the server? can you be more specific about the problem? 11/17/16 update from @adidahiya, so as not to have the response buried: We're going to look at server side rendering more seriously some time in the next couple months. Watch this issue for updates. |
Ahh gotcha. Yeah it seems that dom4 is pretty client specific, I went down the path of mocking dom4 is looking for things like Are there specific components that are using dom4 more than others? I would assume things like datetime are doing js DOM manipulations heavily which is why its moved out of core. Ex: Currently I'm doing this myself building on |
Hi, I was experimenting with next.js and tried to add your blueprints but I got this exception as well. Do you think you can split somehow the component so both client side and server side rendering is possible? |
+1 to @schrepfler's point that SSR is a must for some. My quick and ugly hack is the following:
function DefaultComponent(props) {
return <div>{this.props.children}</div>;
} I then do some shady componentDidMount stuff like so: let Popover = defaultComponent; // Initialize Popover to be the default component
export const MyComponent = React.createClass({
componentDidMount() {
Popover = require('@blueprintjs/core').Popover; // Overwrite the default component with the real component
this.forceUpdate(); // Trigger a re-render
},
render() {
return (
<div>
<Popover
content={<div>This is my popover content</div>}
popoverClassName="pt-popover-content-sizing"
useSmartPositioning={true}
>
<button className="pt-button">Click for Popover</button>
</Popover>
</div>
)
}
}); Because It's ugly, it makes my insides hurt - but for many of the components I'm excited about, this'll work for the time being. It won't work for things that need the JS API and have inherit style as they will flicker on load. I also tried messing with JSdom in dom4, and faking window, document, etc in the blueprint source - but as @RobAWilkinson said, it gets pretty untenable. Thanks for all this work - excited to see it progress! |
Thanks for this great tip, this is awesome but just warning everyone, if you try to do this with some complicated components, that internally use refs i.e. |
For anyone else who's stuck at this - I have been able to to fix this by manually patching following file:
I have Seems to work fine so far, although haven't tested all the components. If anyone finds any memory leaks during SSR, please let me know. |
Is that available via some PR @abhishiv? |
@schrepfler no, but I put them up in a gist in case anyone needs it. Simple stuff like checking for navigator existence etc. https://gist.github.com/anonymous/7d011dddb77fbce1f378f62f77553c58 |
What does this patch do? Why is dom4j strictly needed on the server side, can't the react dom be used instead? |
I believe it is mainly being used for it's keyboard events. |
Yeah, and for some other stuff I think. These patches, comment the line including dom4j, so it doesn't get loaded on the server. However on the client, you need to include it so that things work - I did it via a script tag. The other two files are patched to check for existence of document/navigator. |
@abhishiv are you saying this was patched and should work now? |
@DClark5218 Only if you patch it yourself using the files I uploaded. |
you can see a diff here of some of my SSR research over the weekend applied to core: summary...
these fixes will effectively render the markup, but anything relying on popover/portal will trigger a re-render on client (checksum mismatch) and will break event handlers due to direct dom manipulation related to // portal.tsx
// ...
const targetElement = document.createElement("div");
targetElement.classList.add(Classes.PORTAL);
document.body.appendChild(targetElement);
this.targetElement = targetElement; bypassing this on server is easy and will stop checksum warnings since dom is the same, but now we've lost an HTMLElement that react expects as target so throws reference error i didn't have time to look into a full migration this weekend, but based on my research these issues could likely be mitigated by replacing ad hoc portal solution with react-portal or react-tether, both of which seem to have addressed these issues using controlled component state @abhishiv have you tested your patch with overlays and tooltips? class PasswordField extends Component {
toggleVisbile = e => {
e.preventDefault()
e.stopPropagation()
this.props.toggle()
}
render () {
const { showPassword, setText } = this.props
let button = (
<Tooltip content={`${showPassword ? "Hide" : "Show"} Password`}>
<Button
className={Classes.MINIMAL}
intent={Intent.WARNING}
iconName={showPassword ? "unlock" : "lock"}
onClick={this.toggleVisbile}
/>
</Tooltip>
)
return (
<div className="pt-app">
<InputGroup
className="pt-large"
placeholder="Enter your password..."
rightElement={button}
type={showPassword ? "text" : "password"}
onChange={e => setText(e.target.value.trim())}
/>
</div>
)
}
} AFAICT this will break, since once in dom context react will not be able to find Tooltip portal's target element |
Hey @justingreenberg, weirdly for me it works both on client/server without any warnings/errors. It's weird, because our patches are almost the same. The function you wrote about in portal.tsx is run in componentDidMount, so I don't think it should break anything. How does it break for you? Can you share the warnings/errors you get? |
Can we get a build with this patch? |
@schrepfler sorry, we won't just release a quick patch for this. It's something we care about and very much want to do right -- we're investigating SSR now and once we're solid on all the use cases, we'll do a release with first-class SSR support. In the meantime, definitely feel free to experiment with the changes proposed above. @adidahiya anything you'd like to add? |
I started compiling a list of fixes needed before I found this post. I eventually found the number of fixes needed to be very minimal, and so made them.
Some points need to be addressed to ensure Blueprintjs' server rendering is maintained going forward.
You can find my
|
Sorry for that megapost. A few more comments: @justingreenberg the popover/portal code is fine. As mentioned by @abhishiv, this is called from @RobAWilkinson @schrepfler DOM4 is a polyfill for the W3C DOM level 4 living specification. Because this is related to DOM manipulation, it isn't needed server-side (but is still be needed browser-side). @isTravis that's an interesting approach, but seems overcomplicated given that the amount of patching needed to get Blueprintjs to work server-side is minimal. @justingreenberg your patch for conditional import of 'dom4' breaks the build
unless the dom4 types (required for TypeScript to correctly compile) are included. This is an easy change, though:
|
Awesome great work @codebling thanks for spending the time on this, I'll be using your fork until this gets merged. |
Just in case anyone comes across this while trying to use Blueprint SSR in Deno (or ESBuild, which Deno uses). Unfortunately it doesn't seem to work. You get these errors:
I suspect this is because ESBuild does not support conditional imports like the one Blueprint uses; basically:
And that is conflated with the fact that dom4 has side effects when it is imported (terrible design). The clean solutions is to change dom4 so it doesn't have side effects on import, but requires a
But seeing as that requires modifying dom4 in a backwards incompatible way I won't hold my breath. I don't have a solution, sorry. Just posting this here because it's high in the Google results for relevant searches. |
sounds like a good feature request for ESBuild? |
Thanks for the info @Timmmm ! I think there are a few potential solutions here (though I'm not 100% sure about the feasibility of any of them),
What do you think about these? If you come up with a solution and open a PR, my experience has been that the team here has been very receptive :) |
Yeah it does feel like something esbuild could support. Thanks for the ideas:
Anyway I gave up on Deno for now and went back to Node. I suspect the most prudent action is simply to wait until you guys drop IE support and then all the polyfills can just be removed (as far as I can tell only IE needs the dom4 or fetch polyfills). Actually now that I think about it I'm still using esbuild but directly instead of through esm.sh and it works fine. Weird. This legacy module stuff is a mess! |
yes, this is one option. note that this is coming later this year with v5.0: #5143 |
For 2, I'd meant to include more details. I was thinking it might be possible to create temporary globals right before Actually Webpack can target specific browsers and do any transpilation, courtesy Babel, so this library probably isn't required at all.
Looks like you're back to Node for now. Thanks for sharing your experience, I have not made the jump to Deno yet, for a few reasons, but I am keeping a close eye on it.
nice! |
I agree.
Ah nice. That is definitely the sensible solution!
I only have limited experience but I'm sold. It's definitely the future, if not quite the present. The URL import system feels very weird at first but after using it for a while I think it's actually the best way to go. It's especially good for replacing shell scripts. You get to write single file scripts in a sane statically typed language and you can use third party libraries without some extra project config file. I don't think anything else can offer that. Anyway I shall look forward to Blueprint 5. Great project btw! |
Server side rendering with blueprint breaks,
dom4.max.js
is requiring tons of things.The text was updated successfully, but these errors were encountered: