ASP.NET MVC4 捆綁(Bundle)技術下的 JavaScript

說到 Web 應用中 JavaScript 的模塊化,很容易想到 RequireJS、SeaJS 和 ECMAScript 6。ES6 要全面應用還得有段時間,RequireJS 和 SeaJS 的模塊化在實際應用中又有兩個分支:一是經過按需加載的方式加載並建立模塊,二是經過工具打包成單一文件,一次性加載,按需建立模塊。ASP.NET MVC4 的捆綁(Bundle)技術相似後者。html


MVC4 Bundle 主要用於優化 JavaScript 和 CSS 資源的加載。關於這個技術的介紹,能夠參考《ASP.NET Mvc4 Bunlde 捆綁壓縮技術》,或者《CSS編程:捆綁和縮小》。其特色很鮮明,主要有兩點:git


  1. 在開發環境,加載原文件,便於定位和 Debug;編程

  2. 在生產環境,按配置將全部資源分類打包壓縮,優化瀏覽器對資源加載。xcode


也正是因爲它的這兩個特色,若是要使用 Bundle 技術,就很難使用現有的 JavaScript 模塊化工具來進行開發。翻了下百度和 Google,沒找到合適的解決方案,因而決定本身寫個簡單的模塊加載器,主要實現以下目標:瀏覽器


  1. 模塊化開發緩存

  2. 大部分 JavaScript 文件由 MVC4 一次性加載,但模塊按需建立app

  3. 部分頁面的腳本,能夠按頁面須要單獨加載,但一樣是模塊化的框架


分析目標,歸整一下,大概有以下要點須要實現ide


  1. 因爲 Bundle 以後模塊不能以文件爲單位,因此須要重用的模塊都應該是命名模塊。考慮到具體頁面本身的模塊不須要重用,因此這種狀況下能夠定義爲匿名模塊。因此模塊定義函數要像這樣:模塊化

    funciton define(name, factory) {
        if (isFunction(name)) {
            factory = name
            name = undefined
        }
        // ......
    }

    模塊名稱惟一性由人來控制,可是應提供檢查機制,因此若是出現重複定義的狀況,拋出異常。由是在一個項目中,命名衝突這種狀況應該不是主要矛盾。若是不幸命名衝突成爲了主要矛盾,基本上也能夠經過定義命名空間來解決。最簡單的命名空間就是在模塊名中加入命名空間部分,好比 "app.core.codec.hexcode"


  2. 按需加載,使用 require 函數

    function require(moduleName) {
        // ......
    }


  3. 執行模塊的入口。雖然能夠用 require 做爲入口,可是 require 須要一個模塊名稱做爲參數,不能用於匿名模塊做爲入口的狀況。假想以下應用場景:

    define(function() {
        // ......
    }).use()

    要實現這種應用場景,就須要 define 返回一個對象,該對象擁有 use 方法,能夠經過 use 方法一次性調用當前模塊的 factory 函數。比較簡單直接的方式就是在內部定義一個 Module 類來裝載模塊配置,在 define 的時候生成 Module 對象,並返回出來。

    function define(name, factory) {
        // ......
        var module = new Module(factory)
        // ......
        return module
    }


  4. 內部模塊管理。經過一個 map<name, module> 來管理全部模塊定義,這在實現上就是一個普通的 JavaScript 對象。匿名模塊由於是當即使用,因此不須要進行管理。模塊管理的核心實際上是 Module 類,須要經過它完成建立模塊、緩存導出對象和提供導出對象等。並且除了 use 方法須要暴露出來以後,其它方法都應該隱藏起來。

    通過參考、推敲和實驗,得出了以下的一個代碼框架

    // 這是全部命名模塊保存的地方
    var modules = {}
    
    function Module(name, factory) {
        // 建立模塊對象,保存 factory 函數
    }
    
    Module.prototype.use = function() {
        // 執行 factory 函數
        // 處理 exports 和 isExported 等狀態
        return exports
    }
    
    function define(name, factory) {
        // 定義並保存模塊
        modules[name] = new Module(name, factory)
    }
    
    function require(name) {
        // 按名稱找到模塊,並執行之
        return modules[name].use()
    }


在最終實現的時候,還須要處理容錯,以及若干細節問題。最終代碼命名爲 js-modular.js,在附件中能夠下載。在使用的時候只須要注意一點,頁面上加載腳本的時候,記得把 js-modular.js 放在全部模塊定義腳本以前便可。



目前已經創建了開源項目 jNs,基於命名空間的模塊管理工具,是在 js-modular.js 的基礎之上發展而來的。若是有興趣的話,請關注一下這個項目。


js-modular.js 及 Demo(VS2013 + MVC4 + NuGet)下載

相關文章
相關標籤/搜索