react-dom-html

1.4.0 • Public • Published

react-dom-html

The easiest way to render full-page react-dom applications

It's react-dom, without the need for any html boilerplate

Supports React version 16+

npm npm CircleCI branch Maintainability Test Coverage Conventional Commits

Test coverage: ~98.5%

Contents

Introduction

react-dom-html is a thin wrapper around the client and server render methods of react-dom that takes care of all the html boilerplate.

If you want to define HTML metadata in your react application (similar to react-helmet), you can use react-dom-html-tags.

Browser methods supported:

  • renderHtml
  • hydrateHtml

Server methods supported:

  • renderHtmlToString
  • renderHtmlToStaticMarkup
  • renderHtmlToNodeStream
  • renderHtmlToStaticNodeStream
Bundle size:

~500 bytes gzipped for the client production build.

Install

// npm
npm install --save react-dom-html
 
// yarn
yarn add react-dom-html

Both react and react-dom are peer dependencies, so make sure you have them installed.

// npm
npm install --save react react-dom
 
// yarn
yarn add react react-dom

Usage

Browser

Client-side render

Use when renderHtmlToStaticMarkup, renderHtmlToStaticNodeStream or react-dom-html-cli is used to serve the application.

// browser.js
import {renderHtml} from "react-dom-html";
import MyApplication from "./MyApplication";
 
renderHtml(<MyApplication />);
Hydrate a server render

Use when renderHtmlToString or renderHtmlToNodeStream is used to serve the application.

// browser.js
import {hydrateHtml} from "react-dom-html";
import MyApplication from "./MyApplication";
 
// if the server rendered the page using react-dom-html you don't need to specify a container
hydrateHtml(<MyApplication />);

Server

Render to string
// server.js
import {renderHtmlToString, HTML5_DOCTYPE} from "react-dom-html/server";
import MyApplication from "./MyApplication";
 
// Render the app in a default html template
const html = renderHtmlToString(<MyApplication />);
 
// Using expressjs or another http framework
res.send(HTML5_DOCTYPE + html);
Render using node streams
import {renderHtmlToNodeStream, HTML5_DOCTYPE} from "react-dom-html/server";
import MyApplication from "./MyApplication";
 
const stream = renderHtmlToNodeStream(<App />);
 
res.write(HTML5_DOCTYPE);
return stream.pipe(res);

Server render options

Of course, you'll probably want to customize the Html and include your application bundle.

html: The simple option

The html option accepts a React component to render custom Html. The root element must be a <html> element.

The <app> element represents the application container where the application will be rendered in the HTML output. The <app> element must be defined in the html, and it must be an immediate child of the <body> element.

Optionally, you can customize the html tag used for the application container using the appContainerTagName option.

Here is a simple example:

// server.js
import {renderHtmlToString, HTML5_DOCTYPE} from "react-dom-html/server";
import MyApplication from "./MyApplication";
 
 
// The `<app />` element represents your application container.
// It's REQUIRED, and defines where your application will be rendered
 
// You can configure the html template using JSX
const html = renderHtmlToString(<MyApplication />, {
  html: (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <title>My Application</title>
      </head>
      <body className="pageBackground">
 
        {/*Include content before your application*/}
        <noscript>JavaScript must be enabled</noscript>
 
        {/*The `<app />` element is always REQUIRED*/}
        <app className="appBackground" />
 
        {/*Include content after your application*/}
        <script src="/public/scripts/appBundle.js" />
 
      </body>
    </html>
  ),
 
  // optionally, change the appContainer tag name
  appContainerTagName: "span"
}
 
// Using expressjs or another http framework
res.send(HTML5_DOCTYPE + html);

The html options also accepts a callback function that will be invoked after the application has rendered (for String rendering only). This enables you to assign content to the html output that is a result of the render

Here's a more complex example using the html option as a callback that is invoked after the application is rendered. This example includes:

import {renderHtmlToString, HTML5_DOCTYPE} from "react-dom-html/server";
import {ServerStyleSheet} from "styled-components";
import createReduxStore from './store';
import MyApplication from "./MyApplication";
 
const store = createReduxStore();
const sheet = new ServerStyleSheet();
 
const html = renderHtmlToString(sheet.collectStyles(<MyApplication />), {
    html: () => (
      // After the application is rendered, you can access styles created during the render
      const styleTags = sheet.getStyleElement();
 
      return (
        <html>
          <head>
              <meta charSet="utf-8" />
              <title>My Application</title>
              {styleTags}
          </head>
          <body>
            <app />
 
            {/*Serialize store data, and include bundle*/}
            <script dangerouslySetInnerHTML={__html: `__appData=${JSON.stringify(store.getState())};`} />
            <script src="/public/scripts/appBundle.js" />
          </body>
        </html>
      );
    )
});
htmlElements: The advanced option

Using the htmlElements options is slightly more complex but gives you much greater control of how the Html is rendered. This additional control is often required when rendering using streams.

You can use the above html option with streams when you do not need to serialize any state to the response (or write any other data to the response as a result of the application render). However, if you need to serialize state (or write other data to the response as a result of the application render) you must use the htmlElements option that enables element-specific callback(s) to be invoked. This allows you to serialize application state for the response.

If your application needs to render using both strings and streams with callbacks, you must use the htmlElements option.

IMPORTANT: The htmlElement and bodyElement options must not include any child elements.

Here is an example using all available htmlElements options:

import {renderHtmlToNodeStream, HTML5_DOCTYPE} from "react-dom-html/server";
import createReduxStore from './store';
import MyApplication from "./MyApplication";
 
const store = createReduxStore();
 
const stream = renderHtmlToNodeStream(<MyApplication />, {
    htmlElements: {
        htmlElement: <html lang="en" />,
        headElement: (
          <head>
            <meta charSet="utf-8" />
            <title>My Application</title>
          </head>
        ),
        headIsReactRoot: true,
        bodyElement: <body className="appBody" />,
        beforeAppContainerElement: <noscript>JavaScript must be enabled</noscript>,
        afterAppContainerElement: () => (
            <script dangerouslySetInnerHTML={__html: `__appData=${JSON.stringify(store.getState())};`} />
            <script src="/public/scripts/appBundle.js" />
        )
    }
});

Generating static Html

If you're not rendering your application on the server, you can still take advantage of react-dom-html to generate the .html page used to serve your application in the browser.

You can use react-dom-html-cli to generate .html files usin the same simple syntax. The cli utility makes it easy to integrate the html generator into your build process.

API

The API is very similar to react-dom, additional options have been added for sever methods.

If you're new to React, read the react-dom documentation first

Client

Unlike react-dom the container argument is optional for client methods if you used react-dom-html to generate the html used to render the app.

type renderCallback = () => void;
 
// Render the application in the browser
 
renderHtml(element: Element<any>, container?: DOMNode, callback?: renderCallback): void
 
// Hydrate the application in the browser
 
hydrateHtml(element: Element<any>, container?: DOMNode, callback?: renderCallback): void

Server

type renderElement = null | Element<any>;
 
type htmlElementOptions = {
  htmlElement?: Element<'html'> | () => Element<'html'>,
  headElement?: Element<'head'> | () => Element<'head'>,
  bodyElement?: Element<'body'> | () => Element<'body'>,
  appContainerElement?: Element<'*'> | () => Element<'*'>,
  beforeAppContainerElement?: Element<'*'> | () => Element<'*'>,
  afterAppContainerElement?: Element<'*'> | () => Element<'*'>,
  headIsReactRoot?: boolean = false
};
 
type serverRenderOptions = {
  html:? Element<'html'> | () => Element<'html'>,
  htmlElements:? htmlElementOptions | () => htmlElementOptions,
  appContainerTagName?: string = "div"
};
 
// Render to String
 
renderHtmlToString(element?: renderElement, options?: serverRenderOptions = {}): string
 
renderHtmlToStaticMarkup(element?: renderElement, options?: serverRenderOptions = {}): string
 
// Render to Node Stream
 
renderHtmlToNodeStream(element?: renderElement, options?: serverRenderOptions = {}): Stream
 
renderHtmlToStaticNodeStream(element?: renderElement, options?: serverRenderOptions = {}): Stream

Contribute

For questions or issues, please open an issue, and you're welcome to submit a PR for bug fixes and feature requests.

This package exists as a yarn workspace, you will need to fork and then clone the parent workspace. Follow the instructions in the workspace README file for installing the workspace dependencies.

Before submitting a PR, ensure you run npm test to verify that your code adheres to the configured lint rules and passes all tests. Be sure to include tests for any code changes or additions.

License

MIT

Package Sidebar

Install

npm i react-dom-html

Weekly Downloads

0

Version

1.4.0

License

MIT

Unpacked Size

85.1 kB

Total Files

31

Last publish

Collaborators

  • adam-26