Subscribe on changes!

SFC compiler: optional chaining generates different event

avatar
Jul 12th 2021

Version

3.1.4

Reproduction link

https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8ZGl2IEBjbGljaz1cImEuYlwiPkNsaWNrICh3b3Jrcyk8L2Rpdj5cbiAgPGRpdiBAY2xpY2s9XCJhPy5iXCI+Q2xpY2sgKGJyb2tlbik8L2Rpdj5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQgc2V0dXA+XG5jb25zdCBhID0ge1xuICBiKCkgeyBhbGVydChcIndvcmtzXCIpIH1cbn1cbjwvc2NyaXB0PiJ9

Steps to reproduce

Click on the repro divs, one works, the other doesn't.

The reason why is evident if you look at the generated JS code. SFC compiler handles event listeners that are an expression, such as a.b, as functions themselves and invokes (...args) => a.b && a.b(args) It does not consider a?.b to be such an expression, though, and invokes () => a?.b.

What is expected?

Both works

What is actually happening?

Only first link works


You could take this opportunity to optimise generated code a.b && a.b(...args) into a.b?.(...args). Not only is the latter shorter, it also evaluates the first part only once, which might be relevant if there are side-effects -- and one common side-effect is reactivity tracking, so it's just more performant.

Downside: if targeting a browser that doesn't support optional chaining, the code needs to be transpiled. With evergreen broswers, everybody supports it nowadays (Chrome 80, FF 74, Safari 13.1): https://caniuse.com/mdn-javascript_operators_optional_chaining

PS: The issue creation app replaces + with everywhere, including in the repro link and that breaks links to sfc.vuejs.org.

avatar
Jul 13th 2021

source:

transformOn
      const isMemberExp = isMemberExpression(exp.content);

a?.b evals to false, that is where the logic differ compared to the a.b expression.

also isMemberExpression is used to check for assignability of an expression, and optional chaining is not assignable. that is not the best fit check for: is an invokable expression or an "optional chained member expression"