Yet another babel plugin that lets you freely customize polyfills.
There are several ways to insert polyfill via babel, including @babel/preset-env and @babel/transform-runtime. Recently, babel-plugin-polyfill-es-shims and others have been created to provide more options other than core-js.
On the other hand, core-js and es-shims are specialized for ECMAScript polyfills, and there is a lack of DOM API polyfills.
babel-plugin-polyfill-custom allows you to set any polyfills you want.
For example, if you want to insert a polyfill for fetch, you can choose whatwg-fetch or unfetch. When considering a polyfill for Promise, you can also choose an alternative other than core-js, such as Zousan, Yaku, or Aigle.
In addition, babel-plugin-polyfill-custom can determine which polyfill is needed based on the browsers listed in the browserslist. This is highly beneficial when using the differencial bundle serving.
npm install --dev @babel/core babel-plugin-polyfill-custom
babel-plugin-polyfill-custom inserts polyfill using base64 data URIs. When used with a bundler, the bundler should be able to recognize base64 data URIs.
webpack 5.38.0 or later supports data scheme.
const config = {
module: {
rules: [
{
mimetype: 'text/javascript',
scheme: 'data',
type: 'javascript/auto',
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
...,
},
},
],
},
],
},
};
@rollup/plugin-data-uri
needs to be loaded.
const { babel } = require('@rollup/plugin-babel');
const dataUri = require('@rollup/plugin-data-uri');
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const config = {
plugins: [
babel({
...,
}),
dataUri(),
nodeResolve(),
commonjs(),
],
};
Parcel does not have a feature to recognize base64 data URIs. You can create your own Parcel Resolver to recognize base64 data URIs.
See ./examples/parcel
for more details.
{
"extends": "@parcel/config-default",
"resolvers": [
// You should create resolver as parcel-resolver-data-uri.
"parcel-resolver-data-uri",
"@parcel/resolver-default"
]
}
You can find more examples in ./examples
.
const polyfills = {
'polyfill:abort-controller': {
features: ['api.AbortController'],
packages: [
{
packageName: 'abort-controller/polyfill',
},
],
},
'polyfill:fetch': {
features: ['api.fetch', 'api.fetch.init_signal_parameter'],
packages: [
{
definitions: {
['fetch']: 'fetch',
},
packageName: 'whatwg-fetch',
},
],
},
};
const config = {
plugins: [
[
'polyfill-custom',
{
method: 'entry-global',
polyfills,
},
],
],
};
entry-global
is only supported.
See https://github.com/babel/babel-polyfills#injection-methods.
An Object for the definition of polyfill. A key of object is the identifier of the polyfill and is used as the package name when importing.
// Source
import 'polyfill:fetch';
import 'polyfill:abort-controller';
const abortController = new AbortController();
fetch('https://example.com', {
signal: abortController.signal,
}).then(function (res) {
if (!res.ok) {
throw new Error('Failed to fetch: ' + String(res.status));
}
console.log(res);
});
// Transpiled
import 'data:text/javascript;base64,aW1wb3J0e2ZldGNoIGFzIF9fZmV0Y2h9ZnJvbSJ3aGF0d2ctZmV0Y2giO3ZhciBleHBvcnRzPWZ1bmN0aW9uKCl7cmV0dXJuIHR5cGVvZiBnbG9iYWxUaGlzIT09InVuZGVmaW5lZCI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZiE9PSJ1bmRlZmluZWQiP3NlbGY6dHlwZW9mIHdpbmRvdyE9PSJ1bmRlZmluZWQiP3dpbmRvdzp0eXBlb2YgZ2xvYmFsIT09InVuZGVmaW5lZCI/Z2xvYmFsOkZ1bmN0aW9uKCJyZXR1cm4gdGhpcyIpKCl9KCk7ZXhwb3J0cy5mZXRjaD1fX2ZldGNoOw==';
import 'abort-controller/polyfill';
const abortController = new AbortController();
fetch('https://example.com', {
signal: abortController.signal,
}).then(function (res) {
if (!res.ok) {
throw new Error('Failed to fetch: ' + String(res.status));
}
console.log(res);
});
A list of features that polyfill has. Fill in the @mdn/browser-compat-data identifier.
For example, in the case of polyfill supporting the fetch API, the identifier is api.fetch
.
The definition of the package to be inserted as polyfill.
packageName
is the name of the package.
definitions
specifies which export variables are to be inserted as what global object.
// To assign `import { Aigle } from 'aigle'` to `window.Promise`,
// specify `Promise` on the left side and `Aigle` on the right side.
{
definitions: {
['Promise']: 'Aigle',
},
packageName: 'aigle',
}
// To assign `import matches from '@ungap/element-matches'` to `Element.prototype.matches`,
// specify `Element.prototype.matches` on the left side and `default` on the right side.
{
definitions: {
['Element.prototype.matches']: 'default',
},
packageName: '@ungap/element-matches',
}
PRs accepted.