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

Adds support for ESM tailwind.config.js files #3544

Closed
wants to merge 2 commits into from

Conversation

natemoo-re
Copy link
Contributor

@natemoo-re natemoo-re commented Feb 8, 2021

ESM adoption in Node is becoming more common—it would be really great for Tailwind to get out ahead of a lot of the issues people are about to run into as the ecosystem shifts to support ESM.

Currently, users who rely on Node ESM with "type": "module" (officially supported since node@12.17.0) must use a tailwind.config.cjs file in CJS format (#3181) inside of their ESM project. This is great! But the best solution would be to allow ESM projects to use the normal tailwind.config.js file in ESM format, as requested in discussion #2284.

I thought this would be a bigger problem, but it turned out to be fairly simple. The magic here is a utility function that attempts to require the config path (will work for CJS files), catch any errors with code: "ERR_REQUIRE_ESM", and then import the config path instead (will work for ESM files). Note that this util function is split into a separate file and excluded from the babel config, otherwise babel transpiles out the native import statement.

Two issues I'd love some assistance on:

  • I don't really know how to write tests for this.
  • There is probably additional logic that needs to be updated to accommodate ESM config files... getModuleDependencies and maybe others?

try {
return require(config)
} catch (e) {
if (e.code === 'ERR_REQUIRE_ESM') {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it is a different exception? Right now you will return null, but I think you should throw the original exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, that makes total sense. I will update this!

if (e.code === 'ERR_REQUIRE_ESM') {
try {
return import(config).then(mdl => mdl.default)
} catch (e) {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to my previous comment, maybe just throw the original exception in here if import also failed, instead of an empty catch?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@natemoo-re Might you update the pull request, please?

@daskyrk
Copy link

daskyrk commented Jan 5, 2022

Any update on this? I want to import esm file in tailwind.config.js, but import statement return a promise, and tailwind.config.js seems not support return a function.

const plugin = require('tailwindcss/plugin');
const erdaTheme = import('./app/erda-theme.mjs');

modules.exports = {
  theme: { colors: erdaTheme } // is a promise instead of plain object
}

I think this may help if i can change the config file to esm type.

@xiaoxiangmoe
Copy link

Any update on this?

@dlugoschvincent
Copy link

I would really appreciate this feature!

@thecrypticace
Copy link
Contributor

Hey! So this has been open as a draft for a while now and I'm looking through issues. Looking into this we'd need to make a handful things async (some of which you have done) but this will definitely break intellisense with the way it's currently implemented. Many things there are assumed to be entirely synchronous. We definitely would love to have ESM support (I would love it personally too) for config files but it can't happen in v3.1. The other thing is that getModuleDependencies would need to be able to track ESM imports/exports in addition to requires. This is further complicated by the fact that, in ESM, you can create your own require function using createRequire. Detecting config changes is simple enough but tracking ESM dependencies could be significantly more involved. I'm not sure if this will be something we want to look at in v3.2 or for a v4.0 in the future.

Given that this would be a non-trivial time sink for Tailwind CSS, Intellisense, and possibly the prettier plugin, we would need to be sure we could support and update all of those at the same time. Neither I nor the rest of the team have the time to do this properly right now so I'm gonna close this. I really appreciate your work on this and will absolutely reference and credit it in the future when we have a chance to think through this and implement it in a way that we feel comfortable with shipping.

Really do appreciate your time on this though! ✨

@FossPrime
Copy link

FossPrime commented Nov 11, 2022

Given that this would be a non-trivial time sink for Tailwind CSS, Intellisense, and possibly the prettier plugin

ESM support is more important than intellisense or the prettier plugin. Not having ESM means I won't be using tailwind for my next project. I often don't have intellisense (TM), due to the sea of cloud IDE's with their own flavor of it, so that's not an issue. Anthony Fu has even renounced prettier in favor of other workflows for similar reasons reasons.

What I'm saying is, ESM should have been supported Q4 2021, at the latest, and not having it is a really bad look, so it should be priority number one. Off the top of my head, node-fetch, test runner, speed, top-level async and avoiding configuration nightmares are well worth drooping tailwind for UnoCSS or bare-metal PostCSS, depending on whether you can use Vite.

@dionsaur84
Copy link

dionsaur84 commented Dec 31, 2022

theres a workaround by using this code for your postcss config:

import autoprefixer from 'autoprefixer'
import tailwind from 'tailwindcss'
import tailwindConfig from './tailwind.config.js'

export default {
    plugins: [tailwind(tailwindConfig), autoprefixer],
}

then your tailwind config file can use esm e.g.:

export default {
    content: ['./src/components/**/*.jsx'],
    theme: {
        extend: {},
    },
    plugins: [],
}

credit to @muuvmuuv for this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants