Giter Club home page Giter Club logo

htm's Introduction

HTM (Hyperscript Tagged Markup) npm

hyperscript tagged markup demo

htm is JSX-like syntax in plain JavaScript - no transpiler necessary.

Develop with React/Preact directly in the browser, then compile htm away for production.

It uses standard JavaScript Tagged Templates and works in all modern browsers.

htm by the numbers:

🐣 < 600 bytes when used directly in the browser

⚛️ < 500 bytes when used with Preact (thanks gzip 🌈)

🥚 < 450 byte htm/mini version

🏅 0 bytes if compiled using babel-plugin-htm

Syntax: like JSX but also lit

The syntax you write when using HTM is as close as possible to JSX:

  • Spread props: <div ...${props}> instead of <div {...props}>
  • Self-closing tags: <div />
  • Components: <${Foo}> instead of <Foo> (where Foo is a component reference)
  • Boolean attributes: <div draggable />

Improvements over JSX

htm actually takes the JSX-style syntax a couple steps further!

Here's some ergonomic features you get for free that aren't present in JSX:

  • No transpiler necessary
  • HTML's optional quotes: <div class=foo>
  • Component end-tags: <${Footer}>footer content<//>
  • Syntax highlighting and language support via the lit-html VSCode extension and vim-jsx-pretty plugin.
  • Multiple root element (fragments): <div /><div />
  • Support for HTML-style comments: <div><!-- comment --></div>

Installation

htm is published to npm, and accessible via the unpkg.com CDN:

via npm:

npm i htm

hotlinking from unpkg: (no build tool needed!)

import htm from 'https://unpkg.com/htm?module'
const html = htm.bind(React.createElement);
// just want htm + preact in a single file? there's a highly-optimized version of that:
import { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js'

Usage

If you're using Preact or React, we've included off-the-shelf bindings to make your life easier. They also have the added benefit of sharing a template cache across all modules.

import { render } from 'preact';
import { html } from 'htm/preact';
render(html`<a href="/">Hello!</a>`, document.body);

Similarly, for React:

import ReactDOM from 'react-dom';
import { html } from 'htm/react';
ReactDOM.render(html`<a href="/">Hello!</a>`, document.body);

Advanced Usage

Since htm is a generic library, we need to tell it what to "compile" our templates to. You can bind htm to any function of the form h(type, props, ...children) (hyperscript). This function can return anything - htm never looks at the return value.

Here's an example h() function that returns tree nodes:

function h(type, props, ...children) {
  return { type, props, children };
}

To use our custom h() function, we need to create our own html tag function by binding htm to our h() function:

import htm from 'htm';

const html = htm.bind(h);

Now we have an html() template tag that can be used to produce objects in the format we created above.

Here's the whole thing for clarity:

import htm from 'htm';

function h(type, props, ...children) {
  return { type, props, children };
}

const html = htm.bind(h);

console.log( html`<h1 id=hello>Hello world!</h1>` );
// {
//   type: 'h1',
//   props: { id: 'hello' },
//   children: ['Hello world!']
// }

If the template has multiple element at the root level the output is an array of h results:

console.log(html`
  <h1 id=hello>Hello</h1>
  <div class=world>World!</div>
`);
// [
//   {
//     type: 'h1',
//     props: { id: 'hello' },
//     children: ['Hello']
//   },
//   {
//     type: 'div',
//     props: { class: 'world' },
//     children: ['world!']
//   }
// ]

Caching

The default build of htm caches template strings, which means that it can return the same Javascript object at multiple points in the tree. If you don't want this behaviour, you have three options:

  • Change your h function to copy nodes when needed.
  • Add the code this[0] = 3; at the beginning of your h function, which disables caching of created elements.
  • Use htm/mini, which disables caching by default.

Example

Curious to see what it all looks like? Here's a working app!

It's a single HTML file, and there's no build or tooling. You can edit it with nano.

<!DOCTYPE html>
<html lang="en">
  <title>htm Demo</title>
  <script type="module">
    import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';

    class App extends Component {
      addTodo() {
        const { todos = [] } = this.state;
        this.setState({ todos: todos.concat(`Item ${todos.length}`) });
      }
      render({ page }, { todos = [] }) {
        return html`
          <div class="app">
            <${Header} name="ToDo's (${page})" />
            <ul>
              ${todos.map(todo => html`
                <li key=${todo}>${todo}</li>
              `)}
            </ul>
            <button onClick=${() => this.addTodo()}>Add Todo</button>
            <${Footer}>footer content here<//>
          </div>
        `;
      }
    }

    const Header = ({ name }) => html`<h1>${name} List</h1>`

    const Footer = props => html`<footer ...${props} />`

    render(html`<${App} page="All" />`, document.body);
  </script>
</html>

⚡️ See live version

⚡️ Try this on CodeSandbox

How nifty is that?

Notice there's only one import - here we're using the prebuilt Preact integration since it's easier to import and a bit smaller.

The same example works fine without the prebuilt version, just using two imports:

import { h, Component, render } from 'preact';
import htm from 'htm';

const html = htm.bind(h);

render(html`<${App} page="All" />`, document.body);

Other Uses

Since htm is designed to meet the same need as JSX, you can use it anywhere you'd use JSX.

Generate HTML using vhtml:

import htm from 'htm';
import vhtml from 'vhtml';

const html = htm.bind(vhtml);

console.log( html`<h1 id=hello>Hello world!</h1>` );
// '<h1 id="hello">Hello world!</h1>'

Webpack configuration via jsxobj: (details here) (never do this)

import htm from 'htm';
import jsxobj from 'jsxobj';

const html = htm.bind(jsxobj);

console.log(html`
  <webpack watch mode=production>
    <entry path="src/index.js" />
  </webpack>
`);
// {
//   watch: true,
//   mode: 'production',
//   entry: {
//     path: 'src/index.js'
//   }
// }

Demos & Examples

Project Status

The original goal for htm was to create a wrapper around Preact that felt natural for use untranspiled in the browser. I wanted to use Virtual DOM, but I wanted to eschew build tooling and use ES Modules directly.

This meant giving up JSX, and the closest alternative was Tagged Templates. So, I wrote this library to patch up the differences between the two as much as possible. The technique turns out to be framework-agnostic, so it should work great with any library or renderer that works with JSX.

htm is stable, fast, well-tested and ready for production use.

htm's People

Contributors

alonski avatar artisonian avatar blikblum avatar developit avatar drjayvee avatar graynorton avatar grgur avatar jodiwarren avatar jviide avatar kristoferbaxter avatar lmorchard avatar marvinhagemeister avatar mathiasbynens avatar saravieira avatar schalkventer avatar sibbng avatar sijmenhuizenga avatar solarliner avatar spoerri avatar styfle avatar surma avatar vikerman avatar wesleyac avatar wight554 avatar xmonkee avatar yhatt avatar yuezk avatar yuler avatar zaygraveyard avatar zserge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

htm's Issues

Should fragments return one `h` call of array?

Was wondering if it makes more sense that fragments return one h call of the produced array.

Similar to h([h('div', 'First'), insertCat, h('div', 'Last')]).

I'm asking since I ran into this issue myself using this lib without a VDOM library but with something like the original hyperscript.

https://github.com/hyperhype/hyperscript/blob/master/index.js#L51

A plain array can't be appended as DOM nodes is the minor issue I guess.
It would be easy to transform the resulting array into a document fragment and append it but it would be nice the result of html`<div/><div/>` could be appended as is.

Is there a way to do this?
Or does it make more sense to have a plain array for most use cases?

Thanks

Ampersand escapes in text content handled differently to JSX

Reproduction

With the following code:

import htm from "https://unpkg.com/[email protected]/dist/htm.mjs";
import { h } from "https://unpkg.com/[email protected]/dist/preact.mjs";
const html = htm.bind(h);

console.log(html`<div>&lt;</div>`)

I get a VNode with .children = ["&lt;"] — i.e. what I mean to render as < gets rendered as &lt; instead.

Expected results

Testing this in JSX via say https://jsx.egoist.moe/?mode=vue, <div>&lt;</div> gets transformed into h("div", ["<"]); as I originally expected.

I haven't poked into how they are doing this… seems like something that ultimately relies on a lookup table.

Workaround

I am able to escape via string interpolation (e.g. ${'<'} instead of &lt;). Changing the last line in my sample code to:

// …

console.log(html`<div>${'<'}</div>`)

Results in a VNode with .children = ["<"] as I need. Is this the recommended style?

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

Optimize adjacent static parts+fields

I've been toying around with optimizing Tagged Templates by merging literal field values (strings, numbers and booleans) into their adjacent static part and collapsing the adjacent static parts into a single part:

// input:
<div class={"foo"}>hello</div>
<button id={1} />

// current output:
html`<div class=${"foo"}>hello</div>`
html `<button id=${1} />`

// optimized output:
html`<div class="foo">`
html`<button id=1 />`

It'd be really neat to get this behavior into babel-plugin-transform-jsx-to-htm, since additional assumptions could be made about nested Arrays:

const color = 'red';

// input:
<style jsx>{`
  .foo { color: ${color}; }
`}</style>

// current output:
html`
  <style jsx>${`
    .foo { color: ${color}; }
  `}</style>
`

// optimized output:
html`
  <style jsx>
    .foo { color: ${color}; }
  </style>
`

Thoughts?

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

SVG attributes missing

I tried to use htm 2.1.1 in my project, but the output doesn't contain any SVG attributes.

Code:

var htm = require('htm')
var h = require('hyperscript')

const html = htm.bind(h);

(html`
<a class="pagination__arrow pagination__arrow--prev">
    <svg viewBox="0 0 9 17">
        <path d="M8.74211278,7.70898691 L1.41374436,0.245094159 C1.09218045,-0.081698053 0.571195489,-0.081698053 0.248819549,0.245094159 C-0.0727443609,0.571886371 -0.0727443609,1.10268241 0.248819549,1.42947462 L6.99590977,8.30114267 L0.249631579,15.1728107 C-0.0719323308,15.4996029 -0.0719323308,16.030399 0.249631579,16.3580185 C0.571195489,16.6848107 1.09299248,16.6848107 1.41455639,16.3580185 L8.74292481,8.89412576 C9.05961654,8.57071178 9.05961654,8.03157357 8.74211278,7.70898691 Z"></path>
    </svg>
</a>
`).outerHTML

Output:

<a class=\"pagination__arrow pagination__arrow--prev\"><svg><path></path></svg></a>

`is` property, or make html clean again

htm looks brilliant so far.
The only thing that does not seem elegant is components. Both having tag name as variable and having closing tag seems external to html syntax. Besides, trying to couple components with semantic HTML oftentimes brings unnecessary wrapping and long nesting, also creates shallow tags like Contexs, Providers, HOCs etc.

A possible elegant way to bring clean html to htm would be making components just modifiers for actual tags, like

<nav is=${NavBar()}/>
<main is=${App(props)}>
  <header is=${Header(props)} />
  <section ${Content()}>...</section>
  <footer is=${Footer(props)} />
</main>

Compared to current code:

<${NavBar}/>
<${App} ...${props}>
  <${Header} ...${props}/>
  <${Content}>...<//>
  <${Footer} ...${props} />
<//>

That idea would allow collapsing HOCs/Providers as well:

<main is=${App()} provider=${[Lang, Store, Theme]}>
<aside context=${Lang} compose=${[withPagination, reduxForm()]}/>
</main>

Just wonder - if that's worth of separate package and what's possible way to introduce that to htm.

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

How to use with server side rendering?

It would be nice if there was documentation on how to use this with server side rendering.

Such that:

  1. Server sends the prerendered compontent
  2. Client receives the prerendered component and makes it interactive for the user

ES Module Usage

This is a question (I asked on twitter first) more than an issue, but I would love to hear thoughts from anyone who has tried this and gather consensus..

If you were using htm?module straight from unpkg then would you do this at the top of every file.. or would you do the binding once in your app.js and then make it global; say, window.html?

import htm from 'https://unpkg.com/htm?module'
const html = htm.bind(React.createElement)

string interpolation in attribute does not work as expected

html`<div class="${'1'} ${'2'} ${'3'}"></div>`

currently returns

VNode {
  nodeName: 'div',
  children: [],
  attributes: { class: '1' },
  key: undefined }

expected

VNode {
  nodeName: 'div',
  children: [],
  attributes: { class: '1 2 3' },
  key: undefined }

Inline style issue with variable on return

There is a render issue(might be related with hyperscript) when you want to give style attribute with variable;
<div class="competency-level" style="width: ${this.state.percentage};" title="Percentage"></div>
In this case, width is not rendered inside the style attribute.

However, when you give the style with an object;
<div class="competency-level" style="${{ width: this.state.percentage + '%' }};" title="Percentage"></div>
the problem is gone.

Silently fails with HTML comments

Hi there,

Neat library! I really like developing components but don't like shipping large bundle files to the browser. For simple apps, it would be nice to do server-side components that get rendered as strings.

I've been playing around with htm recently (inspired by @timarney's htm-ssr-demo), and got a pretty minimal proof-of-concept up and running. (Most of the code is from a preact-render-to-string example.)

package.json
{
  "name": "ssr-htm-hello-world",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "express": "^4.16.4",
    "htm": "^2.1.1",
    "preact": "^8.4.2",
    "preact-render-to-string": "^4.1.0"
  },
  "scripts": {
    "start": "node index.js"
  }
}
index.js
const express = require("express");
const { h, Component } = require("preact");
const render = require("preact-render-to-string");
const htm = require("htm");

const html = htm.bind(h);

const Page = ({ name }) => {
  return html`
    <div class="page">
      <h1>${name}</h1>
      <p>This page is all about ${name}.</p>
    </div>
  `;
};

const app = express();

app.get("/:page", (req, res) => {
  let markup = render(
    html`
      <${Page} name=${req.params.page} />
    `
  );
  res.send(`<!DOCTYPE html><html><body>${markup}</body></html>`);
});

app.listen(3000);

So that works well enough to prove the concept.

However, if I change Page to this:

const Page = ({ name }) => {
  return html`
    <div class="page">
      <!-- html comment -->
      <h1>${name}</h1>
      <p>This page is all about ${name}.</p>
    </div>
  `;
};

then I just get a white page, and if I open devtools, I see <undefined></undefined> in the markup.

There's no warning message or anything, so I'm wondering

  • if this is a bug
  • if I'm using this library in a way it's not supposed to be used
  • or if there's any eslint config or anything that I can set up to catch this kind of thing

Any help or suggestions would be appreciated! I'd like to build a little prototype using htm, but if it fails silently on syntax issues then it probably won't scale very well once you started nesting components inside each other.

Silent error when used with Unistore

I wrote the Unistore README counter component example using h() directly with no compile step, but when I try migrating the Provider component to be rendered via htm, the script silently fails and nothing is rendered.

Attached is the full failing standalone HTML file.

When I've migrated everything in the script to htm except the Provider component, it works:

render((
    h(Provider, { store },
      html`<${App} />`,
    )
), document.body);

But when I change the Provider to be rendered via htm, I get the white screen of death and no console output:

    render(html`
        <${Provider} store=${store}>
          <${App} />
        <//>
    `, document.body);

I assume I've got a syntax error of some kind or I've stumbled on some complexity of the Unistore/HTM interplay. Should there be console error output in this case?

Interestingly, the htm version does work if I just render out "Hello world" inside it, in place of the App component.

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

css prop

The idea is just great, but I ran into a problem.
How to use with emotions?
Screen Shot 2019-05-12 at 21 40 47
Screen Shot 2019-05-12 at 21 45 18

Beginner friendly babel-plugin-htm

Hi, I'm relatively new to web development and only know a little about babel - and webpack.
So I want to start a new project and have my webpack config which holds my babel config. I don't know if this is best practice ... anyway - I would like to add the plugin but I am struggeling with it.

Is it possible to change the readme for this plugin so that noobs like me can understand where to put:
[ ["htm", { "pragma": "React.createElement" }] ]

Thank you for htm!

Optional tags problem

According to the standard, some elements may omit closing tags.
Example:

import htm from 'https://unpkg.com/htm?module'
let html = htm.bind((a, b, c) => console.log(a, b, c))

html`<ul><li><li></ul>`

As we see in the output, a single h('li', null, undefined) was called.

It seems that htm disregards the actual closing tag and just matches the </ signature, so that any open tag can be closed with "generic" end tag as <someTag><//>, which is quite handy in many ways.

This brings more serious problem with br tag.
Example (from the spec):

html`<p>P. Sherman<br>
42 Wallaby Way<br>
Sydney</p>`

that gives a single h('br', null, undefined) call.

small demo

put up a demo I was using to check out features, feel free to use any of it if you want
https://github.com/jeremy-coleman/preactive-htm

it has both rollup and webpack builds with babel and without.

I added rollup because i wanted to look over the non-minified bundled code and noticed that the babel plugin wasn't working, I assume because of .mjs extension - might be worth noting in the readme or something. probably a lot of pepople dont know if you use resolve.extensions in your webpack config it resets all the defaults (to exclude mjs) it's also required to manually add to rollup inside the babel plugin.
if u want to see the difference just change the rollup config from: babel({extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"]}), to: babel(). Gonna explore a bit more with a real app

can use with `vhtml` ?

such as

import htm from 'htm'
import h from 'vhtml'

const html = htm.bind(h)

const hello = 'Hello'

console.log(html`<h1 id={ hello }>{ hello } world!</h1>`)

Build failing

Downloaded, installed dependencies and ran npm run build. Got the following error:

> npm run -s build:main && npm run -s build:preact && npm run -s build:babel

(node:4286) Warning: N-API is an experimental feature and could change at any time.
(nodent plugin) Error: Plugin 'jsx' not found
Error: Plugin 'jsx' not found
    at Parser.loadPlugins (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/node_modules/acorn/dist/acorn.js:543:26)
    at new Parser (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/node_modules/acorn/dist/acorn.js:469:8)
    at Object.parse (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/node_modules/acorn/dist/acorn.js:5288:10)
    at acornParse (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/compiler.js:37:21)
    at NodentCompiler.parseCode [as parse] (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/compiler.js:177:17)
    at NodentCompiler.compile (/Users/rbiggs/Github/htm-master/node_modules/nodent-compiler/compiler.js:112:19)
    at Object.transform (/Users/rbiggs/Github/htm-master/node_modules/rollup-plugin-nodent/index.js:35:25)
    at /Users/rbiggs/Github/htm-master/node_modules/rollup/dist/rollup.js:20847:25
    at <anonymous>

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

how to convert jsx to htm?

How can I convert my existing jsx project to use htm as tagged template literals (possibly using babel)?
Is there a convenient configuration for transforming my project easily?

Thanks very much,

Syntax error with material react components

Trying to run material-ui/lab/Slider, get an error

let {render} = require('react-dom')
let h = require('htm').bind(require('react').createElement)
let Slider = require( '@material-ui/lab/Slider' ).default

render(htm`
	<${Slider}/>
`, document.body.appendChild(document.createElement('div')))
VM960:3
Uncaught SyntaxError: Unexpected token ,
    at Function (<anonymous>)
    at htm.js:1
    at Function.<anonymous> (htm.js:1)
    at Object.297../ (test? [sm]:39)
    at o (_prelude.js:1)
    at r (_prelude.js:1)
at _prelude.js:1

babel-plugin-transform-jsx-to-htm does not works with webpack

When using babel-plugin-transform-jsx-to-htm in a webpack project, it returns an invalid plugin: the inherits option gets a module object ({default: jsx(), _esModule: true}) instead of jsx()

This occurs because webpack loads the *.mjs file (pointed by package module field) and imports @babel/plugin-syntax-jsx as a module object instead of importing the default export.

As a workaround add resolve: { mainFields: ['main'] } to webpack configuration

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

Document fragment as multiple elements

There was a discussion in JSX spec to enable fragments as first class citizen via just multiple elements, which is really natural syntax for fragments, facebook/jsx#58.
For me that would be a killing feature for htm.

return html`
            <${Header} name="ToDo's (${page})" />
            <ul>
              ${todos.map(todo => html`
                <li>${todo}</li>
              `)}
            </ul>
            <button onClick=${this.addTodo.bind(this)}>Add Todo</button>
            <${Footer}>footer content here<//>
        `;

Any thoughts on enabling that?

Join forces with TJSX

I've long ago created a project like this, TJSX, and I feel we can join forces and create something even better.

Want to do it?

Question: String template literal vs JSX compatibility?

tl;dr

edit: This issue is meant to be a broader discussion based off of issues like: #56, #58, #60, #76

After upgrading to 2.* I ran into a lot of issues where htm removed functionality that string template literals ( and html 5 in general have ).

So the question is:

Should htm be chasing jsx compatibility or string template literal behavior?

Issues that bit me

  • no longer allowing tags that html 5 allows:
    • <input type="text"> vs <input type="text"/>, <img> etc.
  • no longer rendering nested template literals
<${MyComponent}
  href="/path/${id}"
><//>

now needs to be:

<${MyComponent}
  href="${'/path/' + id}"
><//>

These are small things that cause hard to debug issues for anyone familiar with how String Template Literals work.

Browser support?

For a library supposed to run directly in the browser, it would be nice to list the browser support. From what I can tell, IE<=11 won't work, due to the template element not being supported: https://caniuse.com/#feat=template

Are there other limitations?

Question: How well does this work with TypeScript?

Hey, apologies to take your time on a question I could answer myself with a few minutes of trying it out (and I still might do that if I get a few minutes). It would be nice to just have a quick answer to this question somewhere in this project, maybe in the readme. I guess specifically I'd like to know the following.

  1. Does this package have typings?
  2. Does TypeScript provide compile time errors for passing incorrect prop values to components when using this package?

Standalone demo clears the DOM (body) after ~15 seconds

I've not looked into the details, but for some reason when I test this example code it clears the DOM (body) after about 15 seconds. I've tested with a local PHP CLI server, npmjs.com/package/serve, and with a production NGINX setup.
While observing the local cli server, it seems to trying to access different ports.

Example:

name@supersecret:[htm]:php -S 0.0.0.0:1337
PHP 7.2.10-0ubuntu0.18.04.1 Development Server started at Wed Nov 21 09:45:23 2018
Listening on http://0.0.0.0:1337
Document root is /home/name/Code/htm
Press Ctrl-C to quit.
[Wed Nov 21 09:45:48 2018] 127.0.0.1:35880 [200]: /
[Wed Nov 21 09:45:52 2018] 127.0.0.1:35916 [200]: /
[Wed Nov 21 09:45:53 2018] 127.0.0.1:35920 [200]: /

Snippet tested from your readme:

<!DOCTYPE html>
<html lang="en">
  <title>htm Demo</title>
  <script type="module">
    import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.mjs';

    class App extends Component {
      addTodo() {
        const { todos = [] } = this.state;
        this.setState({ todos: todos.concat(`Item ${todos.length}`) });
      }
      render({ page }, { todos = [] }) {
        return html`
          <div class="app">
            <${Header} name="ToDo's (${page})" />
            <ul>
              ${todos.map(todo => html`
                <li>${todo}</li>
              `)}
            </ul>
            <button onClick=${this.addTodo.bind(this)}>Add Todo</button>
            <${Footer}>footer content here<//>
          </div>
        `;
      }
    }

    const Header = ({ name }) => html`<header><h1>${name} List</h1></header>`

    const Footer = props => html`<footer ...${props} />`

    render(html`<${App} page="All" />`, document.body);
  </script>
</html>

Confusing error message when not closing an element

Example code:

import htm from "htm"

const e = htm`<input>` // element is not closed

Being used to write HTML and not having to close every element (especially inputs), i can write this sort of code
With htm, i get the following error: SyntaxError: missing ) after argument list
This errors seems non-intuitive to me

Question: package peerDependencies

Hi,

currently the npm package declares a peerDependency to preact at the root level (/package.json) and no peerDependency at react or preact level (/[p]react/package.json).
Is it on purpose (e.g. that some bundlers/tools do not support peerDeps on sub packages) or should it be fixed ?

Cheers !

Missing text in CodeSandbox sample

Hello!

I was playing around with your CodeSandbox sample and noticed some missing text.

Here's my fork of the sample: https://codesandbox.io/s/7jx016lwo6

Notice that the name prop passed to header has some static text appended to the beginning.

<${Header} name="THIS SHOULD BE RENDERED (${page})" />

When the header is rendered, the static text is missing and just All List is rendered.

I might be missing something here but I would expect the header to say THIS SHOULD BE RENDERED (All) List instead of just All List.

Thanks!

EDIT: This is reproducible in your CodeSandbox demo as well - I just made a few changes to make it more clear.

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.