Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

requireJS and LESS

I'm using the client-side javascript version of LESS to compile out less code, and would like to continue using this even on the final live site (I know... bad form, but it gives me the ability to allow users to customize a few less variables and have that "theme" their whole app on the fly, seeing as it's a webapp that once loaded never refreshes, I'm thinking the additional second of load time to compile the less is acceptable).

I'm also using requireJS.

The question is:

A) How do I get requireJS to load less code?

B) Does less dispatch any events when compilation is complete? and

C) Is there a way to trigger less to re-compile on command?

Thanks.

like image 636
nicholas Avatar asked May 04 '11 21:05

nicholas


People also ask

What is RequireJS used for?

RequireJS is a JavaScript library and file loader which manages the dependencies between JavaScript files and in modular programming. It also helps to improve the speed and quality of the code.

What is define in RequireJS?

The define() function can be used to load the modules (module can be an object, function, class or a code which is executed after loading a module). You can load different versions of the same module in the same page.

What is a RequireJS module?

RequireJS is a JavaScript file and module loader. It improves perceived page load times because it allows JavaScript to load in the background. In particular, it enables asynchronous JavaScript loading.

Is RequireJS synchronous?

So, RequireJS doesn't support it. From your use case it seems that you don't need synchronous RequireJS, you need to return result asynchronously. AMD pattern allows to define dependencies and load them asynchronously, but module's factory function must return result synchronously.


2 Answers

I have used the text loader plugin for RequireJS to load the .less file as text, then create a new less.Parser instance to parse the text, then add the style text myself:

(new less.Parser()).parse(lessText, function (err, css) {
  if (err) {
    if (typeof console !== 'undefined' && console.error) {
      console.error(err);
    }
  } else {
    var style = document.createElement('style');
    style.type = 'text/css';
    style.textContent = css.toCSS();
  }
});

You could take a similar approach, but give the style node an ID and remove that ID and then add back another reparsed LESS text when you want on demand.

A caveat: the text plugin can only load text files on demand when the text file is on the same domain as the web page. If you use the RequireJS optimizer, you can inline the text into a built, optimized JS file.

like image 95
jrburke Avatar answered Oct 05 '22 23:10

jrburke


@jrburke: I've put together a quick requirejs plugin based on your code:

define({

    version: '0.1',

    load: function(name, req, onLoad, config) {

        req(['text!' + name, 'base/less'], function(lessText) {

            var styleElem;

            (new less.Parser()).parse(lessText, function (err, css) {
                if (err) {
                    if (typeof console !== 'undefined' && console.error) {
                        console.error(err);
                    }
                } else {
                    styleElem = document.createElement('style');
                    styleElem.type = 'text/css';

                    if (styleElem.styleSheet) 
                        styleElem.styleSheet.cssText = css.toCSS();
                    else 
                        styleElem.appendChild( document.createTextNode( css.toCSS() ) );

                    document.getElementsByTagName("head")[0].appendChild( styleElem );
                }

                onLoad(styleElem);
            });

        });     
    }

});

"base/less" points to the less source. You could also load this ahead of time, and assume the global less object exists. Ideally, I'd like to pull the less Parser object into this plugin itself so it doesn't create a global at all.

Using this I can do stuff like:

require(['less!global.less'], function(elem) {

});

At which point, global.less has been parsed and added to the page and gives back elem pointing to the style element in case I need to remove or modify it for some reason.

Does anyone have any input or know a better way of doing this?

Cheers

like image 22
nicholas Avatar answered Oct 06 '22 00:10

nicholas