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

Enable ESM and TS based config files #10785

Merged
merged 44 commits into from Mar 15, 2023

Conversation

RobinMalfait
Copy link
Contributor

@RobinMalfait RobinMalfait commented Mar 13, 2023

This PR adds support for loading and scaffolding ESM and TypeScript config files.

ESM and TS syntax support

Prior to this PR, your tailwind.config.js file had to be in CommonJS format. This was surprising to people using "type": "module" in their projects, and made it more difficult to do things like extract your theme tokens into a separate module that you could import into your tailwind.config.js as well as into your application code to maintain a single source of truth.

To make this work, we need to transpile ESM and TS config files on the fly (using jiti), since Tailwind itself isn't published in native ESM and of course there's no native TS support in Node.js. This means there is a performance penalty to using ESM and TS config files, which we're mitigating as much as possible by using Sucrase as the parser instead of Babel. The penalty on my machine is about ~10ms (~50ms using Babel) for one-off builds and the initial build in watch mode, and basically not measurable for incremental builds.

CLI improvements

This PR also adds --esm and --ts flags to the tailwindcss init CLI command to generate your config file using your preferred syntax:

npx tailwindcss init --esm

When running the init command with no flags, Tailwind will guess which syntax to use based on the "type" field in your package.json.

When using the --postcss flag, the generated postcss.config.js file will use the same syntax as your tailwind.config.js file, whether inferred or specified explicitly on the command line.


@natemoo-re and @innocenzi have been credited as co-authors for their efforts in earlier PRs:

@RobinMalfait RobinMalfait force-pushed the feat/esm-and-typescript-config-file branch 2 times, most recently from 1758789 to bb3c480 Compare March 15, 2023 17:56
…file

The root `defaultConfig` is still there for backwards compatibilty
reasons. But the `module.exports = requrie('./config.full.js')` was
causing some problems when actually using tailwindcss.

So dropped it instead.
@RobinMalfait RobinMalfait force-pushed the feat/esm-and-typescript-config-file branch from bb3c480 to 9bcf8ba Compare March 15, 2023 17:58
loadConfig.d.ts Show resolved Hide resolved
src/lib/load-config.ts Show resolved Hide resolved
integrations/io.js Outdated Show resolved Hide resolved
A little smaller but just for tests so doesn't matter too much here 👍
@adamwathan adamwathan merged commit 7e9a53f into master Mar 15, 2023
21 checks passed
@adamwathan adamwathan deleted the feat/esm-and-typescript-config-file branch March 15, 2023 21:04
@innocenzi
Copy link
Contributor

innocenzi commented Mar 15, 2023

Super happy we finally have this, great job guys ❤️

Tested with two medium projects:

  • Both with @tailwindcss/forms and a few other external plugins
  • Both greatly customized
  • One that uses two configs through @config

Everything works perfectly fine, migration is easy. Super nice.

I've noticed zIndex has type issues. I had the following:

zIndex: {
	'sticky-on-scroll': 20,
	'chat-bubble': 30,
	'navbar': 30,
	'navbar-dropdown': 25,
	'dialog-base': 35,
	'dialog-panel': 36,
	'notification': 50,
},

But I had to make the values strings instead of numbers. Using @type {import('tailwindcss').Config} did not catch that before.

The only thing I miss is a defineConfig util instead of having to add satisfies Config at the end of the exported object, which is subjectively less pretty. But it's minor.

Thank you for this! ❤️

@woss
Copy link

woss commented Mar 24, 2023

hi, has this been released? i'm trying to get the TS and ESM js config to work but it doesn't.

@RobinMalfait
Copy link
Contributor Author

@woss no not yet, it will be soon though!

If you want to know what's released and what isn't you can always take a look at the CHANGELOG.md file.

That said, you can already play with it using the insiders version: npm install tailwindcss@insiders.

@karlhorky
Copy link

karlhorky commented Mar 24, 2023

This looks great, thanks for this @RobinMalfait 🙌

Since the current version number is 3.2.7, I guess this will be probably released in a new minor (tailwindcss@3.3.0)?

@joshmanders
Copy link
Contributor

Thank you @RobinMalfait this is a long awaited feature I've been waiting for! Happy early birthday to me!

@klib19
Copy link

klib19 commented Mar 28, 2023

Thank you all for this feature! This is exactly what I needed for my project, I appreciate all the hard work!

One thing that is unclear to me and isn't addressed in the documentation, is how do I import the Tailwind colors into my ESM config file? None of these work

const colors = require('tailwindcss/colors')
import colors from "tailwindcss/colors";
import colors from "tailwindcss/colors.js";

@seb-jean
Copy link
Contributor

Hello,

How to add defaultTheme, plugin, etc with TS.

Like this?

const defaultTheme = require('tailwindcss/defaultTheme');
const plugin = require('tailwindcss/plugin');

@karlhorky
Copy link

karlhorky commented Mar 31, 2023

The more common style is import in TypeScript:

import defaultTheme from 'tailwindcss/defaultTheme';
import plugin from 'tailwindcss/plugin';

Often your editor / IDE can do this conversion for you like Convert 'require' to 'import' in VS Code (either use the lightbulb or hover over the three dots -> Quick Fixes -> "Convert 'require' to 'import'")

@RobinMalfait
Copy link
Contributor Author

@klib19 while I wouldn't recommend to mix everything. All three of those should just work:
image

If you are experiencing issues then I would recommend to open an issue with a minimal reproduction repo attached that shows the issue.


@seb-jean as @karlhorky mentioned, you would use the import syntax in this case 👍

@seb-jean
Copy link
Contributor

thanks @RobinMalfait

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.

None yet

9 participants