Upgrade Guide ============= ## v4 to v5 ### Breaking changes - The `onAfterUpdate` lifecycle event was renamed to `onUpdate` - The `init()` constructor for a widget is only called _once_ even if a widget is rerendered - When a nested widget is rerendered, it is no longer reinitialized. - Everything related to Dust has been removed. ### New features - Integrated [morphdom](https://github.com/patrick-steele-idem/morphdom) to more efficiently transform the existing DOM instead of replacing it entirely - Significant performance improvements - Code cleanup - Stable IDs for widgets that are not assigned a `ref` - New lifecycle event: 'onRender' ## v3 to v4 ### Breaking changes - `Widget.prototype.render = function(input, out) { ... }` is no longer allowed. Use `Widget.prototype.renderer = function(input, out) { ... }` or `defineComponent(...)` instead (recommended). - NOTE: `this.widgets.foo` has been removed since `marko-widgets@^3` ### New features - Simpler syntax for defining widget types: ___Old:___ ```javascript function Widget() { this.doSomething(); } Widget.prototype = { doSomething: function() { } }; module.exports = Widget; ``` ___New:___ ```javascript module.exports = require('marko-widgets').defineWidget({ init: function() { this.doSomething(); }, doSomething: function() { } }); ``` - Ability to define the _widget_ and the _renderer_ in the same JavaScript file: ```javascript module.exports = require('marko-widgets').defineComponent({ template: require.resolve('./template.marko'), getTemplateData: function(state, input) { return { hello: 'world' }; }, init: function() { this.doSomething(); }, doSomething: function() { } }); ``` - Support for stateful widgets (changing widget state causes a widget to be rerendered) ```javascript module.exports = require('marko-widgets').defineComponent({ template: require.resolve('./template.marko'), getInitialState: function(input) { return { size: input.size || 'normal' }; }, getInitialBody: function(input) { return input.label || input.renderBody; }, getTemplateData: function(state, input) { var rootAttrs = {}; var classParts = ['app-button']; var type = 'button'; var size = state.size; if (size !== 'normal') { classParts.push('app-button-' + size); } rootAttrs['class'] = classParts.join(' '); return { type: type, rootAttrs: rootAttrs }; }, setSize: function(size) { this.setState('size', size); }, getSize: function() { return this.state.size; } }); ``` ## v2 to v3 With marko-widgets, `this.widgets.foo` is no longer support and `this.widgets` will be `null`. Instead, you should `this.getWidget('foo')`. ## v1 to v2 marko-widgets v2 introduced the potential for a circular dependency. To avoid problems, you should no longer use `module.exports` in your widget JavaScript module as shown below: _Old widget.js:_ ```javascript function Widget() { // ... } Widget.prototype = { // ... }; module.exports = Widget; ``` _New widget.js:_ ```javascript function Widget() { } Widget.prototype = { }; exports.Widget = Widget; ``` You should also do the same for your UI component renderer: _Old renderer.js:_ ```javascript module.exports = function render(input, out) { // ... } ``` _New renderer.js:_ ```javascript exports.renderer = function(input, out) { // ... } ```