create-renderer.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /* @flow */
  2. import RenderStream from './render-stream'
  3. import { createWriteFunction } from './write'
  4. import { createRenderFunction } from './render'
  5. import { createPromiseCallback } from './util'
  6. import TemplateRenderer from './template-renderer/index'
  7. import type { ClientManifest } from './template-renderer/index'
  8. export type Renderer = {
  9. renderToString: (component: Component, context: any, cb: any) => ?Promise<string>;
  10. renderToStream: (component: Component, context?: Object) => stream$Readable;
  11. };
  12. type RenderCache = {
  13. get: (key: string, cb?: Function) => string | void;
  14. set: (key: string, val: string) => void;
  15. has?: (key: string, cb?: Function) => boolean | void;
  16. };
  17. export type RenderOptions = {
  18. modules?: Array<(vnode: VNode) => ?string>;
  19. directives?: Object;
  20. isUnaryTag?: Function;
  21. cache?: RenderCache;
  22. template?: string;
  23. inject?: boolean;
  24. basedir?: string;
  25. shouldPreload?: Function;
  26. clientManifest?: ClientManifest;
  27. runInNewContext?: boolean | 'once';
  28. };
  29. export function createRenderer ({
  30. modules = [],
  31. directives = {},
  32. isUnaryTag = (() => false),
  33. template,
  34. inject,
  35. cache,
  36. shouldPreload,
  37. clientManifest
  38. }: RenderOptions = {}): Renderer {
  39. const render = createRenderFunction(modules, directives, isUnaryTag, cache)
  40. const templateRenderer = new TemplateRenderer({
  41. template,
  42. inject,
  43. shouldPreload,
  44. clientManifest
  45. })
  46. return {
  47. renderToString (
  48. component: Component,
  49. context: any,
  50. cb: any
  51. ): ?Promise<string> {
  52. if (typeof context === 'function') {
  53. cb = context
  54. context = {}
  55. }
  56. if (context) {
  57. templateRenderer.bindRenderFns(context)
  58. }
  59. // no callback, return Promise
  60. let promise
  61. if (!cb) {
  62. ({ promise, cb } = createPromiseCallback())
  63. }
  64. let result = ''
  65. const write = createWriteFunction(text => {
  66. result += text
  67. return false
  68. }, cb)
  69. try {
  70. render(component, write, context, () => {
  71. if (template) {
  72. result = templateRenderer.renderSync(result, context)
  73. }
  74. cb(null, result)
  75. })
  76. } catch (e) {
  77. cb(e)
  78. }
  79. return promise
  80. },
  81. renderToStream (
  82. component: Component,
  83. context?: Object
  84. ): stream$Readable {
  85. if (context) {
  86. templateRenderer.bindRenderFns(context)
  87. }
  88. const renderStream = new RenderStream((write, done) => {
  89. render(component, write, context, done)
  90. })
  91. if (!template) {
  92. return renderStream
  93. } else {
  94. const templateStream = templateRenderer.createStream(context)
  95. renderStream.on('error', err => {
  96. templateStream.emit('error', err)
  97. })
  98. renderStream.pipe(templateStream)
  99. return templateStream
  100. }
  101. }
  102. }
  103. }