Breaking: make current "useBuiltIns" auto import only used + necessary polyfills per file#241
Breaking: make current "useBuiltIns" auto import only used + necessary polyfills per file#241
Conversation
Codecov Report
@@ Coverage Diff @@
## 2.0 #241 +/- ##
======================================
Coverage ? 87.67%
======================================
Files ? 6
Lines ? 284
Branches ? 99
======================================
Hits ? 249
Misses ? 17
Partials ? 18
Continue to review full report at Codecov.
|
| @@ -0,0 +1,4 @@ | |||
| "use strict"; | |||
|
|
|||
| import "core-js/modules/es6.promise"; | |||
There was a problem hiding this comment.
bug: not transformed due to program.exit
| @@ -0,0 +1,108 @@ | |||
| export const definitions = { | |||
There was a problem hiding this comment.
This is basically the opposite of built-in-features.js so maybe can just reverse it somehow
src/index.js
Outdated
| if (useBuiltIns) { | ||
| plugins.push([transformPolyfillRequirePlugin, { polyfills, regenerator }]); | ||
| } else if (addUsedBuiltIns) { | ||
| plugins.push([addUsedBuiltInsPlugin, { polyfills, regenerator }]); |
There was a problem hiding this comment.
right now it's a separate option/plugin/file to make it easier to look at
b96525c to
761a146
Compare
|
Can we track |
|
Yeah we can just dono if it's worth doing it |
|
new idea: Make this the default behavior in 2.0 (useBuiltIns: true) which is "aggressive" in removing polyfills that aren't used in the files. Another option would be the current We need to make sure that babel-polyfill/core-js is included as a dependency though which I'm not sure how to do other than making a runtime error if it's not defined. |
…t core-js return babel-polyfill require instead of core-js
|
9f754cf just appends |
|
|
||
| > NOTE: Only use `require("babel-polyfill");` once in your whole app. One option is to create a single entry file that only contains the require statement. | ||
|
|
||
| This option enables a new plugin that replaces the statement `import "babel-polyfill"` or `require("babel-polyfill")` with individual requires for `babel-polyfill` based on environment. |
There was a problem hiding this comment.
Worth adding a note this was the behavior in 1.x?
There was a problem hiding this comment.
Eh, maybe not and just put it in upgrade guide.
src/add-used-built-ins-plugin.js
Outdated
| state.opts.addUsedBuiltIns && | ||
| console.warn( | ||
| ` | ||
| Adding "import 'babel-polyfill'" isn't necessary with the addUsedBuiltIns option anymore. |
There was a problem hiding this comment.
addUsedBuiltIns -> useBuiltIns: true (same on L84)
src/normalize-options.js
Outdated
| moduleType: validateModulesOption(opts.modules), | ||
| targets: opts.targets, | ||
| useBuiltIns: opts.useBuiltIns, | ||
| useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Maybe convert this to a destructure with a default?
There was a problem hiding this comment.
Along with opts.target and opts.debug
There was a problem hiding this comment.
We may also want to validate valid useBuiltIn values (false|true|'entry')
| @@ -1,5 +1,5 @@ | |||
| function isPolyfillSource(value) { | |||
| return value === "babel-polyfill" || value === "core-js"; | |||
There was a problem hiding this comment.
since the 7.0 babel-polyfill will have core-js modules in it we can just target that
| ``` | ||
|
|
||
| This option enables a new plugin that replaces the statement `import "babel-polyfill"` or `require("babel-polyfill")` with individual requires for `babel-polyfill` based on environment. | ||
| #### `useBuiltIns: true` |
There was a problem hiding this comment.
Are you missing docs for useBuiltIns: false now? May seem obvious, but now that it's not the default you should at least describe the option.
src/index.js
Outdated
| useBuiltIns && | ||
| plugins.push([transformPolyfillRequirePlugin, { polyfills, regenerator }]); | ||
| if (useBuiltIns === true) { | ||
| plugins.push([addUsedBuiltInsPlugin, { polyfills, regenerator, debug }]); |
There was a problem hiding this comment.
The debug flag is used in the plugin =>
babel-preset-env/src/use-built-ins-plugin.js
Line 142 in ebf77d8
There was a problem hiding this comment.
Maybe we don't want to have those warnings, not sure if it's useful or not but we can iterate
src/normalize-options.js
Outdated
| moduleType: validateModulesOption(opts.modules), | ||
| targets: opts.targets, | ||
| useBuiltIns: opts.useBuiltIns, | ||
| useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Maybe convert this to a destructure with a default?
src/normalize-options.js
Outdated
| moduleType: validateModulesOption(opts.modules), | ||
| targets: opts.targets, | ||
| useBuiltIns: opts.useBuiltIns, | ||
| useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Along with opts.target and opts.debug
src/use-built-ins-plugin.js
Outdated
| t.isIdentifier(prop) && | ||
| has(definitions.instanceMethods, prop.name) | ||
| ) { | ||
| state.opts.debug && warnOnInstanceMethod(getObjectString(node)); |
There was a problem hiding this comment.
Maybe move debug check into warnOnInstanceMethod?
src/use-built-ins-plugin.js
Outdated
| function addUnsupported(path, polyfills, builtIn, builtIns) { | ||
| if (Array.isArray(builtIn)) { | ||
| for (const i of builtIn) { | ||
| if (polyfills.indexOf(i) !== -1) { |
There was a problem hiding this comment.
Maybe polyfills could be a Set so you get O(1) lookups instead of O(n)? Might be premature optimization.
There was a problem hiding this comment.
It's passed in as an array, so can turn it into a set before passing it down
There was a problem hiding this comment.
Might be better to review using a Set throughout the plugin in 2.x?
src/use-built-ins-plugin.js
Outdated
| if (isRequire(bodyPath)) { | ||
| console.warn( | ||
| ` | ||
| Adding "require('babel-polyfill')" isn't necessary with the useBuiltIns option anymore. |
There was a problem hiding this comment.
Avoid "anymore". This message is valid for new and old users. To users it never was necessary
src/use-built-ins-plugin.js
Outdated
| const builtIn = definitions.instanceMethods[prop.name]; | ||
| addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns); | ||
| } else if ( | ||
| node.computed && |
There was a problem hiding this comment.
This is very cool that it catches: b['find'] but it won't catch var c = 'find'; b[c];.
And I know it's literally impossible to statically guarantee that you'll find all cases because of stuff like var c = 'fi' + 'nd'; b[c];
However, maybe it makes sense to iterate over all string literals and if any match an instance method name, include the polyfill?
I only say that because it's far more likely to see: b[someCondition ? 'find' : 'findIndex'] and you never see the literal string form because you can use non computed always in that case.
There was a problem hiding this comment.
Ok #241 (comment). Yeah we could check strings.
src/use-built-ins-plugin.js
Outdated
| const res = path.get("property").evaluate(); | ||
| if (res.confident) { | ||
| const builtIn = definitions.instanceMethods[res.value]; | ||
| warnOnInstanceMethod(state, `${obj.name}['${prop.value}']`); |
src/use-built-ins-plugin.js
Outdated
| When setting 'useBuiltIns: true', polyfills are automatically imported when needed. | ||
| Please remove the call or use 'useBuiltIns: "entry"' instead. | ||
| When setting "useBuiltIns: true", polyfills are automatically imported when needed. | ||
| Please remove the "import 'babel-polyfill'" call or use "useBuiltIns: 'entry'" instead. |
There was a problem hiding this comment.
Should be "require('babel-polyfill')"
There was a problem hiding this comment.
lol almost forgot why it was 2 messages in the first place then
README.md
Outdated
| ### `useBuiltIns` | ||
|
|
||
| `boolean`, defaults to `false`. | ||
| `boolean`, defaults to `true`. |
There was a problem hiding this comment.
maybe consider with entry option?
There was a problem hiding this comment.
what do you mean? I have #### useBuiltIns: 'entry' below
There was a problem hiding this comment.
entry is a string, maybe boolean | "entry"?
|
👏 |
https://twitter.com/left_pad/status/847911365645938690
Ref #84
TL;DR: automatically add polyfills based on actual usage in the file (check the presence of
Promise), and remove any polyfills supported by the target environment (Chrome 55 already supportsPromise). Check the tests in this pr for more examples!Size savings: if you don't use any polyfills in your code: then none will be added. If you do use polyfills, only the ones not supported in your target environment will be added.
Examples
Older browser (like IE): imports are added
Modern browser (Chrome 58): no imports added
astexplorer live example (only the adding part): http://astexplorer.net/#/gist/dc031f702921a727ec5f82c2bc3341b0/6b87729fb2ed77e8512c0b137e8a3c19dbcdc63c
The only issue not covered in #84 (comment) is regarding the rest of node_modules (3rd party).
Basically the issue is that if you don't use
Promisein any of the code that you run Babel on, this option doesn't know to include thePromisepolyfill if a library you use needs it.A workaround is a disclaimer of the option and to use
includesinstead. We can even warn if you include but it's natively supported.Not sure about the option name, or if we should making a breaking change for it. It does seem like this should be opt-in since it doesn't know about the use of polyfills in 3rd party modules unless you run babel over those too
useBuiltIns: "entry"