34

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

我的项目的目录结构如下:

httpdocs_siteroot/
    应用程序/
        php文件...
    媒体/
        css/
            css 文件...
        js/
            库/
                jQuery.js
                需要.js
                小胡子.js
            电源/
                main.page1.js
                main.page2.js
                main.page3.js
            插件/
                jquery.plugin1.js
                jquery.plugin2.js
                jquery.plugin3.js
            实用程序/
                util1.js
                util2.js
        图片/

由于该项目不是单页应用程序,因此我为每个页面都有一个单独的主文件(尽管有些页面使用相同的主文件)。

我的问题是:

  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 的使用是否存在明显问题?

4

2 回答 2

57

首先,这不是一个有唯一解的问题。我将解释我使用对我有用的 RequireJS 的方式,并且可能对你有用:)

其次,英语不是我的母语。非常感谢有关该语言的更正和提示。随意,伙计们:)

1)对于非单页的项目,require js 是否实用?

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

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

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

3) r.js 应该放在 httpdocs_siteroot 的父目录中吗?

不必要。你可以把它放在 /media 目录中,因为你所有的客户端东西都在那里。

4) 我的应用程序目录结构或我对 requirejs 的使用是否存在明显问题?

我不会这么说。另一方面,结构可能有点过于分散。例如,您可以将所有“第 3 方的东西”放在 /vendor 目录中。但这只是糖;您的结构将运行良好并且看起来是正确的。我认为主要问题是多个主文件中的 requirejs.config() 调用。

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

1) 不要用定义包装不符合 AMD 标准的文件。虽然它有效,但您可以使用 requirejs.config 中的“shim”属性获得相同的结果(见下文)。

2)在多页面应用程序中,我的解决方案是不需要优化后的 main.js 文件中的页面特定模块。相反,我需要主文件中的所有共享代码(第 3 方和我自己的),将特定于页面的代码留在每个页面上加载。主文件最终只是一个加载器,它在加载所有共享/lib 文件后启动特定于页面的代码。

这是我用 requirejs 构建多页应用程序的样板

目录结构:

/src - 我把所有客户端的东西放在一个 src 目录中,所以我可以在这个目录中运行优化器(这是你的媒体目录)。

/src/vendor - 我在这里放置所有 3rd 方文件和插件,包括 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,它包含“/vendor”和“/lib”目录(共享资源)中的所有文件,但不包含特定于页面的脚本/模块,因为它们不是在 main.js 中硬编码为依赖项。页面特定的模块将分别加载到应用程序的每个页面上。

“page main”模块应该返回一个function()将由上面的“app main”执行。

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 安装 node 和 r.js 模块并执行 build.cmd (在 /build 目录内,否则会失败,因为它使用相对路径)

我希望我已经清楚了。让我知道是否听起来很奇怪;)

问候!

于 2012-07-30T21:47:02.727 回答
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
    });
});

这是我在我的项目中使用的。

于 2013-03-28T05:25:19.663 回答