layout: true
M2 Linking JS Components
--- class: center, middle, krakow, bgimage # Magento 2 ## Linking JS Components Meet Magento Poland 2017 --- class: center, middle ### This slide is made possible with RemarkJS ??? Reminder: Make a silly joke on that this slide is using RemarkJS and refer to these student notes as an example. --- class: center, middle ### This slide is also made possible with RemarkJS --- class: orange # About me - Jisse Reitsma -- - Founder and lead developer of Yireo -- - Trainer, enterpreneur, coder -- - Magento 2 Master "Mover" (2017) -- - Knockout JiSse (I don't why) -- - Loving Magento 2 --- # My talk - JS Components - RequireJS - KnockoutJS -- - Linking Components - imports - exports - links -- - Personal opinion on this --- class: center, middle ## Sample module ### [yireo-training/magento2-example-component-linking](https://github.com/yireo-training/magento2-example-component-linking) --- # Sample module - `etc/module.xml` - `registration.php` - `view/frontend/layout/default.xml` - `view/frontend/templates/component1.phtml` - `view/frontend/templates/component2.phtml` - `view/frontend/requirejs-config.js` - `view/frontend/web/js/component1.js` - `view/frontend/web/js/component2.js` --- # XML layout File `view/frontend/layout/default.xml`: ```xml
``` --- # XML layout File `view/frontend/layout/default.xml`: ```xml
``` --- # XML layout File `view/frontend/layout/default.xml`: ```xml
``` --- # PHTML template File `view/frontend/templates/component2.phtml`: ```php
``` -- ```php ``` ??? Linking only works if both components are delivering ViewModels that are registered in the uiRegistry. --- # PHTML template File `view/frontend/templates/component1.phtml`: ```php
Waiting
``` -- ```php ``` --- # RequireJS configuration File `view/frontend/requirejs-config.js`: ```js var config = { paths: { component1: 'Yireo_ExampleComponentLinking/js/component1', component2: 'Yireo_ExampleComponentLinking/js/component2' } }; ``` --- # Draft of component2 File `view/frontend/web/js/component2.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ // @todo }); } ); ``` --- # Draft of component1 File `view/frontend/web/js/component1.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ defaults: { message: 'Hello World' } }); } ); ``` --- class: center, middle
--- # What happened -- - XML layout and PHTML are used to create placeholders -- - `x-magento-init` is used to initialize JS components -- - `component1` delivers output through KnockoutJS -- - `component2` is not doing anything yet --- class: center, middle ### Exporting and importing --- # Export from component2 File `view/frontend/web/js/component2.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ defaults: { message: 'Hello from component 2', exports: { message: 'component1:message' } } }); } ); ``` --- class: center, middle
--- # Plain component2 File `view/frontend/web/js/component2.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ defaults: { message: 'Hello from component 2' } }); } ); ``` --- # Imports from component2 File `view/frontend/web/js/component1.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ defaults: { message: 'Hello World', imports: { message: 'component2:message' } } }); } ); ``` ??? For this to work, `component2` needs to be loaded earlier in the DOM than `component2`. --- class: center, middle ### Providers --- # Remember the PHTML File `view/frontend/templates/component1.phtml`: ```php ``` --- # Internal property File `view/frontend/web/js/component1.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ initialize: function() { this._super(); console.log('Provider: ' + this.provider); return true; } }); } ); ``` --- # Template literals File `view/frontend/web/js/component1.js`: ```js define(['uiComponent'], function (Component) { 'use strict'; return Component.extend({ defaults: { message: 'Hello World', imports: { message: '${ $.provider }:message' } } }); } ); ``` --- class: center, middle ### What are we doing? --- # Ingredients -- - RequireJS for dependency management -- - KnockoutJS for managing ViewModels -- - uiRegistry keeping track of ViewModels -- - Imports/exports allowing to connect everything -- ### But is this all ok? --- class: center, middle
--- # Clean code -- - Design patterns -- - Composition over inheritance -- - Link components, not component properties --- class: center, middle
--- # Manually using uiRegistry File `view/frontend/web/js/component1.js`: ```js define(['uiComponent', 'uiRegistry'], function (Component, uiRegistry) { 'use strict'; return Component.extend({ defaults: { message: 'Hello from component 1' }, initialize: function() { this._super(); this.providerObject = uiRegistry.get('component2'); this.message = this.providerObject.message; return this; } }); } ); ``` --- # Manually using DI File `view/frontend/web/js/component1.js`: ```js define(['uiComponent', 'component2'], function (Component, component2) { 'use strict'; var component2 = component2(); return Component.extend({ defaults: { message: 'Hello from component 1' }, initialize: function() { this._super(); this.message = component2.message; return this; } }); } ); ``` --- # My advice -- - Prefer DI over linking -- - Keep reading on JavaScript -- - Focus on JS testing --- class: center, middle ### Before I stop talking --- class: orange, center, middle
Mage
Test
Fest
---
Mage Test Fest
-- - Magento. Software Testing. Party. -- - November 15th-18th 2017 -- - Prodent Factory, Amersfoort, The Netherlands -- - 7 awesome speakers -- - [magetestfest.com](https://magetestfest.com/) --- class: center, middle, world # Any questions? ### @yireo ### @jissereitsma