Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a local file during Require.js optimisation, but a CDN-hosted version at runtime?

My page includes several components that exist as separate AMD modules. Each of these components is turned into a single file by the Require.js optimiser. Because several of these components share dependencies (e.g. jQuery and d3), the optimiser paths config uses CDN URLs for those dependencies, rather than bundling them into the optimised file.

Here's where it gets tricky. I've written a module loader plugin for Ractive.js called rvc.js, which allows me to include Ractive components that are defined in HTML files. (Yes, I'm asking for help on how to use my own library.)

This works fine - code like this gets optimised as you'd expect:

define( function ( require ) {
  var ChartView = require( 'rvc!views/Chart' );
  var view = new ChartView({ el: 'chart' });
});

Because Ractive is used by several of the components, it should be served from a CDN like jQuery and d3. But it's used by rvc.js during the optimisation process, which means that the Ractive entry for the optimiser's paths config can't point to a CDN - it has to point to a local file.

Is there a way to tell Require.js 'use the local file during optimisation, but load from CDN at runtime'?

like image 994
Rich Harris Avatar asked Oct 01 '22 11:10

Rich Harris


1 Answers

So here's the solution I eventually settled on. It feels somewhat kludgy, but it works:

  1. Stub out the loaders and the library you don't want bundled
  2. Add an onBuildWrite function that rewrites modules depending on the library, so that they think they're requiring something else entirely - in this case Ractive_RUNTIME
  3. Add an entry to your runtime AMD config's paths object, so that Ractive_RUNTIME points to the CDN

My optimiser config now looks like this:

{
  baseUrl: 'path/to/js/',
  out: 'build/js/app.js',
  name: 'app',
  optimize: 'none',

  paths: {
    'amd-loader': 'loaders/amd-loader',
    'rvc': 'loaders/rvc',
    'Ractive': 'lib/Ractive'
  },

  stubModules: [ 'amd-loader', 'rvc', 'Ractive' ],

  onBuildWrite: function ( name, path, contents ) {
    if ( contents === "define('Ractive',{});" ) {
      // this is the stub module, we can kill it
      return '';
    }

    // otherwise all references to `Ractive` need replacing
    return contents.replace( /['"]Ractive['"]/g, '"Ractive_RUNTIME"' );
  }
}

Meanwhile, the script that loads the app.js file created by the optimiser has a config entry that points to the CDN:

require.config({
  context: uniqueContext,
  baseUrl: baseUrl,

  paths: {
    'amd-loader': 'loaders/amd-loader',
    'rvc': 'loaders/rvc',
    'Ractive': 'lib/Ractive',
    'Ractive_RUNTIME': 'http://cdn.ractivejs.org/releases/0.3.9/Ractive.min'
  }
});
like image 66
Rich Harris Avatar answered Oct 12 '22 01:10

Rich Harris