icube
icube

Reputation: 2798

Consuming a Component Library that uses TailwindCSS

We have a Component library (VueJS) that uses TailwindCSS which we are going to publish as a private npm package. The questions I have are

  1. How do we also expose the tailwind.config.js in the Component Library so the consuming project can make use of the settings in the Component Library for example the colors in the consuming project's tailwind.config.js.
  2. Is there a recommended way of "inheriting" the styles defined in the Component library?
  3. And also since TailwindCSS V3 uses JIT to generate the classes, how do I also include the classes in the Component library?

Upvotes: 22

Views: 8211

Answers (3)

agm1984
agm1984

Reputation: 17132

I just accomplished this as part of a design system by providing the config in the dist folder:

./src/assets/tailwind/config.js

const content = [
    './index.html',
    './src/**/*.{vue,js,ts,jsx,tsx}',
];

// theme values to be shared
const theme = {};

const plugins = [
    '@tailwindcss/line-clamp',
];

module.exports = {
    defaultContent: content,
    defaultTheme: theme,
    defaultPlugins: plugins,
};

./tailwind.config.js

const { defaultContent, defaultTheme, defaultPlugins } = require('./src/assets/tailwind/config');

module.exports = {
  content: [
    ...defaultContent,
  ],
  theme: {
    ...defaultTheme,
  },
  plugins: [
    ...defaultPlugins.map(plugin => require(plugin)),
  ],
}

Also I have a rollup build step that executes this:

"scripts": {
    "publish:lib": "normalstuff && node build-meta",
},

./build-meta.js

const fs = require('fs-extra');
const path = require('path');

fs.copySync(path.resolve(__dirname, './src/assets/tailwind/config.js'), 'dist/assets/tailwind-defaults.js');
// I learned this technique from PrimeVue (so check their GitHub repo)

consuming applications

const { defaultContent, defaultTheme, defaultPlugins } = require('@yolo-inc/package-name/assets/tailwind-defaults');

module.exports = {
  content: [
    ...defaultContent,
  ],
  theme: {
    ...defaultTheme,
  },
  plugins: [
    ...defaultPlugins.map(plugin => require(plugin)),
  ],
}

Upvotes: 0

Al Pal
Al Pal

Reputation: 335

I had to do exactly this not too long ago and we used rollup for our tailwind component library. I installed the copy plugin for rollup (from their official plugin list) and in my rollup.config.js I had something to this effect:

import copy from "rollup-plugin-copy";

const config = {
  plugins: [
      copy({
        targets: [
          {
            src: "./tailwind.config.js",
            dest: "dist",
          }
        ]
      })
  ]
}
export default config;

So that copied that file into my output and I use that in whichever application is consuming this library like so:

//tailwind.config.js
const commonConfig = require("component_library/dist/tailwind.config.js")
module.exports = { ...config }

and that works to solve #1 and #2 of your questions. I remember reading about this being supported somewhere in Tailwind documentation but can't remember where. You can also do overriding in your consumer app with basic destructuring like so:

//tailwind.config.js
const commonConfig = require("component_library/dist/tailwind.config.js")

module.exports = {
  ...commonConfig,
  plugins: [
    ...commonConfig.plugins,
    require("@tailwindcss/line-clamp"),
  ],
}

As for question #3, I was able to go with @harryg 's method of just adding "./node_modules/my-component-library/dist/*.js" to my tailwind.config.js in my component library and when I imported that config to the consumer app it was able to pick up all the needed styles/classes to compile without needing to export an entire tailwind stylesheet from the library. Hope this helped.

Upvotes: 6

harryg
harryg

Reputation: 24077

For 1 and 2 it looks like your component library could export a Tailwind plugin that a consuming project would register in their own Tailwind config.

The second argument to plugin() can be any configuration your component libary wants to merge with the user's Tailconfig config.

E.g.

// plugin.js
const plugin = require('tailwindcss/plugin')

const myComponentLibraryConfig = {
  theme: {
    extend: {
      colors: {
        salmon: 'salmon'
      }
    }
  }
}

module.exports = plugin(({ addUtilities, addComponents, e, config }) => {
  // Add your custom styles here
}, myComponentLibraryConfig),

When publishing your component library as a package, ensure the plugin is included.

Then, in your consuming project:

// tailwind.config.js

module.exports = {
    //...
    plugins: [
        require('my-component-library/plugin')
    ]

}

For 3, it looks like you might need to explicitly add the location of your component library's components to the content section. E.g.

// tailwind.config.js

module.exports = {
    content: [
        "./node_modules/my-component-library/**/*.js",
        "./src/components/**/*.{js,jsx,ts,tsx}", // or whatever
    ]
}

The actual paths to things will depend on your project strucutures, but hopefully you get the idea.

Upvotes: 10

Related Questions