检测 React/ReactDOM 开发/生产构建



React 开发构建的行为与生产构建不同,例如错误处理。

可以从环境中找出使用哪一个,但只能在模块化环境中使用,因为 React 包如何使用process.env.NODE_ENV

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}

process.env可能不适用的情况是 React 全局用作 UMD 模块、window.Reactwindow.ReactDOM

<script src="some-unknown-react-version.js"></script>
<script>
React // is it in production mode?
</script>

可能的用途是:

  • 可以在模块化和全局环境中工作的组件(发布为 UMD),并在生产中以不同的方式呈现

  • ReactReactDOM对象中检测到生成/生产模式的浏览器扩展或用户脚本

如何在运行时准确检测 React 开发/生产构建,而无需求助于环境?

如果可能的话,我正在寻找适用于 React 15 和 React 16 的可靠且干净的解决方案。

这不是类似问题的重复,因为现有的答案通过process.env解决问题。

有区别。在开发模式下,React 元素_self定义了属性,而在生产模式下,该属性没有定义。

因此,解决方案是使用如下代码测试此属性:

function ReactIsInDevelomentMode(){ 
return '_self' in React.createElement('div');
}

使用 umd 构建在客户端检测开发/生产构建似乎很漫长。 如果存在这样的要求,为什么不使用create-react-app构建您的应用程序?

我不会评判你的决定,所以这里有一些有用的东西。

facebook提供的react-dev-tools插件检测构建类型。

以下是上述插件的相关部分:

https://github.com/facebook/react-devtools/blob/faa4b630a8c055d5ab4ff51536f1e92604d5c09c/backend/installGlobalHook.js#L23

希望你能让它有用。

你的问题很清楚,但你没有澄清你的构建系统,你使用webpack还是parcel? 你有没有Server Side Rendering? 您是通过node还是pm2运行构建的应用程序? 或者您只是构建应用程序,然后将构建的捆绑文件放入由其他技术(如PHPC#)制作的页面中?

实际上,上述问题可以决定您的答案,但可以肯定的是,您使用模块捆绑器,因此我建议使用解析项目中的config文件。

如果我是你的地方,毫无疑问,我使用webpack,两个 webpack 配置文件,一个用于开发,一个用于生产模式。 然后我创建一个文件夹,其中包含两个带有config.dev.jsconfig.prod.js的文件。在开发 webpack 中:

~~~
module.exports = {
~~~
resolve: {
extensions: ['.js', '.jsx'],
alias: {
~~~
Config: `${srcDir}/config/config.dev.js`,
// srcDir is a defined variable for source directory
}
},
~~~

在生产 webpack 中:

~~~
module.exports = {
~~~
resolve: {
extensions: ['.js', '.jsx'],
alias: {
~~~
Config: `${srcDir}/config/config.prod.js`,
// srcDir is a defined variable for source directory
}
},
~~~

现在,您可以放置构建类型的每个devprod数据。 例如,在您的config.dev.js可以写入:

module.exports = {
buildType: "dev"
};

当然,在你的config.prod.js可以写:

module.exports = {
buildType: "prod"
};

绝对,您可以使用react文件中的以下代码访问配置数据:

import config from 'Config';

使用此解决方案,您可以在应用程序的实时执行中了解构建的类型。

注意:有关更多信息,您可以查看我的中等文章,如果您不熟悉长阅读,请参阅文章存储库还有包含配置的我的答案存储库示例的较新版本。

有一个小的"黑客"可以用来检查哪个版本的 React 已经加载了。

React对象在全局变量中可用,React 的生产版本与开发版本至少有一个不同:它通常是缩小的。因此,我们可以尝试检查我们是否正在使用缩小版本。

要检查,您可以将函数名称与某些 React 对象方法的属性名称进行比较,例如:

let func = 'Component'
if (React[func].name === func) {
// non-minified -> development build
}

这种方法不是关于检查生产和开发,而是关于检查缩小,并且由于生产构建通常是缩小的,它确实可以提供帮助。

React 提供了 react 的开发和生产版本.js链接:

发展:

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

生产:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>


要知道它是处于开发模式还是没有环境变量的生产模式,您必须通过分配其模式来显式声明某个变量:(包括以下脚本以及反应脚本)

<script>
var devMode = 'development';
</script>

并在必要时检查开发模式。


或者,您可以检查其模式,例如:(您必须在脚本标签中添加 id)

var script_id = document.getElementById('script-attached-id');
console.log(script_id.getAttribute('src').includes('development'));

这样,您只需要更新源路径并检测模式。


最后一个选项,我可以考虑读取文件本身并检测其模式,因为 react 在其评论中提到过:

发展:

/** @license React v16.5.2
* react.development.js

生产:

/** @license React v16.5.2
* react.production.min.js

因此,在阅读文件后,只需在第二行中检查其模式即可。或者,您可以在不逐行检查的情况下测试react.development.js

您的部署设置是什么样的?没有"正确"的方式来做你想做的事情。我将专注于生产/开发构建之间的差异,并创建自己的帮助程序函数。

编辑:看起来不可能从React类中检测到生产/开发版本。

两个想法:

  1. 我不确定应用程序是如何构建的,但PropTypes应该是一个很好的 ENV 标识符。
  2. 如果你的生产 React 应用程序被缩小了,那么你可以简单地检测反应代码是否被缩小了(这将是黑客,但它应该有效,专注于一些空格或行长,...

我在下面的评论中注意到,你说minified !== production如果你能做到这一点,那么这可能是你最好的选择。无论如何,您都不需要缩小开发反应代码。

有些人谈到了生产将始终被缩小而开发不会缩小的事实。下面是使用它的具体解决方案:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.js"></script>
<script>
const reactInfo = {
version: React.version,
development: (String((new React.Children.map()).constructor).length > 100)
};
console.log(reactInfo);
</script>
<div id="content"></div>

我已经在从 v14 到 v16 的大约十几个版本的 react 上对此进行了测试。从这里你可以看到这段代码自第一次编写以来就没有被触及过,除了一年前的一个小编辑(这不会影响这个答案,因为它的字符太少了,尽管我已经测试了 11 个月之前的版本无论如何,有一个相当大的差距)。

注意

Dev 是 200 个字符,Prod是 70 个字符,因此 Dev:Prod 字符比率为 3:1。我选择了 100,因为添加 90 个字符的代码将向 prod 添加 30 行,因此 100 是给定信息的最佳位置(技术上 ~105 或其他)。对于这样一个简单的函数(一个 5 年只用 20 个字符编辑接触过一次的函数),添加 90 个字符或删除 100 个字符是极不可能的,所以我认为这应该是稳定的。

为了提高稳定性,或者至少知道它是否损坏,您可以检查它是否在 70 和 200 的 25 个字符以内,如果不是,则抛出错误。这应该捕获任何重大更改(我会给该选项近 100% 确定它永远不会隐藏错误),但您可能会收到误报。您想要哪一个取决于您的用例。

编辑:

研究缩小,这是一个正则表达式,可以推断出一个函数是否已被缩小,因此您可以安全地使用这个函数。如果React.Children.map不是一个函数,它也会崩溃(几乎肯定永远不会发生),你可以捕获或不捕获,这取决于你想要处理不太可能的错误事件的严格程度(或者只是忽略它,因为就像,他们为什么要改变它)。即使它被缩小为[native code],函数签名仍然存在,因此它是相当面向未来的 imo。不过,为了简单起见,我会选择第一个。

const reactInfo = {
version: React.version,
development: !/functions?w?(w(,w)*)/.test(String((new React.Children.map()).constructor).split("{")[0])
};

最新更新