wmr icon indicating copy to clipboard operation
wmr copied to clipboard

Add option to disable jsx -> htm conversion

Open marvinhagemeister opened this issue 5 years ago • 6 comments

I'm using wmr in the test suite for our Preact Devtools extension and I need to verify that it works with a range of Preact versions.

To do so I've set up multiple aliases:

{
  "alias": {
    "[email protected]": "/vendor/preact-10.0.0-rc.0/preact.js",
    "[email protected]": "/vendor/preact.10.3.4/preact.js"
}

And than we can use that with standard imports:

import { h, render } from "[email protected]";

render(
  <p>Rendered with 10.3.4</p>,
  document.getElementById("app")
);

This works really well except for when I use JSX. JSX is transpiled to htm template strings, but by adding a import htm from "htm/preact" import, an additional version of Preact is pulled in.

import { html } from "/@npm/htm/preact"; // Pulls in wrong version
import { h, render } from "[email protected]";

render(
  html`<p>Rendered with 10.3.4</p>`,
  document.getElementById("app")
);

To solve this I can come up with two options:

  1. Transpile JSX to createElement calls

This is arguable the more verbose version, but it works. The parsing performance benefit of tagged template strings doesn't really come to play in my set up, so I'm good with createElement calls.

import { h, render } from "[email protected]";

render(
  h("p", null, "Rendered with 10.3.4"),
  document.getElementById("app")
);
  1. Inject htm.bind(h) calls into every file

Another option could be to drop the htm/preact import and initialize the htm constructor anew in each file:

import htm from "/@npm/htm";
import { h, render } from "[email protected]";

const html = htm.bind(h);

render(
  html`<p>Rendered with 10.3.4</p>`,
  document.getElementById("app")
);
  1. Transpile to html calls, but don't inject htm.bind(h) automatically

This closely ties to 2) and is probably a lot more flexible for the end user. Essentially he'd need to make sure that an html function is present in the module scope themselves.

marvinhagemeister avatar Sep 21 '20 08:09 marvinhagemeister

Ooooh so this is 100% a bug in the npm resolution. Does it happen on master?

developit avatar Sep 21 '20 13:09 developit

Yeah happens on master too. Not sure if it's a resolution issue too. htm can't know which preact version is used on the page. I'm passing the version via an url parameter so that I can run a test against multiple preact versions. So wmr is correct in resolving the preact import inside htm/preact via node resolution to node_modules.

marvinhagemeister avatar Sep 21 '20 15:09 marvinhagemeister

Ah interesting, yeah that's kinda a funky case. A thought: what if we had the HTM plugin detect /** @jsx h */ at the top of files and insert htm.bind(h)? The default would be to pull in htm/preact`, but any file could opt out of it.

developit avatar Sep 30 '20 15:09 developit

@developit ohh I like that very much! That's much better than my proposed solution!! 👍

marvinhagemeister avatar Sep 30 '20 15:09 marvinhagemeister

I just thought of another idea: we could use the new jsxRuntime comment option from Babel to generate a module that pulls in a different h()/jsx().

developit avatar Sep 30 '20 16:09 developit

@developit That sounds even better and more future proof. Love that 👍

marvinhagemeister avatar Sep 30 '20 19:09 marvinhagemeister