3

I am attempting to configure babel preset-env to take care of injecting polyfills automatically, with respect to the specified list of target browsers.

The documentation states that configuring the preset-env preset with a property in the form of "useBuiltIns": "usage" will do exactly this.

(I noticed that specifying this property alone caused a warning to show in the console, however, stating that I ought to specify a core-js version to use, so I have added this too.)

Therefore, my babel.config.js is looking like this:

module.exports = {
  "presets": [
    "@babel/preset-react",
    "@babel/preset-typescript",
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ],
  "plugins": ['macros'],
};

Fantastic! This should be a breeze!

However, having re-compiled with webpack, my app now dies in the browser, with a console message of:

Uncaught TypeError: __webpack_require__(...) is not a function
at Module../node_modules/webpack/buildin/harmony-module.js (harmony-module.js:24)

I've done some research (only about 3 hours worth!) and I understand this is the result of babel trying to transpile babel, or something of that sort...that I need to add some files to a list of ignores that will not be transpiled, or doubly-transpiled, perhaps.

In my webpack config, I've put the following. (Note the exclude entries).

module: {
  rules: [
    {
      test: /\.(js|jsx|ts|tsx)$/,
      exclude: [/core-js/, /regenerator-runtime/],
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: babelConfig.presets,
            cacheDirectory: babelCacheDir
          }
        },
        'eslint-loader'
      ]
    }
  ]
}

I've also tried adding a few variations on the ignore pattern, but I still have fatal console errors.

Another thing I've tried, is ignoring the node_modules folder, but then I have big chunks of code that aren't transpilled at all. i.e. In IE11, I get syntax errors regarding ES6 arrow functions that originate in untranspilled vendor scripts.

If anyone is able to explain why __webpack_require__ is being altered in an undesirable way, I would be very greteful, as the exact solution that this problem requires is being quite resistant to research.

Edit: The following suggests that babel must be made to ignore core-js, which seems very reasonable. It suggets using the following in the babel config file:

{
  ignore: [
    /\/core-js/,
  ],
  sourceType: "unambiguous",
  presets: [
    ['@babel/preset-env', { modules: false, useBuiltIns: 'usage' }],
  ],
}

However, this causes another fairly, seemingly nonspecific error to arise:

has.js:4 Uncaught TypeError: Cannot convert undefined or null to object
    at hasOwnProperty (<anonymous>)
    at push../node_modules/core-js/internals/has.js.module.exports (has.js:4)
kohloth
  • 742
  • 1
  • 7
  • 21
  • Excellent question. It seems that setting `useBuiltIns: 'usage'` brings more Babel pipework into play than before, and things that used to just work (in my case, importing node.js-style code that exports using assignments to `module.exports`) now break. Using `sourceType: "unambiguous"` helped me, YMMV. (https://stackoverflow.com/a/52415747/435004) – DomQ Jul 12 '21 at 10:11

2 Answers2

2

Under useBuiltins: "usage", Babel needs to take a guess wrt. ES6 vs. CJS import styles; and it better guess the same way as Webpack.

This is very briefly covered in the Babel docs. The simplest way to make that happen, as explained elsewhere, is to also set sourceType: "unambiguous" in the options passed to @babel/preset-env.

To answer the “why” question the best I can:

  • useBuiltIns: "usage" means that Babel will set out to find and polyfill a number of method calls (and other JS constructs) that may not exist in some browsers. This requires injecting some fixup code into your module at Babel rewrite time.
  • A lot of these fixups consist of importing pieces of core-js to ensure that the Array etc. prototypes are populated to satisfaction; e.g. Babel may insert things such as
    import "core-js/modules/es.array.map.js";
  • There is, quite unfortunately, more than one way to import things in JavaScript. Babel has to take a guess at which one is best for the downstream tool chain. If Babel is upstream of Webpack, which is a pretty typical scenario (and is the case for your question), it could derail some auto-detection logic in Webpack by adding import statements into code that uses require() or module.exports.
  • Instead of throwing a parse error outright, Webpack will unfortunately try and process such tainted code; causing a variety of inscrutable compile-time or run-time symptoms down the line (here is another example).

Until such time that Babel and Webpack agree on some sort of convention or secret handshake that papers over the ES6 / CJS impedance mismatch, you as a module author will have to make sure somehow that Babel and Webpack have the same idea of which source file is using which format; or just disable Babel for your “old“ (CJS) code, whether in node_modules/ or elsewhere.

DomQ
  • 4,184
  • 38
  • 37
0

Excluding /webpack/ did the trick for me !

Clement Dungler
  • 737
  • 6
  • 10