123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /* @flow */
- import RenderStream from './render-stream'
- import { createWriteFunction } from './write'
- import { createRenderFunction } from './render'
- import { createPromiseCallback } from './util'
- import TemplateRenderer from './template-renderer/index'
- import type { ClientManifest } from './template-renderer/index'
- export type Renderer = {
- renderToString: (component: Component, context: any, cb: any) => ?Promise<string>;
- renderToStream: (component: Component, context?: Object) => stream$Readable;
- };
- type RenderCache = {
- get: (key: string, cb?: Function) => string | void;
- set: (key: string, val: string) => void;
- has?: (key: string, cb?: Function) => boolean | void;
- };
- export type RenderOptions = {
- modules?: Array<(vnode: VNode) => ?string>;
- directives?: Object;
- isUnaryTag?: Function;
- cache?: RenderCache;
- template?: string | (content: string, context: any) => string;
- inject?: boolean;
- basedir?: string;
- shouldPreload?: Function;
- shouldPrefetch?: Function;
- clientManifest?: ClientManifest;
- serializer?: Function;
- runInNewContext?: boolean | 'once';
- };
- export function createRenderer ({
- modules = [],
- directives = {},
- isUnaryTag = (() => false),
- template,
- inject,
- cache,
- shouldPreload,
- shouldPrefetch,
- clientManifest,
- serializer
- }: RenderOptions = {}): Renderer {
- const render = createRenderFunction(modules, directives, isUnaryTag, cache)
- const templateRenderer = new TemplateRenderer({
- template,
- inject,
- shouldPreload,
- shouldPrefetch,
- clientManifest,
- serializer
- })
- return {
- renderToString (
- component: Component,
- context: any,
- cb: any
- ): ?Promise<string> {
- if (typeof context === 'function') {
- cb = context
- context = {}
- }
- if (context) {
- templateRenderer.bindRenderFns(context)
- }
- // no callback, return Promise
- let promise
- if (!cb) {
- ({ promise, cb } = createPromiseCallback())
- }
- let result = ''
- const write = createWriteFunction(text => {
- result += text
- return false
- }, cb)
- try {
- render(component, write, context, err => {
- if (err) {
- return cb(err)
- }
- if (context && context.rendered) {
- context.rendered(context)
- }
- if (template) {
- try {
- const res = templateRenderer.render(result, context)
- if (typeof res !== 'string') {
- // function template returning promise
- res
- .then(html => cb(null, html))
- .catch(cb)
- } else {
- cb(null, res)
- }
- } catch (e) {
- cb(e)
- }
- } else {
- cb(null, result)
- }
- })
- } catch (e) {
- cb(e)
- }
- return promise
- },
- renderToStream (
- component: Component,
- context?: Object
- ): stream$Readable {
- if (context) {
- templateRenderer.bindRenderFns(context)
- }
- const renderStream = new RenderStream((write, done) => {
- render(component, write, context, done)
- })
- if (!template) {
- if (context && context.rendered) {
- const rendered = context.rendered
- renderStream.once('beforeEnd', () => {
- rendered(context)
- })
- }
- return renderStream
- } else if (typeof template === 'function') {
- throw new Error(`function template is only supported in renderToString.`)
- } else {
- const templateStream = templateRenderer.createStream(context)
- renderStream.on('error', err => {
- templateStream.emit('error', err)
- })
- renderStream.pipe(templateStream)
- if (context && context.rendered) {
- const rendered = context.rendered
- renderStream.once('beforeEnd', () => {
- rendered(context)
- })
- }
- return templateStream
- }
- }
- }
- }
|