Polyfill means something that comes from the bottom of your pocket. In computer science, a “bottom-of-the-barrel” operation on a client that failed to materialize. Patch er in front is a common thing, combined with the author’s daily work experience, summed up three ways to patch. Involves @babel/preset-env, @babel/polyfill, @babel/ transform-Runtime, @babel/ Runtime, and core-js. If there is a flaw, do not give advice.
In general, there are three main ways to patch:
- Manually Installing patches
- Patches are automatically installed based on coverage
- Patch dynamically based on browser features
The three methods can be combined to complete the patch required by the business. Introduction:
Manually Installing patches
Back in the Stone Age, we manually imported the required patches. Take ES6’s object#assign as an example. Even on IE 11, errors were reported
So we need to patch it. You can use the mature package of the third party, or you can use the template provided by MDN to patch:
Object.assign = require('object-assign')
// or
// Refer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign ! ='function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object.'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
'use strict'
if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object')}var to = Object(target)
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index]
if(nextSource ! =null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey]
}
}
}
}
return to
},
writable: true.configurable: true})},Copy the code
The problem is solved, but the advantages and disadvantages are quite obvious: the advantages are to keep the introduction to a minimum, there is no extra redundant code overhead, and the performance of the application is guaranteed. The disadvantage is that manual import is difficult to manage and maintain, and the maintenance cost is high for diversified polyfills and varied Web applications.
Patches are automatically installed based on coverage
With the dark Magic Webpack, we can patch in a more modern way. Related dependencies are: @babel/preset-env, @babel/ plugin-transform-Runtime, core-js, @babel/polyfill. Let’s look at them one by one:
-
@babel/preset-env – Build on demand and patch on demand
@babel/preset-env
is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!@babel/preset-env will compile and patch based on the target environment. Specifically, targets is used to determine the target environment. By default, it is compiled as ES2015 and can be configured according to project requirements:
. Presets: [[' @ Babel/preset - env, {/ / support chrome 58 + 11 + the targets and IE: {chrome: '58', IE: '11',}},],]...Copy the code
For details about targets parameters, see BrowserList.
-
Core-js JavaScript standard library
Core-js is one of the runtime libraries implementing the JavaScript standard. It provides implementations of JavaScript from ES3 to ES7+ as well as JavaScript in the proposal stage.
-
@babel/plugin-transform-runtime – reuse the Babel helper method
A plugin that enables the re-use of Babel’s injected helper code to save on codesize.
Babel/plugin-transform-Runtime reuses the helper methods generated during Babel compilation to reduce the packaging volume. It also serves to avoid global patch contamination by providing “sandbox” patches to packaged Bunlers.
-
Implementation library for @babel/ polyfill-core-js and Regenerator-Runtime patches
Babel includes a polyfill that includes a custom regenerator runtime and core-js.
This will emulate a full ES2015+ environment (no < Stage 4 proposals) and is intended to be used in an application rather than a library/tool. (this polyfill is automatically loaded when using
babel-node
)A library of polyfill in the ES2015+ environment is provided by customizing Polyfill and Regenerator. Since it was implemented by two other libraries and can be imported directly into the other two libraries, it has been deprecated **.
// implement @babel/polyfill equivalent import 'core-js/stable' import 'regenerator-runtime/runtime' Copy the code
Method of use
According to the different objectives of construction, the author believes that there should be two patching methods: application patch and library patch:
Applied patches – use@babel/preset-env
+ useBuiltIns
Since core-JS includes all of the JavaScript standard libraries, is there any way to automatically get patches based on your application’s compatibility goals? This is where the useBuiltIns parameter @babel/preset-env is used. UseBuiltIns tells @babel/preset-env how to handle polyfills based on the targets of the application.
First, introduce core-js in the application portal:
import 'core-js'
Copy the code
Then, set the useBuiltIns parameter to Entry and specify the core-js version:
{
"presets": [["@babel/preset-env",
{
"useBuiltIns": "entry"."corejs": 3}]."@babel/preset-react"]}Copy the code
For an example of the code, see: babel-preth-ENV-1: The result after packaging is:
It converts all ECMAScript 2015+ code by default. Unless the business requires it, specify the browser environment that the application will support to avoid unnecessary patches and reduce the volume of packaged output. The supported environment can be specified using the targets parameter, whose syntax can be identified by referring to browserslist. The usage is also simple, assuming the app only needs to support Chrome 58:
{
"presets": [["@babel/preset-env",
{
"useBuiltIns": "entry"."corejs": 3."targets": {
"chrome": 58}}]."@babel/preset-react"]}Copy the code
As you can see, the volume is significantly smaller after packaging:
If your application introduces multiple third libraries and they have common helper methods, you should introduce @babel/ plugin-transform-Runtime to reduce packaging volume. The usage method is not described here, please refer to the documentation.
In addition, the useBuiltIns value of @babel/preset-env also has an experimental usage value, which introduces corresponding patches according to the required patches of different files, which can reduce unnecessary patches to a certain extent. Reference usebuiltins – usage – experimental.
The above is a simple summary of how to patch an application based on coverage:
-
Introduce Core-JS in the application portal
import 'core-js' Copy the code
-
Use @babel/preset-env to specify useBuiltIns, core-js, and targets based on the application
{ "presets": [["@babel/preset-env", { "useBuiltIns": "entry"."corejs": 3."targets": { "chrome": 58}}]."@babel/preset-react"]}Copy the code
-
For example, the project introduces multiple third-party libraries containing common helper methods, and the reuse method @babel/ plugin-transform-Runtime is introduced to reduce packaging volume.
Patches for the library – Only the proprietary patches that the library relies on are provided
Since the library is introduced by the application, it should not provide common patches such as Promises, maps, etc. These should be provided by the application itself, and the library itself should only introduce its own proprietary libraries.
For example, if I wanted to make a multilingual date picker component, I would introduce a multilingual implementation of Polyfill, such as Intl.
Patch dynamically based on browser features
Both approaches have a downside — patch redundancy. In the case of Object#assign, there is no need to introduce this patch for browsers that support this feature, which inevitably results in a certain amount of patch redundancy, so there is a solution to dynamically patch based on the browser characteristics.
Polyfill. IO is the service that implements this solution, and it returns different patches depending on the UA of the browser. If you want the Promise patch, introduce it on the page:
<script src="https://polyfill.io/v3/polyfill.js? features=Promise"></script>
Copy the code
On older browsers (Chrome 75), opening the link returns an empty page:
/* Polyfill service v3.34.0 * For Detailed credits and licence information see https://github.com/financial-times/polyfill-service. * * Features requested: Promise * */
/* No polyfills found for current settings */
Copy the code
If you change the UA of the browser to IE 11, the corresponding polyfill will be returned:
You can also customize Polyfill by attaching query parameters, as described in the official documentation.
In addition, if Polyfill. IO needs stability and security, you can build your own service based on the open source Polyfill Service and deploy it on the CDN.
In the future
Based on the current solution, I think the on-demand feature patch + online patch is the ultimate solution in the future. The on-demand feature is implemented by referring to the Usage parameter of useBuiltIns – only the necessary patches are introduced in the current file, and only once. Polyfill service is used for online patches. The combination of the two ensures that the introduction of patches is minimized, and different patches are made according to different devices.
The above.