1 |
|
2 |
|
3 | import RenderStream from './render-stream'
|
4 | import { createWriteFunction } from './write'
|
5 | import { createRenderFunction } from './render'
|
6 | import { createPromiseCallback } from './util'
|
7 | import TemplateRenderer from './template-renderer/index'
|
8 | import type { ClientManifest } from './template-renderer/index'
|
9 |
|
10 | export type Renderer = {
|
11 | renderToString: (component: Component, context: any, cb: any) => ?Promise<string>;
|
12 | renderToStream: (component: Component, context?: Object) => stream$Readable;
|
13 | };
|
14 |
|
15 | type RenderCache = {
|
16 | get: (key: string, cb?: Function) => string | void;
|
17 | set: (key: string, val: string) => void;
|
18 | has?: (key: string, cb?: Function) => boolean | void;
|
19 | };
|
20 |
|
21 | export type RenderOptions = {
|
22 | modules?: Array<(vnode: VNode) => ?string>;
|
23 | directives?: Object;
|
24 | isUnaryTag?: Function;
|
25 | cache?: RenderCache;
|
26 | template?: string | (content: string, context: any) => string;
|
27 | inject?: boolean;
|
28 | basedir?: string;
|
29 | shouldPreload?: Function;
|
30 | shouldPrefetch?: Function;
|
31 | clientManifest?: ClientManifest;
|
32 | serializer?: Function;
|
33 | runInNewContext?: boolean | 'once';
|
34 | };
|
35 |
|
36 | export function createRenderer ({
|
37 | modules = [],
|
38 | directives = {},
|
39 | isUnaryTag = (() => false),
|
40 | template,
|
41 | inject,
|
42 | cache,
|
43 | shouldPreload,
|
44 | shouldPrefetch,
|
45 | clientManifest,
|
46 | serializer
|
47 | }: RenderOptions = {}): Renderer {
|
48 | const render = createRenderFunction(modules, directives, isUnaryTag, cache)
|
49 | const templateRenderer = new TemplateRenderer({
|
50 | template,
|
51 | inject,
|
52 | shouldPreload,
|
53 | shouldPrefetch,
|
54 | clientManifest,
|
55 | serializer
|
56 | })
|
57 |
|
58 | return {
|
59 | renderToString (
|
60 | component: Component,
|
61 | context: any,
|
62 | cb: any
|
63 | ): ?Promise<string> {
|
64 | if (typeof context === 'function') {
|
65 | cb = context
|
66 | context = {}
|
67 | }
|
68 | if (context) {
|
69 | templateRenderer.bindRenderFns(context)
|
70 | }
|
71 |
|
72 |
|
73 | let promise
|
74 | if (!cb) {
|
75 | ({ promise, cb } = createPromiseCallback())
|
76 | }
|
77 |
|
78 | let result = ''
|
79 | const write = createWriteFunction(text => {
|
80 | result += text
|
81 | return false
|
82 | }, cb)
|
83 | try {
|
84 | render(component, write, context, err => {
|
85 | if (err) {
|
86 | return cb(err)
|
87 | }
|
88 | if (context && context.rendered) {
|
89 | context.rendered(context)
|
90 | }
|
91 | if (template) {
|
92 | try {
|
93 | const res = templateRenderer.render(result, context)
|
94 | if (typeof res !== 'string') {
|
95 |
|
96 | res
|
97 | .then(html => cb(null, html))
|
98 | .catch(cb)
|
99 | } else {
|
100 | cb(null, res)
|
101 | }
|
102 | } catch (e) {
|
103 | cb(e)
|
104 | }
|
105 | } else {
|
106 | cb(null, result)
|
107 | }
|
108 | })
|
109 | } catch (e) {
|
110 | cb(e)
|
111 | }
|
112 |
|
113 | return promise
|
114 | },
|
115 |
|
116 | renderToStream (
|
117 | component: Component,
|
118 | context?: Object
|
119 | ): stream$Readable {
|
120 | if (context) {
|
121 | templateRenderer.bindRenderFns(context)
|
122 | }
|
123 | const renderStream = new RenderStream((write, done) => {
|
124 | render(component, write, context, done)
|
125 | })
|
126 | if (!template) {
|
127 | if (context && context.rendered) {
|
128 | const rendered = context.rendered
|
129 | renderStream.once('beforeEnd', () => {
|
130 | rendered(context)
|
131 | })
|
132 | }
|
133 | return renderStream
|
134 | } else if (typeof template === 'function') {
|
135 | throw new Error(`function template is only supported in renderToString.`)
|
136 | } else {
|
137 | const templateStream = templateRenderer.createStream(context)
|
138 | renderStream.on('error', err => {
|
139 | templateStream.emit('error', err)
|
140 | })
|
141 | renderStream.pipe(templateStream)
|
142 | if (context && context.rendered) {
|
143 | const rendered = context.rendered
|
144 | renderStream.once('beforeEnd', () => {
|
145 | rendered(context)
|
146 | })
|
147 | }
|
148 | return templateStream
|
149 | }
|
150 | }
|
151 | }
|
152 | }
|