New UI extension point to extend the global RequireJS configuration

Hi devs,

ATM if you want to use a RequireJS module you have to know its path. Some known RequireJS modules are defined globally in javascript.vm and thus can be used without knowing their path (e.g. jquery, bootstrap). The idea is to make the list of globally known RequireJS modules extensible, i.e. to allow extensions to “publish” RequireJS modules that others can use.

I need this for the in-place edit: I know the id of the configured WYSIWYG editor (e.g. ckeditor) and I want to load the corresponding RequireJS module without knowing its path or the extension that provides it. In other words I want to load CKEditor (the configured WYSIWYG editor) without depending on CKEditor.

For this I propose to add an UI extension point in javascript.vm without content, supporting these parameters:

  • id : the RequireJS module id
  • path : maps to require.config.paths
  • bundles : maps to require.config.bundles
  • deps : maps to require.config.shim.deps
  • exports : maps to require.config.shim.deps
  • config : maps to require.config.config

As for the extension point id, I’m currently using

org.xwiki.platform.requirejs.module

but I know some of you will argue that it doesn’t follow the naming convention. javascript.vm is currently in xwiki-platform-flamingo-skin-resources but I don’t think the extension point should depend on the skin, I’m -1 to that. This extension point should be generic. It just happens that Flamingo skin customizes this Velocity template. Any other skin should provide this extension point.

Alternative:

org.xwiki.platform.web.requireJSModule

but I prefer the first. WDYT?

Thanks,
Marius

+1 in general for a new UIXP for requireJS with the mentioned parameters.

Any reason why not to have this template in platform-web then, if it’s something generic?

Why not a regular XWiki class? UI extensions are for… UI. Here it is only for a technical reason, only for javascript developers. Seeing it in the same list than regular UI extensions is a non sense to me.

But I’m OK with the general idea.

Because it loads JavaScript resources specific to Flamingo skin, most importantly Bootstrap. Other skins may not depend on Bootstrap and will have other needs in terms of JavaScript resources to load.

A couple of reasons:

  • xclasses don’t support scoping: I don’t want a non-admin to be able to “publish” (or overwrite) a RequireJS module that affects everyone
  • I want in the future to be able to “publish” RequireJS modules from a WebJar; e.g. have a Java component that looks in the installed WebJars for some “descriptor” and registers UI extensions for this extension point; the goal being to (more or less) auto discover and register RequireJS modules when installing a WebJar. It feels wrong to rely on wiki pages for this.

Thanks,
Marius

+1 for the general idea

UIExtension is a bit of a stretch since there is no concept of block or execution in this use case but there is not much else which already exist currently. At some point we should probably introduce some new more generic component (ExtensionPointEntry or something like this) which have everything currently in UIExtension except execute() and make UIExtension extend it but in the meantime I guess it’s OK.

Yes, I agree. My use case is to load CKEditor on demand after page load (for in-place editing) without depending on CKEditor (i.e. without having to specify where to load CKEditor from). And for this the only clean solution I found was to allow CKEditor to extend the RequireJS configuration. This way I can load CKEditor only by knowing the hint of the configured WYSIWYG editor (component, i.e. “ckeditor”).

Thanks,
Marius

There’s also the fact that the code that generates the RequireJS configuration is in a Velocity template (javascript.vm), and making it depend on a wiki page (even if it’s an automatically generated xclass) is not nice.

Note that I could have used the org.xwiki.platform.html.head UI extension point to inject a <script> tag into the page HTML head like this:

{{velocity}}
{{html clean="false"}}
<script type="text/javascript">
require.config({
  paths: {
    'xwiki-ckeditor': "$xwiki.getURL('CKEditor.EditSheet', 'jsx', $escapetool.url({'v': $services.extension.installed.getInstalledExtension('org.xwiki.contrib:application-ckeditor-ui', "wiki:$xcontext.database").version.value}))"
  }
});
</script>
{{/html}}
{{/velocity}}

But writing this boilerplate code each time you need to publish a RequireJS module is a pain and it leads to many in-line script tags in the page HTML head. So the UI extension point I propose is trying to improve on this, and thus is as good as an extension point as org.xwiki.platform.html.head: it does add something to the page HTML head, but you only have to specify the module id and path.

Thanks,
Marius

I agree with that, I really don’t think you should try to find a block oriented use at all cost. My point was more that it’s not the first time we have a need for a more generic version of UI extensions without the block execution part.