Updated
—
5 min read
I recently published react-google-reviews, a library for integrating Google reviews with ReactJS.
And in publishing this library, I originally wanted to use TailwindCSS for styling the components in the library.
So here's a step-by-step guide on bundling a React library that uses TailwindCSS using Rollup.js. Let's dive right in!
Create a new project folder:
bashmkdir rollup-tailwind
cd rollup-tailwind
Initialize npm package:
bashnpm init -y
For this tutorial, we'll have a simple folder structure:
bash- package.json
- src
- components
- index.ts
- Button.tsx
- index.ts
Our Button.tsx
will use Tailwind classes like so:
jsximport React from "react";
function Button() {
return (
<button className="outline bg-blue-500 text-white">
Hello World
</button>
);
}
In components/index.ts
we'll export our Button
:
javascriptexport { default as Button } from "./Button";
In src/index.ts
, our entry file, we will similarly export the Button
:
javascriptimport { Button } from "./components";
export {
Button
};
Lastly, let's install some dependencies:
bashnpm i -D react react-dom rollup tailwindcss typescript @types/react @types/react-dom @rollup/plugin-typescript @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-terser rollup-plugin-postcss postcss tslib autoprefixer rollup-plugin-dts
We'll be using several Rollup plugins, as well as installing TailwindCSS and PostCSS.
Now let's create our rollup.config.js
file:
javascriptimport commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import terser from "@rollup/plugin-terser";
import typescript from "@rollup/plugin-typescript";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts";
const packageJson = require("./package.json");
export default [
{
input: "src/index.ts",
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true,
},
{
file: packageJson.module,
format: "esm",
sourcemap: true,
},
],
plugins: [
resolve({
ignoreGlobal: false,
include: ['node_modules/**'],
skip: ['react', 'react-dom'],
}),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
postcss({
extract: true,
minimize: true,
}),
terser(),
],
},
{
input: "dist/esm/types/index.d.ts",
output: [{ file: "dist/index.d.ts", format: "esm" }],
plugins: [dts.default()],
external: [/\.css$/],
},
];
It's a simple setup. We define our entry point, and the output files will point to our package.json
.
We also install several plugins that will be necessary, most importantly rollup-plugin-postcss
.
It's important to skip react-dom
and react
in the node resolve plugin to avoid errors like "Cannot read properties of null (reading 'useRef')".
Similary, since we're building a React library, we should move react-dom
and react
to peerDependencies
in our package.json:
json{
"peerDependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
}
}
By setting react
and react-dom
as externals in our rollup configuration, we avoid these errors caused by having duplicate React versions.
Now let's get back to the project.
Our rollup.config.js
references our main
and module
properties of our package.json
.
So let's modify our package.json
scripts like so:
json"scripts": {
"rollup": "rollup -c --bundleConfigAsCjs"
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"files": [
"dist"
],
We've added a script to run Rollup and also defined two output files for CommonJS and ES Modules, respectively.
Since we're using Typescript, let's initialize a tsconfig.json
:
json{
"compilerOptions": {
"target": "es5",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"lib": ["dom", "dom.iterable", "esnext"],
"skipLibCheck": true,
"jsx": "react",
"module": "ESNext",
"declaration": true,
"declarationDir": "types",
"sourceMap": true,
"outDir": "dist",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"emitDeclarationOnly": true,
},
"include": ["src"],
}
Pretty simple setup, but note that our outDir
points to our dist
directory.
Now we're ready to integrate TailwindCSS into our Rollup bundle process.
You should already have Tailwind installed from previously, but if not:
bashnpm i -D tailwindcss postcss autoprefixer
Then initialize TailwindCSS:
bashnpx tailwindcss init
Modify your tailwind.config.js
like normally:
javascript/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.tsx"
],
theme: {
extend: {},
},
plugins: [],
}
And now we'll create a main.css
located in src/styles/main.css
:
css@tailwind base;
@tailwind components;
@tailwind utilities;
We're almost done, now let's finish up our Rollup config.
The final step is to modify our rollup.config.js
by adding this object to our exported array:
javascript{
input: "src/styles/main.css",
output: [{ file: "dist/index.css", format: "es" }],
plugins: [
postcss({
extract: true,
minimize: true,
}),
],
},
Here we are pointing to our main.css
file and using PostCSS to bundle a dist/index.css
file which will contain our compiled TailwindCSS styles.
If you run Rollup now:
npm run rollup
You should see a dist
folder be generated as follows:
bash- dist
- cjs
- esm
- index.css
In our Button.tsx
component, we had used three classes: outline
, bg-blue-500
and text-white
.
We can verify whether Rollup bundled our Tailwind styles by opening up dist/index.css
:
css.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}
.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}
.outline{outline-style:solid}
And it worked!
We can confirm this further by running npm pack
and installing the package onto a blank NextJS app.
Then we import and use the component like so:
jsximport { Button } from "rollup-tailwind";
import "rollup-tailwind/dist/index.css";
export default function Home() {
return (
<div style={{ padding: "20px" }}>
<Button></Button>
</div>
);
}
Remember to import the index.css
file.
And we see that our Tailwind classes have been bundled using Rollup:
Integrating TailwindCSS with Rollup isn't too challenging, but requires some knowledge of configuration.
We use PostCSS and Rollup plugins to bundle our Tailwind styles into our package for distribution.
Hope this helps!
Meet the Author
Ryan Chiang
Hello, I'm Ryan. I build things and write about them. This is my blog of my learnings, tutorials, and whatever else I feel like writing about.
See what I'm building →.
Thanks for reading! If you want a heads up when I write a new blog post, you can subscribe below: