I have two separate bundles, product list and shopping cart, which are delivered with SSR and hydration.
The shopping cart creates a Svelte store with attached session storage and attaches store to window in the browser or to global on Node.
The product list uses an AddToCart component provided by the shopping cart bundle as a child component.
{{#each products as product}}
<Product :product></Product>
<AddToCart :product></AddToCart>
{{/each}}
<script>
import Product from './components/Product.html';
import AddToCart from 'cartcomponents/components/AddToCart.html';
....
</script>
AddToCart defines the store declaratively and uses the globally defined store, if available.
export default {
store: () => typeof window !== 'undefined' ? window.store : global.store
}
When the product list gets rendered server-side, I get an error because store is not defined.
TypeError: Cannot read property '_init' of undefined
at Object._873.r.AddToCart._render (D:\Dokumente\ws\microfrontends\product\dist\ssr\bundle.js:384:38)
at D:\Dokumente\ws\microfrontends\product\dist\ssr\bundle.js:463:158
at Array.map ()
at Object._873.r.ProductApp._render (D:\Dokumente\ws\microfrontends\product\dist\ssr\bundle.js:463:31)
at Object._873.r.ProductApp.render (D:\Dokumente\ws\microfrontends\product\dist\ssr\bundle.js:444:24)
at D:\Dokumente\ws\microfrontends\product\server.js:14:29
at Layer.handle [as handle_request] (D:\Dokumente\ws\microfrontends\product\node_modules\express\lib\router\layer.js:95:5)
at next (D:\Dokumente\ws\microfrontends\product\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (D:\Dokumente\ws\microfrontends\product\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (D:\Dokumente\ws\microfrontends\product\node_modules\express\lib\router\layer.js:95:5)
AddToCart._render = function(__result, state, options) {
__result.addComponent(AddToCart);
state = Object.assign(options.store._init(["items"]), data(), state); // <-- no store here
...
};
Expected behaviour: it should be possible for AddToCart to define its store even if the parent component does not have one. Or, to put it differently, an application that makes use of a component requiring a global store instance should not have to know about that requirement.
Workaround: let product list define its store declaratively, using a globally defined store if available.
let globalObject = (typeof window !== 'undefined' ? window : global);
let store;
if (typeof globalObject.store === 'undefined') {
store = new Store({
items: []
})
globalObject.store = store;
} else {
store = globalObject.store;
}
What about this?
import { Store } from 'svelte/store.js';
export default {
store: () => (typeof window !== 'undefined' && window.store) || new Store()
}
Is there anything Svelte should be doing differently here?
I'm not sure how your code looks like but maybe the shopping cart shouldn't create the store instance but receive one during creation?
const store = new Store()
const cart = new ShoppingCart({ target: document.getElementById('foo'), store })
const list = new ProductList({ target: document.getElementById('bar'), store })
This would make it easier to test the components in isolation too, having anything attached to a global object sounds at least risky.
Most helpful comment
I'm not sure how your code looks like but maybe the shopping cart shouldn't create the store instance but receive one during creation?
This would make it easier to test the components in isolation too, having anything attached to a global object sounds at least risky.