Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@pleisto/react-helmet

Package Overview
Dependencies
Maintainers
2
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pleisto/react-helmet

Type and thread-safe Helmet for React 16+ and friends

  • 0.1.0
  • latest
  • npm
  • Socket score

Version published
Weekly downloads
2
Maintainers
2
Weekly downloads
 
Created
Source

react-helmet-async-ts

This is intended as a drop-in replacement for react-helmet-async, if you encounter any differences, please raise an Issue

This package is a fork of React Helmet Async but with stricter typings and written in typescript.

Usage is mostly identical to react-helmet-async however under the hood there are a few differences:

  • Helmet, HelmetContext, and HelmetProvider are now Functional components, rather than Class Components.
  • Testing has been rewritten to use React 18 and get rid of enzyme which doesn't appear to be getting any updates for React 18.

<Helmet> usage is synonymous with react-helmet, but server and client now requires <HelmetProvider> to encapsulate state per request.

react-helmet relies on react-side-effect, which is not thread-safe. If you are doing anything asynchronous on the server, you need Helmet to encapsulate data on a per-request basis, this package does just that.

Usage

The main way that this package differs from react-helmet is that it requires using a Provider to encapsulate Helmet state for your React tree. If you use libraries like Redux or Apollo, you are already familiar with this paradigm:

import React from 'react';
import ReactDOM from 'react-dom';
import { Helmet, HelmetProvider } from 'react-helmet-async';

const app = (
  <HelmetProvider>
    <App>
      <Helmet>
        <title>Hello World</title>
        <link rel="canonical" href="https://www.tacobell.com/" />
      </Helmet>
      <h1>Hello World</h1>
    </App>
  </HelmetProvider>
);

ReactDOM.hydrate(
  app,
  document.getElementById(‘app’)
);

On the server, we will no longer use static methods to extract state. react-side-effect exposed a .rewind() method, which Helmet used when calling Helmet.renderStatic(). Instead, we are going to pass a context prop to HelmetProvider, which will hold our state specific to each request.

import React from 'react';
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetProvider } from 'react-helmet-async';

const helmetContext = {};

const app = (
  <HelmetProvider context={helmetContext}>
    <App>
      <Helmet>
        <title>Hello World</title>
        <link rel='canonical' href='https://www.tacobell.com/' />
      </Helmet>
      <h1>Hello World</h1>
    </App>
  </HelmetProvider>
);

const html = renderToString(app);

const { helmet } = helmetContext;

// helmet.title.toString() etc…

Streams

This package only works with streaming if your <head> data is output outside of renderToNodeStream(). This is possible if your data hydration method already parses your React tree. Example:

import through from 'through';
import { renderToNodeStream } from 'react-dom/server';
import { getDataFromTree } from 'react-apollo';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import template from 'server/template';

const helmetContext = {};

const app = (
  <HelmetProvider context={helmetContext}>
    <App>
      <Helmet>
        <title>Hello World</title>
        <link rel='canonical' href='https://www.tacobell.com/' />
      </Helmet>
      <h1>Hello World</h1>
    </App>
  </HelmetProvider>
);

await getDataFromTree(app);

const [header, footer] = template({
  helmet: helmetContext.helmet,
});

res.status(200);
res.write(header);
renderToNodeStream(app)
  .pipe(
    through(
      function write(data) {
        this.queue(data);
      },
      function end() {
        this.queue(footer);
        this.queue(null);
      },
    ),
  )
  .pipe(res);

Usage in Jest

While testing in using jest, if there is a need to emulate SSR, there is a render helper function available in the __tests__/setup folder. Import this rather than the one from @testing-library/react and you can pass in a 2nd argument of true to emulate SSR. A third argument allows a custom context value to be passed. The render function then returns all the same properties as the @testing-library/react version, as well as the context to allow it to be used modified.

const render = (
  node: JSX.Element,
  mockSSR: boolean = false,
  context: HelmetContext = {},
): ReturnType<typeof rtlRender> & { context: HelmetContext }

Prioritizing tags for SEO

It is understood that in some cases for SEO, certain tags should appear earlier in the HEAD. Using the prioritizeSeoTags flag on any <Helmet> component allows the server render of react-helmet-async to expose a method for prioritizing relevant SEO tags.

In the component:

<Helmet prioritizeSeoTags>
  <title>A fancy webpage</title>
  <link rel='notImportant' href='https://www.chipotle.com' />
  <meta name='whatever' value='notImportant' />
  <link rel='canonical' href='https://www.tacobell.com' />
  <meta property='og:title' content='A very important title' />
</Helmet>

In your server template:

<html>
  <head>
    ${helmet.title.toString()}${helmet.priority.toString()}${helmet.meta.toString()}$
    {helmet.link.toString()}${helmet.script.toString()}
  </head>
  ...
</html>

Will result in:

<html>
  <head>
    <title>A fancy webpage</title>
    <meta property="og:title" content="A very important title" />
    <link rel="canonical" href="https://www.tacobell.com" />
    <meta name="whatever" value="notImportant" />
    <link rel="notImportant" href="https://www.chipotle.com" />
  </head>
  ...
</html>

A list of prioritized tags and attributes can be found in constants.js.

Usage without Context

You can optionally use <Helmet> outside a context by manually creating a stateful HelmetData instance, and passing that stateful object to each <Helmet> instance:

import React from 'react';
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetData } from 'react-helmet-async';

const helmetData = new HelmetData({});

const app = (
  <App>
    <Helmet helmetData={helmetData}>
      <title>Hello World</title>
      <link rel='canonical' href='https://www.tacobell.com/' />
    </Helmet>
    <h1>Hello World</h1>
  </App>
);

const html = renderToString(app);

const { helmet } = helmetData.context;

License

Licensed under the Apache 2.0 License, Copyright © 2022 Tetarchus

FAQs

Package last updated on 28 Feb 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc