-
-
Notifications
You must be signed in to change notification settings - Fork 17
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
enable server side rendering #6
Conversation
Thanks for the contribution @barbalex 😃 The example code you've given seems a bit unnecessary (or not minimal?) -- you don't need to dynamically import to get around the non-existent i.e. you could do: import { persist } from 'mst-persist'
...
if (typeof window !== 'undefined') {
persist('store', store, {
storage: localForage,
jsonify: false,
}).then(() => {
console.log('store has been hydrated')
...
})
} The code you added in this PR potentially makes sense for non-browser support, but not really for SSR -- you're not going to want to hydrate the store on the server anyway. That would be accessing your server's storage instead of the browser's. I'd be happy to add this for NodeJS support, but you'll need an if statement to check that you're in the browser environment in any case, so that wouldn't actually solve your specific issue. |
Re-reading and I see once more that you wrote the build fails ("on import"). The check for It sounds like Gatsby might be trying to make a Node-only build and during transpilation or bundling has some issues? I'm still not sure why it would be running that code however, since it's not top-level. What's the error you're getting? |
Yes, that should work. And often it does. But sometimes it has blown up in my face in the past and also when first implementing mst-persist. I do not know why this happens but I am not taking any more risks as failing builds can be really bad if it happens after changing db structure and you need to build on time. I suspect there are edge cases when the window reference in a library provokes the error purely by importing the library. But I can not explain this behavior. Anyway: If the library has no unchecked window reference this will not happen and then I can import it directly.
I did not mean SSR. Rather: Gatsby builds the project in node (gatsbyjs/gatsby#13355 (comment)). And that is why window references do not work.
I don't understand why I would have to check that I am in the browser environment: Gatsby apps always run in the browser. But they build in node. Hm. You mean: I would not want to rehydrate during SSR so I would have to leave my code as it is (but I could import mst-persist directly) in order to not rehydrate server side. O.k., that probably makes sense - I am a complete noob when it comes to SSR. But it would still be nice if a gatsby build would not break and force users to debug that.
The node:20912-Error gets repeated about a hundred times . It does not point to any specific location so if you are not familiar to what is happening it is a bit oblique. |
Yup, exactly! You still need to check if you're in browser or not so as to not rehydrate server-side.
Thanks for the error log. It fails on build because Gatsby isn't a server, it's a static site generator, but may use SSR mechanics in order to generate the static HTML (whereas a server would only error at runtime, Gatsby doesn't have a "runtime", the build is its runtime). Semantics, I suppose, but "at build-time" has a bit of a different meaning when you're not just transpiling / bundling, but creating HTML (a bit of an impedance mismatch). When I first saw Gatsby, I didn't immediately realize that and didn't realize it until I saw the log saying "Building static HTML" 😅 I think I understand what's going on. Because it's generating HTML, it is actually rendering all your components and running your client-side code. I'm guessing it's giving 1 error per page (or however many times a page is rendered)? That being said, importing directly and putting the
And this is where I'm confused too. It definitely should work and definitely shouldn't be non-deterministic like that. The error is occurring at render-time (let's the use the term "render-time" instead of "build-time" to be more explicit), so it shouldn't pass the window check, and if it did, it shouldn't say window doesn't exist immediately after confirming it indeed exists. The issue you referenced said it might be different in dev vs. prod builds. That might help narrow it down from something so non-deterministic as you observe.
Initially I was thinking of just merging it as there wouldn't seem to be any harm done (though you should be able to import directly), but the behavior is not necessarily ideal, because it means Perhaps |
Sounds good. But to be honest: You obviously understand these processed a lot better so I am not going to try to influence you. |
- add a `nodeNoop` option that is `true` by default - generally folks do not want to hydrate their store during SSR, so no-op by default and require explicit opt-in to Node hydration - see #6 for discussion - also throw an Error if localStorage isn't supported and no alternative storage provider has been given (docs): add `nodeNoop` option and section on Node and SSR usage to give more details and note possible gotchas
- add a `nodeNoop` option that is `true` by default - generally folks do not want to hydrate their store during SSR, so no-op by default and require explicit opt-in to Node hydration - see #6 for discussion - also throw an Error if localStorage isn't supported and no alternative storage provider has been given (docs): add `nodeNoop` option and section on Node and SSR usage to give more details and note possible gotchas
Were you able to confirm that statically importing still gives you a render-time error even when I've added a replacement PR in #9 that adds a The problem was that when I was writing the docs, I realized there are going to be some potential gotchas on testing and other environments due to the default no-op in Node, so I'm having second thoughts 😖. Need to look at what some other libraries that support SSR out-of-the-box and see how they handle the situation. |
No. I changed the code to import it directly and the project built just fine. But that was only a single test. It had broken that way while implementing first. But I can't be 100% sure that was not caused by something different. I had similar problems using react-leaflet. The problem there is that react-leaflet uses leaflet which actually manipulates the window object. I spent a rather long time trying to get my gatsby project to build again and found that the only working version was hiding the map components (that use react-leaflet) behind this component here: import React, { useState } from 'react'
/**
* do not load Karte on server
* because leaflet calls windows
* see: https://github.com/PaulLeCam/react-leaflet/issues/45#issuecomment-257712370
*/
export default ({ treeName }) => {
const [Karte, setKarte] = useState(null)
if (typeof window === 'undefined') return null
import('./Karte').then(module => setKarte(module.default))
if (!Karte) return null
return <Karte treeName={treeName} />
} As found in PaulLeCam/react-leaflet#45 the way to solve is to conditionally import. But this case may be different as leaflet does not only reference but manipulates the window object. Not sure if that makes a difference. |
- add a `nodeNoop` option that is `true` by default - generally folks do not want to hydrate their store during SSR, so no-op by default and require explicit opt-in to Node hydration - see #6 for discussion (docs): add `nodeNoop` option and section on Node and SSR usage to give more details and note possible gotchas
Ok. That's a pretty important difference if you can't reproduce it. It is almost certainly something else and not this package.
It doesn't necessarily matter whether it manipulates or not. Per that issue and the quoted README section: "Leaflet makes direct calls to the DOM when it is loaded" -- i.e. Going to close this out. Implementation-specific discussion of |
@agilgur5 thanks for taking this so serious and for providing this great tool |
Made one more replacement PR for this in #15 that I'll be merging in shortly. It opts to just add docs for adding a conditional environment check, which is a lot more intuitive and doesn't have quite as many gotchas as #9, albeit requiring a bit more work on top of the "out-of-the-box" experience for SSR. Due to my discovery noted in #13, @barbalex I also made sure you're credited for the code you added for Node support there. |
I use GatsbyJS in my App. Which means that as soon as mst-persist is imported, the gatsby project can not be built any more: the build errors
window is not defined
.So I now have to use mst-persist like this:
Thus it is much easier if
if (typeof window !== 'undefined')
is done in mst-persist itself.