npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

esbuild-plugin-react-hydration

v1.0.1

Published

An esbuild plugin to generate react components html and insert it in a main html file

Downloads

2

Readme

esbuild-plugin-react-hydration

An esbuild plugin to generate react components html and insert it in an existing html file.

Features

  • Parse any react component with .static.jsx suffix into html
  • Retrieve all html files from a specified directory
  • Inject the component's html into a main html file which has an id corresponding with component's name
  • Get a new minified html file from it
  • Can pass props to component from html file
  • Can use redux to share a store by using the Provider component
  • Use specials tags in html for auto inject scripts, css and assets
  • Generate a json file representing multiple files from assets (Array of objects with name & path of each file)

Before installation

You must have esbuild@^0.17.3, React@^18.2.0 and ReactDOM@^18.2.0 installed.

Installation

Install the plugin with npm

  npm i esbuild-plugin-react-hydration

Usage

Begin by adding the plugin to esbuild config:

Example for dev

// esbuild.mjs

import * as esbuild from "esbuild";
import { Provider } from "react-redux";
import store from "./src/redux/store.js";
import reactHydrationPlugin from "../index.min.js";

const SRC = "test/src";
const OUT = "test/dev";
const REDUX = { store, Provider };

const ctx = await esbuild.context({
  entryPoints: [`${SRC}/main.js`],
  bundle: true,
  plugins: [
    reactHydrationPlugin({
      redux: REDUX,

      cssFrom: `/${SRC}/styles`,
      htmlFrom: `/${SRC}/pages`,
      assetsFrom: `/${SRC}/files`,

      outDir: `/${OUT}`,
      jsOut: "/js", // => /${OUT}/js => /test/dev/js
      htmlOut: "/", // => /${OUT}/   => /test/dev/

      galleries: ["cars", "images/dbz"],
    }),
  ],
  outdir: `${OUT}/js`, // must be the same as jsOut option
});

await ctx.watch();

Example for prod

import * as esbuild from "esbuild";
import { Provider } from "react-redux";
import store from "./src/redux/store.js";
import { writeFile } from "node:fs/promises";
import reactHydrationPlugin from "../index.min.js";

const SRC = "test/src";
const OUT = "test/prod";
const REDUX = { store, Provider };

const TIME_LOG = `Build time`;

console.time(TIME_LOG);
const result = await esbuild.build({
  entryPoints: [`${SRC}/main.js`],
  bundle: true,
  minify: true,
  plugins: [
    reactHydrationPlugin({
      redux: REDUX,

      cssFrom: `/${SRC}/styles`,
      htmlFrom: `/${SRC}/pages`,
      assetsFrom: `/${SRC}/files`,

      outDir: `/${OUT}`,
      jsOut: "/js", // => /${OUT}/js => /test/prod/js
      htmlOut: "/", // => /${OUT}/   => /test/prod/
      cssOut: "/css",
      assetsOut: "/assets",

      galleries: ["cars", "images/dbz"],
    }),
  ],
  outdir: `${OUT}/js`, // must be the same as jsOut option
  metafile: true,
  legalComments: "none",
  pure: ["console"],
});
console.timeEnd(TIME_LOG);

await writeFile("meta.json", JSON.stringify(result.metafile));

Babel config

Then, create a config file for babel. This is with the help of babel that we can "transform" a react component into html from a .jsx file.

// babel.config.json

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

Entry point config

Now, in a main js file, you have to link the html generated and the dynamic code from a react component.

// index.js

import React from "react";
import { hydrateRoot } from "react-dom/client";
import Header from "./components/Header.static";

const header = document.getElementById("header");
if (header) {
  hydrateRoot(header, React.createElement(Header));
}

Build

To build a static version of your project, run:

  npx babel-node esbuild.mjs

Rules

  • Name react components files that you want to inject and hydrate with the ".static.jsx" suffix. (ex: Header.static.jsx)
  • The id corresponding in html file must be the name of the component in camelCase. (MyComponent.static.jsx ===> <div id="myComponent"></div>)
  • You must declare the id attribute as the last attribute of the html element.
  • In your html files, add <!-- {scripts} --> where you want inject your js, <!-- {styles} --> where you want inject your css and {assets} everywhere you have a relative path to your assets folder
<head>
  <!-- {styles} -->
</head>
<body>
  <img
    src="{assets}/images/myPicture.png"
    alt="logo"
  />

  <!-- {scripts} -->
</body>

With props to add

In html file

If you want to pass some props to a component injected in html, you can do it by adding a data attribute.

<div
  data-myComponent='{"someData":3242, "someOtherData":"My data"}'
  id="myComponent"
></div>
  • The format of the attribute is data-COMPONENT_ID.
  • The format of the value must be a litteral object stringified.
  • The data attribute must be placed just before the id attribute.

In js file

Retrieve data from html in your main js file:

// index.js

import { hydrateRoot } from "react-dom/client";
import MyComponent from "./components/MyComponent.static";

const component = document.getElementById("myComponent");
if (component) {
  const json = component.getAttribute("data-myComponent");
  const data = JSON.parse(json);
  hydrateRoot(component, React.createElement(MyComponent, { data }) />);
}

You can now retrieve data via props in your component.

const MyComponent = ({ data }) => {
  return <p>{data.someOtherData}</p>;
};

With Redux

If you want to share a store between differents components injected in different place, or not, you can do it.

  • First, add the redux object option in the esbuild config like seen in the Usage section.
  • Then, import the store and the Provider in your main js file to inject the store in the components you want.
// index.js

import { Provider } from "react-redux";
import myStore from "./redux/store.js";
import { hydrateRoot } from "react-dom/client";
import Header from "./components/Header.static#provider";

const header = document.getElementById("header");
if (header) {
  const component = React.createElement(Header);
  hydrateRoot(header, React.createElement(Provider, { store: myStore }, component));
}

That's all ! And you can do it for every component you want.

!! To work correctly you must add the suffix #provider in the import of the component which need the store !!



🚀 About Me

I'm just a javascript and light weight app lover

🛠 Skills

Javascript, ReactJS, NodeJS, Redux, Angular, NextJS, Esbuild, Postgres, MongoDB, Wordpress...

Related

Here are some related projects

esbuild-plugin-save-server-data

esbuild-plugin-css-opti

License

MIT License