DEV Community

Will Medina
Will Medina

Posted on • Edited on

3 1

Complete React 19 setup with SSR, CSR, TailwindCSS 4, and Jest using esbuild

This is a continuation of my first blog post:

In this post I will extend the setup adding TailwindCSS for styling, Jest for unit testing.

Configuring TailwindCSS

To enable TailwindCSS we need to add PostCSS and write a small esbuild plugin to enable TailwindCSS in our css file.

First we'll need to install the following dependencies:

npm i --save-dev postcss tailwindcss @tailwindcss/postcss
Enter fullscreen mode Exit fullscreen mode

Now lets create a esbuild plugin that we can add to our scripts to enable postcss and tailwindcss:

import { readFile } from 'node:fs/promises';
import postcss from 'postcss';
// esbuild Plugin to process css files with postcss
export const postcssPlugin = ({
  plugins = []
} = {}) => {
  return {
    name: 'postcss',
    setup(build) {
      build.onLoad({ filter: /\.css$/ }, async (args) => {
        const raw = await readFile(args.path, 'utf8');
        const source = await postcss(plugins).process(raw.toString(), {
            from: args.path
          });
        return {
          contents: source.css,
          loader: 'css'
        };
      });
    }
  };
}

export default postcssPlugin;
Enter fullscreen mode Exit fullscreen mode

In your esbuild configuration now we can use the plugin:

import tailwindcss from '@tailwindcss/postcss';
{
  //...esbuildConfig,
  plugins: [
    postcssPlugin({
      plugins: [
        tailwindcss
      ]
    })
  ]
}
Enter fullscreen mode Exit fullscreen mode

Since version 4 tailwindcss does not require a config script but instead configures it with CSS. This is a basic style.css using dynamic background and foreground colors:

@import "tailwindcss";

@theme {
  --color-background: #ffffff;
  --color-foreground: #171717;
}

@variant dark (&:where(.dark, .dark *));

@layer base {
  body {
    @apply text-foreground bg-background;
  }
  .dark {
    --color-background: #0a0a0a;
    --color-foreground: #ededed;
  }
}
Enter fullscreen mode Exit fullscreen mode

Configuring Jest

To enable Jest in our project we will use @testing-library as it will facilitate the configuration and testing utilities.

Install the following dependencies:

npm i --save-dev jest jest-environment-jsdom @testing-library/jest-dom @testing-library/react @types/jest
Enter fullscreen mode Exit fullscreen mode

To configure Jest with react and esbuild we'll need to create a transformer to transpile typescript and jsx.

import { transformSync } from 'esbuild';
export default {
  process(src, filename) {
    // Ensure only TypeScript and JavaScript files are processed
    if (/\.(ts|tsx|js|jsx)$/.test(filename)) {
      const result = transformSync(src, {
        loader: filename.endsWith('ts') || filename.endsWith('tsx') ? 'tsx' : 'jsx',
        format: 'esm',  // ESM format
        sourcemap: 'inline', // Inline sourcemaps for debugging
        target: 'esnext', // Set the target to latest ECMAScript
        tsconfigRaw: {
          compilerOptions: {
            jsx: 'react-jsx'
          },
        }
      });
      return { code: result.code, map: result.map };
    }
    return src;
  },
};
Enter fullscreen mode Exit fullscreen mode

We'll also need a environment setup file to import jest-dom from @testing-library that way we can use the library matches like toBeInTheDocument and toBeInTheDOM.

import '@testing-library/jest-dom';
Enter fullscreen mode Exit fullscreen mode

Lastly we can create a config file jest.config.json that will use our custom esbuild transformer and setup file.

{
  "testMatch": [
    "<rootDir>/**/?(*.)+(test).(ts|tsx)"
  ],
  "transform": {
    "^.+\\.(ts|tsx)$": "<rootDir>/scripts/testTransformer.js"
  },
  "setupFilesAfterEnv": [
    "<rootDir>/scripts/testSetup.ts"
  ],
  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
  "extensionsToTreatAsEsm": [".ts", ".tsx", ".svg"],
  "transformIgnorePatterns": ["/node_modules/"],
  "testEnvironment": "jsdom"
}
Enter fullscreen mode Exit fullscreen mode

This will allow us to run jest test files in the project. since we are using esm we have to use node --experimental-vm-modules flag.

There are also others utilities that are commonly used in react projects like importing SVG as Components and auto reload on changes. I have included these in my repository:

GitHub logo willyelm / react-app

A Simple react app setup with SSR, CSR, Jest, TailwindCSS and esbuild

A Simple react app setup with SSR and esbuild

This project leverages the latest features of react@19, react-router-dom@7, and others to configure SSR.

Depdendencies

  • react: Component-based and interactive UI library.
  • react-dom: Hydrates SSR content with React functionality.
  • react-router-dom: Handle Routes with React.
  • express: Node.js simple server for static and REST APIs.
  • esbuild: Transile TypeScript and bundle JS, CSS, SVG, and other files.
  • typescript: Adding Typing to our source code.
  • jest: Unit testing.
  • postcss: Preprocess css files.
  • tailwindcss: css utilities.
  • svgo: converting svg to JSX component modules.

Project Structure

react-app/             # This will be our workspace directory.
  - public/
  - scripts/           
    - build.js         # Bundle our server and client scripts.
    - config.js        # esbuild config to bundle.
    - dev.js           # Bundle on watch mode and run server.
  - src/
    - App/             # Our components will be here.
      - App.tsx        # The
Enter fullscreen mode Exit fullscreen mode

Billboard image

Deploy and scale your apps on AWS and GCP with a world class developer experience

Coherence makes it easy to set up and maintain cloud infrastructure. Harness the extensibility, compliance and cost efficiency of the cloud.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay