javascript 如何在多页面项目中使用RequireJS build profile + r.js
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11674824/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use RequireJS build profile + r.js in a multi-page project
提问by AndyPerlitch
I am currently learning RequireJS fundamentals and have some questions regarding a build profile, main files, and use of RequireJS with multi-page projects.
我目前正在学习 RequireJS 基础知识,并且对构建配置文件、主文件以及在多页项目中使用 RequireJS 有一些疑问。
My project's directory structure is as follows:
我的项目的目录结构如下:
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/
Since this project is not a single-page app, I have a separate main file for each page (although some pages use the same main file).
由于这个项目不是单页应用程序,我为每个页面都有一个单独的主文件(尽管有些页面使用相同的主文件)。
My questions are:
我的问题是:
Is RequireJS even practical for projects that are not single-page?
Without using the optimizer, each of my main files start with essentially the same config options:
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 */ });
Is there a way to avoid this? Like having each main file include the same build profile without having to actually build it?
Should r.js go in
httpdocs_siteroot
's parent directory?Is there something glaringly wrong with my app dir structure or my use of RequireJS?
对于非单页项目,RequireJS 甚至实用吗?
在不使用优化器的情况下,我的每个主要文件都以基本相同的配置选项开始:
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 */ });
有没有办法避免这种情况?就像让每个主文件包含相同的构建配置文件而不必实际构建它一样?
r.js 应该进入
httpdocs_siteroot
的父目录吗?我的应用程序目录结构或我对 RequireJS 的使用有什么明显的错误吗?
回答by Marcelo De Zen
First of all, this is not a question with a unique solution. I'll explain the way I use RequireJS that works for me, and may work for you :)
首先,这不是一个有唯一解的问题。我将解释我使用 RequireJS 的方式对我有用,并且可能对你有用:)
Second, English is not my mother language. Corrections and tips about the language will be very appreciated. Feel free, guys :)
其次,英语不是我的母语。关于语言的更正和提示将不胜感激。随意,伙计们:)
1) Is require js even practical for projects that are not single-page?
1) require js 对于非单页项目是否实用?
It depends. If your project does not have shared code between pages for example, RequireJS help will be modest. The main idea of RequireJS is modularize the application into chunks of reusable code. If your application uses only page-specific code, then using RequireJS may not be a good idea.
这取决于。例如,如果您的项目在页面之间没有共享代码,则 RequireJS 帮助将是适度的。RequireJS 的主要思想是将应用程序模块化为可重用的代码块。如果您的应用程序仅使用特定于页面的代码,那么使用 RequireJS 可能不是一个好主意。
2) Without using the optimizer, each of my main files start with essentially the same config options. Is there a way to avoid this? Like having each main file include the same build profile without having to actually build it?
2) 在不使用优化器的情况下,我的每个主要文件都以基本相同的配置选项开始。有没有办法避免这种情况?就像让每个主文件包含相同的构建配置文件而不必实际构建它一样?
The only way I see is making the configuration on the main file, or create a module that will configure RequireJS and then use that module as the first dependency on main.js. But this can be tricky. I do not use many main.js files in my applications; I use only one that acts as a loader (see below).
我看到的唯一方法是在主文件上进行配置,或者创建一个将配置 RequireJS 的模块,然后将该模块用作 main.js 的第一个依赖项。但这可能很棘手。我的应用程序中没有使用很多 main.js 文件;我只使用一个充当加载器的工具(见下文)。
3) Should r.js go in httpdocs_siteroot's parent directory?
3) r.js 应该放在 httpdocs_siteroot 的父目录中吗?
Not necessarily. You can put it inside the /media directory, since all your client stuff is there.
不必要。你可以把它放在 /media 目录中,因为你所有的客户端东西都在那里。
4) Is there something glaringly wrong with my app dir structure or my use of requirejs?
4)我的应用程序目录结构或我对requirejs的使用有什么明显的错误吗?
I would not say that. On the other hand, the structure is perhaps a bit too fragmented. For example, you can put all '3rd party stuff' inside a /vendor directory. But this is just sugar; your structure will work well and seems right. I think the major problem is the requirejs.config() call in multiple main files.
我不会那样说。另一方面,结构可能有点过于分散。例如,您可以将所有“第 3 方内容”放在 /vendor 目录中。但这只是糖;您的结构将运行良好,看起来是正确的。我认为主要问题是多个主文件中的 requirejs.config() 调用。
I had the same problems you are having now and I ended up with the following solution:
我遇到了与您现在相同的问题,最终得到了以下解决方案:
1) Do not wrap the non-AMD-compliant files with a define. Although it works, you can achieve the same results using the "shim" property in requirejs.config (see below).
1) 不要用定义包装非 AMD 兼容的文件。虽然它有效,但您可以使用 requirejs.config 中的“shim”属性获得相同的结果(见下文)。
2) In a multi-page application, the solution for me is not to require the page-specific modules from the optimized main.js file. Instead, I require all the shared code (3rd party and my own) from the main file, leaving the page-specific code to load on each page. The main file ends up only being a loader that starts the page-specific code after loading all shared/lib files.
2) 在多页面应用程序中,我的解决方案是不需要优化 main.js 文件中的页面特定模块。相反,我需要主文件中的所有共享代码(第 3 方和我自己的),而将特定于页面的代码保留在每个页面上。主文件最终只是一个加载器,它在加载所有共享/lib 文件后启动特定于页面的代码。
This is the boilerplate I use to build a multi-page application with requirejs
这是我用来使用 requirejs 构建多页应用程序的样板
Directory structure:
目录结构:
/src - I put all the client stuff inside a src directory, so I can run the optimizer inside this directory (this is your media directory).
/src - 我把所有客户端的东西放在一个 src 目录中,所以我可以在这个目录中运行优化器(这是你的媒体目录)。
/src/vendor - Here I place all 3rd party files and plugins, including require.js.
/src/vendor - 我在这里放置了所有 3rd 方文件和插件,包括 require.js。
/src/lib - Here I place all my own code that is shared by the entire application or by some pages. In other words, modules that are not page-specific.
/src/lib - 我在这里放置了我自己的所有代码,这些代码由整个应用程序或某些页面共享。换句话说,不是特定于页面的模块。
/src/page-module-xx - And then, I create one directory for each page that I have. This is not a strict rule.
/src/page-module-xx - 然后,我为我拥有的每个页面创建一个目录。这不是一个严格的规则。
/src/main.js: This is the only main file for the entire application. It will:
/src/main.js:这是整个应用程序的唯一主文件。它会:
- configure RequireJS, including shims
- load shared libraries/modules
- load the page-specific main module
- 配置RequireJS,包括垫片
- 加载共享库/模块
- 加载特定页面的主模块
This is an example of a requirejs.config call:
这是一个 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"] }
}
});
And then, after configuration we can make the first require() request for all those libraries and after that do the request for our "page main" module.
然后,在配置之后,我们可以对所有这些库发出第一个 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(); }
});
});
}
});
As you can see in the body of the require() above, we're expecting another attribute on the require.js script tag. The data-startattribute will hold the name of the module for the current page.
正如您在上面 require() 的正文中所见,我们期望 require.js 脚本标签上有另一个属性。该数据开始属性将保持当前页面模块的名称。
Thus, on the HTML page we must add this extra attribute:
因此,在 HTML 页面上,我们必须添加这个额外的属性:
<script data-main="main" data-start="pagemodule/main" src="vendor/require.js"></script>
By doing this, we will end up with an optimized main.js that contains all the files in "/vendor" and "/lib" directories (the shared resources), but not the page-specific scripts/modules, as they are not hard-coded in the main.js as dependencies. The page-specific modules will be loaded separately on each page of the application.
通过这样做,我们将最终得到一个优化的 main.js,其中包含“/vendor”和“/lib”目录(共享资源)中的所有文件,但不包含特定于页面的脚本/模块,因为它们不是在 main.js 中硬编码为依赖项。特定于页面的模块将在应用程序的每个页面上单独加载。
The "page main" module should return a function()
that will be executed by the "app main" above.
“page main”模块应该返回一个function()
将由上面的“app main”执行的。
define(function(require, exports, module) {
var util = require("lib/util");
return function() {
console.log("initializing page xyz module");
};
});
EDIT
编辑
Here is example of how you can use build profile to optimize the page-specific modules that have more than one file.
下面是如何使用构建配置文件优化具有多个文件的特定于页面的模块的示例。
For example, let's say we have the following page module:
例如,假设我们有以下页面模块:
/page1/main.js
/page1/main.js
/page1/dep1.js
/page1/dep1.js
/page1/dep2.js
/page1/dep2.js
If we do not optimize this module, then the browser will make 3 requests, one for each script. We can avoid this by instructing r.js to create a package and include these 3 files.
如果我们不优化这个模块,那么浏览器会发出 3 个请求,每个脚本一个。我们可以通过指示 r.js 创建一个包并包含这 3 个文件来避免这种情况。
On the "modules" attribute of the build profile:
在构建配置文件的“模块”属性上:
...
"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"]
}
]
By doing this, we create another per-page main file with all its dependencies. But, since we already have a main file that will load all our shared stuff, we don't need to include them again in page1/main module. The config is a little verbose since you have to do this for each page module where you have more than one script file.
通过这样做,我们创建了另一个每页主文件及其所有依赖项。但是,因为我们已经有一个主文件可以加载我们所有的共享内容,所以我们不需要再次将它们包含在 page1/main 模块中。配置有点冗长,因为您必须为每个包含多个脚本文件的页面模块执行此操作。
I uploaded the code of the boilerplate in GitHub: https://github.com/mdezem/MultiPageAppBoilerplate. It is a working boilerplate, just install node and r.js module for node and execute build.cmd (inside the /build directory, otherwise it will fail because it uses relative paths)
我在 GitHub 上传了样板代码:https: //github.com/mdezem/MultiPageAppBoilerplate。它是一个工作样板,只需为 node 安装 node 和 r.js 模块并执行 build.cmd (在 /build 目录中,否则会因为使用相对路径而失败)
I hope I have been clear. Let me know if something sounds strange ;)
我希望我已经清楚了。如果有什么事情听起来很奇怪,请告诉我;)
Regards!
问候!
回答by John Xiao
<script data-main="js/main" src="js/lib/require.js"></script>
// file: js/main
require(['./global.config'], function(){
require(['./view/home'], function() {
// do something
});
});
This is what I used in my project.
这是我在我的项目中使用的。