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

1

6

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'?

Stableman answered 25/2, 2014 at 20:32 Comment(2)
set a var like fileToUse= amILocal() ? "lib.js" : "lib.min.js"; and pass fileToUse to require instead of a hard-coded literal.Homily
The trouble is that whichever value of fileToUse is given to the optimiser, that's both a) the file used during optimisation and b) the file that the optimiser includes (or tries to) in the build. So if fileToUse is local, the local file is used by rvc.js during optimisation, but it also gets bundled; if it's remote, the optimisation fails.Stableman
S
5

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'
  }
});
Stableman answered 3/3, 2014 at 19:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.