Inject CSS From Your RequireJS Module Into The Main App


We’ve been doing some work on a data display app that serves as a framework for a bunch of modules. We picked RequireJS to create the app due to its modular structure and used it with a Node.js backend to build a small app that we can now create child data modules for.

Each child module needs to be fully responsible for its own content and assets as they are loaded asynchronously as needed.

What’s the problem?

Since there’s no way to know what modules are going to be part of the app when it loads, it’s not feasible (or optimal) to load all assets for all modules into the app when it loads. If each module has its own CSS and we end up with a library of 100 modules, we don’t want to pre-emptively load all of those assets into the main app.

Injecting a stylesheet reference into a page is easy enough, but we need to get a reference to the asset.

require.toUrl

As well as registering dependencies to your own modules in RequireJS, you can also register the require module. This contains some helper functions including toUrl. This method allows you to generate a relative URL from your app to whatever path you pass in.

Inside your module, paths starting with ./ are relative to the module itself. By combining these, you can generate a link to an asset within your module.

So, if your app has this structure:

- YourModule/
---- images/
---- ---- icon.gif
---- main.js
---- styles.css

You can use this:

define(['require'], function (require) {
  var localPath = './styles.css';
  var pathFromApp = require.toUrl(localPath);
});

Registering your CSS with the page

To register your local CSS file with the page, you can create a simple helper module like this:

CSSLoader.js

(function () {
  'use strict';
 
  define(function () {
    var link = function (url) {
      var css = document.createElement('link');
      css.rel = 'stylesheet';
      css.href = url;
 
      document.head.appendChild(css);
    };
 
    return {
      link: link,
    };
  });
})();

With this, you can update the earlier example to load pass your CSS in and get it onto the page:

define(['require', 'cssLoader'], function (require, cssLoader) {
  var localPath = './styles.css';
  var pathFromApp = require.toUrl(localPath);
 
  cssLoader.link(pathFromApp);
});