Svelte: Store with multiple apps

Created on 23 Dec 2017  ·  2Comments  ·  Source: sveltejs/svelte

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.
Stack trace
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.
Attaching store to global object
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;
}

question

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?

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.

All 2 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

st-schneider picture st-schneider  ·  3Comments

matt3224 picture matt3224  ·  3Comments

davidcallanan picture davidcallanan  ·  3Comments

Rich-Harris picture Rich-Harris  ·  3Comments

Rich-Harris picture Rich-Harris  ·  3Comments