Closed LinusBorg closed 6 years ago
Yes this is a big issue for me.
I use Vuetify and it relies on some new features like Object.values()
which I don't use and without including all babel polyfills in main.js, my app breaks in IE.
And including all babel polyfills adds up a weight of around 34 KB gzipped which is costly.
But I also faced an issue where I use Promise.finally
in my code but it doesn't get included at all in polyfills, no matter what I do. I had to rely on polyfill service for that, and so I disabled all babel polyfills and just relied on the service.
May be I did something wrong, but didn't change any cli3 configs, it just doesn't work out of the box for Promise.finally
Promise.finally is a stage4 proposal, it's not officially standard yet. and I babel-preset-env only polyfills things that are in the standard right now, as far as I understand it.
you can probably use the include
option to force adding such a polyfill.
I'm not sure but what does following part mean in @vue/babel-preset-app/index.js
Doesn't it mean that it will include all proposals from stage 2 and above?
// stage 2. This includes some important transforms, e.g. dynamic import
// and rest object spread.
presets.push([require('@babel/preset-stage-2'), {
loose,
useBuiltIns: useBuiltIns !== false,
decoratorsLegacy: decoratorsLegacy !== false
}])
Doesn't it mean that it will include all proposals from stage 2 and above?
It will include all babel-transform
plugins for stage two, not polyfills. Those are two different things.
Thanks man. You comment and you know things !!😄
By the way how do we explicitly add stage x polyfills gracefully with vue-cli 3?
the most easy way would be to import them from core-js
which babel-polyfill uses under the hood):
import 'core-js/fn/promise/finally'
// https://github.com/zloirock/core-js/blob/master/fn/promise/finally.js
With useBuiltIns: 'entry'
and the default browsers target it bloats the hello world app by about 24kb gzipped (vendor chunk size: 21.86kb vs 45.49.kb), which is a lot, especially when a large chunk of them may end up not used at all. I'm not sure if this is something we should use as the default.
Speaking of dependencies, isn't it a convention for any library to clearly state its browser compatibility requirements?
If a dependency ships code that is ES5, then it doesn't quite make sense for it to use any ES6-only built-ins (except for Promises).
If a dependency ships ES6 code, then we should explicitly transpile it (with the new transpileDependencies
option) which will trigger polyfill detection on it with useBultIns: 'usage'
.
I think it's quite rare for a dependency to (1) ship ES5 code that doesn't need transpilation and (2) at the same time requires some ES6 only polyfill to work (again, excluding Promise).
So I think the saner default would be:
include a number of commonly needed polyfills by default (Promise
, Object.assign
). This should cover most use cases (e.g. Vuex). In addition these should only be included if they are actually needed for the project's browserslist
targets.
For dependencies that does not work in the target environment, the user should explicitly include it in transpileDependencies
, which would handle both syntax and polyfills.
In the rare case where a dependency ships ES5 code but requires ES6 polyfills, the user need to explicitly include the polyfills.
I see the issue concerning the bundle size, definitely a problem.
If we keep usage
as the default, we will have to make sure that users understand the implications.
I think it's quite rare for a dependency to (1) ship ES5 code that doesn't need transpilation and (2) at the same time requires some ES6 only polyfill to work (again, excluding Promise).
A prominent example would be Vuetify - I think their use of Object.values()/entries()
was what made me aware of the issue.
In a perfect world, packages that provide ES5 would also make sure not to use Es6 features that require polyfills, or if they do, make sure to explain that - and indeed, Vuetify does so:
https://vuetifyjs.com/en/getting-started/quick-start
But my experience is that there are many developers out there that don't understand the intricacies of of how babel-preset-env works regarding polyfills (for beginners it's even hard to undestand the differences between tranforms and polyfills), so once reading that vue-cli included polyfills, they often think they are fine - "what should be left to do? polyfills are already included!".
Vue-cli's promise it to abstract way the dependencies and configuration, so it's understandable people don't feel the need to instantly learn in detail how all the moving parts that the cli covers for them work.
So in short: yes, I agree we can keep usage
for the sake of bundle-size, but then we have to make people aware what that means.
I think it's problematic for Vuetify to rely on Object.entries()
and Object.values()
which are pretty new additions (ES2017) - they provide marginal value but complicate the user polyfill requirements. /cc @johnleider
I'll take a look at the scope of this.
Looks like Vuetify relies on too many ES6+ built-ins to be special-cased for, so I think Vuetify users should just manually opt-in to useBuiltIns: 'entry'
+ @import '@babel/polyfill
.
This is what we have setup on our cli plugin https://github.com/vuetifyjs/vue-cli-plugin-vuetify/blob/dev/generator/index.js#L67 . So I think that covers it.
@johnleider ah cool. Yeah that covers it.
I intend to keep the default for now (with Promise
included by default as it is required by Vuex and most ajax clients). We will have a dedicated section in docs talking about browser targets and polyfills etc.
is this issue solved?
according this guide: https://cli.vuejs.org/guide/browser-compatibility.html#polyfills
if I set transpileDependencies: ['pretty-ms']
in vue.config.js
,
webpack warn me
"export 'default' (imported as 'prettyMs') was not found in 'pretty-ms'
with
import prettyMs from 'pretty-ms'
statement.
if use const prettyMs = require('pretty-ms')
instead, seems to solve the problem.
but both show this error in browser: Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
(highlighted code throw error)
I just took a look at that repository, there's no reason to add it to transpileDependencies, it contains no es6 code?
arrow function and constants declaration?
pretty-ms
source: https://github.com/sindresorhus/pretty-ms/blob/master/index.js
Oh, must have been blind for a second...
um, I'm not sure this would be a solution, but solved my problem.
I create a new project using webpack template and enforce included all dependencies
defined in package.json
to babel-loader
, and set preset-env to modules: commonjs
.
this make babel detect all used modules, also include promise polyfill for vuex automatically, and transpile all es6 imports into commonjs.
webpack template demo: https://gitlab.com/MiausF2E/F_2_E-todo/
OK, I got it.
vue-cli require a minor hack, set process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true
to ask @vue/babel-preset-app
to transpile modules into commonjs.
vue-cli demo: https://gitlab.com/MiausF2E/f2e-todos-cli-demo
Looks like Vuetify relies on too many ES6+ built-ins to be special-cased for, so I think Vuetify users should just manually opt-in to
useBuiltIns: 'entry'
+@import '@babel/polyfill
.
Guys I've tryied many solution and nothing seems to work. Still have blank pages in EDGE (no errors) and IE11 (error: &
Do you have any ideas what is wrong?
What problem does this feature solve?
The current implementation of our bable preset sets the
useBuiltIns
option of the`babel-preset-env
preset tousage
:https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/babel-preset-app/index.js#L19
What that means it that only feature that babel comes across during transpilation are actually polyfilled.
The good
This is awesome since it keeps unnecessary polyfills out of our app
the bad
It's bad because any code in
node_modules
that relies on a poylfill requires the developer to manually inlcude this polyfill in i.e.main.js
so it's picked up by babel. This is because we don't run/node_modules
contents through babel, so theusage
options doesn'T pick up the featureThe alternative
I think the current default is resulting in bad dev UX, because the dev has to know and understand about the way that
usage
works.As an alternative, I propose to select
entry
as the defsault value foruseBuiltIns
.The good
Now all features necessary for the targeted browsers will be polyfilled. That ensures that all code from
/node_modules
relying on a feature that we ourselves don't use will work nonetheless.The bad
Unnecessary polyfills might be included. To allow the dev to optimize this, we could document how he could switch to
usage
polyfilling and what the implications are.What does the proposed API look like?
https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/babel-preset-app/index.js#L19:
https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/generator/template/src/main.js