Nanostores in SSR
See original GitHub issueHi there!
I saw news on new release, saw allTasks API and decided to research, how nanostores is compatible with SSR
Loading of Node.js template in codesandbox takes forever for some reason, so i decided to create similiar reproduce with basic one:
https://codesandbox.io/s/loving-wilson-4vp4r?file=/src/index.js
(see index.js and console)
Idea is the same:
- Request happens
- Request-handler task is added to event-loop and starts some logic and web or db requests
- Once those web or db requests are over, state is recalculated with new data
- State injected in the app, which then rendered to string
- Resulting string sent as response
During all of these operations is important to isolate state that “belongs” to different requests from each other - otherwise data from one request will leak to the other
Nanostores have two issues there:
-
States of nanostores are shared between requests, which then leads to data prepared for one request to show in another - in result rendered html-string is not correct.
-
State of internal
allTaskscounter is also shared between all requests, which leads to weird bug: responses are not sent until all requests are handled, even if their data is ready.
Possible solutions:
- Many state-managers require creation of new instance of store/stores for every request, like this
const ssr = async (request) => {
const stores = initStores()
await stores.startLogic(request)
return renderAppToString(stores)
}
This will effectively isolate requests from each other, because all of them will have their own instance of stores and all pending operations also will be bounded to this instance Mobx example: https://github.com/vercel/next.js/tree/master/examples/with-mobx-state-tree
- Some other state-managers, like
effector, allow to create separate instance of app state in special way, allowing to reuse already initialized stores and connections, like this:
const ssr = async (request) => {
// all stores and connections already defined somewhere
const scope = fork()
await allSettled(startLogic, { scope, params: request })
return renderAppToString(scope)
}
Example: https://github.com/GTOsss/ssr-effector-next-example/blob/effector-react-form-ssr/src/pages/ssr.tsx
Issue Analytics
- State:
- Created 2 years ago
- Comments:13 (8 by maintainers)
Top Related StackOverflow Question
I have another solution, but the documentation is very weak.
https://github.com/Eddort/nanostores-ssr
The main idea is to create a handler for each request (SSR function) and create a new context for each new request.
I don’t think that wrapper would work - if user missed some store, then it will be missed from serialization and further hydration at the client, which is no good, if it, for example, was changed during SSR (on the other hand, it may make sense to ignore some stores in serialization, for e.g. internal stores of libraries)
Probably it should be a core feature, so all APIs of the library are aware of the scopes and can properly handle it 🤔
I don’t think that it is actually matter, if server context is isolated or not - the problem of collecting all parts of decentralized state of the app is still persists, since it is needed to hydrate app state at the client somehow anyway 🤔