1 |
|
2 | import Vue from 'vue'
|
3 |
|
4 | import './polyfills'
|
5 |
|
6 | import createApp from '#out/create-app'
|
7 | import { routerReady, pageNotFound, runMiddlewares } from './utils'
|
8 | import serverHelpers from './server-helpers'
|
9 | import ReamError from './ReamError'
|
10 |
|
11 | const {
|
12 | app,
|
13 | router,
|
14 | getInitialDataContextFns,
|
15 | event,
|
16 | dataStore,
|
17 | middlewares
|
18 | } = createApp()
|
19 |
|
20 | const getContext = context => {
|
21 | for (const fn of getInitialDataContextFns) {
|
22 | fn(context)
|
23 | }
|
24 | return context
|
25 | }
|
26 |
|
27 | const updateDataStore = (id, data) => {
|
28 | dataStore.setData(id, data)
|
29 | }
|
30 |
|
31 | const handleError = err => {
|
32 | if (err instanceof ReamError) {
|
33 | if (err.code === 'REDIRECT') {
|
34 | router.push(err.redirectURL)
|
35 | } else {
|
36 | app.setError(err)
|
37 | }
|
38 | } else {
|
39 | console.error(err)
|
40 | }
|
41 | }
|
42 |
|
43 | router.beforeResolve(async (to, from, next) => {
|
44 |
|
45 | if (!app.$clientRendered) return next()
|
46 |
|
47 | const matched = router.getMatchedComponents(to)
|
48 | if (matched.length === 0) {
|
49 | app.setError(pageNotFound(to.path))
|
50 | return next()
|
51 | }
|
52 |
|
53 | const prevMatched = router.getMatchedComponents(from)
|
54 | let diffed = false
|
55 | const activated = matched.filter((c, i) => {
|
56 | if (diffed) return diffed
|
57 | diffed = prevMatched[i] !== c
|
58 | return diffed
|
59 | })
|
60 |
|
61 | const components = activated.filter(c => c.getInitialData)
|
62 |
|
63 | try {
|
64 | const ctx = getContext({ route: to, router, ...serverHelpers })
|
65 | await runMiddlewares(middlewares, ctx)
|
66 | await Promise.all(
|
67 | components.map(async c => {
|
68 | const data = await c.getInitialData(ctx)
|
69 | updateDataStore(c.initialDataKey, data)
|
70 | })
|
71 | )
|
72 | next()
|
73 | } catch (err) {
|
74 | err.errorPath = to.path
|
75 | handleError(err)
|
76 | next()
|
77 | }
|
78 | })
|
79 |
|
80 |
|
81 | Vue.mixin({
|
82 | async beforeRouteUpdate(to, from, next) {
|
83 | try {
|
84 | const context = getContext({
|
85 | router,
|
86 | route: to
|
87 | })
|
88 |
|
89 | await runMiddlewares(middlewares, context)
|
90 |
|
91 | const { getInitialData } = this.$options
|
92 | if (getInitialData) {
|
93 | const data = await getInitialData(context)
|
94 | updateDataStore(this.$initialDataKey, data)
|
95 | Object.assign(this, data)
|
96 | }
|
97 | next()
|
98 | } catch (err) {
|
99 | err.url = to.path
|
100 | handleError(err)
|
101 | next()
|
102 | }
|
103 | }
|
104 | })
|
105 |
|
106 |
|
107 |
|
108 | async function main() {
|
109 | event.$emit('before-client-render')
|
110 |
|
111 | if (window.__REAM__.initialData) {
|
112 | dataStore.replaceState(window.__REAM__.initialData)
|
113 | }
|
114 |
|
115 | await routerReady(router)
|
116 |
|
117 | if (router.getMatchedComponents().length === 0) {
|
118 | throw new ReamError(pageNotFound(router.currentRoute.path))
|
119 | }
|
120 | }
|
121 |
|
122 | const mountApp = app => {
|
123 | app.$mount('#_ream')
|
124 | app.$clientRendered = true
|
125 | }
|
126 |
|
127 | main()
|
128 |
|
129 | .then(() => {
|
130 | mountApp(app)
|
131 | })
|
132 | .catch(err => {
|
133 | handleError(err)
|
134 | mountApp(app)
|
135 | })
|