Moodle's AMD modules load JavaScript asynchronously and isolate dependencies using RequireJS. This guide covers module structure, injecting Moodle services, localization, and building production-ready minified output using Grunt.

SOP: Writing and Building AMD Modules in Moodle

This guide will walk you through creating, localizing, and building asynchronous module definition (AMD) JavaScript modules in Moodle, as well as how to pull in core Moodle services (like the notification system) from your AMD code.

1. What is AMD in Moodle?

Moodle uses RequireJS to load JavaScript modules asynchronously. An AMD module is a JavaScript file that:

  • Declares its dependencies via a define([...], function(...) { … }) call.
  • Exports one or more functions (often a single init entry point).
  • Can be minified and concatenated into production-ready code.

By using AMD, modules only load when needed and avoid polluting the global namespace.

2. Folder Layout

Inside your plugin (e.g. mod/assessmentform/), you should have:

mod/assessmentform/
├── amd/
│   ├── src/             ← Your unbuilt source files
│   │   └── survey_init.js
│   └── build/           ← Moodle's build step will place minified files here
│       └── survey_init.min.js
└── view.php             ← Calls your AMD module via js_call_amd()
  • amd/src/Place your human-readable modules here.
  • amd/build/After running the build, minified code will live here. Commit the build outputs so your plugin works without requiring Node on the production server.

3. Writing Your AMD Module

In amd/src/survey_init.js, you might have:

define([
    'jquery',
    'core/notification',
    'core/str',            // for translations
    'survey-core',
    'survey-js-ui'
], function($, notification, str, Survey) {

    return {
        init: function(args) {
            // 1. Localization
            var texts = args.str || {};
            // str.get_string('key','mod_yourplugin') can also be used.

            // 2. Load and render your SurveyJS
            $.getJSON(args.jsonUrl).done(function(def) {
                var survey = new Survey.Model(def);
                survey.render(document.getElementById(args.containerId;

                survey.onComplete.add(function(sender) {
                    // Build payload...
                    $.ajax({
                        url: args.postUrl,
                        method: 'POST',
                        data: JSON.stringify({ /* ... */ }),
                        contentType: 'application/json',
                        dataType: 'json',
                    }).done(function(response) {
                        notification.addNotification({
                            message: texts.responsesavedsuccess || 'Saved successfully!',
                            type: 'success'
                        });
                        // redirect ...
                    }).fail(function() {
                        notification.addNotification({
                            message: texts.responsefailed || 'Save failed.',
                            type: 'error'
                        });
                    });
                });
            }).fail(function() {
                $('#'+args.containerId)
                  .html('<div class="alert alert-danger">Error loading form.</div>');
            });
        }
    };
});

Key points

  • define([...], function(...) { … })List the module IDs you depend on. Moodle’s loader will map these to the right files.
  • core/notificationExposes notification.addNotification({message, type}).
  • core/strOffers str.get_string(key, component) for on-the-fly translations.
  • js_call_amd() in PHPPass an associative array of arguments from PHP into your JS entry-point.

4. Injecting Moodle Services

Just list them in your dependency array:

define([
    'jquery',
    'core/notification',
    'core/str',
    'core/ajax',
    // ...your other libraries...
], function($, notification, str, Ajax) {
    // You now have `notification`, `str` and `Ajax.call()` available.
});
  • core/ajaxUse Moodle’s AJAX wrapper:
  • Ajax.call([{ methodname: 'mod_yourplugin_do_something', args: { foo: 1 }}])[0].then(function(result){ … }).catch(function(err){ notification.exception(err); });

5. Localization

  • In your language file (lang/en/mod_assessmentform.php):
  • $string['responsesavedsuccess'] = 'Assessment saved successfully for {$a->fullname}.';$string['responsefailed'] = 'Error saving assessment.';
  • Pass them into JS when you call your AMD module:
  • $PAGE->requires->js_call_amd( 'mod_assessmentform/survey_init', 'init', [ 'str' => [ 'responsesavedsuccess' => get_string('responsesavedsuccess','mod_assessmentform'), 'responsefailed' => get_string('responsefailed','mod_assessmentform'), ], // …other args… ]);
  • In JS, access args.str.responsesavedsuccess.

6. Building (Minifying) Your AMD

Moodle provides a Grunt setup out of the box. At your plugin root:

  • Install dependencies (one-time, in the Moodle root). Moodle 4.5 requires Node 22.x:
  • npm install
  • Build all AMD modules (including yours), running grunt via npx so no global install is needed:
  • npx grunt amd
  • This reads every amd/src/*.js in all plugins, minifies them, and writes to amd/build/*.min.js.
  • To build just your plugin, change into the plugin directory first, then run the same command. The Gruntfile detects the current directory and scopes the build to that component:
  • cd mod/assessmentform && npx grunt amd
  • Commit the contents of amd/build/ into your plugin’s repository.

You do not need a Gruntfile in your plugin. Moodle has a single core Gruntfile at the Moodle root that handles every plugin; running it from inside your plugin directory (as above) scopes the build to your component, so there is no extra setup needed.

7. Summary Checklist

  • Create amd/src/yourmodule.js with a define([...], ...).
  • Load it in PHP with:
  • $PAGE->requires->js_call_amd('mod_yourplugin/yourmodule','init',[$args]);
  • Use injected services:
  • core/notificationnotification.addNotification(...)
  • core/strstr.get_string(...)
  • core/ajaxAjax.call(...)
  • Build with npm install && grunt amd and commit amd/build/*.min.js.
  • Test on your dev site, then deploy.

With this workflow in place, you can rapidly iterate your JS in amd/src/ and then generate production-ready, minified AMD modules via Moodle’s standard Grunt toolchain.

Solin specializes in Moodle plugin development and AMD module authoring.

Contact us