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

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

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:


This will tell you:
From experience, you might need a few extras for ie11:
custom-event-polyfill (import into .js, it's not provided by babel)whatwg-fetch (import into .js, it's not provided by babel)sourceType: 'unambiguous' (pictured above) Why you may need this: https://github.com/webpack/webpack/issues/4039#issuecomment-419284940Sorry 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.
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 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.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',
}
}
)`
Most helpful comment
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):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: trueinbabel.config.js. Something like:This will tell you:
From experience, you might need a few extras for ie11:
custom-event-polyfill(import into .js, it's not provided by babel)whatwg-fetch(import into .js, it's not provided by babel)sourceType: 'unambiguous'(pictured above) Why you may need this: https://github.com/webpack/webpack/issues/4039#issuecomment-419284940Sorry for taking so long to get back to this issue, hope this helps.