Skip to content

A fork of react-helmet that support for renderToNodeStream and thread safe

License

Notifications You must be signed in to change notification settings

openameba/react-safety-helmet

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React Safety Helmet

npm Version codecov Build Status Dependency Status

A fork of react-helmet that support for renderToNodeStream and thread safe with the power of redux

This reusable React component will manage all of your changes to the document head.

Helmet takes plain HTML tags and outputs plain HTML tags. It's dead simple, and React beginner friendly.

This is a fork of react-helmet.

Example

import React from "react";
import {Helmet} from "react-safety-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <meta charSet="utf-8" />
                <title>My Title</title>
                <link rel="canonical" href="http://mysite.com/example" />
            </Helmet>
            ...
        </div>
    );
  }
};

Nested or latter components will override duplicate changes:

import ReactDOM from 'react-dom';
import { HelmetProvider, createHelmetStore } from 'react-safety-helmet';

function bootstrap() {
    const helmetStore = createHelmetStore();
    ReactDOM.render(
        <HelmetProvider store={helmetStore}>
            <Parent>
                <Helmet>
                    <title>My Title</title>
                    <meta name="description" content="Helmet application" />
                </Helmet>
                <Child>
                    <Helmet>
                        <title>Nested Title</title>
                        <meta name="description" content="Nested component" />
                    </Helmet>
                </Child>
            </Parent>
        </HelmetProvider>,
        document.getElementById('app')
    );
}

outputs:

<head>
    <title>Nested Title</title>
    <meta name="description" content="Nested component">
</head>

See below for a full reference guide.

Features

  • Supports all valid head tags: title, base, meta, link, script, noscript, and style tags.
  • Supports attributes for body, html and title tags.
  • Supports server-side rendering.
  • Nested components override duplicate head changes.
  • Duplicate head changes are preserved when specified in the same component (support for tags like "apple-touch-icon").
  • Callback for tracking DOM changes.

Installation

Yarn:

yarn add react-safety-helmet

npm:

npm install --save react-safety-helmet

Server Usage

To use on the server, call store.renderStatic() after ReactDOMServer.renderToString or ReactDOMServer.renderToStaticMarkup to get the head data for use in your prerender.

import { createHelmetStore, HelmetProvider } from 'react-safety-helmet';

const helmetStore = createHelmetStore();
ReactDOMServer.renderToString(
    <HelmetProvider store={helmetStore}
        <Handler />
    </HelmetProvider>
);
const helmet = helmetStore.renderStatic();

This helmet instance contains the following properties:

  • base
  • bodyAttributes
  • htmlAttributes
  • link
  • meta
  • noscript
  • script
  • style
  • title

Each property contains toComponent() and toString() methods. Use whichever is appropriate for your environment. For attributes, use the JSX spread operator on the object returned by toComponent(). E.g:

As string output

const html = `
    <!doctype html>
    <html ${helmet.htmlAttributes.toString()}>
        <head>
            ${helmet.title.toString()}
            ${helmet.meta.toString()}
            ${helmet.link.toString()}
        </head>
        <body ${helmet.bodyAttributes.toString()}>
            <div id="content">
                // React stuff here
            </div>
        </body>
    </html>
`;

As React components

function HTML () {
    const htmlAttrs = helmet.htmlAttributes.toComponent();
    const bodyAttrs = helmet.bodyAttributes.toComponent();

    return (
        <html {...htmlAttrs}>
            <head>
                {helmet.title.toComponent()}
                {helmet.meta.toComponent()}
                {helmet.link.toComponent()}
            </head>
            <body {...bodyAttrs}>
                <div id="content">
                    // React stuff here
                </div>
            </body>
        </html>
    );
}

Server Usage with ReactDOMServer.renderToNodeStream() and ReactDOMServer.renderToStaticNodeStream()

new Promise((resolve, reject) => {
    const helmetStore = createHelmetStore();
    let body = '';
    ReactDOMServer.renderToNodeStream(
        <HelmetProvider store={helmetStore}>
          <App />
        </HelmetProvider>,
    )
      .on('data', (chunk) => {
        body += chunk;
      })
      .on('error', (err) => {
        reject(err);
      })
      .on('end', () => {
        resolve({
          body,
          helmet: helmetStore.renderStatic(),
        });
      });
}).then(({body, helmet}) => {
    // Create html with body and helmet object
});

Reference Guide

<Helmet
    {/* (optional) set to false to disable string encoding (server-only) */}
    encodeSpecialCharacters={true}

    {/*
        (optional) Useful when you want titles to inherit from a template:

        <Helmet
            titleTemplate="%s | MyAwesomeWebsite.com"
        >
            <title>My Title</title>
        </Helmet>

        outputs:

        <head>
            <title>Nested Title | MyAwesomeWebsite.com</title>
        </head>
    */}
    titleTemplate="MySite.com - %s"

    {/*
        (optional) used as a fallback when a template exists but a title is not defined

        <Helmet
            defaultTitle="My Site"
            titleTemplate="My Site - %s"
        />

        outputs:

        <head>
            <title>My Site</title>
        </head>
    */}
    defaultTitle="My Default Title"

    {/* (optional) callback that tracks DOM changes */}
    onChangeClientState={(newState) => console.log(newState)}
>
    {/* html attributes */}
    <html lang="en" amp />

    {/* body attributes */}
    <body className="root" />

    {/* title attributes and value */}
    <title itemProp="name" lang="en">My Plain Title or {`dynamic`} title</title>

    {/* base element */}
    <base target="_blank" href="http://mysite.com/" />

    {/* multiple meta elements */}
    <meta name="description" content="Helmet application" />
    <meta property="og:type" content="article" />

    {/* multiple link elements */}
    <link rel="canonical" href="http://mysite.com/example" />
    <link rel="apple-touch-icon" href="http://mysite.com/img/apple-touch-icon-57x57.png" />
    <link rel="apple-touch-icon" sizes-"72x72" href="http://mysite.com/img/apple-touch-icon-72x72.png" />
    {locales.map((locale) => {
        <link rel="alternate" href="http://example.com/{locale}" hrefLang={locale} />
    })}

    {/* multiple script elements */}
    <script src="http://include.com/pathtojs.js" type="text/javascript" />

    {/* inline script elements */}
    <script type="application/ld+json">{`
        {
            "@context": "http://schema.org"
        }
    `}</script>

    {/* noscript elements */}
    <noscript>{`
        <link rel="stylesheet" type="text/css" href="foo.css" />
    `}</noscript>

    {/* inline style elements */}
    <style type="text/css">{`
        body {
            background-color: blue;
        }

        p {
            font-size: 12px;
        }
    `}</style>
</Helmet>

Where is Helmet.rewind(), Helmet.renderStatic() and peek() ?

Use helmetStore.renderStatic() instead of Helmet.rewind() and Helmet.renderStatic()

const helmetStore = createHelmetStore();
ReactDOMServer.renderToString(
    <HelmetProvider store={helmetStore}>
        <Helmet>
            <title>My Title</title>
            <meta name="description" content="Helmet application" />
        </Helmet>
    </HelmetProvider>
);

const head = helmetStore.renderStatic();

Use helmetStore.peek() instead of Helmet.peek()

const helmetStore = createHelmetStore();
ReactDOM.render(
    <HelmetProvider store={helmetStore}>
        <Helmet>
            <title>Fancy title</title>
        </Helmet>
    </HelmetProvider>,
    container
);

helmetStore.peek().title; // "Fancy title"

Contributing to this project

Please take a moment to review the guidelines for contributing.

License

MIT

About

A fork of react-helmet that support for renderToNodeStream and thread safe

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%