M2 CPFED
4. Javascript -
RequireJS / jQuery
John Hughes
Head of Magento - Fisheye Media Ltd.
Overview.
● Javascript basics
● RequireJS
● jQuery
● Overrides and mixins
● Minification, merging and bundling
Javascript
basics
Javascript basics.
● How can JS be included on a page via layout?
● How can JS be deferred / loaded async?
● What are the pros / cons of inline JS?
deafult_head_blocks.xml
<?xml version="1.0"?>
<page xmlns:xsi="..." xsi:noNamespaceSchemaLocation="...">
<head>
<script src="js/[Link]"/>
<link src="Vendor_Module::js/[Link]"/>
</head>
</page>
Javascript basics.
● How can JS be included on a page via layout?
● How can JS be deferred / loaded async?
● What are the pros / cons of inline JS?
deafult_head_blocks.xml
<?xml version="1.0"?>
<page xmlns:xsi="..." xsi:noNamespaceSchemaLocation="...">
<head>
<script src="js/[Link]" async="true"/>
</head>
</page>
deafult_head_blocks.xml
<?xml version="1.0"?>
<page xmlns:xsi="..." xsi:noNamespaceSchemaLocation="...">
<head>
<script src="js/[Link]" defer="defer"/>
</head>
</page>
Javascript basics.
How can JS be deferred / loaded async?
● Use RequireJS
Javascript basics.
● How can JS be included on a page via layout?
● How can JS be deferred / loaded async?
● What are the pros / cons of inline JS?
Javascript basics.
Pros Cons
Easy to include Not easily reusable
No additional requests Can block page rendering (not
deferred)
Harder to manage
Can’t use
Content-Security-Policy
Higher risk of XSS exploit
RequireJS
RequireJS intro.
● What is RequireJS?
● How do you include RequireJS files?
● How do you define a RequireJS module?
● How do you define RequireJS dependencies?
RequireJS intro.
What is RequireJS?
● A JavaScript file and module loader
● Based on AMD (Asynchronous Module Definition)
● Encapsulated JS modules (components)
○ i.e. not globally accessible
● Allows for dependencies on other modules
RequireJS intro.
● What is RequireJS?
● How do you include RequireJS files?
● How do you define a RequireJS module?
● How do you define RequireJS dependencies?
RequireJS intro.
How do you include RequireJS files?
● Generally within .phtml template files
○ Using the data-mage-init attribute
○ Or x-magento-init script type
[Link]
<div data-mage-init='{"Magento_Theme/js/path/to/script":{}}'>
...
</div>
[Link]
<div data-mage-init='{"Magento_Theme/js/path/to/script":{}}'>
...
</div>
Resolves to: ‘web/js/path/to/[Link]’ within Magento_Theme
(whether directly in the module or a theme)
[Link]
<div id="some-element">
<p><?= __(Script example') ?></p>
</div>
<script type="text/x-magento-init">
{
"#some-element": {
"Magento_Theme/js/path/to/script": {}
}
}
</script>
RequireJS intro.
● What is RequireJS?
● How do you include RequireJS files?
● How do you define a RequireJS module?
● How do you define RequireJS dependencies?
web/js/path/to/[Link]
define([], function() {
return function(config, element) {
[Link]({
element: element,
config: config
});
}
});
RequireJS intro.
● What is RequireJS?
● How do you include RequireJS files?
● How do you define a RequireJS module?
● How do you define RequireJS dependencies?
web/js/path/to/[Link]
define([
'jquery',
'Magento_Theme/js/path/to/script'
], function($) {
return function(config, element) {
...
}
});
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
What is the purpose of requirejs-confi[Link]?
● To set RequireJS configuration, such as:
○ Mapping aliases to actual files
○ Setting global dependencies
○ Handling non AMD file inclusions / dependencies
○ Declaring mixins
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
Where are requirejs-confi[Link] files found?
● Modules
○ view/<area>/requirejs-confi[Link]
● Themes
○ <Vendor_Module>/requirejs-confi[Link]
○ web/requirejs-confi[Link]
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
What are aliases and map / paths?
● Aliases allow creating shorthand names for AMD modules
● These can be set using map or paths
○ map allows for ‘prefix mapping’
○ paths only allows for exact matches
requirejs-confi[Link]
var config = {
'map': {
'*': {
'theme/script': 'Magento_Theme/js/path/to/script'
}
},
'paths': {
'theme/script2': 'Magento_Theme/js/path/to/script2'
}
};
[Link]
<script type="text/x-magento-init">
{
"#some-element": {
"theme/script": {}
}
}
</script>
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
How can you debug / resolve an alias?
● Use grep on CLI
● Use your IDE to find the alias and filter search to files
named ‘requirejs-confi[Link]’
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
What are deps and shims for?
● deps - globally include a JS file
● shims - add support for non AMD JS files
○ Dependencies can be declared for these files
requirejs-confi[Link]
var config = {
'deps': [
'Magento_Theme/js/global-script',
'Magento_Theme/js/path/to/nonAmdScript'
],
'shim': {
'Magento_Theme/js/path/to/nonAmdScript': {
'deps': ['jquery']
}
}
};
requirejs-confi[Link]
● What is the purpose of requirejs-confi[Link]?
● Where are requirejs-confi[Link] files found?
● What are aliases and map / paths?
● How can you debug / resolve an alias?
● What are deps and shims for?
● How do you regenerate requirejs-confi[Link]?
requirejs-confi[Link]
How do you regenerate requirejs-confi[Link]?
● developer mode - auto regenerated on each page load
○ Except when FPC enabled and page in cache
● default / production mode - regenerated if doesn’t exist
Passing data to JS files.
● How can config be passed to JS files?
● What is the standard way to pass config from
layout XML?
Passing data to JS files.
How can config be passed to JS files?
● Via JSON in the data-mage-init / x-magento-init
declaration
[Link]
<div data-mage-init='{"Magento_Theme/js/path/to/script":
{"someKey": "value"}
}'>
...
</div>
[Link]
<script type="text/x-magento-init">
{
"#some-element": {
"Magento_Theme/js/path/to/script": {
"someKey": "value"
}
}
}
</script>
Passing data to JS files.
● How can config be passed to JS files?
● What is the standard way to pass config from
layout XML?
Passing data to JS files.
What is the standard way to pass config from layout XML?
● Using the jsLayout argument
[Link]
<block name="[Link]"
template="Magento_Theme::[Link]">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="some_string"
translate="true"
xsi:type="string">Some String</item>
<item name="some_number"
xsi:type="number">42</item>
</argument>
</arguments>
</block>
[Link]
<script type="text/x-magento-init">
{
"#js-layout-element": {
"theme/jsLayoutExample":
<?= $block->getJsLayout() ?>
}
}
</script>
Magento\Framework\View\Element\AbstractBlock
/**
* Retrieve serialized JS layout configuration
* ready to use in template
*
* @return string
*/
public function getJsLayout()
{
return json_encode($this->jsLayout);
}
jQuery
jQuery.
● What is jQuery / jQuery UI?
● What are widgets and how are they used in M2?
● How can widgets be instantiated & methods called?
● How do you create widgets / use common methods?
● How can you extend / customise widgets?
jQuery.
What is jQuery / jQuery UI?
● jQuery is library that provides shortcut functions to simplify
common javascript needs and aids with cross browser
compatibility
● jQuery UI provide reusable UI components known as
widgets for common functionality such as menus, tabs etc.
jQuery.
● What is jQuery / jQuery UI?
● What are widgets and how are they used in M2?
● How can widgets be instantiated & methods called?
● How do you create widgets / use common methods?
● How can you extend / customise widgets?
jQuery.
What are widgets and how are they used in M2?
● In M2 terminology they are custom built jQuery UI widgets
wrapped in RequireJS by Magento for common use cases
● These include: modal, accordion, quicksearch and more
jQuery.
What are widgets and how are they used in M2?
● jQuery UI widgets are included / configured just like any
other RequireJS file using data-mage-init / x-magento-init
● [Link]
-guide/widgets/[Link]
jQuery.
● What is jQuery / jQuery UI?
● What are widgets and how are they used in M2?
● How can widgets be instantiated & methods called?
● How do you create widgets / use common methods?
● How can you extend / customise widgets?
jQuery.
How can widgets be instantiated & methods called?
● Using require() or passing as dependency in AMD module
● Using data-mage-init / x-magento-init
○ Not supported by all widgets (e.g. modal)
[Link]
<div id="accordion-example">
<div data-role="collapsible">
<div data-role="title">
<?= $block->escapeHtml('Accordion Title') ?>
</div>
<div data-role="content">
<p><?= $block->escapeHtml('Accordion content...') ?></p>
</div>
</div>
...
</div>
[Link]
data-role attributes
<div id="accordion-example"> determine the role of
<div data-role="collapsible"> elements for the accordion
<div data-role="title">
<?= $block->escapeHtml('Accordion Title') ?>
</div>
<div data-role="content">
<p><?= $block->escapeHtml('Accordion content...') ?></p>
</div>
</div>
...
</div>
[Link]
<script type="text/x-magento-init">
{
"#accordion-element":
{"accordion": {
/* Config settings here */
}
}
} accordion is an alias for
mage/accordion (found in lib/web)
</script>
[Link]
require([
'jquery',
'Magento_Ui/js/modal/modal'
], function(modal) {
/* Implementation, without
defining a new AMD module */
$('.some-element').modal();
});
[Link]
Modal can be assigned to
define([ element and config passed
'jquery', from template / layout
'Magento_Ui/js/modal/modal'
], function(modal) {
return function (config, element) {
/* Implementation, as part
of a new AMD module */
[Link](config);
}
});
jQuery.
How can widgets be instantiated & methods called?
● Methods can be called by passing method name as an
argument to the widget
[Link]
define([
'jquery',
'Magento_Ui/js/modal/modal'
], function(modal) {
return function (config, element) {
/* Implementation, as part
of a new AMD module */
[Link](config);
[Link]('openModal');
}
});
jQuery.
● What is jQuery / jQuery UI?
● What are widgets and how are they used in M2?
● How can widgets be instantiated & methods called?
● How do you create widgets / use common methods?
● How can you extend / customise widgets?
[Link]
define([
'jquery'
], function($) {
'use strict';
$.widget('[Link]', {
options: {...},
_init: function () {
/* Init widget here - do something */
},
});
return $.[Link];
});
requirejs-confi[Link]
var config = {
'map': {
'*': {
'fisheyeAcademy/widget-example':
'Magento_Theme/js/widget-example'
}
}
};
[Link]
<div data-mage-init='{"fisheyeAcademy/widget-example":{}}'>
<div data-role="content">
<p><?= __('Some content') ?></p>
</div>
<button data-role="showContent">
<?= __('Show') ?>
</button>
<button data-role="hideContent">
<?= __('Hide') ?>
</button>
</div>
[Link]
<div data-mage-init='{"fisheyeAcademy/widget-example":{}}'>
<div data-role="content">
<p><?= __('Some content') ?></p>
</div>
<button data-role="showContent">
<?= __('Show') ?>
</button>
<button data-role="hideContent">
<?= __('Hide') ?>
</button>
</div>
jQuery.
Method Usage
_init() Called on widget initialisation and any
further time widget is called
Should be used for default functionality that
needs to run each time
_create() Called when widget binded to element,
should be used to bind events.
Only ever called once per instance
_destroy() Runs when call .destroy() on widget
To replace / remove widget to avoid
conflicts / clean up
jQuery.
● What is jQuery / jQuery UI?
● What are widgets and how are they used in M2?
● How can widgets be instantiated & methods called?
● How do you create widgets / use common methods?
● How can you extend / customise widgets?
jQuery.
How can you extend / customise widgets?
● Widgets can be extended (inherited) using jQuery UI
● Widgets can be overridden using RequireJS path / map
○ Can also be used in conjunction with an extend
● Use a mixin to override specific methods / settings only
Mixins
jQuery.
● What are mixins and what are they for?
● How do you declare a mixin?
● How do you extend / override target file methods?
jQuery.
What are mixins and what are they for?
● Mixins allow you to modify the functionality of JS
component without extending or replacing/overriding it
● A component can have multiple mixins applied to it unlike
if you were to extend or replace/override it
jQuery.
● What are mixins and what are they for?
● How do you declare a mixin?
● How do you extend / override target file methods?
requirejs-confi[Link]
var config = {
config: {
mixins: {
'mage/accordion': {
'Vendor_Module/js/accordion-mixin': true
}
}
}
};
jQuery.
● What are mixins and what are they for?
● How do you declare a mixin?
● How do you extend / override target file methods?
[Link]
define([
'jquery',
], function ($) {
'use strict';
return function (widget) {
$.widget('[Link]', widget, {
options: {
active: [1] // Override option defaults
},
_create: function () { // Override method
this._super(); // Call parent method
// Do something here…
}
});
return $.[Link];
};
});
Wrap up /
resources
Code challenge 1.
● Add JS files to the page via <head/> in layout XML
● Create a RequireJS config file and add global files using
dep (AMD module) and shim (non AMD module, with
dependency)
Code challenge 2.
● Add a template via layout and use data-mage-init /
x-magento-init to include a simple JS file that logs or alerts
data
● Add an alias in a RequireJS config file and update the file
call in the template
● Pass config data to your JS file via the template, then by
layout using jsLayout
Code challenge 3.
● Create a jQuery widget to perform a simple interaction on
the page
● Set default options and use data-role attributes to set
default properties / roles to elements
● Create a mixin for your widget to modify it’s functionality
Credit / Resources / Thanks.
● Official Magento Study Guide
● Swift Otter Study Guide
● Magento DevDocs