From e37135f10e6c8a8ae38e282be7aa9aea90aaae4a Mon Sep 17 00:00:00 2001 From: Patrick Steele-Idem Date: Fri, 11 Nov 2016 22:34:46 -0700 Subject: [PATCH] Fixes #416 - Allow split widget/render for template as entry --- .../index.marko | 3 + .../renderer.js | 7 ++ .../sanity-check-template-entry-split/test.js | 12 +++ .../widget.js | 5 ++ .../expected.js | 36 +++++++++ .../index.marko | 2 + .../renderer.js | 1 + .../component-template-entry-split/widget.js | 1 + widgets/index-browser.js | 5 ++ widgets/index.js | 5 ++ .../TransformHelper/handleWidgetBind.js | 77 ++++++++++++++++--- 11 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 test/autotests/widgets-browser/sanity-check-template-entry-split/index.marko create mode 100644 test/autotests/widgets-browser/sanity-check-template-entry-split/renderer.js create mode 100644 test/autotests/widgets-browser/sanity-check-template-entry-split/test.js create mode 100644 test/autotests/widgets-browser/sanity-check-template-entry-split/widget.js create mode 100644 test/autotests/widgets-compilation/component-template-entry-split/expected.js create mode 100644 test/autotests/widgets-compilation/component-template-entry-split/index.marko create mode 100644 test/autotests/widgets-compilation/component-template-entry-split/renderer.js create mode 100644 test/autotests/widgets-compilation/component-template-entry-split/widget.js diff --git a/test/autotests/widgets-browser/sanity-check-template-entry-split/index.marko b/test/autotests/widgets-browser/sanity-check-template-entry-split/index.marko new file mode 100644 index 0000000000..caa24f9537 --- /dev/null +++ b/test/autotests/widgets-browser/sanity-check-template-entry-split/index.marko @@ -0,0 +1,3 @@ +
+ Hello ${data.name}! +
diff --git a/test/autotests/widgets-browser/sanity-check-template-entry-split/renderer.js b/test/autotests/widgets-browser/sanity-check-template-entry-split/renderer.js new file mode 100644 index 0000000000..01884e16a0 --- /dev/null +++ b/test/autotests/widgets-browser/sanity-check-template-entry-split/renderer.js @@ -0,0 +1,7 @@ +module.exports = { + getTemplateData: function(state, input) { + return { + name: input.name.toUpperCase() + }; + } +}; \ No newline at end of file diff --git a/test/autotests/widgets-browser/sanity-check-template-entry-split/test.js b/test/autotests/widgets-browser/sanity-check-template-entry-split/test.js new file mode 100644 index 0000000000..3c3bb265dc --- /dev/null +++ b/test/autotests/widgets-browser/sanity-check-template-entry-split/test.js @@ -0,0 +1,12 @@ +var expect = require('chai').expect; + +module.exports = function(helpers) { + + var widget = helpers.mount(require('./index.marko'), { name: 'Frank' }); + + expect(widget.el.innerHTML).to.contain('FRANK'); + + widget.setName('Jane'); + + expect(widget.el.innerHTML).to.contain('Jane'); +}; \ No newline at end of file diff --git a/test/autotests/widgets-browser/sanity-check-template-entry-split/widget.js b/test/autotests/widgets-browser/sanity-check-template-entry-split/widget.js new file mode 100644 index 0000000000..d89f38b1ba --- /dev/null +++ b/test/autotests/widgets-browser/sanity-check-template-entry-split/widget.js @@ -0,0 +1,5 @@ +module.exports = { + setName: function(newName) { + this.getEl('name').innerHTML = newName; + } +}; \ No newline at end of file diff --git a/test/autotests/widgets-compilation/component-template-entry-split/expected.js b/test/autotests/widgets-compilation/component-template-entry-split/expected.js new file mode 100644 index 0000000000..6d95817185 --- /dev/null +++ b/test/autotests/widgets-compilation/component-template-entry-split/expected.js @@ -0,0 +1,36 @@ +var template = require("marko/html").c(__filename); + +var renderer = require("./renderer"); + +var marko_widgets = require("marko/widgets/index"); + +module.exports = marko_widgets.r(renderer, template); + +var marko_registerWidget = marko_widgets.registerWidget, + marko_widgetType = marko_registerWidget("/marko-test$1.0.0/autotests/widgets-compilation/component-template-entry-split/widget", function() { + return require("./widget"); + }), + marko_widgetAttrs = marko_widgets.attrs, + marko_helpers = require("marko/runtime/html/helpers"), + marko_attr = marko_helpers.a, + marko_attrs = marko_helpers.as, + marko_loadTag = marko_helpers.t, + w_widget_tag = marko_loadTag(require("marko/widgets/taglib/widget-tag")); + +function render(data, out) { + w_widget_tag({ + type: marko_widgetType, + _cfg: data.widgetConfig, + _state: data.widgetState, + _props: data.widgetProps, + _body: data.widgetBody, + renderBody: function renderBody(out, widget) { + out.w(""); + } + }, out); +} + +template._ = render; diff --git a/test/autotests/widgets-compilation/component-template-entry-split/index.marko b/test/autotests/widgets-compilation/component-template-entry-split/index.marko new file mode 100644 index 0000000000..2347bdf694 --- /dev/null +++ b/test/autotests/widgets-compilation/component-template-entry-split/index.marko @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/test/autotests/widgets-compilation/component-template-entry-split/renderer.js b/test/autotests/widgets-compilation/component-template-entry-split/renderer.js new file mode 100644 index 0000000000..a099545376 --- /dev/null +++ b/test/autotests/widgets-compilation/component-template-entry-split/renderer.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/test/autotests/widgets-compilation/component-template-entry-split/widget.js b/test/autotests/widgets-compilation/component-template-entry-split/widget.js new file mode 100644 index 0000000000..a099545376 --- /dev/null +++ b/test/autotests/widgets-compilation/component-template-entry-split/widget.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/widgets/index-browser.js b/widgets/index-browser.js index 5429aa5310..641c981e90 100644 --- a/widgets/index-browser.js +++ b/widgets/index-browser.js @@ -83,6 +83,11 @@ exports.c = function(component, template) { return exports.defineComponent(component); }; +exports.r = function(renderer, template) { + renderer.template = template; + return exports.defineRenderer(renderer); +}; + exports.batchUpdate = updateManager.batchUpdate; exports.onAfterUpdate = updateManager.onAfterUpdate; diff --git a/widgets/index.js b/widgets/index.js index b4795da443..8a3b12ff5d 100644 --- a/widgets/index.js +++ b/widgets/index.js @@ -326,6 +326,11 @@ exports.c = function(component, template) { return exports.defineComponent(component); }; +exports.r = function(renderer, template) { + renderer.template = template; + return exports.defineRenderer(renderer); +}; + // registerWidget is a no-op on the server. // Fixes https://github.com/marko-js/marko-widgets/issues/111 exports.registerWidget = function(typeName) { return typeName; }; diff --git a/widgets/taglib/TransformHelper/handleWidgetBind.js b/widgets/taglib/TransformHelper/handleWidgetBind.js index b1ec63b990..494104309d 100644 --- a/widgets/taglib/TransformHelper/handleWidgetBind.js +++ b/widgets/taglib/TransformHelper/handleWidgetBind.js @@ -1,6 +1,7 @@ 'use strict'; let path = require('path'); +var resolveFrom = require('resolve-from'); function isTemplateMainEntry(context) { let filename = path.basename(context.filename); @@ -12,7 +13,7 @@ function isTemplateMainEntry(context) { return filename === 'index'; } -function isCombinedWidget(widgetModulePath) { +function checkCombinedComponent(widgetModulePath) { let filename = path.basename(widgetModulePath); let ext = path.extname(filename); if (ext) { @@ -22,6 +23,13 @@ function isCombinedWidget(widgetModulePath) { return filename !== 'widget'; } +function checkSplitComponent(context) { + let filename = context.filename; + let dir = path.dirname(filename); + let rendererPath = resolveFrom(dir, './renderer'); + return rendererPath != null; +} + module.exports = function handleWidgetBind() { let el = this.el; let context = this.context; @@ -61,7 +69,7 @@ module.exports = function handleWidgetBind() { context.on('beforeGenerateCode:TemplateRoot', function(root) { root.node.generateExports = function(template) { - return buildExport(transformHelper, component, template); + return buildComponentExport(transformHelper, component, template); }; }); } else { @@ -89,9 +97,20 @@ module.exports = function handleWidgetBind() { bindAttrValue); } - let isComponentExport = isMain && isCombinedWidget(modulePath); + let isComponentExport; + let isRendererExport; + let rendererPath; + + if (isMain) { + if (checkCombinedComponent(modulePath)) { + isComponentExport = true; + } else if (checkSplitComponent(context)) { + isRendererExport = true; + rendererPath = './renderer'; + } + } - if (isComponentExport) { + if (isComponentExport || isRendererExport) { transformHelper.markoWidgetsVar = builder.identifier('marko_widgets'); } @@ -100,7 +119,7 @@ module.exports = function handleWidgetBind() { let def; - if (isMain) { + if (isMain && isComponentExport) { def = builder.functionDeclaration(null, [], [ builder.returnStatement(builder.memberExpression(builder.identifier('module'), builder.identifier('exports'))) ]); @@ -110,14 +129,23 @@ module.exports = function handleWidgetBind() { widgetAttrs.type = widgetTypeNode; - if (isComponentExport) { + if (isComponentExport || isRendererExport) { this.context.on('beforeGenerateCode:TemplateRoot', function(root) { root.node.generateExports = function(template) { - var component = builder.require( - builder.literal(modulePath) - ); + if (isComponentExport) { + let component = builder.require( + builder.literal(modulePath) + ); + + return buildComponentExport(transformHelper, component, template); + } else { + let renderer = builder.require( + builder.literal(rendererPath) + ); + + return buildRendererExport(transformHelper, renderer, template); + } - return buildExport(transformHelper, component, template); }; }); } @@ -167,7 +195,7 @@ function getInlineComponent(context) { return component; } -function buildExport(transformHelper, component, template) { +function buildComponentExport(transformHelper, component, template) { let builder = transformHelper.builder; return [ builder.assignment( @@ -192,4 +220,31 @@ function buildExport(transformHelper, component, template) { ) ) ]; +} + +function buildRendererExport(transformHelper, renderer, template) { + let builder = transformHelper.builder; + return [ + builder.assignment( + builder.var('renderer'), + renderer + ), + builder.var(transformHelper.markoWidgetsVar, builder.require(builder.literal(transformHelper.getMarkoWidgetsRequirePath('marko/widgets')))), + builder.assignment( + builder.memberExpression( + builder.identifier('module'), + builder.identifier('exports') + ), + builder.functionCall( + builder.memberExpression( + transformHelper.markoWidgetsVar, + builder.identifier('r') + ), + [ + builder.identifier('renderer'), + builder.identifier('template') + ] + ) + ) + ]; } \ No newline at end of file