UNPKG

3.39 kBJavaScriptView Raw
1/* @flow */
2
3import { escape, isSSRUnsafeAttr } from 'web/server/util'
4import { isObject, extend } from 'shared/util'
5import { renderAttr } from 'web/server/modules/attrs'
6import { renderClass } from 'web/util/class'
7import { genStyle } from 'web/server/modules/style'
8import { normalizeStyleBinding } from 'web/util/style'
9
10import {
11 normalizeChildren,
12 simpleNormalizeChildren
13} from 'core/vdom/helpers/normalize-children'
14
15import {
16 propsToAttrMap,
17 isRenderableAttr
18} from 'web/server/util'
19
20const 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
31export 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
45class 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
72function 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
81function 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
109function 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
120function 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
131function renderSSRClass (
132 staticClass: ?string,
133 dynamic: any
134): string {
135 const res = renderClass(staticClass, dynamic)
136 return res === '' ? res : ` class="${escape(res)}"`
137}
138
139function 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}