【问题标题】:RequireJS: To Bundle or Not to BundleRequireJS:捆绑还是不捆绑
【发布时间】:2013-12-29 05:19:31
【问题描述】:

我正在为我的 Web 应用程序使用 RequireJS。我将 EmberJS 用于应用程序框架。我已经到了一个地步,我认为我应该开始将我的应用程序捆绑到一个 js 文件中。这就是我有点困惑的地方:

如果我最终将所有内容捆绑到一个文件中进行部署,那么我的整个应用程序会一次性加载,而不是按需加载。一般来说,捆绑与 AMD 尤其是 RequireJS 不矛盾吗?

让我更加困惑的是我在RequireJS 网站上发现的内容:

完成开发并希望为最终用户部署代码后,您可以使用优化器将 JavaScript 文件组合在一起并缩小它。在上面的例子中,它可以将 main.js 和 helper/util.js 合并到一个文件中并缩小结果。

我找到了这个similar thread,但它没有回答我的问题。

【问题讨论】:

    标签: requirejs


    【解决方案1】:

    在开发过程中,您希望拥有单一焦点的小文件。这导致他们的数量增加。在生产环境中运行时,许多 HTTP 请求确实会损害性能。再说一次,您不想预先加载整个应用程序 - 这也不是最佳选择。

    为了解决这个问题,我在 GitHub 上创建了一个小项目,require-lazy,你可以将它称为 builder 的插件 - r.js。它可以使用简单的语法延迟加载应用程序的某些部分,然后在构建过程中创建单独的可加载包;因此,如果您的应用程序包含 2 个需要独立加载的视图,则 require-lazy 将(理想情况下)构建 3 个 js 文件:(1)引导代码和公共库,(2)视图 1 及其所有私有脚本和(3 ) 查看 2 及其所有私有脚本。

    懒加载简单定义为:

    define(["lazy!view1"], function(view1) { .... });
    

    并且view1 必须通过承诺访问:

    view1.get().done(function(realView1) {
        ...
    });
    

    项目通过 npm 可用,构建过程通过 grunt 并且有一个 bower 组件。

    欢迎评论。

    【讨论】:

    • 听起来很有趣。有时间会试一试的。现在我将使用@Louis 的回答,因为它回答了我的问题。
    • 当然,RequireJS 在 2014 年初添加了捆绑功能
    【解决方案2】:

    如果我最终将所有内容捆绑到一个文件中进行部署,那么我的整个应用程序会一次性加载,而不是按需加载。一般来说,捆绑与 AMD 尤其是 RequireJS 不矛盾吗?

    这并不矛盾。按需加载模块只是 RequireJS 的一个好处。在我的书中,一个更大的好处是模块化有助于使用分而治之的方法。我们可以这样看:即使我们放在单个文件中的所有函数和类都不能从按需加载中受益,但我们仍然编写多个函数和多个类,因为它有助于以结构化的方式分解问题。

    但是,我们在开发过程中创建的模块的多样性在浏览器中运行应用程序时并不一定有意义。按需加载的最大成本是通过网络发送多个 HTTP 请求。假设您的应用程序有 10 个模块,并且您发送 10 个请求来加载它,因为您分别加载这些模块。您的总成本将是您从 10 个文件中加载字节所必须支付的成本(我们将其称为 Pc 作为有效负载成本),加上每个 HTTP 请求的开销成本(我们称之为Oc,用于间接费用)。开销与启动和关闭这些请求所必须发生的数据和计算有关。它们并非微不足道。所以你支付 Pc + 10*Oc。如果您将所有内容分成一个块发送,则您需要支付 Pc + 1*Oc。您已保存 9*Oc。事实上,节省的成本可能更大,因为(因为通常在两端都使用压缩来减少传输数据的大小)如果将整个数据压缩在一起,比将其压缩为 10 个块,压缩将提供更大的好处。 (注:以上分析省略了无用的细节。)

    有人可能会反对:“但是您正在比较单独加载 所有 模块与加载 所有 模块在一个块中。如果我们按需加载,那么我们将不会” t 加载 所有 模块。”事实上,大多数应用程序都有一个核心模块,无论如何都会被加载。没有这些模块,应用程序将无法运行。对于一些小型应用程序,这意味着所有模块,因此将所有模块捆绑在一起是有意义的。对于更大的应用程序,这意味着每次应用程序运行时都会使用一组核心模块,但偶尔会使用一小部分模块。在后一种情况下,优化应该创建多个捆绑包。我有一个像这样的application。它是一个具有多种编辑需求模式的编辑器。 90% 的模块都属于核心。它们将被加载和使用无论如何,因此捆绑它们是有意义的。模式本身的代码并不总是会被使用,但如果模式完全加载,则将需要给定模式的所有文件,因此每个模式都应该是它自己的包。因此,在这种情况下,具有一个核心包和一系列模式包的模型对于 a) 优化部署的应用程序但 b) 保留按需加载的一些好处是有意义的。这就是 RequireJS 的美妙之处:它不需要只做其中一个。

    【讨论】:

    • 感谢您的详细回答。这很有意义。
    • @Johnathon 我已经在this answer 中介绍了一些关于如何做到这一点的细节。
    • @wired_in “因此模块加载速度比单独文件中的要快。”不,他们没有。在系统中的多个点,通信管道是单通道。您可以通过让多个传输依次共享线路来获得并行性。这就像拥有一个单核系统并通过时间切片并行执行六个 CPU 密集型任务,而不是按顺序执行它们。这六项任务如果按顺序执行会更早完成。
    • @wired_in 你完全误解了。
    • 浏览器上的所有调用与所有进程共享相同的传输管道。可用带宽只有这么多,所以如果每个单独的请求产生xbytes 开销,则管道上的总负载会随着每次连续调用而增加。您不会通过增加队列数量神奇地获得更多带宽。 npmjs.org/package/cjs-vs-amd-benchmark
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    • 2017-08-04
    • 2015-08-15
    • 1970-01-01
    相关资源
    最近更新 更多