@makerinc/babel-plugin-hydrate-or-render
v1.2.3
Published
Babel plugin to transform React App component into universal hydrate-or-render bootstrap code
Readme
@devi/babel-plugin-react-hydrate-or-render
A Babel plugin that transforms React ReactDOM.createRoot().render() calls into universal hydrate-or-render bootstrap code for SSR/CSR applications.
What it does
This plugin automatically transforms your standard React 18+ rendering code into a universal bootstrap pattern that intelligently handles both server-side rendering (SSR) hydration and client-side rendering (CSR).
Input
import './index.css';
import React from "react";
import ReactDOM from "react-dom/client";
import App from './App.jsx';
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);Output
import './index.css';
import React from "react";
import App from './App.jsx';
import { hydrateRoot, createRoot } from "react-dom/client";
const container = document ? document.getElementById("root") : null;
if (container && container.hasChildNodes()) {
container.classList.add("maker-hd-rt");
hydrateRoot(container, <React.StrictMode>
<App />
</React.StrictMode>);
} else {
container.classList.add("maker-cr-rt");
createRoot(container).render(<React.StrictMode>
<App />
</React.StrictMode>);
}Installation
npm install @devi/babel-plugin-react-hydrate-or-render --save-devUsage
With Vite
Add the plugin to your vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
babel: {
plugins: [
['@devi/babel-plugin-react-hydrate-or-render', { containerId: 'root' }]
]
}
})
]
});With Babel
Add to your .babelrc or babel.config.js:
{
"plugins": [
["@devi/babel-plugin-react-hydrate-or-render", { "containerId": "root" }]
]
}Options
containerId (optional)
- Type:
string - Default: Auto-detected from your code, falls back to
'root' - Description: The ID of the DOM element where React will be mounted/hydrated
Note: The plugin automatically detects the container ID from your
document.getElementById()call. You only need to provide this option if you want to override the detected value.
Example:
{
plugins: [
['@devi/babel-plugin-react-hydrate-or-render', { containerId: 'app' }]
]
}Verification
After transformation, the plugin adds CSS classes to the container element for easy debugging:
maker-hd-rt- Added when hydrating (SSR path with pre-rendered HTML)maker-cr-rt- Added when rendering (CSR path, no pre-rendered HTML)
You can verify which path was taken by inspecting the container element in DevTools or running:
document.getElementById('root').className
// Returns: "maker-cr-rt" or "maker-hd-rt"Features
✅ Automatic Detection: Recognizes ReactDOM.createRoot().render() patterns
✅ JSX Preservation: Maintains your entire JSX tree including <React.StrictMode> and other wrappers
✅ Container Auto-Detection: Automatically extracts the container ID from document.getElementById()
✅ Visual Verification: Adds CSS classes (maker-hd-rt for hydration, maker-cr-rt for rendering) to help debug which path is executed
✅ Zero Config: Works out of the box with sensible defaults
How it works
- The plugin detects
ReactDOM.createRoot(document.getElementById("id")).render(<JSX />)patterns - It automatically extracts the container ID from your code
- It transforms the code to:
- Replace
react-dom/clientimports with named imports:{ hydrateRoot, createRoot } - Create a safe container reference with null checking
- Add a CSS class to the container for debugging (
maker-hd-rtormaker-cr-rt) - Conditionally use
hydrateRootfor SSR hydration (when container has child nodes) - Fall back to
createRoot().render()for pure client-side rendering
- Replace
- Your entire JSX tree (including
<React.StrictMode>and other wrappers) is preserved
Use Case
This plugin is designed for universal React applications that need to support both:
- Server-Side Rendering (SSR): Pre-rendered HTML that gets hydrated on the client
- Client-Side Rendering (CSR): Dynamic rendering when no pre-rendered HTML exists
The plugin eliminates the need to manually write the bootstrap logic in every project, ensuring consistency and reducing boilerplate.
Requirements
- React 18+ (uses
react-dom/clientAPI) - Babel 7+
License
MIT
