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

And*_*tch 33 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 */ });
    
    Run Code Online (Sandbox Code Playgroud)

    有办法避免这种情况吗?就像让每个主文件包含相同的构建配置文件而不必实际构建它一样?

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

  4. 我的app目录结构或我使用RequireJS有什么明显的错误吗?

Mar*_*Zen 56

首先,这不是一个独特解决方案的问题.我将解释我使用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兼容文件.尽管它有效,但您可以使用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"] }
        }
    });
Run Code Online (Sandbox Code Playgroud)

然后,在配置之后,我们可以为所有这些库发出第一个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(); }
                });
            });
        }
    });
Run Code Online (Sandbox Code Playgroud)

正如您在上面的require()主体中看到的那样,我们期望require.js脚本标记上有另一个属性.该数据开始属性将保持当前页面模块的名称.

因此,在HTML页面上我们必须添加这个额外的属性:

<script data-main="main" data-start="pagemodule/main" src="vendor/require.js"></script>
Run Code Online (Sandbox Code Playgroud)

通过这样做,我们将得到一个优化的main.js,它包含"/ vendor"和"/ lib"目录(共享资源)中的所有文件,但不包含特定于页面的脚本/模块,因为它们不是在main.js中作为依赖项进行硬编码.特定于页面的模块将在应用程序的每个页面上单独加载.

"页面主"模块应该返回一个function()将由上面的"app main"执行的模块.

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

    return function() {
        console.log("initializing page xyz module");
    };
});
Run Code Online (Sandbox Code Playgroud)

编辑

下面是如何使用构建配置文件来优化具有多个文件的特定于页面的模块的示例.

例如,假设我们有以下页面模块:

/page1/main.js

/page1/dep1.js

/page1/dep2.js

如果我们不优化此模块,那么浏览器将发出3个请求,每个脚本一个.我们可以通过指示r.js创建一个包并包含这3个文件来避免这种情况.

在构建配置文件的"modules"属性中:

...
"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"]
   }
]
Run Code Online (Sandbox Code Playgroud)

通过这样做,我们创建了另一个每页主文件及其所有依赖项.但是,由于我们已经有一个主文件可以加载我们共享的东西,我们不需要再将它们包含在page1/main模块中.配置有点冗长,因为您必须为每个具有多个脚本文件的页面模块执行此操作.

我在GitHub中上传了样板代码:https://github.com/mdezem/MultiPageAppBoilerplate.它是一个工作模板,只是为节点安装节点和r.js模块并执行build.cmd(在/ build目录中,否则它将失败,因为它使用相对路径)

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

问候!

  • 真棒!谢谢你这个优雅的解决方案.我一直在搜索文档,试图找出"正确"的方法来做到这一点.开始怀疑我是否从根本上误解了require.js. (4认同)