Build a React App

When you want a straightforward client-rendered single-page app โ€” no build-time rendering, no hydration โ€” Poops is just your bundler. One scripts entry points at your JSX/TSX entry, esbuild does the rest.

Project layout

react-app/
โ”œโ”€ poops.json
โ”œโ”€ package.json          # react + react-dom installed here
โ””โ”€ src/
   โ”œโ”€ scss/index.scss
   โ”œโ”€ js/
   โ”‚  โ”œโ”€ main.tsx         # entry: mounts the app
   โ”‚  โ”œโ”€ App.tsx
   โ”‚  โ””โ”€ components/
   โ””โ”€ markup/
      โ””โ”€ index.html       # the shell with <div id="root">

The entry

// src/js/main.tsx
import { createRoot } from "react-dom/client";
import App from "./App";

createRoot(document.getElementById("root")!).render(<App />);
// src/js/App.tsx
import { useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <main>
      <h1>Hello from Poops</h1>
      <button onClick={() => setCount((c) => c + 1)}>Count: {count}</button>
    </main>
  );
}

The config

{
  "scripts": [
    {
      "in": "src/js/main.tsx",
      "out": "dist/js/app.js",
      "options": {
        "minify": true,
        "format": "iife",
        "target": "es2019",
        "jsx": "automatic"
      }
    }
  ],
  "styles": [
    {
      "in": "src/scss/index.scss",
      "out": "dist/css/styles.css",
      "options": { "minify": true }
    }
  ],
  "markup": {
    "in": "src/markup",
    "out": "dist",
    "options": {
      "site": { "title": "My React App" },
      "includePaths": ["_layouts", "_partials"]
    }
  },
  "copy": [{ "in": "src/static", "out": "dist" }],
  "serve": { "port": 4040, "base": "/dist" },
  "livereload": true,
  "watch": ["src"]
}

"jsx": "automatic" enables React 17+'s JSX runtime, so you don't import React in every file.

The HTML shell

Poops still builds your index.html โ€” use markup for the shell so relativePathPrefix and site data work:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>{{ site.title }}</title>
    <link rel="stylesheet" href="{{ relativePathPrefix }}css/styles.min.css" />
  </head>
  <body>
    <div id="root"></div>
    <script src="{{ relativePathPrefix }}js/app.min.js"></script>
  </body>
</html>

Note

React comes from your project's node_modules (npm i react react-dom), not from Poops โ€” see React.

Develop and build

poops        # watch + serve + livereload at http://localhost:4040
poops -b     # one-off production build into dist/

Tip

This is a pure SPA: nothing renders until the JS loads. If you want real HTML on first paint (better SEO and perceived speed), pre-render with Reactor instead โ€” see A complete React static site.

Info

For a library rather than an app โ€” shipping ESM/CJS/IIFE builds of your components โ€” see Transpiling JavaScript โ€บ Maintaining a JS library.