Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

YUI/Shifter

From MoodleDocs
(Redirected from Javascript/Shifter)


Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.


This feature has been marked as deprecated since Moodle 2.9


Since Moodle 2.9 Moodle uses Grunt for building YUI modules.

Moodle 2.5

Moodle 2.6

Moodle 2.7


What is Shifter and what does it do?

Shifter is a tool written by the YUI team to help build YUI modules. It has been supported since Moodle 2.5.

It is written in JavaScript itself, and written as a Node.JS module which can be installed from NPM.

Shifter takes your source JavaScript file(s), along with some meta-data, and wraps it all together into a built file. This file is known in YUI parlance as a module. After building this file, Shifter then produces three versions:

  • the file in its original form (DEBUG - '-debug' filename postfix);
  • the DEBUG file with all debugging calls to Y.Log removed (RAW - no filename postfix); and
  • the RAW file minified using UglifyJS ('-min' filename postfix).

The meta-data file includes information on the module name, and its dependencies on other modules.

By separating out the actual JS code from its dependencies, we are able to take those dependencies and use them elsewhere in Moodle. As an example, this dependency data can be used to inform the Loading system to reduce the number of HTTP requests with Combo Loading. This has a benefical effect upon performance.

Another feature of Shifter is its ability to handle rollups. Rollups describe the inclusion of multiple YUI classes in the same module. This means that you can have different but related components all in the same module, but without having a single large and less-managable source file.

Why do I need build my modules?

Technically you don't, and you can continue to use the old data structure, but by doing so you can benefit from:

  • reduced data sent over the wire due to minification - great for slower connections and mobile devices;
  • reduced number of http queries - the separation of module meta-data means that it can be consumed and fed into the Loader allowing your module to use combo-loading;
  • a slightly simplified JS syntax for your source files.

Installing Shifter

As of Moodle 2.9, the shifter process is managed by the "Grunt" task runner. See Grunt for more information.

Shifter is written in JavaScript and the Node.JS environment. You will need to install Node.JS first. This is usually fairly easy as there are pre-built binary packages for Windows and Mac OS.

After installing Node.JS you then use the Node NPM tool to install Shifter:

  npm install shifter@0.4.6 -g

Note: At present, the supported version of Shifter for use in Moodle is version 0.4.6. You are not required to run a specific version of Shifter, but this is the version that Moodle YUI modules will be built with and you may find it beneficial to do so too.

For Ubuntu run:

  sudo apt-get install npm
  sudo apt-get install python-software-properties python g++ make
  sudo apt-get update
  sudo apt-get install nodejs
  sudo ln -s /usr/bin/nodejs /usr/local/bin/node
  sudo npm install shifter@0.4.6 -g

For CentOS run the following as root:

  yum install nodejs npm
  npm install shifter@0.4.6 -g

If you are behind a proxy, you will need to read http://jjasonclark.com/how-to-setup-node-behind-web-proxy.

How do I write a YUI module which uses Shifter?

Easy - it's mostly just a case of building the right directory structure.

Assuming that you are creating a new YUI module in your block named fruit, and that your new YUI module will be called fruitbowl, we know the following:

Plugin type block
Plugin name fruit
Plugin frankenstyle name block_fruit
YUI Module name moodle-block_fruit-fruitbowl

This means that your Moodle plugin directory is:

 /blocks/fruit

And your fruitbowl YUI module source will therefore be in:

 /blocks/fruit/yui/src/fruitbowl

The overall module directory structure looks like this:

yui/
|-- src
    |-- fruitbowl
        |-- build.json
        |-- js
        |   |-- fruitbowl.js
        |-- meta
            |-- fruitbowl.json

build.json

The build.json file defines the eventual modules which will be built, and the source files that you've written:

{
  "name": "moodle-block_fruit-fruitbowl",
  "builds": {
    "moodle-block_fruit-fruitbowl": {
      "jsfiles": [
        "fruitbowl.js"
      ]
    }
  }
}

The above example can be read as "My module has the name 'moodle-block_fruit-fruitbowl'. When building, shifter builds one submodule (?) named 'moodle-block_fruit-fruitbowl' using the Javascript file 'fruitbowl.js'.

meta/MODNAME.json

The meta/MODNAME.json file describes the list of dependencies for each module:

{
  "moodle-block_fruit-fruitbowl": {
    "requires": [
        "base",
        "node"
    ]
  }
}

To build the submodule 'moodle-block_fruit-fruitbowl', it is required to include both the 'base' and 'node' modules.

js/MODNAME.js

The files in the js directory are the contents of your YUI module. This should include setting it up in the M namespace. As an example of a very basic structure:

M.block_fruit = M.block_fruit || {};
M.block_fruit.fruitbowl = {
  init: function() {
    Y.one('#example').set('innerHTML', 'Example content');
  }
};

Can I put two modules in one directory tree?

If you are still using Moodle 2.5, this does not work due to bug MDL-40478 (the non-default files cannot be loaded).

If you are using Moodle 2.6+ this is possible. It may sometimes be sensible if the modules are not independent, e.g. if one module will only ever be used by the other one rather than directly called from PHP, or another module.

If the modules are independent or might well be used separately from each other, then it is probably best to use a separate directory tree for each.

See examples in mod/scorm/yui/src and lib/yui/src/notification.

How do I load one of these modules from PHP code?

You need to run Shifter so that it generates the compiled code. See below.

Once you've done that, you can use PHP code like the following:

$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl', 'M.block_fruit.fruitbowl.init', array());

(The last empty array contains parameters for the init function, if required.)

How do I use shifter?

So after writing out your structure, you now need to build it into a module. After installing Shifter, you have several options.

During development

A really nice way of running shifter during development is to have it detect changes to your files as you save them:

 cd ~/git/moodle/blocks/fruit/yui/src
 shifter --watch

The --watch option will watch for any changes to JS, JSON, CSS, or images within any module in the current directory and build that module when it detects changes. Note: There can be a short delay of a few seconds while the changes are discovered and the file is built

This is great for development because you don't have to continously run shifter manually.

All YUI modules for the Moodle plugin you're currently working on

If you are working on several YUI modules at once, then you can have shifter build all of them at the same time:

 cd ~/git/moodle/blocks/fruit/yui/src
 shifter --walk

Just the module you're working on now

If you want to build just the module you're working on at the moment:

 cd ~/git/moodle/blocks/fruit/yui/src
 shifter --walk fruitbowl

Or:

 cd ~/git/moodle/blocks/fruit/yui/src/fruitbowl
 shifter

Across the whole of Moodle

If you want to build every YUI module in Moodle at once:

 cd ~/git/moodle
 shifter --walk --recursive

Submitting my JavaScript back to Moodle core

If you're working on some JavaScript for Moodle core, either in the form of a bug fix or a new feature, then you probably want to know what to do with your built module.

We ask that you build your module and submit both the changes to tbe built module and the source directory.

In addition, the Continuous Integration server (Jenkins) will run shifter --walk --recursive on every run to ensure that all built files are up-to-date and correct.

If there are several commits to the same YUI module within a single period of Moodle integration, then the built files will conflict. In this case the integration team will manually build the module and resolve the conflict. If you are aware that there may be multiple changes to the same file, please indicate this when submitting your change for Integration Review. If you are familiar with the changes, you may wish to consider building the issues upon one another too.

How do I convert my existing module?

If you already have an existing moodle YUI module and want to convert it to the new Shifter format, then it's pretty easy on the whole:

  1. create a new src/MODNAME directory;
  2. create js and meta directories within this;
  3. copy over your existing js file into the js directory;
  4. extract the meta-data;
  5. write your build.json;
  6. remove the YUI.add() wrapper from the top and bottom of your js file; and
  7. remove the old file.

To create the complete directory structure and copy your existing code into the right directory (steps 1 - 3):

 mkdir -p src/MODNAME/{js,meta}
 cp MODNAME/MODNAME.js src/MODNAME/js/

Refer to the section above on the correct contents of the build.json and meta/MODNAME.json files.

Can I run my shifted module in older versions of Moodle 2 (before 2.5)?

We are aware that many developers wish to reduce the overhead of maintaining a plugin for multiple versions of Moodle and that using Shifter will make this much harder. Unfortunately you can't use the shifted version of your module directly, but you can run them in parallel by copying the built file into the old directory structure.

Moodle will always prefer the built shifted module over the older style module if both are present.

If doing this, we would recommend copying over the minified version of your file so that older versions of moodle benefit from your user of shifted code.

On a Linux-like operating system, you can use the following (again with our fruit example):

 cp yui/build/moodle-mod_fruit-fruitbowl/moodle-mod_fruit-fruitbowl-min.js yui/fruitbowl/fruitbowl.js

Whilst developing, you may want to use a symlink so that you don't have to keep copying your changes after building them:

 ln -s yui/build/moodle-mod_fruit-fruitbowl/moodle-mod_fruit-fruitbowl.js yui/fruitbowl/fruitbowl.js

See also