https://github.com/WebReflection/viperHTML
Isomorphic hyperHTML
https://github.com/WebReflection/viperHTML
html isomorphic js lightweight manipulation performance template template-literals vanilla
Last synced: 5 months ago
JSON representation
Isomorphic hyperHTML
- Host: GitHub
- URL: https://github.com/WebReflection/viperHTML
- Owner: WebReflection
- License: isc
- Archived: true
- Created: 2017-03-08T19:25:53.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2020-03-05T13:17:02.000Z (almost 6 years ago)
- Last Synced: 2024-11-10T03:02:50.316Z (about 1 year ago)
- Topics: html, isomorphic, js, lightweight, manipulation, performance, template, template-literals, vanilla
- Language: JavaScript
- Homepage:
- Size: 484 KB
- Stars: 314
- Watchers: 17
- Forks: 10
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
- awesome-tagged-templates - viperHTML
README
# viperHTML

[](https://github.com/WebReflection/donate) [](https://opensource.org/licenses/ISC) [](https://travis-ci.org/WebReflection/viperHTML) [](https://coveralls.io/github/WebReflection/viperHTML?branch=master)  [](https://greenkeeper.io/)
## Warning
Due [low popularity](https://www.npmjs.com/package/viperhtml) of this project after all these years, and because I have shifted focus to better alternatives, this **project is currently in maintenance mode**, meaning that 100% _feature parity_ with _hyperHTML_ is not anymore an achievement, and only the simple/obvious will be fixed.
Among various changes happened to _hyperHTML_, the **sparse attributes** will likely **not** be **supported**, as the refactoring needed here would easily outperform the benefits.
As _sparse attributes_ are never really been a must have, you can simply use `attr=${...}` and concatenate in there anything you want.
This is also true for most modern alternatives of mine, such as [ucontent](https://github.com/WebReflection/ucontent#readme), but if that's the only deal breaker, have a look at [heresy-ssr](https://github.com/WebReflection/heresy-ssr#readme), which is 1:1 based on [lighterhtml](https://github.com/WebReflection/lighterhtml#readme), hence likely always 100% in features parity with it, included sparse attributes.
- - -
[hyperHTML](https://github.com/WebReflection/hyperHTML) lightness, ease, and performance, for the server.
- - -
Don't miss the [viperHTML](https://github.com/WebReflection/viperHTML) version of **Hacker News**
Live: https://viperhtml-164315.appspot.com/
Repo: https://github.com/WebReflection/viper-news
- - -
### Similar API without DOM constrains
Similar to its browser side counterpart, `viperHTML` parses the template string once, decides what is an attribute, what is a callback, what is text and what is HTML, and any future call to the same render will only update parts of that string.
The result is a blazing fast template engine that makes templates and renders shareable between the client and the server.
### Seamlessly Isomorphic
No matter if you use ESM or CommonJS, you can use [hypermorphic](https://github.com/WebReflection/hypermorphic#hypermorphic-)
to load same features on both client and server.
```js
// ESM example (assuming bundlers/ESM loaders in place)
import {bind, wire} from 'hypermorphic';
// CommonJS example
const {bind, wire} = require('hypermorphic');
```
### Automatically Sanitized HTML
Both attributes and text nodes are safely escaped on each call.
```js
const viperHTML = require('viperhtml');
var output = render => render`
${a.text}
${[a.html]}
`;
var a = {
text: 'Click "Me"',
html: '"HTML" Me',
href: 'https://github.com/WebReflection/viperHTML',
onclick: (e) => e.preventDefault()
};
// associate the link to an object of info
// or simply use viperHTML.wire();
var link = viperHTML.bind(a);
console.log(output(link).toString());
```
The resulting output will be the following one:
```html
Click "Me"
"HTML" Me
```
### Usage Example
```js
const viperHTML = require('viperhtml');
function tick(render) {
return render`
Hello, world!
It is ${new Date().toLocaleTimeString()}.
`;
}
// for demo purpose only,
// stop showing tick result after 6 seconds
setTimeout(
clearInterval,
6000,
setInterval(
render => console.log(tick(render).toString()),
1000,
// On a browser, you'll need to bind
// the content to a generic DOM node.
// On the server, you can directly use a wire()
// which will produce an updated result each time
// it'll be used through a template literal
viperHTML.wire()
)
);
```
### The Extra viperHTML Feature: Asynchronous Partial Output
Clients and servers inevitably have different needs,
and the ability to serve chunks on demand, instead of a whole page at once,
is once of these very important differences that wouldn't make much sense on the client side.
If your page content might arrive on demand and is asynchronous,
`viperHTML` offers an utility to both obtain performance boots,
and intercepts all chunks of layout, as soon as this is available.
#### viperHTML.async()
Similar to a wire, `viperHTML.async()` returns a callback that *must be invoked* right before the template string,
optionally passing a callback that will be invoked per each available chunk of text, as soon as this is resolved.
```js
// the view
const pageLayout = (render, model) =>
render`
${model.head}
${model.body}
`;
// the viper async render
const asyncRender = viperHTML.async();
// dummy server for one view only
require('http')
.createServer((req, res) => {
res.writeHead( 200, {
'Content-Type': 'text/html'
});
pageLayout(
// res.write(chunk) while resolved
asyncRender(chunk => res.write(chunk)),
// basic model example with async content
{
head: Promise.resolve({html: 'right away'}),
body: new Promise(res => setTimeout(
res, 1000,
// either:
// {html: '
later on'}
// ['later on']
// wire()'later on'
viperHTML.wire()`later on`
))
}
)
.then(() => res.end())
.catch(err => { console.error(err); res.end(); });
})
.listen(8000);
```
### Handy Patterns
Following a list of handy patterns to solve common issues.
#### HTML in template literals doesn't get highlighted
True that, but if you follow a simple `(render, model)` convetion,
you can just have templates as html files.
```html
Hello, ${model.name}!
It is ${new Date().toLocaleTimeString()}.
```
At this point, you can generate as many views as you want through the following step
```sh
#!/usr/bin/env bash
mkdir -p view
for f in $(ls template); do
echo 'module.exports = (render, model) => render`' > "view/${f:0:-4}js"
cat template/$f >> "view/${f:0:-4}js"
echo '`;' >> "view/${f:0:-4}js"
done
```
As result, the folder `view` will now contain a `tick.js` file as such:
```js
module.exports = (render, model) => render`
Hello, ${model.name}!
It is ${new Date().toLocaleTimeString()}.
`;
```
You can now use each view as modules.
```js
const view = {
tick: require('./view/tick')
};
// show the result in console
console.log(view.tick(
viperHTML.wire(),
{name: 'user'}
));
```