Important
You are browsing the documentation for version 3.1 of OroCommerce, OroCRM and OroPlatform, which is no longer maintained. Read version 5.1 (the latest LTS version) of the Oro documentation to get up-to-date information.
See our Release Process documentation for more information on the currently supported and upcoming releases.
JavaScript Modularity¶
Overview¶
OroPlatform uses Asynchronous Module Definition to provide JavaScript modularity.
AMD (Asynchronous Module Definition) – is a concept of creating modular JavaScript code with a defined set of dependencies. It defines the order in which resources have to be loaded and executed and, therefore, keeping the global scope clean.
RequireJS¶
OroPlatform leverages the RequireJS library to follow the AMD approach. RequireJS is a JavaScript library that provides functions to define modules and to declare dependencies on other modules in a module. A module is like common JavaScript, except that it defines a well-scoped object and does not pollute the global namespace. To use the functions from other modules, developers uses the RequireJS syntax to list the dependencies a module requires. Instead of pulling the required dependencies into the module manually, RequireJS ensures that all dependencies are injected into the module following the inversion of control principle and makes it possible to load dependencies asynchronously.
See also
You can find more information on how to write modular JavaScript using AMD in:
RequireJS comes with two important functions that form the backbone of the library:
Define a Module¶
Each module is defined in its own file using define()
which has the following signature:
1define(
2 module_id /*optional*/,
3 [dependencies] /*optional*/,
4 definition function /*function for instantiating the module or object*/
5);
In its simplest form, a RequireJS module is just an object defining pair-value pairs:
1// foo.js
2
3define({
4 foo: bar,
5 foobar: baz,
6 baz: function (param) {
7 // do something
8
9 return ...;
10 }
11});
You can use a function if you need to do some initialization works:
1// foo.js
2
3define(function () {
4 var bar = ...;
5
6 return {
7 foo: bar,
8 foobar: baz,
9 baz: function (param) {
10 // do something
11
12 return ...;
13 }
14 }
15});
Note
Usually, you do not have to define module_id
since it is automatically derived from the
path of the file the module is stored in by the RequireJS optimization tool. In the example
above, the module name would be foo
, as it was stored in the foo.js
file.
Usually, your modules will need to work with some code from other modules. For example, a bar
module depends on the previously created foo
module:
1// bar.js
2define(['foo'], function (foo) {
3 var baz = ...;
4 var bar = foo.baz(baz);
5
6 return bar;
7});
In this example, the list of dependencies specified in the first argument is resolved by RequireJS,
and then the resolved modules are passed as arguments to the module function. This way, the baz
function defined in the foo
module can be called by invoking baz
on the foo
variable
which actually holds the foo
module object.
Load Dependencies with require
¶
Sometimes, you do not need to define a module, but you need to pull in some dependencies and use
them immediately. For example, your application may require both the foo
and the bar
module
to boot:
1require(['app', 'foo', 'bar'], function (app, foo, bar) {
2 app.start(foo.baz(bar));
3});
The usage of require()
looks almost the same as define()
, but there are some important
differences to note:
require()
does not build a module. Thus, you cannot specify a module id, and nothing will be exported.The last argument for
require()
is always a function that will be executed when all dependencies are loaded. Contrary, the last argument passed todefine()
can be an object if you do not need to execute any initialization logic. Indefine()
, you cannot omit the last argument, while inrequire
, you do not need it at all, but only use it to load the application dependencies, for example.
Use RequireJS with OroPlatform¶
The RequireJSBundle eases the RequireJS integration into an application based on the Oro
Platform. It scans each bundle for a RequireJS configuration file named requirejs.yml
located in its Resources/config
directory.
Such configuration file can define two sections:
See also
You can find detailed information about the RequireJS configuration in the reference section.
RequireJSBundle was developed to simplify RequireJS configuration and
building process. It collects parts of RequireJS configuration
Resources/config/requirejs.yml
from the bundles and merges them
into a single config file.
Configuration¶
shim
¶
Use the shim option to configure exports and dependencies for JavaScript libraries that do not
support RequireJS, but are loaded in the traditional way. For example, the following
configuration defines modules named underscore
(for the Underscore.js library) and backbone
for the Backbone.js library:
1# src/Acme/DemoBundle/Resources/config/requires.yml
2config:
3 shim:
4 'underscore':
5 exports: '_'
6 'backbone':
7 deps:
8 - 'underscore'
9 - 'jquery'
10 exports: 'Backbone'
The deps
option is used to define the list of dependencies (the Backbone.js library requires
the Underscore.js and the jQuery libraries). The exports
option specifies which object will be
exposed by the module.
Note
Use the paths option to configure the paths where the library files can be located.
map
¶
Sometimes, you may want to load a different version of a module based on the context it requires. For example, the OroUIBundle comes with an extended version of the jQuery library. Use the map option to substitute a module ID for a given prefix:
1# src/Acme/DemoBundle/Resources/config/requires.yml
2config:
3 map:
4 '*':
5 'jquery': 'oroui/js/jquery-extend'
6 'oroui/js/jquery-extend':
7 'jquery': 'jquery'
The example uses the special *
which maps all module prefixes. This means that all modules get
the extended jQuery library from the OroUIBundle. However, since the bundle itself needs the
original version of the library to be able to extend it, it will receive the original version providing
that there is more specific oroui/js/jquery-extend
entry that will take precedence.
paths
¶
The paths option tells the optimization tool under which locations certain modules can be found:
1# src/Acme/DemoBundle/Resources/config/requires.yml
2config:
3 paths:
4 'jquery': 'bundles/oroui/lib/jquery-1.10.2.js'
5 'underscore': 'bundles/oroui/lib/underscore.js'
6 'backbone': 'bundles/oroui/lib/backbone.js'
7 'oroui/js/jquery-extend': 'bundles/oroui/js/jquery-extend.js'
Build Process Customization¶
You can use the build
option to exclude a module from being included in the build file by the
optimization tool:
1# src/Acme/DemoBundle/Resources/config/requirejs.yml
2build:
3 paths:
4 'bootstrap': 'empty:'
With this configuration, the bootstrap
module will be loaded from its actual path on runtime.
Override RequireJS Modules¶
You can override RequireJS modules with the map
configuration in Resources/config/requirejs.yml
.
For example:
1config:
2 map:
3 '*':
4 'oroemail/js/email/variable/view': 'acmeemail/js/email/variable/view'
5 'acmeemail/js/email/variable/view':
6 'oroemail/js/email/variable/view': 'oroemail/js/email/variable/view'
- This configuration says:
all modules that require
oroemail/js/email/variable/view
should actually getacmeemail/js/email/variable/view
fileand only
acmeemail/js/email/variable/view
will get the originaloroemail/js/email/variable/view
And inside you module, you can extend original EmailVariableView:
1define(function (require) {
2 'use strict';
3
4 var MyEmailVariableView,
5 BaseEmailVariableView = require('oroemail/js/email/variable/view');
6
7 MyEmailVariableView = BaseEmailVariableView.extend({
8 /* define extended logic here */
9 });
10
11 return MyEmailVariableView;
12});
Full Configuration Example¶
A full working example of a RequireJS configuration in a bundle can look like this:
1# src/Acme/DemoBundle/Resources/config/requirejs.yml
2config:
3 shim:
4 # shim configures the exports and dependencies for older, traditional
5 # "browser globals" scripts that do not use define() to declare
6 # the dependencies and set a module value;
7 'jquery-ui':
8 deps:
9 - 'jquery'
10 'underscore':
11 exports: '_'
12 'backbone':
13 deps:
14 - 'underscore'
15 - 'jquery'
16 exports: 'Backbone'
17 map:
18 # maps for the given module prefix, instead of loading the module with
19 # the given ID, substitutes a different module_id;
20 '*':
21 'jquery': 'oroui/js/jquery-extend'
22 'oroui/js/jquery-extend':
23 'jquery': 'jquery'
24 paths:
25 # path mappings for module names not found directly under baseUrl
26 'jquery': 'bundles/oroui/lib/jquery-1.10.2.js'
27 'jquery-ui': 'bundles/oroui/lib/jquery-ui.min.js'
28 'bootstrap': 'bundles/oroui/lib/bootstrap.min.js'
29 'underscore': 'bundles/oroui/lib/underscore.js'
30 'backbone': 'bundles/oroui/lib/backbone.js'
31 'oroui/js/jquery-extend': 'bundles/oroui/js/jquery-extend.js'
32
33build:
34 paths:
35 # says not to include bootstrap module into the build file
36 'bootstrap': 'empty:'