将 Require.js 与 Angular.js 一起使用是否有意义?

IT技术 javascript requirejs angularjs
2021-02-10 10:37:19

我是 Angular.js 的新手,并试图了解它与 Backbone.js 的不同之处......我们曾经在使用 Backbone 时使用 Require.js 管理我们的包依赖项。用 Angular.js 做同样的事情有意义吗?

6个回答

是的,angular.jsrequire.js其中可以require.js用于module化组件的一起使用是有意义的

有一个种子项目使用both angular.js and require.js.

请注意,这些种子项目都没有得到 Angular 团队的认可。Require 是一种在其他上下文中更有意义的模式,恕我直言,将其硬塞到 Angular 中并不是最佳实践。
2021-03-22 10:37:19
@tnajdek,我更新了 Anshu 的回答中的链接,指向您建议的那个。
2021-04-03 10:37:19
上面提到的种子项目已经一年没有动过了,所以我使用最新的 AngularJS 和 RequireJS创建了一个新项目,并完全支持睾丸驱动测试。
2021-04-04 10:37:19
Brad Green 和 Shyam Seshadri 所著的 O'Reilly AngularJS 一书(今年 4 月发布)也建议在 Angular 项目的早期添加 RequireJS,并且非常清楚地列出了细节。
2021-04-08 10:37:19
我宁愿在编译的时候1.千方百计browserify.org 2. npmjs.org/package/gulp-angular-filesort
2021-04-12 10:37:19

重申我认为 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 场景。)

同意。但是 OP 的主旨似乎是:“如果我主要在 Angular 中构建应用程序,并且(隐式地)在 Grunt 时代这样做,并且我可能有几个额外的库依赖项,那么 Require 添加明确的、特定的value我在没有 Require 的情况下使用 Angular 会得到什么?” 我相信,答案是:不。如果你有一个巨大的应用程序有 40 个外部依赖,或者你无法控制你的 CI 环境,或者你的老板喜欢 Require,或者你喜欢 Require,或者 Angular 只是一个更大的应用程序的一部分,等等,那么天啊。
2021-03-16 10:37:19
但是因为他似乎没有问这些问题,而且因为他只是提到了 Backbone 应用程序的替代上下文,所以他似乎在问:“vanilla Angular 需要 Require 来有效地管理其组件吗?” 答案是:“除非你有其他事情要做。” 此外,这个问题出现在 Javascript CI 运动的风口浪尖上,其中我们有更好的方法来处理基本的物理“脚本加载”。如果你解决了这个问题,Require 基本上是关于依赖匹配和封装的。Angular 会为你做这两件事。
2021-03-24 10:37:19
NG-Boilerplate 种子项目 ( github.com/ngbp/ngbp ) 还创建了一个带有一个 js 文件的单页 web 应用程序。使用 HTML5 清单可确保每个版本仅加载此文件一次。
2021-03-28 10:37:19
谷歌在它的一些 AngularJS 项目中使用延迟加载,否则,用户将在第一页加载时下载 24mb 的文件(这是带有丑化和连接的文件)。所以是的,在复杂的应用程序中,当用户不会在每次访问时打开某些部分时,它不会只连接所有部分。
2021-04-04 10:37:19
不过,一如既往,<i>这取决于</i>。许多人将 Require 用于他们的整个架构,并且需要将 Angular 集成到该生态系统中。这与单独构建应用程序时的情况截然不同。
2021-04-06 10:37:19

是的,这是有道理的。

Angular module不会尝试解决脚本加载顺序或延迟脚本获取的问题。这些目标是正交的,两个module系统可以并存并实现它们的目标。

来源:Angular JS 官网

我在这里用我的语言不清楚:利用 Angular 自己的内置module加载器并遵循 Angular 模式的特点有显着的优势。问题不在于是否要避免Require,而在于添加额外的复杂层是否有value。很明显的是,Angular 的内置模式将轻松优雅地满足加载 Angular 自己的module的需求。如果 Require 用于在 Angular 上下文之外加载module,那么就这样吧。但是对 Angular 使用 Require 是无关紧要的。
2021-03-23 10:37:19
@XMLilley:你能提供一个链接来解释在使用 Angular 时避免 Require 的优点吗?我正在决定是否在我的项目中使用 Require ,这听起来很有帮助。
2021-03-29 10:37:19
@Tiago:请提供指向您从中获取此信息的位置的链接。我在任何地方都找不到。我猜它来自早期版本的 Angular 文档,在 Angular 的模式还没有得到完善之前,并且在避免 Require 有显着优势之前,至少对于 Angular 组件来说是显而易见的。
2021-03-30 10:37:19
如果每个 js 文件使用一个module,则可以按任何顺序加载 angular module。但是,如果您想将例如不同的服务放在不同的 js 文件中,但又想将它们附加到同一个 angular module上,则必须在服务声明之前加载module声明。所以这是一个架构决策。
2021-03-31 10:37:19
@XMLilley Angular 所做的就是为您提供依赖注入。module的实际加载是您的责任。您可以通过添加脚本标签、使用构建脚本或使用 requirejs 来完成此操作。Angulars module系统对此没有意见。
2021-04-09 10:37:19

我认为这是一个主观问题,因此我将提供我的主观意见。

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%。

事实上,在 Angular.js 中配置服务比使用 Require.js 加载module更好。这使得使用 $scope 和服务更容易,就像我使用 Socket.io 一样
2021-03-16 10:37:19

将 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”,这里是链接

感谢您进行这些编辑并解释 RequireJS 如何帮助管理依赖项以避免 Angular 尝试加载尚不存在的内容时出现问题。
2021-03-20 10:37:19
好了,谢谢 jmort253。
2021-03-21 10:37:19
我完全同意,最好将这种方法用于大型应用程序,否则您的应用程序中将有多个 <script> 标签。
2021-03-25 10:37:19
在包含链接时,最好在 Stack Overflow 上总结链接的内容。如果您的链接会中断,就像 Internet 上的链接一样,那么您在此处的回答对未来的访问者将毫无用处。考虑进行编辑以引入摘要并改进这篇文章。祝你好运!
2021-04-05 10:37:19