The BA-Server's client-side Javascript is making the transition from plain Javascript files to AMD-compatible script modules. This began with the 4.5 release and has continued in 4.8 where we've also taken the opportunity to update to RequireJS 2.0. The following describes the system as it exists in 4.8.
What is AMD?
First-off, you have to understand AMD modules. Asynchronous Module Definitions are JavaScript files that declare a module name and optionally list their dependencies. These script files are not included directly in the HTML source, rather they're loaded using the RequireJS script. Once a call has be made to load a module, it's retrieved from the server based on the URL mappings, dependencies are computed and retrieved, and baring any unresolved dependencies it is finally loaded and returned to the requestor.
...
In practice we omit the module name from our script files as the system will infer the module name based on how the script is loaded.
Tying together AMD and Platform Plugins
As plugins become more and more capable we've started sharing Javascript code between them. This is most commonly done by providing Javascript from one plugin to extend the functionality of another. In other cases a plugin may have a hard dependency upon script provided by another. This cross-plugin loading is accomplished through RequireJS and setup by module path mappings.
Module Path Mappings
By default RequireJS will try to load modules relative to the current URL. So if the current page is /pentaho/foo/index.html, a call to load the "Utils" module will have the system try to load it from /pentaho/foo/Utils.js. This is not very valuable to us so we've adopted a namespaced approach. Each plugin is able to define root namespaces and provide URL path mappings for them. For instance the CDF plugin defines modules with the "cdf" namespace like "cdf/CoreComponents.js". It also provides a configuration for the RequireJS system mapping the "cdf" namespace like so:
...
Note that CONTEXT_PATH is provided by the webcontext.js file and is supplies the webapp name ("/pentaho/" by default). So when a user makes a call to require "cdf/CoreComponents" RequireJS will load it from "/pentaho/content/pentaho-cdf/js". This provides from a greater degree of abstraction in where scripts are loaded.
Providing RequireJS Configurations
To understand how plugins supply their configuration, you have to understand the webcontext.js Filter and External Resource definitions.
Anchor | ||||
---|---|---|---|---|
|
webcontext.js
Almost every page supplied by our server will include a webcontext.js script tag. You won't find a webcontext.js file anywhere in the system, the content is actually supplied by an HTTP Servlet Filter. It's writes out several things which are critical for the execution of most of our client-side Javascript. Most calls to webcontext.js also include an additional "context" parameter telling it what area of the Platform it's intended for. This context is tied into the External Resources system described later.
...
You'll notice several scripts are injected before the inclusion of require.js and require-cfg.js. These scripts are provided by the plugins and contain code extending the RequireJS configuration object. As mentioned, they are provided through the External Resource system.
External Resources
Plugins can provide scripts and CSS to be loaded in other areas of the platform by including entries in their plugin.xml. For instance, Analyzer provides it's Dashboard Widget and it's configuration for RequireJS by defining the following in it's plugin.xml:
...
It adds an "analyzer" root namespace to the "paths" entry. This is what routes requests for modules beginning with "analyzer/" to the appropriate URL location. The check for "debug=true" is changing the location where the system loads the scripts so that the uncompressed files are available for debugging.
Helpful links!
https://github.com/amdjs/amdjs-api/wiki/AMD
http://requirejs.org/