Skip to content

Commit 7e9a53f

Browse files
RobinMalfaitadamwathanthecrypticacenatemoo-reinnocenzi
authored
Enable ESM and TS based config files (tailwindlabs#10785)
* add `jiti` and `detective-typescript` dependencies * use `jiti` and `detective-typescript` Instead of `detective`, this way we will be able to support `tailwind.config.ts` files and `ESM` files. * use `@swc/core` instead of the built-in `babel` form `jiti` * update changelog * add `jiti` and `detective-typescript` dependencies to `stable` * use `sucrase` to transform the configs * add `sucrase` dependency to `stable` engine * make loading the config easier * use abstracted loading config utils * WIP: make `load` related files public API * use new config loader in PostCSS plugin * add list of default config files to look for * cleanup unused arguments * find default config path when using CLI * improve `init` command * make eslint happy * keep all files in `stubs` folder * add `tailwind.config.js` stub file * Initialize PostCSS config using the same format as Tailwind config * Rename config content stubs to config.*.js * Improve option descriptions for init options * Remove unused code, remove `constants` file * Fix TS warning * apply CLI changes to the Oxide version * update `--help` output in CLI tests * WIP: make tests work on CI TODO: Test all combinations of `--full`, `--ts`, `--postcss`, and `--esm`. * wip * remove unused `fs` * Fix init tests Did you know you could pass an empty args to a command? No? Me neither. ¯\_(ツ)_/¯ * bump `napi-derive` * list extensions we are interested in * no-op the `removeFile` if file doesn't exist * ensure all `init` flags work * ensure we cleanup the new files * test ESM/CJS generation based on package.json * remove unnecessary test We are not displaying output in the `--help` anymore based on whether `type: module` is present or not. Therefore this test is unneeded. * only look for `TypeScript` files when the entryFile is `TypeScript` as well * refactor `load` to be `loadConfig` This will allow you to use: ```js import loadConfig from 'tailwindcss/loadConfig' let config = loadConfig("/Users/xyz/projects/my-app/tailwind.config.ts") ``` The `loadConfig` function will return the configuration object based on the given absolute path of a tailwind configuration file. The given path can be a CJS, an ESM or a TS file. * use the `config.full.js` stub instead of the `defaultConfig.stub.js` 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. * apply `load` -> `loadConfig` changes to `Oxide` engine CLI * ensure we write the config file in the Oxide engine * improve type in Oxide engine CLI * catch errors instead of checking if the file exists A little smaller but just for tests so doesn't matter too much here 👍 * ensure we publish the correct stub files --------- Co-authored-by: Adam Wathan <[email protected]> Co-authored-by: Jordan Pittman <[email protected]> Co-authored-by: Nate Moore <[email protected]> Co-authored-by: Enzo Innocenzi <[email protected]>
1 parent 694aea0 commit 7e9a53f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1709
-621
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- Add `justify-normal` and `justify-stretch` utilities ([#10560](https://github.com/tailwindlabs/tailwindcss/pull/10560))
2121
- Add `content-normal` and `content-stretch` utilities ([#10645](https://github.com/tailwindlabs/tailwindcss/pull/10645))
2222
- Add `line-clamp` utilities from `@tailwindcss/line-clamp` to core ([#10768](https://github.com/tailwindlabs/tailwindcss/pull/10768))
23+
- Enable ESM and TS based config files ([#10785](https://github.com/tailwindlabs/tailwindcss/pull/10785))
2324

2425
### Fixed
2526

integrations/execute.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module.exports = function $(command, options = {}) {
2626
let args = options.shell
2727
? [command]
2828
: (() => {
29-
let args = command.split(' ')
29+
let args = command.trim().split(/\s+/)
3030
command = args.shift()
3131
command =
3232
command === 'node'

integrations/io.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,12 @@ module.exports = function ({
9797
},
9898
async removeFile(file) {
9999
let filePath = path.resolve(toolRoot, file)
100+
100101
if (!fileCache[filePath]) {
101-
fileCache[filePath] = await fs.readFile(filePath, 'utf8')
102+
fileCache[filePath] = await fs.readFile(filePath, 'utf8').catch(() => null)
102103
}
103-
await fs.unlink(filePath)
104+
105+
await fs.unlink(filePath).catch(() => null)
104106
},
105107
async readOutputFile(file) {
106108
file = await resolveFile(file, absoluteOutputFolder)

integrations/tailwindcss-cli/tests/cli.test.js

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,46 @@ describe('Build command', () => {
532532
})
533533

534534
describe('Init command', () => {
535+
it.each([
536+
{ flags: [], name: 'tailwind.config.js' },
537+
{ flags: ['--ts'], name: 'tailwind.config.ts' },
538+
{ flags: ['--esm'], name: 'tailwind.config.js' },
539+
{ flags: ['--full'], name: 'tailwind.config.js' },
540+
{ flags: ['--ts', '--full'], name: 'tailwind.config.ts' },
541+
{ flags: ['--esm', '--full'], name: 'tailwind.config.js' },
542+
])('works with all these flags: %j', async ({ flags, name }) => {
543+
cleanupFile(name)
544+
await removeFile(name)
545+
546+
let { combined } = await $(`${EXECUTABLE} init ${flags.join(' ')}`)
547+
548+
expect(combined).toMatchInlineSnapshot(`
549+
"
550+
Created Tailwind CSS config file: ${name}
551+
"
552+
`)
553+
554+
expect(await fileExists(name)).toBe(true)
555+
556+
let content = await readOutputFile(`../${name}`)
557+
558+
if (flags.includes('--ts') || flags.includes('--esm')) {
559+
expect(content).toContain('export default')
560+
expect(content).not.toContain('module.exports =')
561+
} else {
562+
expect(content).toContain('module.exports =')
563+
expect(content).not.toContain('export default')
564+
}
565+
566+
if (flags.includes('--ts')) {
567+
expect(content).toContain('satisfies Config')
568+
}
569+
570+
if (flags.includes('--full')) {
571+
expect(content.split('\n').length).toBeGreaterThan(50)
572+
}
573+
})
574+
535575
test('--full', async () => {
536576
cleanupFile('full.config.js')
537577

@@ -577,14 +617,19 @@ describe('Init command', () => {
577617
tailwindcss init [options]
578618
579619
Options:
580-
-f, --full Initialize a full \`tailwind.config.js\` file
620+
--esm Initialize configuration file as ESM
621+
--ts Initialize configuration file as TypeScript
581622
-p, --postcss Initialize a \`postcss.config.js\` file
623+
-f, --full Include the default values for all options in the generated configuration file
582624
-h, --help Display usage information
583625
`)
584626
)
585627
})
586628

587-
test('--help in ESM package', async () => {
629+
test('ESM config is created by default in an ESM project', async () => {
630+
cleanupFile('tailwind.config.js')
631+
await removeFile('tailwind.config.js')
632+
588633
let pkg = await readOutputFile('../package.json')
589634

590635
await writeInputFile(
@@ -595,50 +640,47 @@ describe('Init command', () => {
595640
})
596641
)
597642

598-
let { combined } = await $(`${EXECUTABLE} init --help`)
643+
let { combined } = await $(`${EXECUTABLE} init`)
599644

600-
expect(dedent(combined)).toEqual(
601-
dedent(`
602-
tailwindcss v${version}
645+
expect(combined).toMatchInlineSnapshot(`
646+
"
647+
Created Tailwind CSS config file: tailwind.config.js
648+
"
649+
`)
603650

604-
Usage:
605-
tailwindcss init [options]
651+
expect(await fileExists('./tailwind.config.js')).toBe(true)
606652

607-
Options:
608-
-f, --full Initialize a full \`tailwind.config.cjs\` file
609-
-p, --postcss Initialize a \`postcss.config.cjs\` file
610-
-h, --help Display usage information
611-
`)
612-
)
653+
// Not a clean way to test this.
654+
expect(await readOutputFile('../tailwind.config.js')).toContain('export default')
613655

614656
await writeInputFile('../package.json', pkg)
615657
})
616658

617-
test('cjs config created when in ESM package', async () => {
618-
cleanupFile('tailwind.config.cjs')
659+
test('CJS config is created by default in a non-ESM project', async () => {
660+
cleanupFile('tailwind.config.js')
661+
await removeFile('tailwind.config.js')
619662

620663
let pkg = await readOutputFile('../package.json')
621664

622665
await writeInputFile(
623666
'../package.json',
624667
JSON.stringify({
625668
...JSON.parse(pkg),
626-
type: 'module',
627669
})
628670
)
629671

630672
let { combined } = await $(`${EXECUTABLE} init`)
631673

632674
expect(combined).toMatchInlineSnapshot(`
633675
"
634-
Created Tailwind CSS config file: tailwind.config.cjs
676+
Created Tailwind CSS config file: tailwind.config.js
635677
"
636678
`)
637679

638-
expect(await fileExists('./tailwind.config.cjs')).toBe(true)
680+
expect(await fileExists('./tailwind.config.js')).toBe(true)
639681

640682
// Not a clean way to test this.
641-
expect(await readOutputFile('../tailwind.config.cjs')).toContain('module.exports =')
683+
expect(await readOutputFile('../tailwind.config.js')).toContain('module.exports')
642684

643685
await writeInputFile('../package.json', pkg)
644686
})

loadConfig.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import type { Config } from './types/config'
2+
3+
declare function loadConfig(path: string): Config
4+
export = loadConfig

loadConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let loadConfig = require('./lib/public/load-config')
2+
module.exports = (loadConfig.__esModule ? loadConfig : { default: loadConfig }).default

oxide/Cargo.lock

Lines changed: 15 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

oxide/crates/node/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ crate-type = ["cdylib"]
99
[dependencies]
1010
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
1111
napi = { version = "2.10.0", default-features = false, features = ["napi4"] }
12-
napi-derive = "2.9.1"
12+
napi-derive = "2.11.1"
1313
tailwindcss-core = { path = "../core" }
1414
rayon = "1.5.3"
1515

0 commit comments

Comments
 (0)