Grunt构建不暴露我需要的全局变量

时间:2014-04-16 20:09:06

标签: javascript requirejs gruntjs amd r.js

当我使用我的grunt:server任务在本地运行我的项目时,该项目按预期工作。但是,在构建了所有供应商代码并将其放入一个文件之后,我需要的两个模块不可用,并且项目不起作用。

这是我的requirejs配置:

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看起来像

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

当我通过grunt在本地运行项目时,我看到打印出的所有全局变量。然而,当我构建项目时,Backbone Underscore和JQuery打印出来,而堆栈失败(hljs也不可用,如果我从app / vendor中删除堆栈,它不会修复突出显示,所以它可能不是订单的事情)

使用以下配置调用requirejs优化器:

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'] }

堆栈是否有问题并突出显示我需要修复的文件以便进行requirejs优化并使用uglify进行处理?

我通过bower安装了highlightjs,将"highlightjs": "~8.0"添加到我的bower.json文件并运行bower install。我从mbostockstack project下载了stack.js。我现在正在使用v0,只需稍作修改即可使其在此项目中正常运行。所有这些的来源都在components directory of my github project

BOUNTY 如果有人愿意自己克隆存储库,并尝试使用grunt servergrunt build运行项目来帮助我追踪问题,那么我会非常感激欣赏它。目前我在github repo本身有供应商脚本,所以你需要的就是指南针和凉亭来运行它。

1 个答案:

答案 0 :(得分:3)

这是由于r.js配置中的wrap: true。这是一个简单的配置隔离了问题:

<强> 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
}

让我们运行r.js(r.js -o build.json)并考虑结果(由我格式化):

(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

从上面的代码中可以看出,globalThing不再是全球性的。使用var和函数声明来定义它们的全局变量时,项目中的堆栈和高亮库也会发生同样的情况。

要解决这个问题,我们有几个选择。首先是考虑配置中是否真的需要wrap: true。如果删除它,全局变量将再次变为全局,并且一切都应该按预期开始工作。第二个选项是尝试将wrapShim: true添加到配置中。您可以阅读使用此选项here的细微差别。如果我们尝试使用我们的示例配置,我们将得到类似的结果:

(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);
    });

})();

对我来说很好。