检测 React/ReactDOM development/production 构建

Detect React/ReactDOM development/production build

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

可以从环境中判断出使用哪一个,但仅限于模块化环境,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>

可能的用途是:

如何在不借助环境的情况下,在运行时准确检测 React development/production 构建?

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

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

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


并且要知道它是处于开发模式还是生产模式没有环境变量,你必须通过分配显式声明一些变量它的模式:(包括以下脚本和反应脚本)

<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 而无需逐行检查。

使用 umd 构建在客户端检测 dev/production 构建似乎是一个漫长的过程。 如果存在这样的要求,为什么不使用 create-react-app 构建您的应用程序?

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

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

这里是上述插件的相关部分:

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

希望你能使它有用。

有一点 'hack' 可以检查已加载的 React 版本。

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

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

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

这种方法不是检查生产和开发,而是检查缩小,而且由于生产构建通常是缩小的,所以它真的很有帮助。

您的部署设置如何?没有 "correct" 方法可以做您想做的事。我会关注 production/development 构建和创建我自己的辅助函数之间的差异。

编辑: 看起来无法从 React class.

中检测到 prod/dev 版本

两个想法:

  1. 我不确定应用程序是如何构建的,但 PropTypes 应该是一个很好的 ENV 标识符。
  2. 如果您的生产 React 应用程序被缩小,那么您可以简单地检测 React 代码是否被缩小。(这将是 hacky 但它应该工作,关注一些空格或线长,... )

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

你的问题很明确,但是你没有说明你的构建系统,你用的是webpack还是parcel?你有没有Server Side Rendering?您 运行 是 node 还是 pm2 构建的应用程序?或者你只是构建你的应用程序,然后将构建的捆绑文件放入你的页面中,该文件是由 PHPC#?

等其他技术制作的

其实上面的问题就可以决定你的答案了,但是你肯定使用了module bundler,所以我建议在你的项目中使用解析一个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, And if you are not familiar with long reads see the article repository Also the newer version of the example of my answer repository,其中包含配置。

有些人谈到了使用生产总是会被缩小而开发不会被缩小的事实。这是一个使用它的具体解决方案:

<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 你可以看到这段代码自第一次编写以来没有被修改过,除了一年前的一次小修改(这不会影响这个答案,因为它的字符太少了,虽然我已经无论如何,在 11 个月前测试过版本并且存在相当大的差距)。

备注

Dev 为 200 个字符,Prod 为 70 个字符,因此 3:1 字符比率为 Dev:Prod 字符比率。我选择了 100,因为添加 90 个字符的代码会给产品添加 30 行,所以 100 是给定信息的最佳位置(技术上~105 左右)。这么简单的功能(5年才接触过一次20个字符编辑的功能),添加90个字符或删除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])
};

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

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

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