[] tsOptimizer: three codegen defects (param renamed to _rawProps, duplicate `context` binding, invalid destructuring)
Summary
Enabling the TypeScript optimizer (qwikVite({ tsOptimizer: true })) on main at c25867def produces three distinct codegen defects in our app. Two of them occur in entirely ordinary source with no user-side workaround.
We reached for tsOptimizer as a way around #9012 (the Rust optimizer's duplicate _defaultValue consts). It does avoid that, but the build then fails on the issues below. Filing separately from #9012 since the cause is unrelated.
I see 3dfe6f9fc fix(qwik-vite): restore Rust optimizer default reverted it as the default, and 0fb2c6a80 test(ts-optimizer): require full rust parity suggests parity is a known work item — so this is offered as three concrete parity gaps rather than a regression report.
All three come from the same area: the destructuring-elimination pass emits binding names that are either non-unique or syntactically invalid.
Reproduction
- Qwik
main@c25867def4d2a11d84f8497925771789e04ce298(tarballs from pkg.pr.new self-report2.0.0-beta.43) - Vite 8 (Rolldown), Qwik Router,
pnpm
// vite.config.mts
qwikVite({ tsOptimizer: true })then build the app. Note Rolldown reports a batch of errors and stops, so the three below are a floor, not necessarily the full set.
1. A nested $-segment's destructured callback param is treated as component props
Source — a useComputed$ with a destructured ctx param, inside a component$ that destructures its own props:
export const WalletModalWithdraw = component$<Props>(({ isOpen, initialFee, ... }) => {
const networkFee = useComputed$(async ({ track }) => {
const open = track(() => isOpen?.value ?? true);
// ...
});
});Generated (segment s_cGRGAVNcn80):
export const s_cGRGAVNcn80 = async (_rawProps) => {
const _rawProps = _captures[0], initialFee = _captures[1], selectedSignal = _captures[2];
const open = _rawProps.track(() => _rawProps.isOpen?.value ?? true);The callback's { track } parameter has been renamed to _rawProps, which (a) collides with the _rawProps declared on the next line from the capture list, and (b) is semantically wrong — it now reads track off the component's props rather than off the computed context.
This one does have a user-side workaround: write async (ctx) => ctx.track(...) instead of destructuring the ctx param.
2. Two useContext results renamed to the same identifier
Source — ordinary, no Qwik-specific shape involved:
const { wallets, activeCode, setCode$ } = useContext(WalletsContextId);
const coinIcons = useContext(CoinIconMapContextId);
const { user, isAuthenticated } = useContext(SessionContextId);Generated — two separate declarations collapse onto the same name in one scope:
const context = useContext(WalletsContextId);
// ...
const context = useContext(SessionContextId);Identifier 'context' has already been declaredNo user-side workaround.
3. Syntactically invalid destructuring emitted
Source — two rest-destructures of props in different blocks of the same component:
const { loadingBenefitWidths, className, ...rest } = props;Generated:
const { loadingBenefitWidths, className: props.className, ...rest } = props;className: props.className is not a valid destructuring binding — the value position of a shorthand rename must be an identifier or pattern, not a member expression.
No user-side workaround.
Environment
- Qwik:
main@c25867def(2.0.0-beta.43) @qwik.dev/router: same SHA- Vite: 8.x (Rolldown)
- Node 22, pnpm 10.17, macOS arm64
Happy to provide a minimal reproduction repo for any of the three if that would help — 2 and 3 in particular look like they should reduce to a few lines.
Source: QwikDev/qwik