As a front developer, we should keep in mind what browsers are used by our customers. We say only modern browsers and IE 11 are supported, at least users won’t get an error on IE 11. Our config is : ['last 2 versions', 'ie >= 11'] and here’s detailed browsers: last 2 versions. If you find your config is different from this one, please ensure your config is a superset of the above list.
Mystery of Babel
With Babel, we could use new features of ES without worrying about compatibility. You must have got some error saying browser doesn’t support it even you’re using babel. Yeah, you might know we still have to take care of polyfill. Have you ever been confused about various babel packages?
var array = [1, 2, 3, 4, 5, 6]; array.includes(function (item) { return item > 2; }); var set = newPromise();
As we can see, babel transforms new syntax to the old one for us. But didn’t change the static methods in the new feature. (Notice it’s using global regeneratorRuntime )
If we specify targets only for modern browsers like below:
The outcode is almost same with source code. It’s not surprising.
Let’s move on. Now we set useBuiltIns as ‘usage’
1 2 3 4 5 6 7 8 9 10 11
[ '@babel/preset-env', { targets: { browsers: ['defaults'], }, useBuiltIns: 'usage', corejs: 3, // using useBuiltIns without declare corejs version will get warning. modules: false, }, ],
We found babel imported a few files for us.
1 2 3 4 5 6 7 8 9
import"core-js/modules/es.symbol"; import"core-js/modules/es.symbol.description"; import"core-js/modules/es.array.from"; import"core-js/modules/es.array.includes"; import"core-js/modules/es.object.to-string"; import"core-js/modules/es.promise"; import"core-js/modules/es.string.iterator"; import"regenerator-runtime/runtime"; // Below is same with output1
From now I set modules as false, so the outcode is using import rather than require.
useBuiltIns has another option: ‘entry’.
It won’t import polyfill for us. We still have to import polyfill by yourself but it will import specific files in terms of your target setting.
If in your entry files, you have the above code, it will transform to the below one. (It depends on your target browsers. Even you never use it in your code.)
1 2 3 4 5 6
import"core-js/modules/es.symbol.description"; import"core-js/modules/es.symbol.async-iterator"; import"core-js/modules/es.array.flat"; import"core-js/modules/es.array.flat-map"; .... // very long
Transform-runtime
Let’s disable useBuiltIns and move on. Add plugins to babel config file: "plugins": ["@babel/plugin-transform-runtime"]
This outcode is a bit different from the previous. As the documentation, by default, it set regenerator as true. Besides, it replaced inline helper with the module. But it didn’t import any polyfill files.
Let’s try other params: ["@babel/plugin-transform-runtime", {"corejs": 3 }]
_includesInstanceProperty(array).call(array, function (item) { return item > 2; });
var promise = new_Promise();
Here you see: it helped us handle new global properties even instance properties in a different way. It was using internal methods, which means it won’t pollute prototype or global namespace.
It’s commonly used in the development of the third library.
Also, you might have already noticed, we should ensure the packages used in outcode is accessible. @babel/runtime or core-js or regenerator-runtime/runtime (@babel/polyfill has been deprecated. use core-js/stable and regenerator-runtime/runtime directly. )
For us, maybe the best way is aligning our solution to CRA. For the micro front end, the best way is to import polyfill in the shell entry, others don’t need import twice.
I know, even we import all polyfill files, it doesn’t make much difference. Anyway, we’re stepping into the right direction.