facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.68k stars 26.84k forks source link

Pin babel-preset-react-app to a minor core-js version as per core-js readme #8779

Open Mrman opened 4 years ago

Mrman commented 4 years ago

Is your proposal related to a problem?

I've been trying to polyfill Promise.allSettled for Edge by using react-app-polyfill/stable but failing. My expectation was that it should work since react-app-polyfill@1.0.6 depends on core-js@3.6.4 and Promise.allSettled was moved into core-js/stable on v3.2.0.

I've dug a bit deeper to find that babel-preset-react-app has corejs set to major version 3 (https://github.com/facebook/create-react-app/blob/v3.4.1/packages/babel-preset-react-app/dependencies.js#L91)

Looking at the core-js readme I see this:

Warning! Recommended to specify used minor core-js version, like corejs: '3.6', instead of corejs: 3, since with corejs: 3 will not be injected modules which were added in minor core-js releases.

Locally I've set corejs in babel-preset-react-app to 3.2 (just a proof this is the issue) and I can see Promise.allSettled is now polyfilled correctly.

It's not clear to me why babel-preset-react-app does not follow the advice of core-js and pin to a minor version?

Describe the solution you'd like

Update babel-preset-react-app to pin to a minor version of corejs in it's configuration.

Describe alternatives you've considered

Eject and manage babel-preset-env myself but I'm very reluctant to go down this route.

I look forward to being told why things aren't as simple as changing babel-preset-react-app configuration :)

pakaponk commented 4 years ago

I had the same problem four months ago.

At that time, I solved it by importing the specific polyfill instead of just corejs

import 'core-js/modules/esnext.string.match-all';
Mrman commented 4 years ago

I had the same problem four months ago.

At that time, I solved it by importing the specific polyfill instead of just corejs

import 'core-js/modules/esnext.string.match-all';

Thanks @pakaponk, I'm doing the same as you as a workaround in my project knowing the CRA is specifically targetting v3 of core-js.

This issue is really to explore what's stopping CRA from targetting a more recent version of core-js. core-js@3.0.0 was released over a year ago now (19 Mar 2019).

puopg commented 3 years ago

Yea agreed, or at least expose an option to configure it if you so desire.

xprommer commented 2 years ago

The similar issue, babel-plugin-polyfill-corejs3 removes my side-effect import because of babel-preset-react-app provides old version of core-js and there is no way to specify a correct version at least 3.17. So I just wanted to use the latest stable ES with nice stuff like Array.prototype.at, Object.hasOwn and so on and importing it like a polyfill import "core-js/es/array/at"; with only side effect does not work :( The sole solution I've found so far is to use export * from "core-js/es/array/at"; instead of side effect import, but I don't like it. It would be much better to add an option for corejs version, or at least update it to the latest 3.20

AndyBoat commented 2 years ago

I have a similar issue when polyfilling Array.prototype.at and an ugly but useful workaround is to force import and use it to avoid tree-shaking (? or anything like that)

import R from "core-js/stable";
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

// eslint-disable-next-line no-unused-expressions
R;
jakwuh commented 1 year ago

If you are using craco to override CRA config - you can override corejs version by using the following code

// craco.config.js

const path = require("path");

const fixCoreJsVersion = (babelConfig) => {
  babelConfig.presets.forEach((preset) => {
    if (preset?.[1]?.corejs)
      preset[1].corejs = require("core-js/package.json").version;
  });
};

const fixPresetReactAppLoaderOptions = (babelLoaderOptions) => {
  const babelPresetReactAppDependencies =
    require("babel-preset-react-app/dependencies")(null, {
      helpers: true,
    });

  const babelPresetReactApp = require("babel-preset-react-app")(null, {
    runtime: "automatic",
  });

  fixCoreJsVersion(babelPresetReactAppDependencies);
  fixCoreJsVersion(babelPresetReactApp);

  return {
    ...babelLoaderOptions,
    presets: babelLoaderOptions.presets?.map((preset) => {
      if (
        typeof preset?.[0] === "string" &&
        preset[0].includes("babel-preset-react-app/dependencies")
      ) {
        return babelPresetReactAppDependencies;
      }
      if (
        typeof preset?.[0] === "string" &&
        preset[0].includes("babel-preset-react-app/index")
      ) {
        return babelPresetReactApp;
      }
      return preset;
    }),
  };
};

module.exports = {
  // ...
  babel: {
     // ...
    loaderOptions: fixPresetReactAppLoaderOptions,
  },
};

As soon as CRA will be updated to automatically use current node_modules core-js version (same as in the snippet above) – you will be able to remove this code snippet from you craco config 🙌