1 | import { createApp } from './app.js'
|
2 | import { callAsyncRecursive } from './ssr/callAsyncRecursive.js'
|
3 | import { registerStoreModules } from './ssr/registerStoreModules.js'
|
4 | import root from 'src/app.vue'
|
5 |
|
6 | /**
|
7 | * Generate App with pre-fetched data in store state
|
8 | */
|
9 | export default function (context) {
|
10 | return new Promise((resolve, reject) => {
|
11 | const { app, router, store } = createApp()
|
12 |
|
13 | if (context.req.access_token) app.$cubic.setAccessToken(context.req.access_token)
|
14 | if (context.req.refresh_token) app.$cubic.setRefreshToken(context.req.refresh_token)
|
15 |
|
16 | // Init vue-meta
|
17 | const meta = app.$meta()
|
18 |
|
19 | // Set router's location
|
20 | router.push(context.req.url)
|
21 |
|
22 | // Wait until router has resolved possible async hooks
|
23 | router.onReady(async () => {
|
24 | const routerView = router.getMatchedComponents()
|
25 |
|
26 | // Register all dynamic store modules in components first since asyncData
|
27 | // functions will likely depend on them. This also avoids the necessity to
|
28 | // load dependencies first if they're already present in the template.
|
29 |
|
30 | // router-view doesn't contain root template, so we call it additionally
|
31 | registerStoreModules(root, store)
|
32 | routerView.map(component => registerStoreModules(component, store))
|
33 |
|
34 | // Call asyncData hooks on components matched by the route recursively.
|
35 | // A asyncData hook dispatches a store action and returns a Promise,
|
36 | // which is resolved when the action is complete and store state has been
|
37 | // updated.
|
38 |
|
39 | // router-view doesn't contain root template, so we call it additionally
|
40 | await callAsyncRecursive(root, store, router)
|
41 | await Promise.all(routerView.map(component => callAsyncRecursive(component, store, router, router.currentRoute)))
|
42 |
|
43 | // After all asyncData hooks are resolved, our store is now
|
44 | // filled with the state needed to render the app.
|
45 | // Expose the state on the render context, and let the request handler
|
46 | // inline the state in the HTML response. This allows the client-side
|
47 | // store to pick-up the server-side state without having to duplicate
|
48 | // the initial data fetching on the client.
|
49 | context.state = store.state
|
50 |
|
51 | // Give access token to state so the client can use it
|
52 | if (context.req.access_token) context.state.$access_token = context.req.access_token
|
53 | if (context.req.refresh_token) context.state.$refresh_token = context.req.refresh_token
|
54 |
|
55 | // Finally, add meta tags to context for injection in renderer
|
56 | context.meta = { inject: function () { Object.assign(this, meta.inject()) } }
|
57 |
|
58 | resolve(app)
|
59 | })
|
60 | })
|
61 | }
|