-
-
Notifications
You must be signed in to change notification settings - Fork 158
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bug: not transformed due to program.exit
@@ -0,0 +1,108 @@ | |||
export const definitions = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically the opposite of built-in-features.js so maybe can just reverse it somehow
src/index.js
Outdated
plugins.push([transformPolyfillRequirePlugin, { polyfills, regenerator }]); | ||
} else if (addUsedBuiltIns) { | ||
plugins.push([addUsedBuiltInsPlugin, { polyfills, regenerator }]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
README.md
Outdated
|
||
> 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth adding a note this was the behavior in 1.x?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addUsedBuiltIns
-> useBuiltIns: true
(same on L84)
src/normalize-options.js
Outdated
@@ -76,6 +76,6 @@ export default function normalizeOptions(opts) { | |||
loose: validateLooseOption(opts.loose), | |||
moduleType: validateModulesOption(opts.modules), | |||
targets: opts.targets, | |||
useBuiltIns: opts.useBuiltIns, | |||
useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
breaking: default to true!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe convert this to a destructure with a default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Along with opts.target and opts.debug
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since the 7.0 babel-polyfill will have core-js modules in it we can just target that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
README.md
Outdated
npm install babel-polyfill --save | ||
``` | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stray debug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The debug flag is used in the plugin =>
babel-preset-env/src/use-built-ins-plugin.js
Line 142 in ebf77d8
state.opts.debug && warnOnInstanceMethod(getObjectString(node)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -76,6 +76,6 @@ export default function normalizeOptions(opts) { | |||
loose: validateLooseOption(opts.loose), | |||
moduleType: validateModulesOption(opts.modules), | |||
targets: opts.targets, | |||
useBuiltIns: opts.useBuiltIns, | |||
useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe convert this to a destructure with a default?
src/normalize-options.js
Outdated
@@ -76,6 +76,6 @@ export default function normalizeOptions(opts) { | |||
loose: validateLooseOption(opts.loose), | |||
moduleType: validateModulesOption(opts.modules), | |||
targets: opts.targets, | |||
useBuiltIns: opts.useBuiltIns, | |||
useBuiltIns: opts.useBuiltIns === undefined ? true : opts.useBuiltIns, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok #241 (comment). Yeah we could check strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'l use path.evaluate
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}']`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be res.value
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah forgot to change 👍
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be "require('babel-polyfill')"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol almost forgot why it was 2 messages in the first place then
README.md
Outdated
@@ -176,21 +174,60 @@ This option is useful for "blacklisting" a transform like `transform-regenerator | |||
|
|||
### `useBuiltIns` | |||
|
|||
`boolean`, defaults to `false`. | |||
`boolean`, defaults to `true`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe consider with entry
option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean? I have #### useBuiltIns: 'entry'
below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
Promise
in any of the code that you run Babel on, this option doesn't know to include thePromise
polyfill if a library you use needs it.A workaround is a disclaimer of the option and to use
includes
instead. 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"