Uploaded image for project: 'XWiki Platform'
  1. XWiki Platform
  2. XWIKI-13252

Add support for deferred module dependency loading when using RequireJS

    Details

    • Difficulty:
      Medium
    • Similar issues:

      Description

      If your JavaScript code depends on some other module you normally write:

      require(['module'], function(module) {
        // Do something with the module.
      });
      

      This works if 'module' is known by RequireJS. In order to make a module known you need to tell RequireJS where to load that module from. A module can be located in various places: in a WebJar, in the skin, in a JSX object or even in a file attached to a wiki page. If the module you need is common enough that is loaded on every page then chances are it is already known (configured in javascript.vm). Otherwise you need to configure the dependency by using require.config().

      require.config({
        paths: {
          module: "path/to/module"
        },
        shim: {
          module: {
            exports: 'someGlobalVariable',
            deps: ['anotherModule']
          }
        }
      });
      

      If two scripts need the same dependency then they will have to duplicate the require configuration. In order to avoid this you could move the configuration in a separate file and write something like this:

      require(['path/to/config'], function() {
        require(['module'], function(module) {
          // Do something with the module.
        });
      });
      

      but you would still duplicate the configuration path in both scripts. Now, suppose that one of the scripts is only extending a feature provided by the dependency module. This means that it doesn't necessarily need to bring the dependency. It only needs to extend the module if it's present. So it would be nice if the script could say to RequireJS "let me know when this module is loaded by someone else" (someone else being an other script on the same page). This could be achieved using a RequireJS plugin:

      require(['deferred!module'], function(modulePromise) {
        modulePromise.done(function(module) {
          // Do something with the module, if the module is loaded by someone else.
        });
      });
      

      This looks similar with the solution where the require configuration is in a separate file, but the advantage is that the path is not duplicated (i.e. we can move the module to a different path without affecting the scripts that use it).

      Examples where this could be useful:

      • extend the tree widget (if it's available on the current page)
      • extend the WYSIWYG editor (if it's loaded on the current page)

      An alternative is for each module that wants to support extensions to fire some custom events when they are loaded, but I prefer the generic solution.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                mflorea Marius Dumitru Florea
                Reporter:
                mflorea Marius Dumitru Florea
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: