Create-react-app: Webpack Hot Dev Client Breaks on older browsers

Created on 7 Oct 2018  路  38Comments  路  Source: facebook/create-react-app

Is this a bug report?

yes

Did you try recovering your dependencies?

no

Which terms did you search for in User Guide?

hot dev

Environment

System:
OS: macOS High Sierra 10.13.6
CPU: x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
Binaries:
Node: 8.12.0 - /usr/local/opt/node@8/bin/node
Yarn: 1.10.1 - /usr/local/bin/yarn
npm: 6.4.1 - /usr/local/opt/node@8/bin/npm
Browsers:
Chrome: 69.0.3497.100
Safari: 12.0
npmPackages:
react: ^16.5.2 => 16.5.2
react-dom: ^16.5.2 => 16.5.2
react-scripts: 2.0.4 => 2.0.4
npmGlobalPackages:
create-react-app: 2.0.0-next.2150693d

Steps to Reproduce

(Write your steps here:)

  1. npx create-react-app my-app
  2. cd my-app
  3. yarn start
  4. Navigate to app url in old browser that does not have map. E.g. Android 4.4 default browser or ie9 (I used Android 4.4)

Expected Behavior

Default Screen Loads

Actual Behavior

Blank Screen, connecting the debugger reveals the console error Map is not defined

This is caused by a Map call from ansi-styles which is required by chalk.

screen shot 2018-10-07 at 02 00 09

To get past this I added require('react-app-polyfill/ie9'); to the top of webpackHotDevClient (Delete the babel loader cache if you do this). This gets further but then failes on setPrototypeOf. Using the catch all require('core-js'); allows the app to work as expected.

screen shot 2018-10-07 at 02 02 21

Note: the yarn build version always works because the hot dev client is not present

I am not sure if this is something CRA actually wants to support, I think some documentation that the dev mode yarn start may not work with older browsers will be enough.

bug

Most helpful comment

I found the dependencies cause the bug

create-react-app -> react-scripts/config/webpack.config.js -> react-dev-utils/webpackHotDevClient.js -> react-dev-utils/formatWebpackMessages.js ->chalk -> ansi-styles -> Map

and I think we need setupPolyfill ( just like setupProxy)锛宨t should be insert before webpackHotDevClient:

entry: [
  paths.setupPolyfill,
  isEnvDevelopment &&
  require.resolve('react-dev-utils/webpackHotDevClient'),
  // Finally, this is your app's code:
  paths.appIndexJs,
]

All 38 comments

CRA doesn't support old browsers anymore by default. https://reactjs.org/blog/2018/10/01/create-react-app-v2.html#breaking-changes

But I still expected it to work after adding the opt in polyfills

Try to use the latest of CRA. I see that you using a next branch, not sure if it's up to date or not...

@cliedeman do you have import 'react-app-polyfill/ie9'; as the very first line of src/index.js?

I found the dependencies cause the bug

create-react-app -> react-scripts/config/webpack.config.js -> react-dev-utils/webpackHotDevClient.js -> react-dev-utils/formatWebpackMessages.js ->chalk -> ansi-styles -> Map

and I think we need setupPolyfill ( just like setupProxy)锛宨t should be insert before webpackHotDevClient:

entry: [
  paths.setupPolyfill,
  isEnvDevelopment &&
  require.resolve('react-dev-utils/webpackHotDevClient'),
  // Finally, this is your app's code:
  paths.appIndexJs,
]

Having the same issue trying to debug my app on IOS 7 safari.
Is there a workaround for this?

@Nickman87

My temp solution, put this in public/index.html

<% if (process.env.NODE_ENV === 'development') { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.5/es6-sham.min.js"></script>
<% } %>

https://gist.github.com/lomocc/a73ec03d7d01a319098ee90165f74c24

Thanks to @lomocc comment, I sorted it out that way: I added a paths.setupPolyfill in ./config/webpack.config.js like he said:

entry: [
  paths.setupPolyfill,
  isEnvDevelopment &&
  require.resolve('react-dev-utils/webpackHotDevClient'),
  // Finally, this is your app's code:
  paths.appIndexJs,
]

and then in the ./config/paths.js I added and export:

module.exports = {
  //  ... all the exports
  appNodeModules: resolveApp('node_modules'),
  setupPolyfill: resolveApp('node_modules/react-app-polyfill/ie9'), // added
};

I also needed the es6-sham.min.js script to make it work, so in my index.html I added these lines:

<% if (process.env.NODE_ENV === 'development') { %>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.5/es6-sham.min.js"></script>
<% } %>

Solution in my case

Thanks to @lomocc and @arnaudambro for their work on this.

If you want to get the dev build working without altering react-scripts/config.webpack.js and react-scripts/config/paths.js, adding this before my closing </body> tag in index.html worked for me (when trying to support Opera 12.16):

<% if (process.env.NODE_ENV === 'development') { %>
  <script src="https://polyfill.io/v3/polyfill.min.js?features=Map%2CSet%2CObject.setPrototypeOf"></script>
<% } %>

Note that I'm not using es6-sham here. I'm (potentially redundantly) providing polyfills.

Details

How I determined which features were missing

I was specifically trying to enable an app to run in Opera 12.16, which I initially found lacked Map support. So I started by providing a polyfill for that using polyfill.io's URL builder. But then I found it still lacked Set. So one-by-one, I polyfilled each lacking feature that the browser was failing on, and concluded that for Opera 12.16, I needed to polyfill Map, Set, and Object.setPrototypeOf to support the DevTools.

Polyfill redundancy in dev mode

If you're polyfilling anything from react-app-polyfill in index.js, you may now be polyfilling some of the same features again redundantly (purely to provide them in time for the DevTools to use them). In the production build though, neither DevTools nor my above polyfill will be included, so it's a moot point.

IE 10 Compatibility

.NET Core / React / Redux

I just spent a few hours making my .NET Core / React app compatible with IE 10. Here is my solution until this is fixed in create-react-app. The above comments did not discuss MutationObserver, which is what caused me issues after ejecting and changing the order of dependencies.

  1. Eject create-react-app: npm run eject

    • Before doing this you should read about ejecting, you can't turn back once you do.

  2. Change order of appIndexJs and webpackHotDevClient in config/webpack.config.js
  3. Add core-js & mutation-observer: npm install core-js mutation-observer
  4. Modify package.json with browserslist (ie > 9 is what is important here)
"browserslist": [
    "ie > 9",
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
  ],
  1. Modify index.js

    • important: make sure that these go at the very top of index.js

    • Add polyfills, core-js, and mutation-observer

import 'core-js/es';
import 'react-app-polyfill/ie9';
import 'mutation-observer';

Eject create-react-app

@seanbecker15 Just to mention that you can avoid ejecting by using customize-cra or rescripts (they're both about equally as good) and re-ordering the webpack config as you require.

Eject create-react-app

@seanbecker15 Just to mention that you can avoid ejecting by using customize-cra or rescripts (they're both about equally as good) and re-ordering the webpack config as you require.

Do you mind adding how?

You do NOT have to eject from CRA.

Example: https://github.com/ThekhoN/create-react-app-ie11

Steps:

  1. Install react-app-polyfill

    npm i react-app-polyfill

  2. Import react-app-polyfill/ie11 at the TOP of index.js

    import 'react-app-polyfill/ie11'

3. Delete .cache in /node_modules

4. Add ie11 meta tag in index.html (in public folder)

<meta http-equiv="X-UA-Compatible" content="IE=11">

@ThekhoN Your solution doesnt work for me. Clone your repo. it gives me following error with blank page on IE11.

SCRIPT1002: Syntax error
0.chunk.js (15,34)
SCRIPT1002: Syntax error
main.chunk.js (280,62)

@activebiz can u try again.
I updated the repo by adding "IE 11" in the browserslist.

There seems to be some caching issue happening at IE11's end.
Try clearing the IE11 browser cache.
Running npm cache clean --force also seems to resolve the issue.

@ThekhoN
you should also include import 'react-app-polyfill/stable' in according with the doc:
https://github.com/facebook/create-react-app/blob/master/packages/react-app-polyfill/README.md

Unforunately, polyfills are not enough for, let's say, PhantomJS 2.1:
SyntaxError: Unexpected token 'const' file: http://localhost:3000/static/js/0.chunk.js line: 299

I tried including react-dev-utils, chalk, strip-ansi and ansi-styles in the application JS loader, but it's not that simple, because:
Cannot assign to read only property 'exports' of object '#<Object>' at Module../node_modules/react-dev-utils/formatWebpackMessages.js (formatWebpackMessages.js:123) (which was fixed for dependencies, see: https://github.com/facebook/create-react-app/pull/5052/files - especially the comment)

So, I ended up with the following:

const path = require('path');
const {
  override,
  babelInclude,
  getBabelLoader,
} = require('customize-cra');

module.exports = override(
  config => {
    config.entry.unshift(require.resolve('react-app-polyfill/stable'));
    getBabelLoader(config).options.sourceType = 'unambiguous';

    return config;
  },
  babelInclude([
    path.resolve('src'),
    path.resolve('node_modules/react-dev-utils'),
    path.resolve('node_modules/chalk'),
    path.resolve('node_modules/strip-ansi'),
    path.resolve('node_modules/ansi-styles'),
  ]),
);

I still have the same issue, It's a typescript react app that's created using CRA
This is my browserlist

"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all",
      "ie 11"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version",
      "last 1 ie version"
    ]
  }

And the first two lines of index.tsx are

import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';

This is my tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react",
    "sourceMap": true,
    "baseUrl": ".",
    "outDir": "build/dist"
  },
  "include": [
    "src"
  ]
}

It's working the build works fine, I have this problem only with npm start.

I tried removing the node_modules and re-run it but I still face the same issue.

@kareemali-afs - doesn't my solution above help? I haven't yet used the TypeScript compiler, don't know how it fits in. But:

  1. you need to add the polyfill in the first entry of babel-loader (for npm start, index.js is the second entry, so it tries to load webpackHotDevClient before polyfills are applied)
  2. optionally (might not apply to IE11), you need to include the aforementioned node modules (react-dev-utils, chalk, strip-ansi and ansi-styles) alongside src to be processed

@jozsi
Can you write a "craco" version too?

Please..

Sure @rjcnd105, here you go:

// craco.config.js
const { getLoader, loaderByName } = require('@craco/craco');
const path = require('path');

module.exports = {
  plugins: [
    {
      plugin: {
        overrideWebpackConfig: ({ webpackConfig }) => {
          const {
            match: { loader },
          } = getLoader(webpackConfig, loaderByName('babel-loader'));

          loader.options.sourceType = 'unambiguous';
          loader.include = [
            path.resolve('src'),
            path.resolve('node_modules/react-dev-utils'),
            path.resolve('node_modules/chalk'),
            path.resolve('node_modules/strip-ansi'),
            path.resolve('node_modules/ansi-styles'),
          ];

          webpackConfig.entry.unshift(
            require.resolve('react-app-polyfill/stable'),
          );

          return webpackConfig;
        },
      },
    },
  ],
};

Happy Holidays! 馃巹

@jozsi Nope it didn't work, I tried

  1. deleted node_modules
  2. npm i customize-cra react-app-rewired chalk react-dev-utils strip-ansi ansi-styles --save-dev

  3. added your code to config-overrides.js on the same level as package.json

const path = require('path');
const {
  override,
  babelInclude,
  getBabelLoader,
} = require('customize-cra');

module.exports = override(
  config => {
    config.entry.unshift(require.resolve('react-app-polyfill/stable'));
    getBabelLoader(config).options.sourceType = 'unambiguous';

    return config;
  },
  babelInclude([
    path.resolve('src'),
    path.resolve('node_modules/react-dev-utils'),
    path.resolve('node_modules/chalk'),
    path.resolve('node_modules/strip-ansi'),
    path.resolve('node_modules/ansi-styles'),
  ]),
);
  1. npm i; npm start

Still the same issue

@kareemali-afs, a couple of observations:

  • you don't need to install chalk react-dev-utils strip-ansi ansi-styles explicitly (I don't think you should even delete node_modules before)
  • make sure to update your package.json like this (otherwise the override won't have any effect, cause it will call the unmodified react-scripts):
  "scripts": {
    "start": "react-app-rewired start",

@jozsi

  • True, I just do it to make sure it's clean from any changes I may have done while testing other solutions
  • I did add that but forgot to mention it my previous comment

You're probably right that it's because webpackHotDevClient loads first since the console error refers to this file but I am not sure why your solution is not working.

@kareemali-afs - I published the repo with the craco config I made for @rjcnd105, take a look at the changes I've made. It works for the very old, embedded browser I use (same WebKit engine as PhantomJS 2.1 uses, with capabilities similar to Safari 6). I attempted to add IE 11 support, however, I did not test it (don't have an environment for it). Give it a try :)

@kareemali-afs
As a temporary solution to debug in IE you can disable webpackHotDevClient

  • Add debug mode to scripts
  "scripts": {
    "start": "react-app-rewired start",
    "start:debug": "DEBUG_MODE=true react-app-rewired start",
  • update config-overrides.js :
const {
  override,
  babelInclude,
} = require('customize-cra');
const path = require('path');

module.exports = override(
  (config) => {
    if (process.env.DEBUG_MODE) {
      config.entry.shift(); // remove webpackHotDevClient (first as default)
      config.entry.unshift(require.resolve('react-app-polyfill/stable'));
    }

    return config;
  },
  babelInclude([path.resolve('src')])
);

Create a new create-react-app, add react-app-polyfill, update index.js to include the pollyfills, update browserlist to have ie 11 in both prod and dev, and it works in build, but fails in dev, because of the websocket. Workarounds presented here haven't worked for me. I've been having to test changes by doing builds and static serving.

None of the workarounds mentioned worked for me in development mode. Any updates about it?

Create a new create-react-app, add react-app-polyfill, update index.js to include the pollyfills, update browserlist to have ie 11 in both prod and dev, and it works in build, but fails in dev, because of the websocket. Workarounds presented here haven't worked for me. I've been having to test changes by doing builds and static serving.

@RickeyWard Have you resolved this issue yet? I'm having the same problem.

I finally have a workaround after looking at this for a couple of days

I had to change the client for WebpackDevServer from react-dev-utils/webpackHotDevClient to the alternative of webpack/hot/dev-server

You have to go to your webpack.config.js file and swap out this line:

isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),

with this one:

isEnvDevelopment && require.resolve('webpack/hot/dev-server'),

I finally have a workaround after looking at this for a couple of days

I had to change the client for WebpackDevServer from react-dev-utils/webpackHotDevClient to the alternative of webpack/hot/dev-server

You have to go to your webpack.config.js file and swap out this line:

isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),

with this one:

isEnvDevelopment && require.resolve('webpack/hot/dev-server'),

@a1g0rithm This worked for me, thank you very much.

I downgrade CRA to 3.2.0 to make it work.

I finally have a workaround after looking at this for a couple of days

I had to change the client for WebpackDevServer from react-dev-utils/webpackHotDevClient to the alternative of webpack/hot/dev-server

You have to go to your webpack.config.js file and swap out this line:

isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),

with this one:

isEnvDevelopment && require.resolve('webpack/hot/dev-server'),

Did you have to do anything else? Because while this works to load up the page in IE, hot reload no longer works. You have to refresh the page manually to see the changes.

Did you have to do anything else? Because while this works to load up the page in IE, hot reload no longer works. You have to refresh the page manually to see the changes.

Unfortunately, hot reloading won't work. Not sure if downgrading like @Felix-Indoing suggests keeps it from breaking.

Hey, I'm having the same issue with IE9.. anyone here found a solution that does NOT involve ejecting? .. using the polifills does not seems to do any magic.

Hey, I'm having the same issue with IE9.. anyone here found a solution that does NOT involve ejecting? .. using the polifills does not seems to do any magic.

I have a fully functional application that runs in IE9. There were several fixes I had to make that are not mentioned in this thread. I ejected but if you provide your error I may be able to point you in the right direction.

After reading this comment, I found the following solution works with hot reload. I'm on v3.4.1 of react-scripts

  1. In my local node_modules folder, I modified one file in react-dev-utils (a create-react-app dependency) by removing the offending function call and the chalk import statement

    1. Then I used patch-package to patch my project's react-dev-utils

    2. added the package for CRA's polyfills

import "react-app-polyfill/ie9"
import "react-app-polyfill/stable"
  1. I added a meta tag to <head /> element to public/index.html.
    (optional) It prevents IE users from enabling its "compatibility" mode
<meta http-equiv="X-UA-Compatible" content="IE=edge" />

Its also possible browserlist's development environment may need additional configuration.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adrice727 picture adrice727  路  3Comments

alleroux picture alleroux  路  3Comments

alleroux picture alleroux  路  3Comments

DaveLindberg picture DaveLindberg  路  3Comments

Evan-GK picture Evan-GK  路  3Comments