【问题标题】:Requiring React with RequireJS使用 RequireJS 要求 React
【发布时间】:2015-10-17 02:48:33
【问题描述】:

我正在使用 node、react 和 requirejs(并从 Typescript 生成符合 AMD 标准的 JS,但我认为这与手头的问题无关)。我只是想在我的应用中要求 React:

// config.js
require.config({
    baseUrl: '../scripts/lib/node_modules',
    paths: {
        lib: '..',
        react: 'react/lib', 
        app: '../../app',
        jquery: 'jquery/dist/jquery',
        scripts: '../..',
    },
});
require(['react/React'], function (react) {

});

然后我将使用 RequireJS 的 data-main api 加载此配置,导航到此页面:

<!DOCTYPE html>
<html>
    <head>
        <title>My Updated Test Project</title>
        <script data-main="../scripts/config.js" src="../scripts/lib/node_modules/requirejs/require.js"></script>
    </head>
    <body>
        <h1>My Test Project</h1>
    </body>
</html>

RequireJS 在尝试加载 React 时会报错:

Error: Module name "EventPluginUtils" has not been loaded yet for context: _. Use require([])

在 React.js 中,几乎第一行是“裸需求”

var EventPluginUtils = require("./EventPluginUtils");

如果我阅读 RequireJS 的有关此错误消息的信息,它会说修复是停止使用裸 require。

当有一个 require('name') 调用,但 'name' 模块尚未加载时会发生这种情况。 如果错误消息包括 Use require([]),那么它是一个顶级 require 调用(不是 define() 调用中的 require 调用)应该使用异步回调版本的 require 来加载代码

但我不认为将 React 源更改为使用 AMD 要求是 React 的作者的想法。还有其他选择吗?我是否需要将 React.js requires 的每个模块都列为 shim?这让我觉得有很多前期和维护工作。我是否缺少有关 RequireJS 的一些基本知识? (我是这个模块的新手)。

编辑:

React 被打包为 CommonJS 模块,所以看起来 RequireJS 应该能够加载它:http://requirejs.org/docs/api.html#packages

但简单地添加包含 React 的 package.json 文件的文件夹的位置似乎并没有让我到达那里。它正在尝试从 baseUrl 加载 react,就好像它没有识别出为该模块 id 配置了一个包。

【问题讨论】:

    标签: requirejs reactjs


    【解决方案1】:

    这个问题得到了很多人的关注,同时我已经显着改进了我使用 React 的方式,所以我将给出当前的设置。

    如果你想使用 RequireJS 中的 React,这很容易。不需要打包、自定义构建步骤或源代码修改。 NPM React 模块附带一个包含所有 React 的脚本,在 UMD format 中定义,它与 AMD 和 CommonJS 兼容。 node_modules/react/dist/react.js。 (或者选择另一种口味,例如node_modules/react/dist/react.min.js)。大多数 NPM 模块都附带一个 distbuild 文件夹,其中包含您可以要求的单个文件。这是对我提出的原始问题的正确答案。

    然而,尽管结合 RequireJS 和 React 很容易,但如果你使用 NPM 来管理你的前端 JS 依赖项,经过大量的工作和反思,我相信使用打包器是一个更好的选择适用于几乎所有网站。将依赖项打包到几个文件中要容易得多且通常性能更高(在生产中),这样您就不必为应用程序要使用的每个源文件执行 HTTP 请求。作为一个非常好的附带好处,您可以使用更易于理解的 CommonJS 语言(参见上面的链接)而不是 AMD 规范来编写导入语句。 CommonJS 更容易读写,在每个文件的顶部需要更少的样板代码。

    AMD 旨在通过解决延迟加载问题来提高性能 - 您不必一次请求、解析、编译和执行网站的所有代码。相反,当用户导航到需要它们的页面时,会下载并解析新脚本。从理论上讲,这可以让您更快地加载初始页面,这是一个非常重要的指标。然而,实际上,这不成立的原因有两个。首先,每个 HTTP 请求都会引入开销和延迟,最好有几个大的 HTTP 请求而不是很多小的 HTTP 请求。即使您的网站变得足够大,以至于您真的想将代码分解为多个脚本文件,您仍然不希望源代码中的每个代码文件都有一个脚本文件。相反,您需要将代码打包成几个包,并且这两个打包实用程序都有一些复杂的选项可以将您的代码分解成包。其次,实际上,每个页面都需要应用程序中的大量代码,因为它是框架代码。在您的网站变得非常非常大之前,您在 AMD 系统中避免的特定页面代码的数量相对较少。是的,我知道,RequireJS has a way 需要合并文件以提高性能。但你必须选择加入,而不是退出。

    我可以看到包装有两个缺点。一个是构建时间更长,因为打包代码必须递归地遍历整个代码库并解析每个 require 语句的代码,构建一个依赖关系图,然后它必须将所有文件写成一个盒。 Webpack 有多种选项可以在开发过程中缩短构建时间(所谓的“增量构建”)。

    包装的第二个问题有点棘手。您浏览器中的源将是一个大的打包文件。

    构建时间和大型调试包都可以通过仔细配置来解决。对于打包时间问题,您至少需要将大型供应商依赖项排除在重建之外。这不仅提高了构建时间和可读性,而且提高了缓存,因为浏览器的缓存模型是基于文件的,将低波动性和高波动性代码分离到单独的文件中是很好的。在 Webpack 中,您可以通过在 Webpack 配置中将供应商库声明为外部组件来将供应商库排除在构建之外,或者您可以使用 DLL plugin 这会产生类似的结果,但会将各个供应商库打包到一个供应商包中。

    Browserify 与 webpack?在这一点上我已经广泛使用,我推荐 webpack。我发现它更容易配置(这可能是因为文档更适合我的需要)并且它具有我想要的所有功能,以及更多功能,例如常见的块提取。

    最后,如果您使用 typescript,您需要告诉它要发出哪种模块:CommonJS、AMD 或其他。您可以通过设置tsconfig.json.compilerOptions.module 来做到这一点。有效值包括“amd”、“commonjs”、“umd”等。使用 webpack 时,您希望发出“commonjs”。 (但是,webpack 可以为您编译 typescript 作为其过程的一部分,因此您可能需要集成该步骤。)

    注意 RequireJS、browserify 和 webpack 之间的争论。就目前而言,这三个都可以配置为为几乎所有用例产生基本相同的输出。我不认为它总是这样,但现在是这样。区分它们的唯一方法是沿着非功能维度,例如性能、采用和易用性。对我来说,webpack 是最容易设置的,这是决定性的优势。我没有费心进行性能测试。

    【讨论】:

      【解决方案2】:

      尝试使用 Browserify (npm install browserify) 而不是 requirejs。我遇到了这个确切的问题,但由于某种原因,requirejs 无法正常工作。

      如果您知道,这里有一个关于 Browserify 的快速视频。它帮助了我,我希望它也对你有用:http://youtube.com/watch?v=78_iyqT-qT8

      【讨论】:

      • 你是对的,browserify 原来是答案。 (webpack 是做同样事情的替代品)。
      猜你喜欢
      • 2013-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 2013-04-25
      • 2014-01-01
      • 2011-12-15
      相关资源
      最近更新 更多