When @babel/preset-env targets an older browser environment (e.g., chrome >= 52) that lacks native support for the new URL(..., import.meta.url) syntax, it injects a polyfill for the URL constructor from core-js. This polyfilled URL constructor interferes with Webpack's static analysis for Web Workers, which specifically looks for the new URL(...) pattern.
As a result, Webpack fails to create a separate chunk for the worker. Instead, the core-js polyfill is invoked with an incorrect, non-functional path, causing the worker instantiation to fail at runtime.
Environment
@babel/core: ^7.24.7
@babel/preset-env: ^7.24.7
webpack: ^5.91.0
babel-loader: ^9.1.3
core-js-pure: ^3.43.0
babel-plugin-polyfill-corejs3: ^0.12.0
Steps to Reproduce
A full reproduction repository is available here: https://github.com/gregaou/example-babel-polyfill-workers
- Clone the repository.
- Ensure the
.browserslistrc file targets an older browser:
- Install dependencies (
npm install or yarn).
- Run the build (
npm run build or yarn build).
- Inspect the generated output in
dist/.
Expected Behavior
When targeting a modern browser like chrome >= 67 (where new URL(..., import.meta.url) is natively supported), Babel does not polyfill URL. Webpack correctly identifies the syntax and generates a functional worker loader:
// Correct output for modern targets
const newFibWorker = new Worker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("src_worker_ts-_..."), __webpack_require__.b));
This code works as expected.
Actual Behavior
When targeting chrome >= 52, @babel/preset-env injects the core-js polyfill for URL. The resulting code in the bundle looks like this:
// Incorrect output for older targets
const newFibWorker = new Worker(new (core_js_pure_stable_url_index_js__WEBPACK_IMPORTED_MODULE_2___default())('./worker.ts', "file:///.../src/index.tsx"));
This fails at runtime because:
- The
new URL(...) syntax that Webpack's parser looks for has been replaced.
- The
core-js polyfill is invoked with a file-system path (import.meta.url is transpiled to a file path), which is not a valid base for creating a worker URL in the browser.
When
@babel/preset-envtargets an older browser environment (e.g.,chrome >= 52) that lacks native support for thenew URL(..., import.meta.url)syntax, it injects a polyfill for theURLconstructor fromcore-js. This polyfilled URL constructor interferes with Webpack's static analysis for Web Workers, which specifically looks for the new URL(...) pattern.As a result, Webpack fails to create a separate chunk for the worker. Instead, the
core-jspolyfill is invoked with an incorrect, non-functional path, causing the worker instantiation to fail at runtime.Environment
@babel/core:^7.24.7@babel/preset-env:^7.24.7webpack:^5.91.0babel-loader:^9.1.3core-js-pure:^3.43.0babel-plugin-polyfill-corejs3:^0.12.0Steps to Reproduce
A full reproduction repository is available here: https://github.com/gregaou/example-babel-polyfill-workers
.browserslistrcfile targets an older browser:npm installoryarn).npm run buildoryarn build).dist/.Expected Behavior
When targeting a modern browser like
chrome >= 67(wherenew URL(..., import.meta.url)is natively supported), Babel does not polyfillURL. Webpack correctly identifies the syntax and generates a functional worker loader:This code works as expected.
Actual Behavior
When targeting
chrome >= 52,@babel/preset-envinjects thecore-jspolyfill forURL. The resulting code in the bundle looks like this:This fails at runtime because:
new URL(...)syntax that Webpack's parser looks for has been replaced.core-jspolyfill is invoked with a file-system path (import.meta.urlis transpiled to a file path), which is not a valid base for creating a worker URL in the browser.