如何在多页面项目中使用RequireJS构建配置文件+ r.js.

时间:2012-07-26 17:34:07

标签: javascript requirejs

我目前正在学习RequireJS基础知识,并对构建配置文件,主要文件以及RequireJS与多页项目的使用有一些疑问。

我项目的目录结构如下:

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. 我的app dir结构或使用RequireJS有什么明显错误吗?

2 个答案:

答案 0 :(得分:57)

首先,这不是一个独特解决方案的问题。我将解释我使用适用于我的RequireJS的方式,并可能适合您:)

其次,英语不是我的母语。有关该语言的更正和提示将非常感激。感觉自由,伙计们:)

  

1)对于不是单页的项目,是否需要js实用?

这取决于。例如,如果您的项目之间没有页面之间的共享代码,则RequireJS帮助将是适度的。 RequireJS的主要思想是将应用程序模块化为可重用代码块。如果您的应用程序仅使用特定于页面的代码,那么使用RequireJS可能不是一个好主意。

  

2)在不使用优化器的情况下,我的每个主文件都以基本相同的配置选项开头。有办法避免这种情况吗?就像让每个主文件包含相同的构建配置文件而不必实际构建它一样?

我看到的唯一方法是在主文件上进行配置,或创建一个将配置RequireJS的模块,然后将该模块用作main.js的第一个依赖项。但这可能很棘手。我的应用程序中没有使用很多main.js文件;我只使用一个充当装载机的装置(见下文)。

  

3)r.js应该进入httpdocs_siteroot的父目录吗?

不一定。您可以将它放在/ media目录中,因为您的所有客户端都在那里。

  

4)我的app dir结构或我对requirejs的使用是否存在明显的错误?

我不会这么说。另一方面,结构可能有点过于分散。例如,您可以将所有第三方内容放入其中。在/ vendor目录中。但这只是糖;你的结构将运作良好,似乎是正确的。我认为主要问题是在多个主文件中调用requirejs.config()。

我遇到了同样的问题,我最终得到了以下解决方案:

1)不要使用define包装非AMD兼容文件。虽然它有效,但使用" shim"可以达到相同的效果。 requirejs.config中的属性(见下文)。

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,其中包含&#34; / vendor&#34;中的所有文件。和&#34; / lib&#34;目录(共享资源),但不是特定于页面的脚本/模块,因为它们在main.js中不作为依赖项进行硬编码。特定于页面的模块将在应用程序的每个页面上单独加载。

&#34;页面主页&#34;模块应该返回一个function(),它将由&#34; app main&#34;执行。以上。

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个文件来避免这种情况。

在&#34;模块&#34;构建配置文件的属性:

...
"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。 它是一个工作模板,只是为节点安装节点和r.js模块并执行build.cmd(在/ build目录中,否则它将失败,因为它使用相对路径)

我希望我已经清楚了。如果听起来很奇怪,请告诉我;)

问候!

答案 1 :(得分: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
    });
});

这就是我在项目中使用的内容。