我是 Angular.js 的新手,并试图了解它与 Backbone.js 的不同之处......我们曾经在使用 Backbone 时使用 Require.js 管理我们的包依赖项。用 Angular.js 做同样的事情有意义吗?
将 Require.js 与 Angular.js 一起使用是否有意义?
是的,angular.js
与require.js
其中可以require.js
用于module化组件的一起使用是有意义的。
有一个种子项目使用both angular.js and require.js
.
重申我认为 OP 的真正问题是:
如果我主要在 Angular 1.x 中构建应用程序,并且(隐式地)在 Grunt/Gulp/Broccoli 和 Bower/NPM 时代这样做,并且我可能有几个额外的库依赖项,是否需要添加明确的、特定的通过使用 Angular 而无需 Require 获得的value超出了我的value?
或者,换一种方式:
“如果我有其他处理基本脚本加载的方法, vanilla Angular 是否需要 Require 有效管理基本的 Angular 组件加载? ”
我相信对此的基本答案是:“除非您有其他事情要做,和/或您无法使用更新、更现代的工具,否则不会。”
让我们从一开始就明确:RequireJS 是一个很好的工具,它解决了一些非常重要的问题,并让我们开始了我们所走的道路,朝着更具可扩展性、更专业的 Javascript 应用程序迈进。重要的是,这是许多人第一次遇到module化和让事物脱离全局范围的概念。因此,如果您要构建一个需要扩展的 Javascript 应用程序,那么 Require 和 AMD 模式就不是做这件事的坏工具。
但是,Angular 有什么特别之处让 Require/AMD 成为特别合适的选择吗?不。事实上,Angular 为您提供了自己的module化和封装模式,这在许多方面使 AMD 的基本module化特性变得多余。而且,将 Angular module集成到 AMD 模式中并非不可能,但它有点……挑剔。您肯定会花时间让这两种模式很好地集成。
对于 Angular 团队本身的一些观点,有这个来自 Brian Ford,Angular Batarang 的作者,现在是 Angular 核心团队的成员:
我不建议在 AngularJS 中使用 RequireJS。虽然这当然是可能的,但我还没有看到 RequireJS 在实践中有益的任何实例。
因此,关于 AngularJS 的一个非常具体的问题:Angular 和 Require/AMD 是正交的,并且在某些地方重叠。您可以将它们一起使用,但没有理由与 Angular 本身的性质/模式特别相关。
但是对于可扩展的 Javascript 应用程序的内部和外部依赖项的基本管理呢?不需要在那里为我做一些真正重要的事情吗?
我建议查看 Bower 和 NPM,尤其是 NPM。我并不是要针对这些工具的相对优势发起一场圣战。我只想说:还有其他方法可以给那只猫剥皮,这些方法可能比 AMD/Require 还要好。(它们在 2015 年末肯定有更受欢迎的势头,尤其是 NPM,结合 ES6 或 CommonJS module。请参阅相关的 SO 问题。)
延迟加载呢?
请注意,延迟加载和延迟下载是不同的。Angular 的延迟加载并不意味着您直接从服务器中拉取它们。在带有 javascript 自动化的 Yeoman 风格的应用程序中,您将整个 shebang 连接并缩小到一个文件中。它们存在,但在需要之前不会执行/实例化。您通过这样做获得的速度和带宽改进大大超过了延迟下载特定 20 线控制器所带来的任何所谓的改进。事实上,该控制器浪费的网络延迟和传输开销将比控制器本身的大小大一个数量级。
但是,假设您确实需要延迟下载,可能用于应用程序中不常使用的部分,例如管理界面。这是一个非常合法的案例。Require 确实可以为您做到这一点。但也有也 很多 其他的,可能 更 灵活 的选择是完成同样的事情。Angular 2.0 显然会为我们解决这个问题,内置在路由器中。(详情。)
但是在我本地开发箱的开发过程中呢?
如何在不需要手动将它们全部附加到 index.html 的情况下加载所有数十/数百个脚本文件?
查看 Yeoman 的 generator-angular 中的子生成器,或者generator- gulp -angular 中包含的自动化模式,或者 React 的标准 Webpack 自动化。这些为您提供了一种干净、可扩展的方式:在构建组件时自动附加文件,或者如果它们存在于某些文件夹中/匹配某些全局模式,则简单地自动抓取它们。一旦你有了后面的选项,你就再也不需要考虑自己的脚本加载了。
底线?
对于某些事情,Require 是一个很好的工具。但只要有可能,就顺其自然,尽可能分开你的顾虑。让 Angular 去担心 Angular 自身的module化模式,考虑使用 ES6 module或 CommonJS 作为通用的module化模式。让现代自动化工具担心脚本加载和依赖项管理。并以细粒度的方式处理异步延迟加载,而不是将其与其他两个问题纠缠在一起。
也就是说,如果您正在开发 Angular 应用程序,但由于某种原因无法在您的机器上安装 Node 以使用 Javascript 自动化工具,那么 Require 可能是一个很好的替代解决方案。我见过非常精细的设置,人们希望动态加载 Angular 组件,每个组件都声明自己的依赖项或其他东西。虽然我可能会尝试以另一种方式解决这个问题,但我可以看到这个想法的优点,对于那个非常特殊的情况。
但除此之外……当从头开始使用新的 Angular 应用程序和创建现代自动化环境的灵活性时……您有很多其他更灵活、更现代的选择。
(反复更新以跟上不断发展的 JS 场景。)
是的,这是有道理的。
Angular module不会尝试解决脚本加载顺序或延迟脚本获取的问题。这些目标是正交的,两个module系统可以并存并实现它们的目标。
我认为这是一个主观问题,因此我将提供我的主观意见。
Angular 内置了module化机制。当你创建你的应用程序时,你要做的第一件事是
var app = angular.module("myApp");
接着
app.directive(...);
app.controller(...);
app.service(...);
如果您查看 angular-seed,它是 angular 的简洁入门应用程序,它们已将指令、服务、控制器等分离到不同的module中,然后将这些module作为依赖项加载到您的主应用程序上。
就像是 :
var app = angular.module("myApp",["Directives","Controllers","Services"];
Angular 也会延迟加载这些module(到内存中)而不是它们的脚本文件。
在延迟加载脚本文件方面,坦率地说,除非您正在编写非常大的内容,否则这将是一种矫枉过正,因为 angular 本质上会减少您编写的代码量。如果用 angular 编写,用大多数其他框架编写的典型应用程序的 LOC 可能会减少约 30-50%。
将 RequireJS 与 AngularJS 一起使用是有道理的,但前提是您了解它们中的每一个是如何在依赖注入方面工作的,因为尽管它们都注入了依赖项,但它们注入的东西却截然不同。
AngularJS 有自己的依赖系统,可以让你将 AngularJS module注入到新创建的module中,以便重用实现。假设您创建了一个实现 AngularJS 过滤器“greet”的“第一个”module:
angular
.module('first', [])
.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
}
});
现在假设您想在另一个名为“second”的module中使用“greet”过滤器,该module实现了“goodbye”过滤器。您可以将“第一个”module注入“第二个”module:
angular
.module('second', ['first'])
.filter('goodbye', function() {
return function(name) {
return 'Good bye, ' + name + '!';
}
});
问题是,为了在没有 RequireJS 的情况下正常工作,您必须确保在创建“第二个”AngularJS module之前在页面上加载了“第一个”AngularJS module。引用文档:
依赖于一个module意味着需要在加载需要的module之前加载所需的module。
从这个意义上说,这里是 RequireJS 可以帮助您的地方,因为 RequireJS 提供了一种将脚本注入页面的干净方法,帮助您组织彼此之间的脚本依赖关系。
回到“第一个”和“第二个”AngularJS module,这里是如何使用 RequireJS 分离不同文件上的module以利用脚本依赖项加载的方法:
// firstModule.js file
define(['angular'], function(angular) {
angular
.module('first', [])
.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
}
});
});
// secondModule.js file
define(['angular', 'firstModule'], function(angular) {
angular
.module('second', ['first'])
.filter('goodbye', function() {
return function(name) {
return 'Good bye, ' + name + '!';
}
});
});
你可以看到我们依赖于“firstModule”文件被注入,然后RequireJS回调的内容才能被执行,这需要加载“第一个”AngularJSmodule来创建“第二个”AngularJSmodule。
旁注:为了在 RequireJS 回调函数中使用 AngularJS,需要在“firstModule”和“secondModule”文件中注入“angular”作为依赖项,并且必须在 RequireJS 配置中配置它以将“angular”映射到库代码。您也可以以传统方式(脚本标记)将 AngularJS 加载到页面中,尽管会失去 RequireJS 的好处。
有关从 2.0 版本的 AngularJS 核心获得 RequireJS 支持的更多详细信息,请参阅我的博客文章。
根据我的博客文章“使用 AngularJS 了解 RequireJS”,这里是链接。