Warning Node Has Slots In Importing State
# Data Store
During SSR, we are essentially rendering a 'snapshot' of our app. The asynchronous data from our components needs to be available before we mount the client side app - otherwise the client app would render using different state and the hydration would fail.
To address this, the fetched data needs to live outside the view components, in a dedicated data store, or a 'state container'. On the server, we can pre-fetch and fill data into the store while rendering. In addition, we will serialize and inline the state in the HTML after the app has finished rendering. The client-side store can directly pick up the inlined state before we mount the app.
We will be using the official state management library Vuex for this purpose. Let's create a store.js
file, with some mocked logic for fetching an item based on an id:
Variant 1: Drop support for Node.js ≤ 4.4.x and 5.0.0 — 5.9.x. This is the recommended solution nowadays that would imply only minimal overhead. The Node.js 5.x release line has been unsupported since July 2016, and the Node.js 4.x release line reaches its End of Life in April 2018 (→ Schedule). I'd say you should encapsulate as much of your code as possible into functions and classes, limiting the global state when possible. This serves two purposes - the first is that it improves debugging (by limiting the odds that something unintentionally alters global state) and readability (by making it easier to understand what everything does).
WARNING
Most of the time, you should wrap state
in a function, so that it will not leak into the next server-side runs.More info
And update app.js
:
# Logic Collocation with Components
So, where do we place the code that dispatches the on async data during the rendering process.
TIP
You can use serverPrefetch
in any component, not just the route-level components.
Here is an example Item.vue
component that is rendered at the '/item/:id'
route. Since the component instance is already created at this point, it has access to this
:
WARNING
You should check if the component was server-side rendered in the mounted
hook to avoid executing the logic twice.
TIP
You may find the same fetchItem()
logic repeated multiple times (in serverPrefetch
, mounted
and watch
callbacks) in each component - it is recommended to create your own abstraction (e.g. a mixin or a plugin) to simplify such code.
Warning Node Has Slots In Importing Staten Island
# Final State Injection
Now we know that the rendering process will wait for data fetching in our components, how do we know when it is 'done'? In order to do that, we need to attach a rendered
callback to the render context (also new in 2.6), which the server renderer will call when the entire rendering process is finished. At this moment, the store should have been filled with the final state. We can then inject it on to the context in that callback:
When using template
, context.state
will automatically be embedded in the final HTML as window.__INITIAL_STATE__
state. On the client, the store should pick up the state before mounting the application:
# Store Code Splitting
In a large application, our Vuex store will likely be split into multiple modules. Of course, it is also possible to code-split these modules into corresponding route component chunks. Suppose we have the following store module:
Warning Node Has Slots In Importing Statement
We can use store.registerModule
to lazy-register this module in a route component's serverPrefetch
hook:
Because the module is now a dependency of the route component, it will be moved into the route component's async chunk by webpack.
WARNING
Don't forget to use the preserveState: true
option for registerModule
so we keep the state injected by the server.