DEV Community

ynwd
ynwd

Posted on

How to setup react shared components in monorepo with tailwind, webpack and npm workspace

Previously, we have integrated tailwind and react using webpack. Now we will try to apply it to shared components in monorepo.

.
├── package.json
└── web
    ├── components
    │   ├── babel.config.js
    │   ├── package.json
    │   ├── postcss.config.js
    │   ├── src
    │   │   ├── Button.js
    │   │   ├── Header.js
    │   │   ├── index.css
    │   │   ├── index.js
    │   │   └── stories
    │   ├── tailwind.config.js
    │   └── webpack.config.js
    └── modules
        ├── home
        │   └── package.json
        └── root
            ├── src
            │   ├── App.js
            │   └── index.js
            └── package.json
Enter fullscreen mode Exit fullscreen mode

clone our previous branch: https://github.com/ynwd/monorepo/tree/storybook

install postcss & tailwind packages

npm i postcss postcss-cli postcss-import postcss-loader tailwindcss autoprefixer autoprefixer cssnano mini-css-extract-plugin -D
Enter fullscreen mode Exit fullscreen mode

Update webpack config

const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const devMode = process.env.NODE_ENV !== "production"

module.exports = {
    mode: devMode ? "development" : "production",
    entry: {
        index: { import: "./src/index.js" }
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                exclude: /node_modules/,
                loader: "babel-loader",
            },
            {
                test: /\.css$/i,
                use: [
                    devMode ? "style-loader" : MiniCssExtractPlugin.loader,
                    'css-loader',
                    "postcss-loader",
                ],
            },
        ],
    },
    output: {
        filename: "components.bundle.min.js",
        library: 'fstrComponents',
        libraryTarget: 'umd',
        clean: true
    },
    plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]),
}

Enter fullscreen mode Exit fullscreen mode

Create postcss config

module.exports = {
    plugins: [
        require('postcss-import'),
        require('tailwindcss'),
        require('autoprefixer'),
        require('cssnano')({
            preset: 'default',
        }),
    ],
};
Enter fullscreen mode Exit fullscreen mode

Create tailwind config

module.exports = {
  purge: [
    './src/**/*.js',
  ],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Create tailwind entrypoint

/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Create custom components

/* src/Button.js */
import React from "react"

export const Button = ({ text = "" }) => {
    return (
        <button className="p-2 pl-5 pr-5 bg-red-500 text-gray-100 text-lg rounded-lg focus:border-4 border-blue-300">
            {text}
        </button>
    )
}
Enter fullscreen mode Exit fullscreen mode
/* src/Header.js */
import React from "react"

export const Header = ({ text = "" }) => {
    return (
        <div className="bg-blue-300 mx-auto max-w-sm shadow-lg rounded-lg overflow-hidden">
            <div className="sm:flex sm:items-center px-6 py-4">
                <img className="block h-16 sm:h-24 rounded-full mx-auto mb-4 sm:mb-0 sm:mr-4 sm:ml-0" src="https://avatars.githubusercontent.com/u/10122431?s=400&v=4" alt="" />
                <div className="text-center sm:text-left sm:flex-grow">
                    <div className="mb-4">
                        <p className="text-xl leading-tight">John Doe</p>
                        <p className="text-sm leading-tight text-grey-dark"> {text} </p>
                    </div>
                </div>
            </div>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

Update react entry point. We import css file also.

/* src/index.js */
import { Button } from "./Button"
import { Header } from "./Header"
import "./index.css"

export {
    Button,
    Header
}
Enter fullscreen mode Exit fullscreen mode

Update web/components/package.json script

{
   ...
  "scripts": {
    "build": "NODE_ENV=production webpack",
    "build-watch": "webpack --watch",
    "test": "echo \"Error: no test specified\" && exit 1",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Compile

npm run build
Enter fullscreen mode Exit fullscreen mode

Go to app root dir.

cd ../../
Enter fullscreen mode Exit fullscreen mode

And don't forget to link the built package.

npm install
Enter fullscreen mode Exit fullscreen mode

Import react-tailwind components

Update root module entry point. Import generated css from components.

/* web/modules/root/src/index.js */
import React from 'react'
import ReactDOM from 'react-dom'
import "@fstr/components/dist/index.css"
import App from './App'
import reportWebVitals from './reportWebVitals'

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals()

Enter fullscreen mode Exit fullscreen mode

Update react app

/* web/modules/root/src/App.js */
import { Header, Button } from "@fstr/components"

function App() {
  return (
    <div>
      <Header text="from root" />
      <Button text="my button" />
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Still in the app root folder, run this to see the changes

npm start -w @fstr/root
Enter fullscreen mode Exit fullscreen mode

You can see the final source code on this branch: https://github.com/ynwd/monorepo/tree/tailwind

Discussion (0)