In this post I will go over how to create a Tailwind component library. We will be using Vite, Tailwind, React and GitHub.
import react from "@vitejs/plugin-react";
import path from "node:path";
import { defineConfig } from "vitest/config";
import dts from "vite-plugin-dts";
import tailwindcss from "tailwindcss";
import { UserConfigExport } from "vite";
import { name as orName, peerDependencies } from "./package.json";
import { fileURLToPath } from "url";
import { dirname } from "path";
const name = orName.split("/").pop();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const app = async (): Promise<UserConfigExport> => {
return defineConfig({
plugins: [
react(),
dts({
insertTypesEntry: true,
}),
],
css: {
postcss: {
plugins: [tailwindcss],
},
},
build: {
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
name,
formats: ["es", "umd"],
fileName: (format) => `${name}.${format}.js`,
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
external: Object.keys(peerDependencies),
output: {
globals: {
react: "React",
"react/jsx-runtime": "react/jsx-runtime",
"react-dom": "ReactDOM",
tailwindcss: "tailwindcss",
},
},
},
}
});
};
// https://vitejs.dev/config/
export default app;
import type { Config } from "tailwindcss";
const config: Config = {
important: true,
content: [
"./src/**/*.{js,ts,jsx,tsx}",
],
};
export default config;
{
"name": "@your-org/component-lib",
"private": false,
"version": "0.0.1",
"main": "./dist/component-lib.umd.js",
"module": "./dist/component-lib.es.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/component-lib.es.js",
"require": "./dist/component-lib.umd.js"
},
"./dist/style.css": "./dist/style.css"
},
"publishConfig": {
"@your-org:registry": "https://npm.pkg.github.com"
},
"repository": {
"type": "git",
"url": "https://github.com/your-org/component-lib.git"
},
"files": [
"dist"
]
}
The .npmrc is use to authorize you when running npm publish
. You will need to create a token from your GitHub developer settings. The minimum scope needed for the token is package
.
@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}
This is were the fun begins. Now that you have everything setup you can add your components. Make sure to export the components from src/index.ts
(the entry point set in vite.config.ts).
Now you can publish your package using npm publish
from the command line. I prefer to set up a GitHub action to publish when I push a new commit to the main branch. You can set your own action by adding the necessary steps in ./github/workflows. You will also need to set up an action secret PUBLISH_TOKEN
so you are authorized to publish.
name: Publish Package
on:
push:
paths: ["package.json"]
branches: ["main"]
jobs:
publish-gpr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 16
registry-url: https://npm.pkg.github.com/
scope: "@your-org"
- run: npm install
- run: npm run build
- run: npm publish
env:
PUBLISH_TOKEN: ${{secrets.PUBLISH_TOKEN}}
To install your new package, add a .npmrc
file
@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}
Then create a .env file and add your publish token to the file.
PUBLISH_TOKEN=YOUR_GITHUB_PUBLISH_TOKEN
Now when you run npm install @your-org/component-lib
, npm will resolve the PUBLISH_TOKEN
from your .env file.
@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}
Run the npm command to install your package npm install @your-org/component-lib
. And finally, import your components and use them as needed.
import { Button } from '@your-org/component-lib'
import { PiHandWaving } from "react-icons/pi";
const App = ()=>{
return (
<Button icon={<PiHandWaving />} />
)
}