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.React
和window.ReactDOM
:
<script src="some-unknown-react-version.js"></script>
<script>
React // is it in production mode?
</script>
可能的用途是:
可以在模块化和全局环境中工作的组件(发布为 UMD),并在生产中以不同的方式呈现
从
React
或ReactDOM
对象中检测到生成/生产模式的浏览器扩展或用户脚本
如何在运行时准确检测 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
运行构建的应用程序? 或者您只是构建应用程序,然后将构建的捆绑文件放入由其他技术(如PHP
或C#
)制作的页面中?
实际上,上述问题可以决定您的答案,但可以肯定的是,您使用模块捆绑器,因此我建议使用解析项目中的config
文件。
如果我是你的地方,毫无疑问,我使用webpack
,两个 webpack 配置文件,一个用于开发,一个用于生产模式。 然后我创建一个文件夹,其中包含两个带有config.dev.js
和config.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
}
},
~~~
现在,您可以放置构建类型的每个dev
和prod
数据。 例如,在您的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
类中检测到生产/开发版本。
两个想法:
- 我不确定应用程序是如何构建的,但
PropTypes
应该是一个很好的 ENV 标识符。 - 如果你的生产 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])
};