-
Notifications
You must be signed in to change notification settings - Fork 15
Add support for cross-package includes of less resources #206
Description
A common practice when working with LESS files is to import other LESS files that don't declare any CSS, but instead define variables, etc. that are used by the importing file. This works fine if the imported files are co-located relative to the importing file, but does not work if you want to import files that are located in another AMD package because the LESS compiler does not use AMD to import modules.
With CSS files, you can use the CSS loader plugin to require CSS files from different AMD packages simply by naming them in the dependency array of a require() or define() call. This doesn't work for LESS modules, though, because of the need for the LESS compiler to compile the modules as a unit in order for variables declared in one module to be visible to another module.
One solution, of course, is to pre-compile your LESS resources into CSS and use the CSS loader plugin to require the compiled files. However, it would be desirable, particularly for development, to avoid this pre-compile process, and still support the ability to have LESS resource in one AMD package depend on LESS resources in another AMD package.
The LESS loader plugin
Here, we propose the use of a LESS loader plugin with support for special syntax and config properties that allow multiple LESS modules to be required as a single compilation unit. The special syntax allows multiple modules to be specified, separated by the '|' character. For example:
require(['less!packageA/mixin.less|packageB/styles.less'], function(styles) {
When not using the aggregator, the LESS loader plugin will use the text loader plugin to load the specified modules and combine them into a single resource that is sent to the LESS compiler on the client. When using the aggregator, the LESS loader plugin will send the request for the combined files to the aggregator, where the aggregator will aggregate the requested modules on the server and invoke the server-side LESS compiler.
If you have one or more modules that are needed by all the LESS resources in your application, you can use the lessIncludes config property to specify that these files be included with any requests for LESS resources. For example:
require({lessIncludes:['packageA/mixin.less']});
require(['less!packageB/styles.less'], function(styles) {
When packageB/styles.less is required, the effect will be the same as if packageA/mixin.less and packageB/styles.less were required together as in the first example.
The lessIncludes config property can be set for the entire application by setting the property on the global require object, or for parts of the application by setting the lessIncludes config property on a context require.
Limitations
One limitation of this approach has to do with nested imports. Because the module being compiled is an aggregation of modules from different AMD packages, when a nested import is encountered, it is not clear which of the original modules the import should be relative to. The client side-compiler provides the ability to specify an array of paths to search for imports, and the server-side compiler should support this as well since it is ultimately invokes the JavaScript version of the compiler using Rhino, so we should be able to specify the paths of the original modules for the LESS compiler to search for imports. This, however, could result in shadow modules being hidden by other, similarly named modules that occur earlier in the search path.