ProjectEvergreen / ProjectEvergreen/wcc
src/jsx-loader.js: several correctness/DX defects in JSX + inferred-observability compilation
@jstockdi is already working on this.
Since Jul 18, 2026.
- Dominant language
- JavaScript
- Stars
- 126
- Forks
- 17
- PR merge metrics
- No merged PRs in 30d
Description
What happened?
While exercising wc-compiler's JSX + inferred-observability compilation (via Greenwood's @greenwood/plugin-import-jsx), I hit a cluster of correctness/DX defects that all live in src/jsx-loader.js. Each is individually reproducible with a minimal .jsx component; several fail silently (green build, broken or missing output), and a few crash the build with an error that points at wc-compiler internals rather than the user's source.
Because they share one file and some are adjacent, I'm reporting them together; a PR follows with one commit (fix + regression test) per defect.
The defects:
- Unsupported JSX child expressions are silently dropped (
~parseJsxElement, lines ~131–306). Calls, ternaries, binary ops, template literals,.map()lists, and computed members produce no output and no warning — e.g.{items.map(i => <li>{i}</li>)}renders an empty<ul>. Fix: emit aconsole.warnfrom the fall-through so the drop is visible (also handles the{' '}/{'text'}child-Literalidiom, which was itself dropped). class X extends HTMLElement {}; customElements.define(...); export default X;shipsundefined.$$tmpl0(...)(lines ~417–427 / 770 / 819).componentNameis only captured for the inlineexport default class Nameform, so the effect-append pass emitsundefined.$$tmpl0(...)→ clientTypeErroron connect (build green, SSR correct).{this.count.get()}compiles to${undefined.get()}(lines ~280–298), crashing SSR (Cannot read properties of undefined (reading 'get')) on a valid source line. Only the destructured{count.get()}form works today.- A plain
class Foo {}(noextends) in a.jsxfile crashes compilation withCannot read properties of null (reading 'name')(lines ~431 / 698;node.superClassisnull), with no file named. export const inferredObservability = falsestill enables observability (line ~413):Boolean(node.declaration.declarations[0].init.raw)runs on the source text"false", andBoolean("false") === true.- A component with its own
observedAttributes/attributeChangedCallbackgets duplicate members (line ~380hasOwnObservedAttributesis dead/undefined, so the guards at ~505 / ~760 never fire); the user's definitions silently override the injected ones, disabling inferred attribute→signal sync. - Arrow event handlers with double-quoted strings emit malformed HTML (line ~177): the serialized body is placed into a double-quoted
onclick="…"unescaped, and/this./grewritesthiseven inside string literals — e.g.onclick={() => alert("this rocks")}breaks the attribute and turns"this rocks"intoself.rocks. - A JSX root of
<body>/<html>produces a nested full document (lines ~31–35,getParse): parse5's full-document parse +serializeinlines a complete<html><head></head><body>…</body></html>inside the page.
Steps to reproduce
Each defect has a minimal .jsx fixture; see the corresponding commit's regression test in the PR (each proves the failure on unpatched source and passes with the fix). Example (defect 3):
- A
.jsxcomponent withexport const inferredObservability = truethat reads{this.count.get()}directly inrender(). - Compile it (build/SSR).
- Observe
TypeError: Cannot read properties of undefined (reading 'get')pointing at the component'srender, instead of rendering the value.
Environment
- wc-compiler: 0.22.2 (current
master,src/jsx-loader.jsunchanged since the release) - Node: 22.20
- OS: Linux
- Reached via
@greenwood/plugin-import-jsx(Greenwood v0.34.0), but all defects are inwc-compileritself.
Additional Context
Each fix is minimal and confined; the diagnostic-only one (defect 1) is a non-fatal console.warn, not a hard error. Defect 3 covers the direct this.<signal>.get() read; the chained {this.todos.get().length} variant is a broader change left as a follow-up.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.