parcel-bundler / parcel

The zero configuration build tool for the web. šŸ“¦šŸš€
https://parceljs.org
MIT License
43.28k stars 2.25k forks source link

JS Transformer does not correctly polyfill new `core-js` features #9769

Open ChristophP opened 1 month ago

ChristophP commented 1 month ago

šŸ› bug report

The JS transformer with swc under the hood allows tranforming core-js imports into the needed polyfills for the targeted browsers. Due to this bug the needed polyfills do not get included correctly resulting in errors for users with older browsers. I believe this affects anyone trying to polyfill features from core-js that aren't in core-js 3.0.

(I already started a discussion about this but after investigating I was inclined to believe it is a bug)

šŸŽ› Configuration (.babelrc, package.json, cli command)

This is a reproduction example but I think it applies to all newer features polyfilled by core-js. So let's try to polyfill structuredClone, which was added in core-js 3.24 (-ish)

1. Create the following files in an empty directory

.browserslistrc

safari 15.3

package.json

{
  "devDependencies": {
    "core-js": "^3.37.1",
    "parcel": "^2.12.0"
  }
}

index.ts

import "core-js/stable/structured-clone";

console.log(structuredClone({}));

2. Install deps and compile

npm i
npx parcel build index.ts --no-optimize

3. Check the output of dist/index.js

(() => {
console.log(structuredClone({}));

})();
//# sourceMappingURL=index.js.map

The polyfill for structuredClone is not added even though it is needed in Safari 15.3 according to can-i-use.

šŸ¤” Expected Behavior

The polyfills for unsupported features for the target browsers should be included in the output compiled by parcel.

šŸ˜Æ Current Behavior

The polyfills for unsupported features for the target browsers are NOT included in the output compiled by parcel.

šŸ’ Possible Solution

This is not a final solution but I believe this is a hint of where the problem lies. When playing around with the swc playground (since swc is used in the JS transformer) I noticed that the coreJs option is not set.

According to the swc docs it needs to be set with the minor version. Otherwise for example 3 will default to 3.0

It is recommended to specify the minor version (E.g. "3.22") otherwise "3" will be interpreted as "3.0" which may not include polyfills for the latest features.

This swc playground supports this hypothesis. You can see how the polyfill is correctly included in the output,

grafik

but when editing the options via the Edit as JSON button and remove or edit the coreJs option from "3.37" to "3", it is no longer included.

grafik

When set to "3.37" the polyfill is correctly included.

So the solution could be to make sure that parcel sets the core_js Option on the present_env_config struct to the currently installed Version of core-js including the minor version.

šŸ”¦ Context

Finding errors in older but supported browsers for features that should have been polyfilled.

šŸ’» Code Sample

See above and here

šŸŒ Your Environment

Software Version(s)
Parcel 2.12.0
Node 20
npm/Yarn npm 10
Operating System Linux and MacOS
ChristophP commented 1 month ago

Additional troubleshooting info

Setup

Run this script which creates a folder with 3 files (.swcrc, package.json, index.ts) setup a test sample for comparing swc and parcel results for expanding core-js imports

mkdir swc-parcel-comparison
cd swc-parcel-comparison

echo '{
  "$schema": "https://swc.rs/schema.json",
  "env": {
    "targets": "safari 15.3",
    "mode": "entry",
    "coreJs": "3.37.1"
  },
  "minify": false
}' >.swcrc

echo '{
  "name": "swc-parcel-test",
  "scripts": {
    "swc": "swc index.ts",
    "parcel": "parcel build index.ts --no-optimize && cat dist/index.js"
  },
  "browserslist": "safari 15.3",
  "devDependencies": {
    "@swc/cli": "^0.3.12",
    "@swc/core": "^1.5.29",
    "parcel": "^2.12.0"
  }
}' >package.json

echo 'import "core-js/stable/object/has-own"
import "core-js/stable/structured-clone"

console.log(42);
' >index.ts

Compare SWC and Parcel output

Now run the following and compare the outputs of swc and parcel. You will find that swc does expand the core-js imports while parcel does not

cd swc-parcel-comparison
npm install
npm run swc
npm run parcel