javascriptasynchronousrequirejsunderscore.jsdynamic-script-loading

How to mixin Underscore plugins in RequireJS?


What is the right way to execute code on Underscore when it gets loaded? I am trying to execute the below code to extend the _ exported namespace automatically when modules require it:

_.mixin(_.str.exports());

The docs are a bit vague but I think I put it in the shim init section? I tried the below but I can't even get a breakpoint to hit in the init:

require.config({
    paths: {
        jquery: 'libs/jquery/jquery.min',
        underscore: 'libs/underscore/lodash.min',
        underscorestring: 'libs/underscore/underscore.string.min'
    },

    shim: {
        underscore: {
            exports: '_'
        }
        underscorestring: {
            deps: ['underscore'],
            init: function (_) {
                //Mixin plugin to namespace
                _.mixin(_.str.exports());

                return _;
            }
        }
    }
});

When I try to do this and use underscorestring, I get this error:

Uncaught TypeError: Object function s(e){return new o(e)} has no method 'startsWith'

Docs:


Solution

  • I don't know if it's the correct way, but I got it working by inverting things so that underscore depends on underscore.string. Also, this way you don't have to require underscore.string.

    require.config({
      shim: {
        'backbone': {
          deps: ['underscore', 'jquery'],
          exports: 'Backbone'
        },
        'underscore': {
          deps: ['underscore.string'],
          exports: '_',
          init: function(UnderscoreString) {
            _.mixin(UnderscoreString);
          }
        }
      },
      paths: {
        'backbone'          : 'lib/backbone',
        'jquery'            : 'lib/jquery/jquery',
        'text'              : 'lib/require/text',
        'underscore'        : 'lib/underscore',
        'underscore.string' : 'lib/underscore.string'
      }
    });
    

    .

    Update: 3/14/2014

    Underscore.js v1.6.0 brought back AMD compatibility and init() has been removed from RequireJS, so some refactoring is in order. To continue getting Underscore preloaded with Underscore.string I made a mixer module to pull them together.

    New Require.js config

    requirejs.config({
      paths: {
        'backbone'            : '../lib/backbone/backbone',
        'backbone.base'       : '../lib/backbone/backbone.base',
        'backbone.extensions' : '../lib/backbone/backbone.extensions',
        'jquery'              : '../lib/jquery/jquery',
        'text'                : '../lib/require/text',
        'underscore'          : '../lib/underscore/underscore',
        'underscore.mixed'    : '../lib/underscore/underscore.mixed',
        'underscore.string'   : '../lib/underscore/underscore.string'
      },
      shim: {
        'backbone.base': {
          deps: ['underscore.mixed', 'jquery'],
          exports: 'Backbone'
        },
      }
    });
    

    underscore.mixed

    define([
      'underscore',
      'underscore.string'
    ], function(_, _s) {
      _.mixin(_s.exports());
      return _;
    });
    

    The final step is to replace all instances of 'underscore' with 'underscore.mixed' in module definitions. I attempted moving Underscore into a file named underscore.base.js and making the regular underscore the mixer (like the Backbone setup) to avoid this step. Underscore, being a named module, disagreed with the plan.