fix(turbopack): handle unresolvable browserslist via Targets::Query#92244
fix(turbopack): handle unresolvable browserslist via Targets::Query#92244mhdsdt wants to merge 2 commits into
Conversation
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
This comment was marked as spam.
This comment was marked as spam.
Merging this PR will not alter performance
Comparing Footnotes
|
|
@afurm Good call, added that in the second commit. There's now a snapshot test under |
|
This looks good, but you'll need to rebase this onto canary, #92272 was merged in the meantime |
9de4d06 to
051eed3
Compare
Rebased onto canary. The changes in #92272 touched the same match arm, so I wrapped the new preset-env config parsing inside the else branch of our Verified locally: cargo check, fmt, clippy all clean. All 3 preset_env snapshot tests pass. Also rebuilt the SWC binary against the rebased branch and confirmed the reproduction project still renders without the panic. |
|
Now, |
When `browserslist-rs` returns an empty distrib list (e.g. the user wrote `chrome 99999`, or the bundled caniuse-lite is older than the JS-side data), `Versions::parse_versions` produces an all-`None` result. SWC's preset-env treats all-`None` as `is_any_target == true` and short-circuits its caniuse logic to "transform every feature", which then panics in `swc_ecma_compat_es2015::generator` on unsupported nodes such as `**`. Detect that case and re-route the resolution through `Targets::Query` using the original browserslist string from `Environment::browserslist_query`. SWC's own `targets_to_versions` then runs the query, observes the empty result, and sets `unknown_version: true` — the documented "modern browser, supports everything" semantics introduced in swc-project/swc#11457. All user-supplied `swcEnvOptions` (`mode`, `coreJs`, `include`, `exclude`) continue to flow through to SWC, which decides how to honor them.
Cover the case where `browserslist-rs` returns an empty result for an unrecognized version like `chrome 99999`. Without the accompanying fix, preset-env panicked here with the generator transform's `todo!()` for right-associative binary expressions (`**`).
051eed3 to
e7c2e28
Compare
Good point, thanks. Reworked the fix so we don't skip preset-env anymore. When All of New version is pushed and the title/description are updated to match. Verified locally with cargo check, fmt, clippy, the full snapshot suite, and against the reproduction project (page renders with the |
Fixes #92091
What?
When a project has a browserslist like
>0.2%, not dead(the CRA default), Turbopack panics withnot yet implemented: right-associative binary expressionon any code that usesasync+**together.Why?
Next.js resolves the browserslist on the JS side using an up-to-date
caniuse-lite(which knows about Chrome 146, Firefox 149, etc.), then sends the resolved browser strings to Turbopack. Turbopack re-resolves them usingbrowserslist-rsv0.19.0, which only knows up to about Chrome 141. Unknown versions are silently dropped because ofignore_unknown_versions: trueinenvironment.rs.With all versions dropped,
Versions::parse_versionsreturns all-Nonefields. SWC'spreset_envthen seesis_any_target() == trueand short-circuits itscaniuseto "transform every feature", which includesasync-to-generatorand the ES2015 generator transform — and that transform has atodo!()for the**operator atgenerator.rs:507.SWC already handles this case for the raw browserslist path via the
unknown_versionflag added in swc-project/swc#11457. But Turbopack bypasses that flag because it passes pre-resolvedTargets::Versions(versions)directly, andtargets_to_versionsalways setsunknown_version: falseon that variant.How?
When
versions.is_any_target()is true and a browserslist query string is available on theEnvironment, re-route throughTargets::Query(Query::Single(query))instead ofTargets::Versions(empty). SWC's own resolver runs the query, observes the empty result, and setsunknown_version: true— the documented "modern browser, supports everything" semantics from swc#11457.The user's
experimental.swcEnvOptions(mode,coreJs,include,exclude,shippedProposals,forceAllTransforms,debug,loose) continue to flow through to SWC'sConfigunchanged, so SWC remains the source of truth for how those options interact withunknown_version.Test plan
swc_transforms/preset_env_unknown_browserslistcovers an explicitchrome 99999query. Without the fix it panics on the sametodo!(); with the fix theasync function ... return 10n ** 18nis preserved verbatim in the chunk output.next dev --turbopack, page renders with status200, and the emitted chunk contains the originalasync function compute() { return 10n ** 18n; }with no transforms applied.cargo check,cargo fmt --check,cargo clippy --all-targets -- -D warnings, and the fullturbopack-testssnapshot suite all clean.