2012-07-26 103 views
33

我目前正在學習RequireJS基礎知識,並對構建配置文件,主要文件以及RequireJS與多頁面項目的使用有一些疑問。如何在多頁面項目中使用RequireJS構建配置文件+ r.js

我的項目的目錄結構如下:

 
httpdocs_siteroot/ 
    app/ 
     php files... 
    media/ 
     css/ 
      css files... 
     js/ 
      libs/ 
       jquery.js 
       require.js 
       mustache.js 
      mains/ 
       main.page1.js 
       main.page2.js 
       main.page3.js 
      plugins/ 
       jquery.plugin1.js 
       jquery.plugin2.js 
       jquery.plugin3.js 
      utils/ 
       util1.js 
       util2.js 
     images/ 

由於這個項目是不是一個單頁的應用程序,我會爲每個頁面創建一個單獨的主文件(儘管一些網頁使用相同的主文件)。

我的問題是:

  1. 是RequireJS甚至實際爲不是單頁的項目?

  2. 不使用的優化,我的每一個主文件啓動以基本相同的配置選項:

    requirejs.config({ 
        paths: { 
        'jquery': 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min' 
        }, 
        baseUrl: '/media/js/', 
        // etc... 
    }); 
    require(['deps'], function() { /* main code */ }); 
    

    是否有辦法避免這種情況?像每個主文件都包含相同的構建配置文件而不必實際構建它?

  3. r.js應該去httpdocs_siteroot的父目錄嗎?

  4. 我的應用程序目錄結構或使用RequireJS有什麼明顯的錯誤嗎?

+0

我有和簡短的答案,但我需要一些細節:多少頁?每個頁面特定的代碼很少或很多代碼(比如,每個頁面代碼爲10kb)? – devundef 2012-07-29 09:58:11

+0

你使用的是requirejs插件,插件是什麼? – devundef 2012-07-29 10:00:32

+0

通常每個mainjs文件<10kb。我只是將它用於初始化jquery插件之類的東西。將會有很多頁面......我會說20並且在不斷增長。所以可能大約有15個mainjs文件和增長。我使用的插件是jquery插件,並使用define調用包裝以符合AMD標準 – AndyPerlitch 2012-07-29 16:27:44

回答

57

首先,這不是一個獨特的解決方案的問題。我將解釋我使用RequireJS的方式,它適用於我,並可能適合你:)

二,英語不是我的母語。有關該語言的更正和提示將非常感謝。隨意,球員:)

1)是否需要JS甚至實際爲不是單頁的項目?

這取決於。例如,如果你的項目在頁面之間沒有共享代碼,RequireJS的幫助將是適度的。 RequireJS的主要思想是將應用程序模塊化爲可重用代碼的塊。如果你的應用程序只使用頁面特定的代碼,那麼使用RequireJS可能不是一個好主意。

2)不使用優化器,我的每個主文件都以基本相同的配置選項開始。有沒有辦法避免這種情況?像每個主文件都包含相同的構建配置文件而不必實際構建它?

我看到正在對主文件的配置,或創建一個模塊,將配置RequireJS,然後使用該模塊作爲main.js.第一依賴的唯一途徑但這可能會很棘手。我的應用程序中不使用許多main.js文件;我只使用一個充當裝載程序的應用程序(請參見下文)。

3)r.js是否應該進入httpdocs_siteroot的父目錄?

不一定。你可以把它放在/ media目錄中,因爲你所有的客戶端都在那裏。

4)我的應用程序目錄結構或使用requirejs有什麼明顯的錯誤嗎?

我不會那麼說。另一方面,結構可能有點過於分散。例如,你可以把所有的'第三方東西'放在一個/ vendor目錄中。但這只是糖;你的結構將運作良好,看起來是正確的。我認爲主要問題是多個主文件中的requirejs.config()調用。

我現在有同樣的問題,我結束了以下解決方案:

1)不要用規定的包裝不符合要求的AMD-文件。儘管它起作用,但您可以使用requirejs.config中的「shim」屬性(請參見下文)獲得相同的結果。

2)在多頁面應用程序中,我的解決方案是不要求優化的main.js文件中的頁面特定模塊。相反,我需要從主文件中獲取所有共享代碼(第三方和我自己的代碼),並在每個頁面上加載頁面特定的代碼。主文件最終只是一個加載器,在加載所有共享/ lib文件後啓動特定於頁面的代碼。

這是我用它來建立與requirejs一個多頁應用的樣板

目錄結構:

/src目錄 - 我把所有的客戶端的東西一個src目錄裏面,所以我可以運行該目錄內的優化器(這是您的媒體目錄)。

/src/vendor - 這裏我放置所有第三方文件和插件,包括require.js。

/src/lib - 在這裏,我放置了由整個應用程序或某些頁面共享的所有自己的代碼。換句話說,不是頁面特定的模塊。

/src/page-module-xx - 然後,我爲每個頁面創建一個目錄。這不是一個嚴格的規定。

/src/main.js:這是整個應用程序的唯一主文件。它將:

  • 配置RequireJS,包括墊片
  • 負載共享庫/模塊
  • 負載特定頁面的主模塊

這是一個requirejs.config呼叫的例子:

requirejs.config({ 
     baseUrl: ".", 
     paths: { 
      // libraries path 
      "json": "vendor/json2", 
      "jquery": "vendor/jquery", 
      "somejqueryplugion": "vendor/jquery.somejqueryplufin", 
      "hogan": "vendor/hogan", 

      // require plugins 
      "templ": "vendor/require.hogan", 
      "text": "vendor/require.text" 
     }, 
     // The shim section allows you to specify 
     // dependencies between non AMD compliant files. 
     // For example, "somejqueryplugin" must be loaded after "jquery". 
     // The 'exports' attribute tells RequireJS what global variable 
     // it must assign as the module value for each shim. 
     // For example: By using the configutation below for jquery, 
     // when you request the "jquery" module, RequireJS will 
     // give the value of global "$" (this value will be cached, so it is 
     // ok to modify/delete the global '$' after all plugins are loaded. 
     shim: { 
      "jquery": { exports: "$" }, 
      "util": { exports: "_" }, 
      "json": { exports: "JSON" }, 
      "somejqueryplugin": { exports: "$", deps: ["jquery"] } 
     } 
    }); 

然後,配置完成後,我們可以做出第一個require()請求 爲所有這些庫,然後做我們的「頁面主」模塊的請求。

//libs 
require([ 
    "templ",  //require plugins 
    "text", 
    "json",  //3rd libraries 
    "jquery", 
    "hogan", 
    "lib/util" // app lib modules 
], 
    function() { 
     var $ = require("jquery"), 
      // the start module is defined on the same script tag of data-main. 
      // example: <script data-main="main.js" data-start="pagemodule/main" src="vendor/require.js"/> 
      startModuleName = $("script[data-main][data-start]").attr("data-start"); 

     if (startModuleName) { 
      require([startModuleName], function (startModule) { 
       $(function(){ 
        var fn = $.isFunction(startModule) ? startModule : startModule.init; 
        if (fn) { fn(); } 
       }); 
      }); 
     } 
    }); 

正如您在上面require()的主體中看到的那樣,我們期待require.js腳本標記的另一個屬性。 data-start屬性將保存當前頁面的模塊名稱。

因此,在HTML頁面上,我們必須增加這些額外的屬性:

<script data-main="main" data-start="pagemodule/main" src="vendor/require.js"></script> 

通過這樣做,我們將結束與優化main.js一個包含「/供應商」和「所有文件/ lib「目錄(共享資源),但不包括頁面特定的腳本/模塊,因爲它們在main.js中沒有作爲依賴關係進行硬編碼。頁面特定模塊將在應用程序的每個頁面上分別加載。

「頁面主」模塊應返回function(),將由上面的「應用程序主」執行。

define(function(require, exports, module) { 
    var util = require("lib/util"); 

    return function() { 
     console.log("initializing page xyz module"); 
    }; 
}); 

編輯

下面是例子,你如何使用的建造輪廓,以優化有一個以上的文件中的特定頁面模塊。

例如,假設我們有以下頁面模塊:

/page1/main.js

/page1/dep1.js

/page1/dep2.js

如果我們不優化這個模塊,那麼瀏覽器會發出3個請求,每個腳本都有一個請求。 我們可以通過指示r.js創建一個包幷包含這3個文件來避免這種情況。

在建造輪廓的「模塊」屬性:

... 
"modules": [ 
    { 
     name: "main" // this is our main file 
    }, 
    { 
     // create a module for page1/main and include in it 
     // all its dependencies (dep1, dep2...) 
     name: "page1/main", 
     // excluding any dependency that is already included on main module 
     // i.e. all our shared stuff, like jquery and plugins should not 
     // be included in this module again. 
     exclude: ["main"] 
    } 
] 

通過這樣做,我們創建了具有所有依賴另一個單頁主文件。但是,由於我們已經有一個主文件可以加載我們所有的共享內容,因此我們不需要再將它們包含在page1/main模塊中。 該配置有點冗長,因爲您必須爲每個頁面模塊執行此操作,而您有多個腳本文件。

我上傳了GitHub中的樣板代碼:https://github.com/mdezem/MultiPageAppBoilerplate。 這是一個正在運行的樣板,只需爲節點安裝node和r.js模塊並執行build.cmd(位於/ build目錄中,否則將失敗,因爲它使用相對路徑)

我希望我已經清楚。讓我知道是否聽起來有點奇怪;)

問候!

+0

感謝您的出色答案!我還需要再讀幾遍,看看你的github樣板文件才能真正得到它,但我相信我會很快提出一些問題! – AndyPerlitch 2012-07-31 00:08:09

+0

@AndyPerlitch,很高興知道,感謝您的修改。 – devundef 2012-07-31 22:16:08

+0

您是否在每個需要與DOM交互的頁面模塊中使用$(document).ready()函數?所以它看起來像: 定義( 函數(){ 恢復功能(){ $(文件)。就緒(函數(){// 做的東西 });} } ); 似乎有點冗長......你可以把需要的腳本放在頁面的末尾嗎?我不知道,因爲我知道require文檔要求將它放在頭部 – AndyPerlitch 2012-08-03 17:45:46

1
<script data-main="js/main" src="js/lib/require.js"></script> 


// file: js/main 

require(['./global.config'], function(){ 
    require(['./view/home'], function() { 
     // do something 
    }); 
}); 

這是我在我的項目中使用的。

相關問題