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

时间:2018-10-08 12:36:47

标签: javascript reactjs react-dom

反应开发版本的行为与生产版本不同,例如错误处理。

可以确定在环境中使用了哪一个,但仅在模块化环境due to how process.env.NODE_ENV is used by React package中使用

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解决了该问题。

7 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:3)

您的问题很明确,但是您没有阐明构建系统,您使用的是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';

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

注意:有关更多信息,请参见我的medium article。如果您不熟悉长篇小说,请参阅文章repository我的答案repository的示例的较新版本,其中包含配置。

答案 2 :(得分:1)

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

我不是要判断您的决定,所以这里有用。

react-dev-tools提供的

facebook插件检测构建类型。

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

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

希望您可以使它有用。

答案 3 :(得分:1)

可以执行一些“ hack”操作,以检查已加载哪个版本的React。

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

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

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

此方法与检查生产和开发无关,而与检查缩小有关,并且由于通常最小化生产构建,因此可以提供帮助。

答案 4 :(得分:0)

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>

source


要知道它是处于开发模式还是生产模式而没有环境变量,您必须通过分配其模式明确声明一些变量:(包括以下脚本以及react脚本)

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

并在必要时检查devMode。


或者,您可以检查其模式,例如:(必须在脚本标签中添加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而无需逐行检查。

答案 5 :(得分:0)

您的部署设置如何?没有“正确”的方式来做您想做的事。我将专注于生产/开发版本之间的差异,并创建自己的帮助程序功能。

编辑:似乎无法检测到React类中的prod / dev版本。

两个想法:

  1. 我不确定应用程序是如何构建的,但是PropTypes应该是很好的ENV标识符。
  2. 如果您的生产React应用程序已缩小,那么您只需检测一下React代码是否已缩小。(这很容易理解,但可以正常工作,请注意多个空格或行长,)。 ..)

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

答案 6 :(得分:0)

有些人已经在使用这样一个事实,那就是生产将始终被最小化而发展不会被最小化。这是使用此方法的具体解决方案:

<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。在here中,您可以看到该代码自首次编写以来就没有被触及过,除了一年前的一次小小的编辑(由于我的字符太少,因此不会影响此答案,因为它的字符太少了无论如何,在11mo之前进行了测试的版本,仍然存在很大差距。

注意

Dev是200个字符,Prod是70个字符,因此Dev:Prod字符比率为3:1。我之所以选择100,是因为添加90个字符的代码将在生产过程中增加30行,因此100个位置是给出信息的最佳位置(技术上是〜105左右)。对于这样一个简单的功能(该功能在5年中只有20个字符的编辑仅被触摸过一次),添加或删除100个字符是极不可能的,所以我认为这应该是稳定的。

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

编辑:

考虑缩小,这是一个正则表达式,可以推断出函数是否已经缩小,因此可以安全地使用它。如果React.Children.map不是一个函数(也几乎肯定不会发生),它也会崩溃,您可以根据是否要处理不太可能的错误事件的严格程度来捕获或不捕获(或者忽略它) ,因为他们为什么要更改它)。即使将函数签名缩小为[native code],函数签名也会保留,因此它是面向未来的imo。为了简单起见,我会选择第一个。

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