Domanda

When I run my project locally with my grunt:server task, the project works as I expect. However, after building which takes all the vendor code and puts it into one file, two of my needed module aren't avialable, and the project doesn't work.

Here is my requirejs configuration:

requirejs.config
  baseUrl: './js'
  shim:
    'underscore':
      exports: '_'
    'backbone':
      deps: ['underscore', 'jquery']
      exports: 'Backbone'
    'stack':
      deps: ['d3.global']
      exports: 'stack'
    'highlight':
      exports: 'hljs'

  paths:
    'underscore': '../components/underscore/underscore'
    'backbone': '../components/backbone/backbone'
    'jquery': '../components/jquery/jquery'
    'd3': '../components/d3/d3'
    'd3.global': '../components/d3.global/d3.global'
    'stack': '../components/stack/stack'
    'highlight': '../components/highlightjs/highlight.pack'

require ['app/vendors'],->
  console.log("Backbone", Backbone)
  console.log("_", _)
  console.log("$", $)
  console.log("d3", d3)
  console.log("stack", stack)
  console.log("hljs", hljs)

app/vendors looks like

define [
  'underscore'
  'jquery'
  'backbone'
  'text'
  'd3.global'
  'stack'
  'highlight'
], ->

When I run the project locally via grunt, I see all the globals printed out. However, when I build the project, Backbone Underscore and JQuery print out, while stack fails (hljs is also not available, and if I remove stack from app/vendors, it doesn't fix highlight, so its probably not an order thing).

the requirejs optimizer is called with the following configuration:

requirejs:
  compile:
    options:
      baseUrl: 'js/'
      appDir: './<%= yeoman.tmp_dist %>/'
      dir: './<%= yeoman.dist %>/'

      wrap: true

      removeCombined: true
      keepBuildDir: true

      inlineText: true
      mainConfigFile: '<%= yeoman.tmp_dist %>/js/main.js'

      # no minification, is done by the min task
      optimize: "none"

      modules: [
        { name: 'app/vendors', exclude: [] }
        { name: 'app/app', exclude: ['app/vendors'] }
        { name: 'main', exclude: ['app/app', 'app/vendors'] }

Could there be something wrong with the stack and highlight files that I need to fix in order to make requirejs optimization and uglify work with them?

I installed highlightjs via bower by adding "highlightjs": "~8.0" to my bower.json file and running bower install. I downloaded stack.js from mbostock's stack project. I'm using v0 at the moment, with minor changes to make it work in this project. The source for all these are in the components directory of my github project.

BOUNTY If anyone is willing to clone the repo themselves, and try running the project with grunt server and grunt build to help me track down the problem, I'd greatly appreciate it. At the moment I have the vendor scripts in the github repo itself, so all you should need is compass and bower to run it.

È stato utile?

Soluzione

This is due to wrap: true in the r.js config. Here's a simple configuration that isolates the issue:

main.js

define([ 'legacy' ], function(legacy) {
    var greeting = 'hi';
    console.log(greeting, legacy.foo);
});

legacy.js

var globalThing = { foo: 1, bar: 2 };

build.json

{
    "name": "main",
    "optimize": "none",
    "out": "main-built.js",
    "shim": { "legacy": { "exports": "globalThing" } },
    "wrap": true
}

Let's run r.js (r.js -o build.json) and consider the result (formatted by me):

(function() {  // this immediately-invoked function expression (IIFE)
               // is here because r.js has "wrap: true" in the config

    var globalThing = { foo: 1, bar: 2 };

    // code generated from the "shim" entry in the config 
    define('legacy', function(global) {
        return function() {
            var ret, fn;
            // since global.globalThing is undefined,
            // that's where it goes wrong
            return ret || global.globalThing;
        };
    }(this));

    define('main', [ 'legacy' ], function(legacy) {
        var greeting = 'hi';
        console.log(greeting, legacy.foo);
    });

})();  // end of the IIFE

As you can see from the code above, globalThing isn't global any more. The same happens with the stack and highlight libraries in your project as they use var and function declarations to define their globals.

To tackle this issue, we have a couple of options. The first is to consider whether you really need wrap: true in the config. If you drop it, the globals will get global again and everything should start working as expected. The second option is to try adding wrapShim: true to the config. You can read about nuances of using this option here. If we try it with our sample configuration, we'll get something like this:

(function() {

    (function(root) {
        define('legacy', [], function() {
            return function() {
                var globalThing = { foo: 1, bar: 2 };
                return root.globalThing = globalThing;
            }.apply(root, arguments);
        });
    })(this);

    define('main', [ 'legacy' ], function(legacy) {
        var greeting = 'hi';
        console.log(greeting, legacy.foo);
    });

})();

Looks good to me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top