Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parcel does not include polyfill for older browsers even when browserslist is declared in the package.json #7419

Open
SukkaW opened this issue Dec 8, 2021 · 21 comments
Labels
Stale Ignore This issue is exempt from getting flagged as stale and autoremoved swc

Comments

@SukkaW
Copy link
Contributor

SukkaW commented Dec 8, 2021

馃悰 bug report

RT.

馃帥 Configuration (.babelrc, package.json, cli command)

Reproduction: https://github.com/SukkaW/parcel-issue-7419/

馃 Expected Behavior

Parcel should include corresponding polyfills for cutting edge JavaScript features (like WeakMap, Set and Object.fromEntries) from core-js, which is a dependency of @parcel/config-defaults.

SWC Playground

馃槸 Current Behavior

Parcel doesn't include any polyfill at all, even though browserslist is declared in the package.json.

馃拋 Possible Solution

Really? swc already handle this correctly. You guys just don't use coreJs and mode: usage option by default? And you are telling me the parcel can be used with zero-configuration?

馃捇 Code Sample

https://github.com/SukkaW/parcel-issue-7419/

馃實 Your Environment

Software Version(s)
Parcel 2.0.1
Node Node 17.2.0
npm/Yarn 8.1.3
Operating System macOS 12.0.1
@astegmaier
Copy link
Contributor

astegmaier commented Dec 9, 2021

It looks like swc won't add polyfills automatically unless you set it's mode setting to "usage" (see docs). Compare this swc playground where mode = "usage" to this playground where mode = undefined.

Does parcel provide a way for users to supply their own .swcrc, or to tweak the mode setting? If not, maybe it should? (Or at least some note in the docs saying that parcel does not polyfill automatically, and a suggestion on the right way to do this). I was personally surprised that it didn't do this by default - although I guess there are some reasons for it.

@SukkaW
Copy link
Contributor Author

SukkaW commented Dec 11, 2021

It looks like swc won't add polyfills automatically unless you set it's mode setting to "usage" (see docs). Compare this swc playground where mode = "usage" to this playground where mode = undefined.

Does parcel provide a way for users to supply their own .swcrc, or to tweak the mode setting? If not, maybe it should? (Or at least some note in the docs saying that parcel does not polyfill automatically, and a suggestion on the right way to do this). I was personally surprised that it didn't do this by default - although I guess there are some reasons for it.

I am surprised as well since Parcel's documentation says will transpile your code accordingly to ensure compatibility with your supported browsers, as well as core-js is already in the @parcel/config-defaults's dependencies.

@folknor
Copy link

folknor commented Dec 14, 2021

browserslist doesn't really work at all anyway, see #6749

@SukkaW
Copy link
Contributor Author

SukkaW commented Dec 14, 2021

browserslist doesn't really work at all anyway, see #6749

Maybe that's why core-js is already part of the dependencies but is not used. I haven't checked the source code of parcel yet.

@mischnic mischnic added the swc label Dec 15, 2021
@yume-chan
Copy link

Actually, parcel passed "mode": "entry" to swc

preset_env_config.mode = Some(Entry);

swc doc doesn't say what does "mode": "entry" do, but it says "this matches useBuiltIns from Babel", and babel doc says

This option enables a new plugin that replaces the mport "core-js/stable"; and import "regenerator-runtime/runtime" statements (or require("core-js") and require("regenerator-runtime/runtime")) with individual requires to different core-js entry points based on environment.

So you can install core-js and import it from entry point, and parcel (swc) will only include required parts of it for the browserslist you specified.

@yume-chan
Copy link

yume-chan commented Jan 18, 2022

I also tried changing it to Usage, it works, and the produced code size is much smaller.

I don't want to open a PR before someone from parcel team explains why they choose entry over usage.

EDIT: It builds, but throws runtime error. Look like it causes circular dependency in core-js, still investigating...

@mischnic
Copy link
Member

The reason that we don't use usage is that its detection of used language features isn't that accurate. So this should work:

So you can install core-js and import it from entry point, and parcel (swc) will only include required parts of it for the browserslist you specified.

@avalanche1
Copy link

Have stumbled into this issue. Does this mean, that the official doc is misleading?
https://parceljs.org/getting-started/webapp/#declaring-browser-targets

My use case
package.json:

  "browserslist": [
    "last 10 Chrome versions"
  ]

index.js:

// introduced since Chrome 97
console.log(Array.prototype.findLast);

Parcel will not include any polyfill into the output code.

@avalanche1
Copy link

The reason that we don't use usage is that its detection of used language features isn't that accurate. So this should work:

So you can install core-js and import it from entry point, and parcel (swc) will only include required parts of it for the browserslist you specified.

@mischnic unfortunately, it doesnt.
When I do this - my bundle size is 634kb (with --no-optimize --no-scope-hoist)

import "core-js/actual";
console.log(Array.prototype.findLast);

So, it clearly bundles the whole of core-js.


When I do this - my bundle size is 55kb; here only the findLast polyfill is bundled.

import "core-js/actual/array/find-last";
console.log(Array.prototype.findLast);

@kkirby
Copy link
Contributor

kkirby commented Mar 30, 2022

@avalanche1 As far as I can tell, this is actually working mostly as expected. The core-js modules that are included is based on what is in your package.json:browserslist value. If you set it to chrome 99 then the included polyfills will be substantially less. In my case, the resulting bundle was 51.81 KB with --no-optimize --no-scope-hoist. If I change the browserslist to be IE 6, then the resulting bundle is 654.59 KB. Quite a big difference.

Interestingly, in my opinion 51 KB is quite big for targeting only Chrome 99. Upon investigation, it appears that swc isn't quite smart enough to remove polyfills that are depended on by core-js itself. For example, Chrome 99 includes the web.immediate module, when in turn requires object-get-own-property-descriptor despite not actually needing it in chrome 99.

This is the require hierarchy:

core-js/actual
  core-js/stable
    core-js/modules/web.immediate
      core-js/internals/export
        core-js/internals/object-get-own-property-descriptor
          core-js/internals/ie8-dom-define			

Though, since these are internals and not modules, maybe there's a specific reason they aren't removed. Regardless, I don't think this is such a big deal since when you optimize the build, the file size is significantly smaller at 10.21 KB for Chrome 99, and 111.44 KB for IE 6.

@SukkaW
Copy link
Contributor Author

SukkaW commented Aug 14, 2022

The reason that we don't use usage is that its detection of used language features isn't that accurate. So this should work:

So you can install core-js and import it from entry point, and parcel (swc) will only include required parts of it for the browserslist you specified.

@mischnic The swc has evolved and the detection is now accurate (since 1.2.220). Does the parcel team have a plan to adopt it (and solve the issue)?

@folknor
Copy link

folknor commented Aug 14, 2022

1.2.220 was 17 days ago and https://github.com/swc-project/swc/blob/cdb9bbd707b776d43c4c885a98757be8d57914a4/crates/swc_ecmascript/Cargo.toml was 6 days ago, so #8390 might fix it then? Frankly I have no clue.

@SukkaW
Copy link
Contributor Author

SukkaW commented Aug 14, 2022

1.2.220 was 17 days ago and https://github.com/swc-project/swc/blob/cdb9bbd707b776d43c4c885a98757be8d57914a4/crates/swc_ecmascript/Cargo.toml was 6 days ago, so #8390 might fix it then? Frankly I have no clue.

Although the parcel would bump the swc, it still has to enable mode: 'usage' in order to fix the issue.

@gillyspy
Copy link

gillyspy commented Sep 30, 2022

what's the best workaround for this? back to having babel but running parcel to pickup a babel.config.json ? This does work but wonder what is working for others

{
  "presets": [
    [
      "@parcel/babel-preset-env",
      {
        "targets": {
          "chrome": "69"
        },
        "useBuiltIns": "usage",
        "corejs": "3.6.9"
      }
    ]
  ]
}

@Drapegnik
Copy link
Contributor

@devongovett @mischnic, any updates on this? Maybe you should fix documentation (at least add link to this issue)

https://parceljs.org/languages/javascript/#browser-compatibility

You can declare your app鈥檚 supported browsers using the browserslist field in your package.json. When this field is declared, Parcel will transpile your code accordingly to ensure compatibility with your supported browsers.

It doesn't working as expected, misleading and people waste time trying to setup parcel to work correctly

@devongovett
Copy link
Member

Transpilation means syntax is compiled. It doesn't say anything about runtime polyfills.

@SukkaW SukkaW changed the title Parcel does not perform transpilation of JavaScript syntax for older browsers even when browserslist is declared in the package.json Parcel does not include polyfill for older browsers even when browserslist is declared in the package.json Nov 15, 2022
@SukkaW
Copy link
Contributor Author

SukkaW commented Nov 15, 2022

Transpilation means syntax is compiled. It doesn't say anything about runtime polyfills.

@devongovett

I have just updated the issue title to Parcel does not include polyfills for older browsers. The title should be accurate now.

Also FYI, the swc has evolved and the mode: usage detection is now accurate (Shout out to @Austaras. He has fixed this in swc 1.2.220).

@sarkacodes
Copy link

Just a sidenote, but I think Parcel docs are at least a little bit misleading when it says this (in the Browser compatibility section):

When this field is declared, Parcel will transpile your code accordingly to ensure compatibility with your supported browsers.

Compare with Vite docs (also the Browser compatibility section) where you can find the info about polyfills straightaway:

Note that by default, Vite only handles syntax transforms and does not cover polyfills by default.

Of course Parcel docs talk about transpilation only, but I'm not sure if many people make that connection.

@devongovett
Copy link
Member

devongovett commented Nov 27, 2022

Also FYI, the swc has evolved and the mode: usage detection is now accurate

Maybe it has improved, but I don't believe it is possible for mode: 'usage' to be fully accurate without a type checker. For example, core-js includes polyfills for builtin methods like String.prototype.includes. In order to detect when to include this, they'd need to look for any call of any method named includes on any object. Without type information, it's not possible to know whether the target is a string or not. This leads to including way too many polyfills, bloating the bundle. In addition, there are ways of accessing methods that are not statically analyzable, leading to polyfills not being included. Therefore, I'm not sure usage detection is a very good idea.

I think it's better to manually include polyfills either by importing core-js and letting Parcel/SWC include all polyfills needed for your environment, or just including the ones you need. The latter will result in the smallest bundle size.

@SukkaW
Copy link
Contributor Author

SukkaW commented Nov 28, 2022

Therefore, I'm not sure usage detection is a very good idea.

Yeah, I totally agree with that.

However, Babel's @babel/preset-env provides useBuiltIns: 'usage' option and can be enabled in its configuration.
Although it might not be a good idea to enable it by default, IMHO it should be made configurable through .parcelrc.

@blipper
Copy link

blipper commented May 29, 2023

So what is the current recommended solution here?

@github-actions github-actions bot removed the Stale Inactive issues label May 29, 2023
@mischnic mischnic added the Stale Ignore This issue is exempt from getting flagged as stale and autoremoved label May 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Stale Ignore This issue is exempt from getting flagged as stale and autoremoved swc
Projects
None yet
Development

No branches or pull requests