Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support JSX transformations with custom jsxFactory #35929

Open
soncodi opened this issue Dec 31, 2019 · 1 comment
Open

Support JSX transformations with custom jsxFactory #35929

soncodi opened this issue Dec 31, 2019 · 1 comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@soncodi
Copy link

soncodi commented Dec 31, 2019

Search Terms

jsx, jsxFactory, transformer

Suggestion

Allow tapping into the JSX generation process to control React.createElement output format when using --jsxFactory.

Specific cases requested (e.g. #15217, #32619) would also benefit from a generalized solution.

Use Cases

Emit component children as thunks

Useful to reactive frameworks which attach dependency tracking via the JSX component hierarchy.

The internal createJsxFactoryExpression() call LHS is controlled using the --jsxFactory compiler option:

// jsx
<div>
  <div>a</div>
  <div>b</div>
</div>

// current emit (jsxFactory: "h")
h('div', null, 
  h('div', null, 'a'), 
  h('div', null, 'b')
)

This produces a nested React.createElement()/h() chain which evaluates eagerly.

With (still synchronous) thunks, frameworks can track each component dependency as they traverse the tree, for fine-grained change detection:

// thunks (needs transformer)
h('div', null, () => [
  h('div', null, () => ['a']), 
  h('div', null, () => ['b'])
])

This requires recursively transforming the JSX emits to a signature of h() which accepts some args as a thunk.

I've written a hacky (#16607) transformer for this but had to extract most of the JSX-related internals from the TypeScript compiler, whereas making the change to createExpressionForJsxElement() is trivial:

const cs = argumentsList.slice(2);
const argThunk = ts.createArrowFunction(
    [],
    [],
    [],
    undefined,
    undefined,
    ts.createArrayLiteral(cs)
);
const thunkified = [...argumentsList.slice(0, 2), argThunk];

According to #34547, plans are already in motion to pass nested component args as arrays instead of varargs. Specifying the jsxFactory implies we are assuming control of the composition behavior; we should also control the function signature.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Jan 13, 2020
@RyanCavanaugh
Copy link
Member

If you host the compiler through the API, you can already write a custom emit step to do this.

We'd need to know the name of a reasonably popular JSX-based framework that supports this to make it a built-in option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants