在没有Require.js的情况下通过Grunt将JS文件包含在一起

时间:2015-07-16 17:16:22

标签: javascript node.js backbone.js gruntjs

我正在写一个Backbone.js项目。目前,我的所有应用程序代码(一堆视图)都存在于一个巨大的单片文件中,其结构如下:

'use strict';
(function(window, $, Backbone){
    var app = app || {
        Views: {}
        Models: {}
        Collections: {}
    };

    app.Views.MainView = Backbone.View.extend({
       // etc etc. tons of code in here
    });

    app.views.ChildView = Backbone.View.extend({
        // etc. etc. tons of code in here too.
    });

    $(function() {
        new App.Views.MainView();
    });
}(window, jQuery, Backbone))

该文件有点不合适,而我想将我的观点分解为他们自己的文件,即views/Main.jsviews/Child.js

我最初的想法是使用Grunt将所有文件连接在一起,但是我希望所有代码都包含在IIFE中,如上所示。

使用Grunt,最简洁/最简单的方法是"包括"那个IIFE里面的文件?有点像usemin,但对于内部JavaScript而不是标记。

1 个答案:

答案 0 :(得分:0)

根据我的经验,我发现最好将分离的模块留在自己的闭包(IIFE)中。下面的代码示例演示了在单个闭包下组合所有文件的缺陷,而不是将每个文件包装在自己的闭包中:

//Your big closure
(function () {
    
    //Included from file 1
    var defaultOptions = {
        label: 'Testing1'
    };
    
    window.MyObject1 = function (options) {
        this.options = $.extend({}, defaultOptions, options);
    }
    
    //Included from file 2
    var defaultOptions = {
        label: 'Testing2'
    };
    
    window.MyObject2 = function (options) {
        this.options = $.extend({}, defaultOptions, options);
    }
    
})();

//Later in the site, you decide to use some objects:
var obj1 = new MyObject1();
var obj2 = new MyObject2();


$('#obj1').text(obj1.options.label);
$('#obj2').text(obj2.options.label);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="obj1"></div>
<div id="obj2"></div>

我通过利用事件在模块之间进行通信。

例如,假设您有一个工具栏和一个对话框,并且您希望在按下工具栏按钮时打开该对话框。

(function () {

    window.MyToolbar = function () {
        this.onOpenDialogButtonClicked = function () {
            $(document).trigger(window.events.MyDialog.open); //you can also send it data as the second parameter if you need to.
        };
    };

})();

(function (events) {

    //Define your custom events for this dialog.
    $.extend(events, {
        MyDialog: {
            open: 'window.events.myDialog.open' //Need a unique string here. I go back later and CRC32 these to help with minification.
        }
    });

    window.MyDialog = function () {
        $(document).on(window.events.MyDialog.open, function () {
            //open the dialog here!
            $('#dialog').text('opened!');
        });
    };

})(window.events = window.events || {});

var toolbar = new MyToolbar();
var dialog = new MyDialog();

$(document).on('click', '#button', toolbar.onOpenDialogButtonClicked);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="button">Open Dialog</button>
<div id="dialog"></div>

这里的好处是不需要依赖加载顺序。在此示例中,工具栏模块需要加载对话框模块以便window.events.MyDialog.open解析,但只有在实际按下按钮时才需要。

如果这是一个问题,您可以将事件声明移动到名为events.js的单个文件中。

除了事件的名称之外,可以按下工具栏按钮,并且不需要对对话框的引用来打开它。该对话框侦听open事件。如果收到一个,它就会打开。如果没有对话正在收听,那么按钮就什么都不做。

此示例还演示了模块如何通过将项目附加到全局空间中的全局空间来进行通信。就个人而言,我创建了一个位于全局空间的“命名空间”变量,并将所有内容附加到其中。

例如:

(function (myNamespace) {

    //This is assuming myNamespace.events exists already - make sure it does before calling this.
    $.extend(myNamespace.events, {
        MyDialog: { open: 'myNamespace.events.MyDialog.open' }
    });

})(window.myNamespace = window.myNamespace || {});

这只是封装了我写的东西,并防止它与其他库可能放在全球空间中的东西发生碰撞。

因此,虽然您可以通过将所有文件连接到一个闭包来节省缩小过程中的几个字节,但您可能会遇到一些不必要的麻烦。启用缩小和gzip后,在单个闭包下连接所有内容所节省的几个字节是无关紧要的。

我已经展示了闭包如何相互通信,并隐藏了模块专用的项目。

我没有使用Backbone.js,很抱歉在示例中没有包含任何Backbone.js。我确信这些想法可以转化。