diff --git a/.babelrc b/.babelrc
index cff5232..8762b0e 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,12 +1,23 @@
{
"presets": [
- ["@babel/preset-env", {
- "targets": {
- "node": "current"
+ [
+ "@babel/preset-env",
+ {
+ "targets": {
+ "node": "current"
+ }
}
- }]
+ ]
],
"plugins": [
- "@babel/plugin-transform-react-jsx"
+ [
+ "@babel/plugin-transform-react-jsx",
+ {
+ "pragma": "h",
+ "pragmaFrag": "Fragment",
+ "useBuiltIns": true,
+ "throwIfNamespace": false
+ }
+ ]
]
}
diff --git a/.editorconfig b/.editorconfig
index a082ad7..fd375c4 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,11 +6,8 @@ root = true
[*]
-# Change these settings to your own preference
indent_style = space
indent_size = 2
-
-# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
diff --git a/.eslintrc b/.eslintrc
index 6f45e23..483ef4f 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,11 +1,15 @@
{
- "extends": [
- "airbnb",
- "eslint-config-prettier",
- "eslint-config-prettier/react"
- ],
+ "extends": ["airbnb", "eslint-config-prettier", "eslint-config-prettier/react"],
"rules": {
+ "import/prefer-default-export": "off",
+ "no-continue": "off",
"no-plusplus": "off",
+ "no-restricted-syntax": "off",
"prefer-template": "off"
+ },
+ "settings": {
+ "react": {
+ "pragma": "h"
+ }
}
}
diff --git a/.gitattributes b/.gitattributes
index c667fa9..d88a0db 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -11,5 +11,8 @@
.* text eol=lf
*.js text eol=lf
*.json text eol=lf
+*.map text eol=lf
*.md text eol=lf
*.svg text eol=lf
+*.ts text eol=lf
+*.tsx text eol=lf
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e81b4d..e363895 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## [Unreleased][unreleased]
+
+- [BREAKING] Remove higher-order app `withRender` from the library due to redundancy.
+- Support for `className` attribute and allow to use array and object as a value.
+- Compatibility with upcoming [Hyperapp V2](https://github.com/hyperapp/hyperapp/pull/726).
+- Various performance optimizations.
+
## [2.1.0] - 2018-07-11
- Add [TypeScript](https://www.typescriptlang.org/) typings.
diff --git a/README.md b/README.md
index fca5527..710e6f7 100644
--- a/README.md
+++ b/README.md
@@ -5,17 +5,17 @@
[![library size](https://img.shields.io/bundlephobia/minzip/hyperapp-render.svg)](https://bundlephobia.com/result?p=hyperapp-render)
[![slack chat](https://hyperappjs.herokuapp.com/badge.svg)](https://hyperappjs.herokuapp.com 'Join us')
-A [Hyperapp](https://github.com/hyperapp/hyperapp) higher-order `app`
-that allows you to render views to an HTML string.
+This library is allowing you to render
+[Hyperapp](https://github.com/hyperapp/hyperapp) views to an HTML string.
- **User experience** — Generate HTML on the server and send the markup
down on the initial request for faster page loads. Built-in
- [mounting](https://github.com/hyperapp/hyperapp/tree/1.2.0#mounting)
+ [mounting](https://github.com/hyperapp/hyperapp/tree/1.2.9#mounting)
feature in Hyperapp is allowing you to have a very performant first-load experience.
- **Accessibility** — Allow search engines to crawl your pages for
[SEO](https://en.wikipedia.org/wiki/Search_engine_optimization) purposes.
- **Testability** — [Check HTML validity](https://en.wikipedia.org/wiki/Validator) and use
- [snapshot testing](https://facebook.github.io/jest/docs/en/snapshot-testing.html)
+ [snapshot testing](https://jestjs.io/docs/en/snapshot-testing.html)
to improve quality of your software.
## Getting Started
@@ -24,8 +24,8 @@ Our first example is an interactive app from which you can generate an HTML mark
Go ahead and [try it online](https://codepen.io/frenzzy/pen/zpmRQY/left/?editors=0010).
```jsx
-import { h, app } from 'hyperapp'
-import { withRender } from 'hyperapp-render'
+import { h } from 'hyperapp'
+import { renderToString } from 'hyperapp-render'
const state = {
text: 'Hello'
@@ -42,14 +42,13 @@ const view = (state, actions) => (
)
-const main = withRender(app)(state, actions, view)
+const html = renderToString(view(state, actions))
-main.toString() // =>
Hello
-main.setText('World') // <= any sync or async action call
-main.toString() // =>
World
+console.log(html) // =>
Hello
```
-Looking for a boilerplate? Try [Hyperapp Starter](https://github.com/frenzzy/hyperapp-starter)
+Looking for a boilerplate?
+Try [Hyperapp Starter](https://github.com/kriasoft/hyperapp-starter)
with pre-configured server-side rendering and many more.
## Installation
@@ -74,110 +73,56 @@ You can find the library in `window.hyperappRender`.
We support all ES5-compliant browsers, including Internet Explorer 9 and above,
but depending on your target browsers you may need to include
[polyfills]() for
-[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set),
-[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
-[`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) and
+[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
before any other code.
## Usage
-The library provides a few functions which you can use depending on your needs or personal preferences.
+The library provides two functions
+which you can use depending on your needs or personal preferences:
```jsx
-import { withRender, renderToString, renderToStream } from 'hyperapp-render'
-
-const main = withRender(app)(state, actions, view, container)
+import { renderToString, renderToStream } from 'hyperapp-render'
-main.toString() // =>
renderToString() // =>
+renderToString(view(state, actions)) // =>
renderToString(view, state, actions) // =>
-main.toStream() // => =>
renderToStream() // => =>
+renderToStream(view(state, actions)) // => =>
renderToStream(view, state, actions) // => =>
```
-**Note:** functions `toStream` and `renderToStream` are available in
+**Note:** `renderToStream` is available from
[Node.js](https://nodejs.org/en/) environment only (v6 or newer).
## Overview
-The library exposes three functions. The first of these is `withRender` high-order function,
-which adds the `toString` action to be able to render your application to an HTML string at any given time.
-This can be useful for server-side rendering or creating HTML snippets based on current application state.
-
-```jsx
-import { h, app } from 'hyperapp'
-import { withRender } from 'hyperapp-render'
-
-const state = { name: 'World' }
-const actions = { setName: name => ({ name }) }
-const view = (state, actions) =>
Hello {state.name}
-
-const main = withRender(app)(state, actions, view)
+You can use `renderToString` function to generate HTML on the server
+and send the markup down on the initial request for faster page loads
+and to allow search engines to crawl your pages for
+[SEO](https://en.wikipedia.org/wiki/Search_engine_optimization) purposes.
-main.toString() // =>
Hello World
-main.setName('Hyperapp') // <= any sync or async action call
-main.toString() // =>
Hello Hyperapp
-```
-
-The second `renderToString` function generates HTML markup from any of your views without
-app initialization. That could be useful to generate HTML markup from static views.
-
-```jsx
-import { renderToString } from 'hyperapp-render'
+If you call [`hyperapp.app()`](https://github.com/hyperapp/hyperapp/tree/1.2.9#mounting)
+on a node that already has this server-rendered markup,
+Hyperapp will preserve it and only attach event handlers, allowing you
+to have a very performant first-load experience.
-const Component = ({ name }) =>
Hello {name}
-
-renderToString()
-// =>
Hello World
-```
-
-The last `renderToStream` function and `toStream` equivalent return a
-[Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams) that outputs an HTML string.
-The HTML output by this stream is exactly equal to what `toString` or `renderToString` would return.
-They are designed for more performant server-side rendering and here are examples how they could be used
-with [Express](http://expressjs.com/) or [Koa](http://koajs.com/):
-
-```jsx
-app.get('/', (req, res) => {
- res.write('')
- res.write('Page')
- res.write('
-
-
- )
- stream.pipe(res)
-})
-```
+The `renderToStream` function returns a
+[Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams)
+that outputs an HTML string.
+The HTML output by this stream is exactly equal to what `renderToString` would return.
+By using this function you can reduce [TTFB](https://en.wikipedia.org/wiki/Time_to_first_byte)
+and improve user experience even more.
## Caveats
The library automatically escapes text content and attribute values
-of [virtual DOM nodes](https://github.com/hyperapp/hyperapp/tree/1.2.0#view)
-to protect your application against [XSS](https://en.wikipedia.org/wiki/Cross-site_scripting) attacks.
-
-However, it is not safe to allow "user input" for node names or attribute keys because
-the library does not reject injection attack on markup due to performance reasons.
-See:
+of [virtual DOM nodes](https://github.com/hyperapp/hyperapp/tree/1.2.9#view)
+to protect your application against
+[XSS](https://en.wikipedia.org/wiki/Cross-site_scripting) attacks.
+However, it is not safe to allow "user input" for node names or attribute keys:
```jsx
const Node = 'div onclick="alert()"'
diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js
index 28a76de..68690d6 100644
--- a/benchmark/benchmark.js
+++ b/benchmark/benchmark.js
@@ -1,129 +1,135 @@
/** @jsx h */
import { h } from 'hyperapp'
-import { renderToString } from '../src/index'
+import { escapeHtml, concatClassNames, stringifyStyles, renderToString } from '../src/index'
-suite('escape', () => {
- benchmark('empty', () => {
- renderToString(