1 |
|
2 |
|
3 | import { escape, isSSRUnsafeAttr } from 'web/server/util'
|
4 | import { isObject, extend } from 'shared/util'
|
5 | import { renderAttr } from 'web/server/modules/attrs'
|
6 | import { renderClass } from 'web/util/class'
|
7 | import { genStyle } from 'web/server/modules/style'
|
8 | import { normalizeStyleBinding } from 'web/util/style'
|
9 |
|
10 | import {
|
11 | normalizeChildren,
|
12 | simpleNormalizeChildren
|
13 | } from 'core/vdom/helpers/normalize-children'
|
14 |
|
15 | import {
|
16 | propsToAttrMap,
|
17 | isRenderableAttr
|
18 | } from 'web/server/util'
|
19 |
|
20 | const ssrHelpers = {
|
21 | _ssrEscape: escape,
|
22 | _ssrNode: renderStringNode,
|
23 | _ssrList: renderStringList,
|
24 | _ssrAttr: renderAttr,
|
25 | _ssrAttrs: renderAttrs,
|
26 | _ssrDOMProps: renderDOMProps,
|
27 | _ssrClass: renderSSRClass,
|
28 | _ssrStyle: renderSSRStyle
|
29 | }
|
30 |
|
31 | export function installSSRHelpers (vm: Component) {
|
32 | if (vm._ssrNode) {
|
33 | return
|
34 | }
|
35 | let Vue = vm.constructor
|
36 | while (Vue.super) {
|
37 | Vue = Vue.super
|
38 | }
|
39 | extend(Vue.prototype, ssrHelpers)
|
40 | if (Vue.FunctionalRenderContext) {
|
41 | extend(Vue.FunctionalRenderContext.prototype, ssrHelpers)
|
42 | }
|
43 | }
|
44 |
|
45 | class StringNode {
|
46 | isString: boolean;
|
47 | open: string;
|
48 | close: ?string;
|
49 | children: ?Array<any>;
|
50 |
|
51 | constructor (
|
52 | open: string,
|
53 | close?: string,
|
54 | children?: Array<any>,
|
55 | normalizationType?: number
|
56 | ) {
|
57 | this.isString = true
|
58 | this.open = open
|
59 | this.close = close
|
60 | if (children) {
|
61 | this.children = normalizationType === 1
|
62 | ? simpleNormalizeChildren(children)
|
63 | : normalizationType === 2
|
64 | ? normalizeChildren(children)
|
65 | : children
|
66 | } else {
|
67 | this.children = void 0
|
68 | }
|
69 | }
|
70 | }
|
71 |
|
72 | function renderStringNode (
|
73 | open: string,
|
74 | close?: string,
|
75 | children?: Array<any>,
|
76 | normalizationType?: number
|
77 | ): StringNode {
|
78 | return new StringNode(open, close, children, normalizationType)
|
79 | }
|
80 |
|
81 | function renderStringList (
|
82 | val: any,
|
83 | render: (
|
84 | val: any,
|
85 | keyOrIndex: string | number,
|
86 | index?: number
|
87 | ) => string
|
88 | ): string {
|
89 | let ret = ''
|
90 | let i, l, keys, key
|
91 | if (Array.isArray(val) || typeof val === 'string') {
|
92 | for (i = 0, l = val.length; i < l; i++) {
|
93 | ret += render(val[i], i)
|
94 | }
|
95 | } else if (typeof val === 'number') {
|
96 | for (i = 0; i < val; i++) {
|
97 | ret += render(i + 1, i)
|
98 | }
|
99 | } else if (isObject(val)) {
|
100 | keys = Object.keys(val)
|
101 | for (i = 0, l = keys.length; i < l; i++) {
|
102 | key = keys[i]
|
103 | ret += render(val[key], key, i)
|
104 | }
|
105 | }
|
106 | return ret
|
107 | }
|
108 |
|
109 | function renderAttrs (obj: Object): string {
|
110 | let res = ''
|
111 | for (const key in obj) {
|
112 | if (isSSRUnsafeAttr(key)) {
|
113 | continue
|
114 | }
|
115 | res += renderAttr(key, obj[key])
|
116 | }
|
117 | return res
|
118 | }
|
119 |
|
120 | function renderDOMProps (obj: Object): string {
|
121 | let res = ''
|
122 | for (const key in obj) {
|
123 | const attr = propsToAttrMap[key] || key.toLowerCase()
|
124 | if (isRenderableAttr(attr)) {
|
125 | res += renderAttr(attr, obj[key])
|
126 | }
|
127 | }
|
128 | return res
|
129 | }
|
130 |
|
131 | function renderSSRClass (
|
132 | staticClass: ?string,
|
133 | dynamic: any
|
134 | ): string {
|
135 | const res = renderClass(staticClass, dynamic)
|
136 | return res === '' ? res : ` class="${escape(res)}"`
|
137 | }
|
138 |
|
139 | function renderSSRStyle (
|
140 | staticStyle: ?Object,
|
141 | dynamic: any,
|
142 | extra: ?Object
|
143 | ): string {
|
144 | const style = {}
|
145 | if (staticStyle) extend(style, staticStyle)
|
146 | if (dynamic) extend(style, normalizeStyleBinding(dynamic))
|
147 | if (extra) extend(style, extra)
|
148 | const res = genStyle(style)
|
149 | return res === '' ? res : ` style=${JSON.stringify(escape(res))}`
|
150 | }
|