Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new `plugin` and `plugin.withOptions` functions for creating plugins #1268

Merged
merged 1 commit into from Dec 20, 2019

Conversation

@adamwathan
Copy link
Member

adamwathan commented Dec 20, 2019

This PR adds support for a new way of creating plugins using a new plugin function exposed at tailwindcss/plugin.

It allows you to create plugins like this:

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

module.exports = plugin(function({ addUtilities, theme, variants }) {
  // Plugin work goes here
}, {
  theme: {
    // ...
  },
  variants: {
    // ...
  },
})

The first argument to plugin is the traditional Tailwind plugin function. The second argument is your plugin's config object that should be merged with the user's config.

This API replaces the unstable API introduced in #1162 that allowed you to write your plugins as an object with a config and handler property:

module.exports = {
  config: {
    theme: {
      // ...
    },
    variants: {
      // ...
    },
  },
  handler({ addUtilities, theme, variants }) {
    // ...
  }
}

This PR also introduces a plugin.withOption function that allows you to author plugins that accept top-level non-config options:

const plugin = require('tailwindcss/plugin')

module.exports = plugin.withOptions(function(options) {
  return function({ addUtilities, theme, variants }) {
    // ...
  }
}, function(options) {
  return {
    theme: {
      // ...
    },
    variants: {
      // ...
    },
  }
})

These sorts of plugins are used by end-users like this:

// tailwind.config.js
module.exports = {
  plugins: [
    require('some-fancy-plugin')({ optionA: 'foo', optionB: 'bar' })
  ]
}

This is implemented in such a way that if your plugin takes top-level options but those options are optional, the end-user doesn't need to invoke your plugin with no arguments when adding it to their Tailwind config:

// tailwind.config.js
module.exports = {
  plugins: [
    require('some-fancy-plugin')
  ]
}

It's worth noting that under the hood we are still using the { config: ..., handler: .... } format (that's what this helper function spits out) so functions authored that way will continue to work, although you're encouraged to migrate to this new API.

@adamwathan adamwathan merged commit 293900a into master Dec 20, 2019
1 check passed
1 check passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@hacknug

This comment has been minimized.

Copy link
Contributor

hacknug commented Dec 23, 2019

This is implemented in such a way that if your plugin takes top-level options but those options are optional, the end-user doesn't need to invoke your plugin with no arguments when adding it to their Tailwind config

I love this ❤️

@qntndev

This comment has been minimized.

Copy link

qntndev commented Jan 7, 2020

Hey @adamwathan, I use this feature to add plugins to my Vue & Tailwind project and I have a question related to the vue-cli/webpack config on this. Is there a way to use aliases defined in webpack config in tailwind.config.js to require a plugin as require('alias/plugin')?

//vue.config.js
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        TailwindPlugins: 'src/assets/styles/plugins'
      }
    }
  }
};

Neither the base webpack alias for src @ nor the one I have defined can resolve the path correctly. I get an Cannot find module error. Did you get this to works on some of your projects ?

//tailwind.config.js
module.exports = {
  //...
  plugins: [
    require('src/assets/styles/plugins/reset'),   //✅
    require('@/assets/styles/plugins/reset'),     //❌
    require('TailwindPlugins/reset')              //❌
  ]
}
@adamwathan

This comment has been minimized.

Copy link
Member Author

adamwathan commented Jan 7, 2020

My guess is that that file isn't processed by Webpack in the same way since it's not part of the actual modules being bundled, it's just a config file written in CommonJS format that is part of configuring the build rather than being part of the JS that is output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.