babel-polyfill usage scenarios

By default Babel only transforms new JavaScript syntax, not new APIs. For example, global objects such as Iterator, Generator, Set, Maps, Proxy, Reflect, Symbol, Promise, and some methods defined on global objects (such as Object.assign) will not be translated. If you want to use these new objects and methods, you must use babel-polyfill, which provides a shim for the current environment.

babel-runtime usage scenarios

Babel's transpiled code needs to use some helper functions to achieve the same function as the source code. For example, the { [name]: 'JavaScript' } transpiled code is as follows:

'use strict';
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var obj = _defineProperty({}, 'name', 'JavaScript');

Similar to the above helper function _defineProperty may appear repeatedly in some modules, resulting in larger size of compiled code. To solve this problem, Babel provides a separate package  babel-runtime for compiling modules to reuse tool functions.

After enabling the plugin  babel-plugin-transform-runtime , Babel will use  babel-runtime the following utility functions, and the transpiled code is as follows:

'use strict';
// 之前的 _defineProperty 函数已经作为公共模块 `babel-runtime/helpers/defineProperty` 使用
var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var obj = (0, _defineProperty3.default)({}, 'name', 'JavaScript');

In addition to this, babel automatically references polyfills for non-instance methods ( Object.assign, instance methods are something like this  "foobar".includes("foo")) and utility functions under babel-runtime/helps in the source code. This avoids polluting the global namespace and is ideal for JavaScript library and toolkit implementations. For example  const obj = {}, Object.assign(obj, { age: 30 }); , the translated code looks like this:

'use strict';
// 使用了 core-js 提供的 assign
var _assign = require('babel-runtime/core-js/object/assign'); var _assign2 = _interopRequireDefault(_assign); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var obj = {}; (0, _assign2.default)(obj, { age: 30 });

Thinking: Why is babel-runtime suitable for the implementation of JavaScript libraries and toolkits?

  1. Avoid repeated babel-compiled tool functions in each module, reducing the size of libraries and toolkits;

  2. Libraries and toolkits generally do not directly import polyfills until babel-runtime is not used. Otherwise global objects like Promises will pollute the global namespace, requiring users of the library to provide their own polyfills. These polyfills are generally mentioned in the usage instructions of libraries and tools. For example, many libraries will require polyfills for es5. After using babel-runtime, libraries and tools only need to add dependencies to babel-runtime in package.json, and hand it over to babel-runtime to introduce polyfill;

Summarize:

  1. Specific projects still need to use babel-polyfill. If only babel-runtime is used, instance methods cannot work properly (for example  "foobar".includes("foo"));

  2. JavaScript libraries and tools can use babel-runtime, and using these libraries and tools in actual projects requires the project itself to provide polyfills;