Webpacker: .browserslistrc being ignored

Created on 25 Oct 2019  Â·  9Comments  Â·  Source: rails/webpacker

Webpacker seems to be ignoring browserslist.

After having a polyfilling issue in production, we decided to review our .browserslistrc and webpacker setup. We soon found that it seemed to be ignored entirely.
We tried removing almost all customisation, and used the default install config as a guide, to no avail.
Finally, we created a brand new rails new app with complete defaults. A line of ES6 was entered in the application.js alongside the default content, and the filesize was checked when Chrome 77 was the only thing entered in the .browserslistrc and that file size compared against when > 0.1% was the only thing entered in the .browserslistrc. There was no change in file size.

The only assumption that we're making which we're questioning a bit, is that the file size should change when more browsers need to be polyfilled for. That being said, I really think it should 🤔

I've created a reproduction repo

There is a rake task to confirm the issue

Most helpful comment

Apparently the .browserslistrc file is not recommended -- if it's not working, perhaps the installer should just be fixed to add to package.json instead, as the recommended way?

Yes, it is better to add this to package.json.

@sfcgeorge, @dansteele In your example try to target only the latest browsers with > 7%. This is effectively only chrome, but chrome for ios still needs ios polyfills (see how to enable debug info below):
image

That should produce a different file size, You can use this site to compare "> 0.1%, not dead" with the default target browsers:

Once you have nailed that down, you can inspect which browsers are triggering which polyfills by setting debug: true in babel.config.js. Something like:
image
image
This will tell you:

  • What browsers are being targeted.
  • What polyfills/plugins have been loaded for what files.
  • What browsers are being supported by what polyfills.

From experience, you might need a few extras for ie11:

Sorry for taking so long to get back to this issue, hope this helps.

All 9 comments

The background is we need to support IE 11, tried adding it to .browserslistrc, and it didn't seem to make a difference which led us to believe it doesn't work.

I saw something about core-js, and that seems to be what does the actual polyfilling in combination with preset-env. There are some confusing docs but everything seems set up right.

I also found mention of core-js somewhat hidden away in the Webpacker docs.

Both suggest all you need to do is add this:

import "core-js/stable";
import "regenerator-runtime/runtime";

And while that does change the package size it still seems to ignore browserslist.

And while that does change the package size it still seems to ignore browserslist.

@sfcgeorge is correct, you need that part for pollyfills to work.

still seems to ignore browserslist

> 0.1% means you are pollyfilling for 99.9% of global usage, you are most likely getting all the polyfills.

image

I think that once @sfcgeorge added those 2 lines, all polyfills were added and the 99.9% usage did not disable any because of it's broadness. You might instead go with:

> 1%
not dead

I have added those lines and it didn't make a difference. The Rake task @dansteele provided alternates between a recent Chrome and 0.1%; AKA basically no polyfills to all polyfills. Yet in both cases the pack size is the same even with those core-js lines, thus leading us to believe Webpacker is ignoring .browserlistrc entirely.

We spent hours trying different Babel configs, browserlist settings, reading all the docs we could find, but it just doesn't seem to work. Though thousands of people use Webpacker so it's hard to believe that many sites could be missing polyfills without noticing.

Hopefully we've both missed something obvious and it's just a documentation issue. So please download my reproduction and run rake test_browserlist. Modify whatever config is needed to get that task to "pass" AKA make the pack size change and report back. We'll be very grateful so we can get things working for our IE users 😄 I'll be happy to PR any doc improvements.

I am not an expert in this at all. I have also not tried reproducing myself yet.

But browserslist docs suggest that in addition to .browserslistrc, you could put config in a browserlist key in package.json.

Try that and see if it works? Even if it does, it would of course still be a bug of some kind if a .browserslist file generated by new rails app/rake webpacker:install is being ignored. But could be some more info and a possible workaround.

the browserslist docs also say

browserslist key in package.json file in current or parent directories. We recommend this way

Apparently the .browserslistrc file is not recommended -- if it's not working, perhaps the installer should just be fixed to add to package.json instead, as the recommended way?

Apparently the .browserslistrc file is not recommended -- if it's not working, perhaps the installer should just be fixed to add to package.json instead, as the recommended way?

Yes, it is better to add this to package.json.

@sfcgeorge, @dansteele In your example try to target only the latest browsers with > 7%. This is effectively only chrome, but chrome for ios still needs ios polyfills (see how to enable debug info below):
image

That should produce a different file size, You can use this site to compare "> 0.1%, not dead" with the default target browsers:

Once you have nailed that down, you can inspect which browsers are triggering which polyfills by setting debug: true in babel.config.js. Something like:
image
image
This will tell you:

  • What browsers are being targeted.
  • What polyfills/plugins have been loaded for what files.
  • What browsers are being supported by what polyfills.

From experience, you might need a few extras for ie11:

Sorry for taking so long to get back to this issue, hope this helps.

Thank you @jakeNiemiec. Your notes put me on the right path to understanding what was going on.

  • .browserslistrc isn't being ignored, it's fine.
  • Changes made to babel.config.js _are_ being ignored until you rm -r tmp/cache — this is what really screwed me up because I'd change things and seemingly it had no effect. You have to delete tmp/cache every time you change anything really, to be sure.
  • useBuiltIns has the most confusing documentation and API. It suggests you import core-js but only entry re-writes the import, so if you panic and go "all in" and use useBuiltIns: "usage" AND import core-js the bundle is always just massive.
  • fetch not being included is baffling, that's the main issue we had in IE. We assumed this automatic polyfilling system that polyfills features as you use them, well we assumed it did just that. Turns out it only polyfills ES6 features, not DOM features, but how is anyone supposed to know the difference. Apparently fetch isn't an ES6 feature but god knows why not. Babel doesn't give you any warning, and you can only find out by looking at this small note right at the bottom of the core-js docs. Frustrating.
  • Setting debug: true was crazy helpful, thank you! With it on you can see what is or isn't being polyfilled, it'll even warn you if you're using "entry" and haven't imported core-js so it couldn't polyfill anything. It's mental that this is just an info message buried in debug output, it should be an error. If you've asked it to polyfill and it couldn't that's definitely something it should tell you!

So I think this is primarily a documentation issue in Babel and core-js.

Perhaps Webpacker could set debug: true by default as it's pretty useless without, but I can see people not liking that much output.

I don't know if Webpacker can do anything about deleting tmp/cache when needed.

And perhaps Webpacker docs could mention some of these gotchas. Mainly delete tmp/cache, add a fetch polyfill manually, and use debug if stuck. Perhaps clarifying useBuiltIns too.

Apologies for the quick & messy reply:

Changes made to babel.config.js are being ignored...

Could be related to this babel issue: "Changes to .browserslistrc does not invalidate cache" https://github.com/babel/babel-loader/issues/690

useBuiltIns has the most confusing documentation and API

100% agree. We recently switched to useBuiltIns: "usage". It works well.

fetch not being included is baffling

Remember that javascript exists outside of browsers. Babel just handles things covered by the ES6,7,8+ specs. See this classic page: https://kangax.github.io/compat-table/es6/

Perhaps Webpacker could set debug: true by default as it's pretty useless without, but I can see people not liking that much output.

Yes, it's hard to sell people on more output, but some documentation of this would be nice.

I don't know if Webpacker can do anything about deleting tmp/cache when needed.

Webpacker docs on changing the babel loader here: https://github.com/rails/webpacker/blob/749675d9c035dbc8777f718582e3e4804147e9e5/docs/webpack.md#loaders

Webpacker uses a custom location. It might work better if you changed it to cacheDirectory: true:

If the value is set to true in options ({cacheDirectory: true}), the loader will use the default cache directory in node_modules/.cache/babel-loader or fallback to the default OS temporary file directory if no node_modules folder could be found in any root directory. LINK

Thanks again for more helpful notes :) I expect they'll be useful to anyone else who finds this issue.

I don't think there's anything wrong with Webpacker. I think there are multiple confusingly named things, poor documentation, and weird decisions in upstream projects that snowball. I don't think changing the cache location should affect much if there's that upstream bug with it not being cleared. There's not much Webpacker could do to help other than more docs and maybe a generator option that sets up the core-js config for you.

If you're like me and webpacker's choices aren't compatible with how you want to configure webpack, just blow away their babel rules so you can use a babel config from your own project.

```const environment= require("@rails/webpacker").environment;
environment.loaders.delete('babel');
environment.loaders.delete('nodeModules')

environment.loaders.insert(
"babel", {
test: /.(js|jsx|ts|tsx|mjs)?(.erb)?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
}
}
)`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

suhomozgy-andrey picture suhomozgy-andrey  Â·  3Comments

iChip picture iChip  Â·  3Comments

FrankFang picture FrankFang  Â·  3Comments

towry picture towry  Â·  3Comments

Eearslya picture Eearslya  Â·  3Comments