From e1d890a00277926ff6c2f162c03ab1dc79460838 Mon Sep 17 00:00:00 2001 From: Joel Chen Date: Tue, 31 Jul 2018 19:10:07 -0700 Subject: [PATCH] support stopping mid render --- .../lib/async-template.js | 2 +- .../lib/react-webapp.js | 14 ++++--- .../lib/react/token-handlers.js | 6 +-- .../lib/render-context.js | 37 ++++++++++++++++--- .../electrode-react-webapp/lib/renderer.js | 13 +++++-- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/packages/electrode-react-webapp/lib/async-template.js b/packages/electrode-react-webapp/lib/async-template.js index 6c7eae4ec..630467876 100644 --- a/packages/electrode-react-webapp/lib/async-template.js +++ b/packages/electrode-react-webapp/lib/async-template.js @@ -51,7 +51,7 @@ class AsyncTemplate { await r.beforeRender(context); } - const result = context.skip ? context.result : await this._renderer.render(context); + const result = await this._renderer.render(context); for (const r of this._afterRenders) { await r.afterRender(context); diff --git a/packages/electrode-react-webapp/lib/react-webapp.js b/packages/electrode-react-webapp/lib/react-webapp.js index e1fefc18c..ec9537879 100644 --- a/packages/electrode-react-webapp/lib/react-webapp.js +++ b/packages/electrode-react-webapp/lib/react-webapp.js @@ -12,12 +12,16 @@ const getStatsPath = utils.getStatsPath; function makeRouteHandler(routeOptions) { const userTokenHandlers = [].concat(routeOptions.tokenHandler, routeOptions.tokenHandlers); - const reactTokenHandlers = Path.join(__dirname, "react/token-handlers"); - const tokenHandlers = - userTokenHandlers.indexOf(reactTokenHandlers) < 0 - ? [reactTokenHandlers].concat(userTokenHandlers) - : userTokenHandlers; + let tokenHandlers = userTokenHandlers; + + if (!routeOptions.replaceTokenHandlers) { + const reactTokenHandlers = Path.join(__dirname, "react/token-handlers"); + tokenHandlers = + userTokenHandlers.indexOf(reactTokenHandlers) < 0 + ? [reactTokenHandlers].concat(userTokenHandlers) + : userTokenHandlers; + } const asyncTemplate = new AsyncTemplate({ htmlFile: routeOptions.htmlFile, diff --git a/packages/electrode-react-webapp/lib/react/token-handlers.js b/packages/electrode-react-webapp/lib/react/token-handlers.js index d21eebf77..00923e1ee 100644 --- a/packages/electrode-react-webapp/lib/react/token-handlers.js +++ b/packages/electrode-react-webapp/lib/react/token-handlers.js @@ -111,9 +111,9 @@ module.exports = function setup(handlerContext /* , asyncTemplate */) { } const prepareContext = content => { - if (content.render === false || content.html === undefined) { - return context.skipRender(content); - } + // if (content.render === false || content.html === undefined) { + // return context.skipRender(content); + // } let cspScriptNonce; let cspStyleNonce; diff --git a/packages/electrode-react-webapp/lib/render-context.js b/packages/electrode-react-webapp/lib/render-context.js index d808f3156..9598b6df3 100644 --- a/packages/electrode-react-webapp/lib/render-context.js +++ b/packages/electrode-react-webapp/lib/render-context.js @@ -10,6 +10,7 @@ class RenderContext { this.asyncTemplate = asyncTemplate; this._handlersMap = asyncTemplate.handlersMap; this.transform = x => x; + this._stop = 0; } // return a token handler by name @@ -34,11 +35,33 @@ class RenderContext { this.transform = result => transform(result, this); } - // before render starts, call this with any predetermined result - // to use as the output rather than doing actual render for it - // Basically no rendering will occur. - skipRender(result) { - this.skip = true; + get stop() { + return this._stop; + } + + // + // set this any time to fully stop and close rendering + // stop modes: + // 1 - only process string tokens + // 2 - fully stop immediately, no more token processing + // 3 - completely void any render output and stop immediately, + // replace output with result. This only works if output + // is buffered and not streaming out immediately. + // + set stop(f) { + this._stop = f; + } + + fullStop() { + this.stop(RenderContext.FULL_STOP); + } + + softStop() { + this.stop(RenderContext.SOFT_STOP); + } + + voidStop(result) { + this.stop(RenderContext.VOID_STOP); this.result = result; } @@ -67,4 +90,8 @@ class RenderContext { } } +RenderContext.VOID_STOP = 3; +RenderContext.FULL_STOP = 2; +RenderContext.SOFT_STOP = 1; + module.exports = RenderContext; diff --git a/packages/electrode-react-webapp/lib/renderer.js b/packages/electrode-react-webapp/lib/renderer.js index 52fce7d0c..eea87e283 100644 --- a/packages/electrode-react-webapp/lib/renderer.js +++ b/packages/electrode-react-webapp/lib/renderer.js @@ -3,6 +3,7 @@ /* eslint-disable max-statements */ const Promise = require("bluebird"); +const { VOID_STOP, FULL_STOP, SOFT_STOP } = require("./render-context"); class Renderer { constructor(options) { @@ -75,9 +76,15 @@ class Renderer { } _next(xt) { - return xt._tokenIndex >= this.renderSteps.length - ? xt.resolve(xt.context.output.close()) - : this.renderSteps[xt._tokenIndex++](xt); + const stop = xt.context.stop; + + if (stop === VOID_STOP || stop === FULL_STOP || xt._tokenIndex >= this.renderSteps.length) { + return xt.resolve(xt.context.output.close()); + } else if (stop === SOFT_STOP) { + return false; // TODO: support soft stop + } else { + return this.renderSteps[xt._tokenIndex++](xt); + } } }