developit / vhtml

Render JSX/Hyperscript to HTML strings, without VDOM 🌈

Home Page:http://npm.im/vhtml

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fragment / jsxFragment support

mappu opened this issue · comments

commented

Hi, this is a cool project, thanks so much.

I am using Typescript to compile the JSX, with this tsconfig.json:

    "jsx": "react",
    "jsxFactory": "h",

Most code is converted properly, except when using a fragment:

const foo = <>
   <tr><td>row 1</td></td>
   <tr><td>row 2</td></td>
</>

this warning from Typescript is given:

The 'jsxFragmentFactory' compiler option must be provided to use JSX fragments with the 'jsxFactory' compiler option.

I tried "jsxFragmentFactory": "Fragment", in tsconfig.json but of course no such Fragment is known nor exported from the vhtml import.

  • Is it possible to support JSX fragments in VHTML?
  • Is there any other way of storing multiple <tr> siblings as per the above example?
commented

I see there is Fragment support added in #16 but it does not yet conform to the Typescript jsxFragmentFactory implementation in microsoft/TypeScript#35392 at all.

Adding const Fragment = ({ children }: { children: string[] }) => h(null as any, null, ...children); to the source file seems sufficient, but, it should be added into vhtml itself for jsxFragmentFactory to work more seamlessly.

commented

I wanted to mention that configuring tsconfig as

    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "h.Fragment",

allows me to use fragments with vhtml even though #33 is not merged. I don't know why this is.
I suppose it might depend on the bundler. I'm currently using esbuild, but maybe it's worth a shot for others to try instead of waiting for support to be merged here?

The solution is to set up your config like this:

{
    jsxFactory: 'h',
    jsxFragment: 'null',
}

See these test cases:

vhtml/test/vhtml.js

Lines 177 to 191 in 96fe21e

it('should support string fragments', () => {
expect(
h(null, null, "foo", "bar", "baz")
).to.equal(
'foobarbaz'
);
});
it('should support element fragments', () => {
expect(
h(null, null, <p>foo</p>, <em>bar</em>, <div class="qqqqqq">baz</div>)
).to.equal(
'<p>foo</p><em>bar</em><div class="qqqqqq">baz</div>'
);
});

vhtml.Fragment works.

I have a working demo on CodePen