22

React development build behaves differently than production build, e.g. error handling.

It can be figured out which one is used from the environment but only in modular environment, 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');
}

The case when process.env may be inapplicable is React used globally as UMD module, window.React and window.ReactDOM:

<script src="some-unknown-react-version.js"></script>

<script>
React // is it in production mode?
</script>

Possible uses are:

  • a component that can work in modular and global environments (published as UMD) and renders differently in production

  • browser extension or user script where build/production mode is detected from React or ReactDOM object

How can React development/production build be accurately detected at runtime without resorting to the environment?

I'm looking for reliable and clean solution that would be applicable to React 15 and React 16 if possible.

This is not a duplicate of similar questions because existing answers address the problem through process.env.

1
  • How does your deployment setup look like? There is no "correct" way to do what you want to do. I would focus on differences between production/development build and create my own helper function. Look at my answer about prop-types. Commented Oct 16, 2018 at 17:57

7 Answers 7

34
+200

There is difference. In the development mode, React elements have the property _self defined, whereas in production mode that property is not defined.

So, a solution is to test for this property with a code like this:

function ReactIsInDevelomentMode(){ 
    return '_self' in React.createElement('div');
}
Sign up to request clarification or add additional context in comments.

2 Comments

can you please provide a URL to the React's documentation that corroborates what you are stating?
@lmiguelvargasf This behavior is not documented be the React's creators. It's something that I have observed.
2

Detecting dev/production build at client using a umd build seems like a long stretch. If such a requirement exists why not build your app with create-react-app ?

I am not to judge your decisions, so here is something useful.

react-dev-tools plugin provided by facebook detects the build type.

Here is the relevant part of the above mentioned plugin:

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

Hope you could make it useful.

5 Comments

Thanks! I didn't take a look at DevTools because I didn't expect they do something like that; they were just hanging in case of production build without useful message. Please, consider posting relevant code from the link to the answer, so it could be understandable without visiting offsite resources. Yes, the solution seems too hacky to use it in regular components.
ReactDOM code contains a hook for React Dev Tools, so this hack is not available. The best solution is to add proper bundle types into React/ReactDOM itself.
The main target of the question was understanding build type, using a google chrome plugin how can help the developer to collect data?
I'm talking about the solution in this answer: React Dev Tool contains the function which detects React build type, but it works because ReactDOM lib contains a hook for React Dev Tool and it runs on ReactDOM init. So, if ReactDOM lib can contain a hook for React Dev Tool, then it can contain build type, and the best solution is to create the pull request with proper functionality
@DolfBarr I agree that having this functionality in ReactDOM itself could be useful. Yet it's possible to use same method to hook into REACT_DEVTOOLS_GLOBAL_HOOK in regular script, regardless of React Dev Tool. I wouldn't use it in regular component but may be useful for other purposes (browser extension or user script).
2

Your question is clear but you do not clarify your build system, do you use webpack or parcel? do you have Server Side Rendering or not? do you run your built application by node or pm2? or you just build your application and then put the built bundled file inside your page that made by other technology like PHP or C#?

Actually, the above questions can determine your answer, but surely, you use module bundler, so I proffer use resolving a config file in your project.

If I was your place, undoubtedly, I use webpack, two webpack configuration files, one for development and one for production mode. then I create a folder that contains two files with config.dev.js and config.prod.js. In the development webpack:

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

In the production webpack:

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

And now you can put each dev and prod data for your build types. for example in your config.dev.js can write:

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

Surely, in your config.prod.js can write:

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

Absolutely you can access to the config data with below code inside your react files:

import config from 'Config';

And with this solution, you can understand the type of your build in the real-time execution of your application.

Note: For more information, you can see my 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 that contains configs.

3 Comments

As I explained in comments, my own build setup doesn't matter. See 'Possible uses' in the question. E.g. component is built to UMD and can used by a third party. I'm not responsible for building the entire application, just a piece of it that needs to check whether it's development or production environment.
Ok, I assumed this situation that you pointed in your comment under my answer, in any way, you should bundle your component, so you can use my way.
I'm not sure how I can use that. I need to detect the environment where bundled component is used, not my own environment. I'll try to explain. The decision cannot be made at the time when I build the component. If I bundle the component as UMD with 'production' setting, and a developer then uses it in development environment, this is considered development environment, and this is what I'm trying to detect from React object.
1

There'is a little 'hack' which can be done for checking which version of React has been loaded.

React object is available in global variables, and the production build of the React differs from the development version by at least one thing: it's usually minified. So we can try to check if we are working with minified version or not.

To check you can compare function name with the property name of some React object's method, e.g.:

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

This method is not about checking production and development but about check the minification, and since production build is usually minified it can really help.

1 Comment

Sadly, this will result in false negatives because minified !== production. As for me, I tend to use minified code in development. I'd use this only as a fallback for process.env.NODE_ENV check.
1

Some have touched on using the fact that production will always be minified and development won't be minified. Here's a concrete solution that uses this:

<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>

I've tested this on about a dozen versions of react from v14 to v16. From here you can see that this code hasn't been touched since it was first written, except for one small edit from a year ago (Which wouldn't effect this answer because it's too few characters, though I've tested versions before 11mo ago anyway and there's a decent gap).

Note

Dev is 200 characters and Prod is 70, so there's a 3:1 ratio for a Dev:Prod character ratio. I picked 100 because adding 90 characters of code will add 30 lines to prod, so 100 is the best location with the information given (Technically ~105 or something). Adding 90 characters or removing 100 characters is extremely unlikely for such a simple function (a function that has been touched only once in 5 years with a 20 character edit), so I think this should be stable.

For more stability, or at least knowledge if it breaks, you can check if it's within 25 characters of 70 and 200, and throw an error if it's not. That should catch any big changes (I'd give that option near 100% certainty that it'll never hide a bug), but you might get false positives. Which one you want depends on your use case.

EDIT:

Looking into minification, this is a regex that'll deduce if a function has been minified, so you can use this one safely. It'll also crash if React.Children.map is not a function (Will almost certainly never happen), which you can either catch or not catch depending on how strict you want to handle the unlikely event of an error (Or just ignore it, becuase like, why would they ever change it). The function signature remains, even if it gets minified into [native code], so it's rather future-proof imo. I'd go with the first one for simplicity though.

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

1 Comment

Thanks. Very hacky and fragile but may do the trick if tested thoroughly with future versions.
0

React provides both development and production version of react.js links:

Development:

<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>

Production:

<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


And to know if it is in development mode or production mode without environment variable, you have to explicitly declare some variable by assigning its mode: (include the following script along with react script)

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

and check for the devMode whenever necessary.


Alternatively, you may check for its mode like: (you have to add id in the script tag)

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

This way, you only need to update the source path and detect the mode.


And the final option, I can think of reading the file itself and detect its mode since react has mentioned in its comment like:

Development:

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

Production:

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

So, after reading the file, just check for it's mode in second line. Or you may test for react.development.js without line by line check.

4 Comments

This is true. That's why I specified additional conditions in the question. some-react-version.js - it's impossible to figure out which build (development, production) it is from URL. component that renders differently in production, regardless of modular or global environment - a component shouldn't be aware of specific <script> tag.
To make myself clear, I'm asking from developer's perspective, given I have no devMode variable to check and have access to React and ReactDOM objects, not anything else. It could be browser extension I write. Or React library where I need to detect React production mode but don't want to restrict the library to be used in modular environments with process.env. The question is how to detect a build without using process.env.
There's no way. You must explicitly set some variable.
I hope there's a way to detect this, because production and development builds differ in some way. This possibly requires a good knowledge of React source code which I currently don't have.
0

How does your deployment setup look like? There is no "correct" way to do what you want to do. I would focus on differences between production/development build and create my own helper function.

EDIT: It looks like it is not possible to detect prod/dev version from React class.

Two ideas:

  1. I am not sure how is the application built but PropTypes should be a good ENV identifier.
  2. If your production React application is minified then you can simply detect if the react code is minified. (this will be hacky but it should work, focus on a number of spaces or line length, ... )

I noticed in the comments below that you say that minified !== production if you can make it this way then this is probably your best bet. You don't need to minify development react code anyway.

5 Comments

I appreciate the suggestion. My deployment setup doesn't matter at this point because the question primarily applies to my code that will work together with somebody else's application. See 'possible uses'.
@estus I just updated my answer. I kind of hoped that there will be some React.method is that going to be missing in production build but it looks like this is not the case. I would focus on detecting if the react code is minified or not.
In 'possible uses' the minification of my own code doesn't matter. For browser extension, minification doesn't affect anything. For component library, it's the setup of a developer who uses my library that matters, not mine. Another answer already suggested minification thing, I commented on that. It's possible to use that but not reliably and this only makes sense in non-modular environment where React is global. Yes, I looked for such React.method but there's no consistent way. React devtools code linked in another answer shows that it's possible but hacky.
@estus Not to pick up a fight here but not using env variables is a hack. :D
As I said, a component can be used in global environment without process.env, because in basic setups devs may skip build step. I wanted to figure out my options before hard-coding it to process.env. Seems like exposing productionMode prop would be a suitable workaround for such cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.