tailwindcss 0.0.0-insiders.cb6e45a → 0.0.0-insiders.cbbfa82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +85 -28
  2. package/README.md +6 -5
  3. package/lib/cli/build/index.js +5 -1
  4. package/lib/cli/build/plugin.js +32 -5
  5. package/lib/cli/build/watching.js +77 -12
  6. package/lib/cli.js +19 -9
  7. package/lib/corePlugins.js +11 -10
  8. package/lib/css/preflight.css +2 -0
  9. package/lib/lib/content.js +14 -4
  10. package/lib/lib/defaultExtractor.js +1 -1
  11. package/lib/lib/expandApplyAtRules.js +34 -15
  12. package/lib/lib/expandTailwindAtRules.js +1 -1
  13. package/lib/lib/findAtConfigPath.js +4 -4
  14. package/lib/lib/generateRules.js +4 -4
  15. package/lib/lib/setupContextUtils.js +29 -22
  16. package/lib/util/dataTypes.js +3 -0
  17. package/lib/util/formatVariantSelector.js +3 -3
  18. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +2 -2
  19. package/lib/util/normalizeConfig.js +14 -0
  20. package/lib/util/pluginUtils.js +53 -34
  21. package/lib/util/resolveConfig.js +4 -9
  22. package/package.json +9 -10
  23. package/peers/index.js +650 -581
  24. package/src/cli/build/index.js +6 -2
  25. package/src/cli/build/plugin.js +41 -4
  26. package/src/cli/build/watching.js +105 -12
  27. package/src/cli.js +24 -13
  28. package/src/corePlugins.js +13 -11
  29. package/src/css/preflight.css +2 -0
  30. package/src/lib/content.js +16 -8
  31. package/src/lib/defaultExtractor.js +1 -1
  32. package/src/lib/expandApplyAtRules.js +35 -15
  33. package/src/lib/findAtConfigPath.js +4 -6
  34. package/src/lib/generateRules.js +11 -8
  35. package/src/lib/setupContextUtils.js +28 -23
  36. package/src/util/dataTypes.js +4 -0
  37. package/src/util/formatVariantSelector.js +2 -2
  38. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  39. package/src/util/normalizeConfig.js +18 -0
  40. package/src/util/pluginUtils.js +60 -26
  41. package/src/util/resolveConfig.js +3 -9
  42. package/stubs/defaultConfig.stub.js +1 -18
  43. package/types/config.d.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -9,56 +9,108 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Added
11
11
 
12
+ - Add `line-height` modifier support to `font-size` utilities ([#9875](https://github.com/tailwindlabs/tailwindcss/pull/9875))
13
+ - Support using variables as arbitrary values without `var(...)` ([#9880](https://github.com/tailwindlabs/tailwindcss/pull/9880), [#9962](https://github.com/tailwindlabs/tailwindcss/pull/9962))
14
+ - Add `--watch=always` option to prevent exit when stdin closes ([#9966](https://github.com/tailwindlabs/tailwindcss/pull/9966))
15
+
16
+ ### Fixed
17
+
18
+ - Cleanup unused `variantOrder` ([#9829](https://github.com/tailwindlabs/tailwindcss/pull/9829))
19
+ - Fix `foo-[abc]/[def]` not being handled correctly ([#9866](https://github.com/tailwindlabs/tailwindcss/pull/9866))
20
+ - Add container queries plugin to standalone CLI ([#9865](https://github.com/tailwindlabs/tailwindcss/pull/9865))
21
+ - Support renaming of output files by `PostCSS` plugin. ([#9944](https://github.com/tailwindlabs/tailwindcss/pull/9944))
22
+
23
+ ## [3.2.4] - 2022-11-11
24
+
25
+ ### Added
26
+
27
+ - Add `blocklist` option to prevent generating unwanted CSS ([#9812](https://github.com/tailwindlabs/tailwindcss/pull/9812))
28
+
29
+ ### Fixed
30
+
31
+ - Fix watching of files on Linux when renames are involved ([#9796](https://github.com/tailwindlabs/tailwindcss/pull/9796))
32
+ - Make sure errors are always displayed when watching for changes ([#9810](https://github.com/tailwindlabs/tailwindcss/pull/9810))
33
+
34
+ ## [3.2.3] - 2022-11-09
35
+
36
+ ### Fixed
37
+
38
+ - Fixed use of `raw` content in the CLI ([#9773](https://github.com/tailwindlabs/tailwindcss/pull/9773))
39
+ - Pick up changes from files that are both context and content deps ([#9787](https://github.com/tailwindlabs/tailwindcss/pull/9787))
40
+ - Sort pseudo-elements ONLY after classes when using variants and `@apply` ([#9765](https://github.com/tailwindlabs/tailwindcss/pull/9765))
41
+ - Support important utilities in the safelist (pattern must include a `!`) ([#9791](https://github.com/tailwindlabs/tailwindcss/pull/9791))
42
+
43
+ ## [3.2.2] - 2022-11-04
44
+
45
+ ### Fixed
46
+
47
+ - Escape special characters in resolved content base paths ([#9650](https://github.com/tailwindlabs/tailwindcss/pull/9650))
48
+ - Don't reuse container for array returning variant functions ([#9644](https://github.com/tailwindlabs/tailwindcss/pull/9644))
49
+ - Exclude non-relevant selectors when generating rules with the important modifier ([#9677](https://github.com/tailwindlabs/tailwindcss/issues/9677))
50
+ - Fix merging of arrays during config resolution ([#9706](https://github.com/tailwindlabs/tailwindcss/issues/9706))
51
+ - Ensure configured `font-feature-settings` are included in Preflight ([#9707](https://github.com/tailwindlabs/tailwindcss/pull/9707))
52
+ - Fix fractional values not being parsed properly inside arbitrary properties ([#9705](https://github.com/tailwindlabs/tailwindcss/pull/9705))
53
+ - Fix incorrect selectors when using `@apply` in selectors with combinators and pseudos ([#9722](https://github.com/tailwindlabs/tailwindcss/pull/9722))
54
+ - Fix cannot read properties of undefined (reading 'modifier') ([#9656](https://github.com/tailwindlabs/tailwindcss/pull/9656), [aa979d6](https://github.com/tailwindlabs/tailwindcss/commit/aa979d645f8bf4108c5fc938d7c0ba085b654c31))
55
+
56
+ ## [3.2.1] - 2022-10-21
57
+
58
+ ### Fixed
59
+
60
+ - Fix missing `supports` in types ([#9616](https://github.com/tailwindlabs/tailwindcss/pull/9616))
61
+ - Fix missing PostCSS dependencies in the CLI ([#9617](https://github.com/tailwindlabs/tailwindcss/pull/9617))
62
+ - Ensure `micromatch` is a proper CLI dependency ([#9620](https://github.com/tailwindlabs/tailwindcss/pull/9620))
63
+ - Ensure modifier values exist when using a `modifiers` object for `matchVariant` ([ba6551db0f2726461371b4f3c6cd4c7090888504](https://github.com/tailwindlabs/tailwindcss/commit/ba6551db0f2726461371b4f3c6cd4c7090888504))
64
+
65
+ ## [3.2.0] - 2022-10-19
66
+
67
+ ### Added
68
+
69
+ - Add new `@config` directive ([#9405](https://github.com/tailwindlabs/tailwindcss/pull/9405))
70
+ - Add new `relative: true` option to resolve content paths relative to the config file ([#9396](https://github.com/tailwindlabs/tailwindcss/pull/9396))
71
+ - Add new `supports-*` variant ([#9453](https://github.com/tailwindlabs/tailwindcss/pull/9453))
72
+ - Add new `min-*` and `max-*` variants ([#9558](https://github.com/tailwindlabs/tailwindcss/pull/9558))
73
+ - Add new `aria-*` variants ([#9557](https://github.com/tailwindlabs/tailwindcss/pull/9557), [#9588](https://github.com/tailwindlabs/tailwindcss/pull/9588))
74
+ - Add new `data-*` variants ([#9559](https://github.com/tailwindlabs/tailwindcss/pull/9559), [#9588](https://github.com/tailwindlabs/tailwindcss/pull/9588))
12
75
  - Add new `break-keep` utility for `word-break: keep-all` ([#9393](https://github.com/tailwindlabs/tailwindcss/pull/9393))
76
+ - Add new `collapse` utility for `visibility: collapse` ([#9181](https://github.com/tailwindlabs/tailwindcss/pull/9181))
77
+ - Add new `fill-none` utility for `fill: none` ([#9403](https://github.com/tailwindlabs/tailwindcss/pull/9403))
78
+ - Add new `stroke-none` utility for `stroke: none` ([#9403](https://github.com/tailwindlabs/tailwindcss/pull/9403))
79
+ - Add new `place-content-baseline` utility for `place-content: baseline` ([#9498](https://github.com/tailwindlabs/tailwindcss/pull/9498))
80
+ - Add new `place-items-baseline` utility for `place-items: baseline` ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507))
81
+ - Add new `content-baseline` utility for `align-content: baseline` ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507))
13
82
  - Add support for configuring default `font-feature-settings` for a font family ([#9039](https://github.com/tailwindlabs/tailwindcss/pull/9039))
14
- - Add a standalone CLI build for 32-bit Linux on ARM (`node16-linux-armv7`) ([#9084](https://github.com/tailwindlabs/tailwindcss/pull/9084))
83
+ - Add standalone CLI build for 32-bit Linux on ARM (`node16-linux-armv7`) ([#9084](https://github.com/tailwindlabs/tailwindcss/pull/9084))
15
84
  - Add future flag to disable color opacity utility plugins ([#9088](https://github.com/tailwindlabs/tailwindcss/pull/9088))
16
85
  - Add negative value support for `outline-offset` ([#9136](https://github.com/tailwindlabs/tailwindcss/pull/9136))
17
- - Allow negating utilities using min/max/clamp ([#9237](https://github.com/tailwindlabs/tailwindcss/pull/9237))
18
- - Add new `collapse` utility for `visibility: collapse` ([#9181](https://github.com/tailwindlabs/tailwindcss/pull/9181))
19
- - Allow resolving content paths relative to the config file ([#9396](https://github.com/tailwindlabs/tailwindcss/pull/9396))
20
- - Add `@config` support ([#9405](https://github.com/tailwindlabs/tailwindcss/pull/9405))
21
- - Add `fill-none` and `stroke-none` utilities by default ([#9403](https://github.com/tailwindlabs/tailwindcss/pull/9403))
22
- - Support `sort` function in `matchVariant` ([#9423](https://github.com/tailwindlabs/tailwindcss/pull/9423))
23
- - Implement the `supports` variant ([#9453](https://github.com/tailwindlabs/tailwindcss/pull/9453))
24
- - Add experimental `label`s for variants ([#9456](https://github.com/tailwindlabs/tailwindcss/pull/9456), [#9520](https://github.com/tailwindlabs/tailwindcss/pull/9520))
25
- - Added 'place-content-baseline' utility ([#9498](https://github.com/tailwindlabs/tailwindcss/pull/9498))
26
- - Added 'place-items-baseline' utility ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507))
27
- - Added 'content-baseline' utility ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507))
28
- - Prepare for container queries setup ([#9526](https://github.com/tailwindlabs/tailwindcss/pull/9526))
29
86
  - Add support for modifiers to `matchUtilities` ([#9541](https://github.com/tailwindlabs/tailwindcss/pull/9541))
30
- - Switch to positional argument + object for modifiers ([#9541](https://github.com/tailwindlabs/tailwindcss/pull/9541))
31
- - Add new `min` and `max` variants ([#9558](https://github.com/tailwindlabs/tailwindcss/pull/9558))
32
- - Add `aria-*` variants ([#9557](https://github.com/tailwindlabs/tailwindcss/pull/9557), [#9588](https://github.com/tailwindlabs/tailwindcss/pull/9588))
33
- - Add `data-*` variants ([#9559](https://github.com/tailwindlabs/tailwindcss/pull/9559), [#9588](https://github.com/tailwindlabs/tailwindcss/pull/9588))
87
+ - Allow negating utilities using `min`/`max`/`clamp` ([#9237](https://github.com/tailwindlabs/tailwindcss/pull/9237))
88
+ - Implement fallback plugins when there is ambiguity between plugins when using arbitrary values ([#9376](https://github.com/tailwindlabs/tailwindcss/pull/9376))
89
+ - Support `sort` function in `matchVariant` ([#9423](https://github.com/tailwindlabs/tailwindcss/pull/9423))
34
90
  - Upgrade to `postcss-nested` v6.0 ([#9546](https://github.com/tailwindlabs/tailwindcss/pull/9546))
35
- - Expose `context.getVariants` for intellisense ([#9505](https://github.com/tailwindlabs/tailwindcss/pull/9505))
36
91
 
37
92
  ### Fixed
38
93
 
39
94
  - Use absolute paths when resolving changed files for resilience against working directory changes ([#9032](https://github.com/tailwindlabs/tailwindcss/pull/9032))
40
95
  - Fix ring color utility generation when using `respectDefaultRingColorOpacity` ([#9070](https://github.com/tailwindlabs/tailwindcss/pull/9070))
41
- - Sort tags before classes when `@applying` a selector with joined classes ([#9107](https://github.com/tailwindlabs/tailwindcss/pull/9107))
96
+ - Sort tags before classes when `@apply`-ing a selector with joined classes ([#9107](https://github.com/tailwindlabs/tailwindcss/pull/9107))
42
97
  - Remove invalid `outline-hidden` utility ([#9147](https://github.com/tailwindlabs/tailwindcss/pull/9147))
43
98
  - Honor the `hidden` attribute on elements in preflight ([#9174](https://github.com/tailwindlabs/tailwindcss/pull/9174))
44
99
  - Don't stop watching atomically renamed files ([#9173](https://github.com/tailwindlabs/tailwindcss/pull/9173), [#9215](https://github.com/tailwindlabs/tailwindcss/pull/9215))
45
- - Re-use existing entries in the rule cache ([#9208](https://github.com/tailwindlabs/tailwindcss/pull/9208))
46
- - Don't output duplicate utilities ([#9208](https://github.com/tailwindlabs/tailwindcss/pull/9208))
100
+ - Fix duplicate utilities issue causing memory leaks ([#9208](https://github.com/tailwindlabs/tailwindcss/pull/9208))
47
101
  - Fix `fontFamily` config TypeScript types ([#9214](https://github.com/tailwindlabs/tailwindcss/pull/9214))
48
102
  - Handle variants on complex selector utilities ([#9262](https://github.com/tailwindlabs/tailwindcss/pull/9262))
49
- - Don't mutate shared config objects ([#9294](https://github.com/tailwindlabs/tailwindcss/pull/9294))
103
+ - Fix shared config mutation issue ([#9294](https://github.com/tailwindlabs/tailwindcss/pull/9294))
50
104
  - Fix ordering of parallel variants ([#9282](https://github.com/tailwindlabs/tailwindcss/pull/9282))
51
105
  - Handle variants in utility selectors using `:where()` and `:has()` ([#9309](https://github.com/tailwindlabs/tailwindcss/pull/9309))
52
- - Improve data type analyses for arbitrary values ([#9320](https://github.com/tailwindlabs/tailwindcss/pull/9320))
106
+ - Improve data type analysis for arbitrary values ([#9320](https://github.com/tailwindlabs/tailwindcss/pull/9320))
53
107
  - Don't emit generated utilities with invalid uses of theme functions ([#9319](https://github.com/tailwindlabs/tailwindcss/pull/9319))
54
108
  - Revert change that only listened for stdin close on TTYs ([#9331](https://github.com/tailwindlabs/tailwindcss/pull/9331))
55
109
  - Ignore unset values (like `null` or `undefined`) when resolving the classList for intellisense ([#9385](https://github.com/tailwindlabs/tailwindcss/pull/9385))
56
- - Implement fallback plugins when arbitrary values result in css from multiple plugins ([#9376](https://github.com/tailwindlabs/tailwindcss/pull/9376))
57
110
  - Improve type checking for formal syntax ([#9349](https://github.com/tailwindlabs/tailwindcss/pull/9349), [#9448](https://github.com/tailwindlabs/tailwindcss/pull/9448))
58
- - Don't require `content` key in custom plugin configs ([#9502](https://github.com/tailwindlabs/tailwindcss/pull/9502), [#9545](https://github.com/tailwindlabs/tailwindcss/pull/9545))
111
+ - Fix incorrect required `content` key in custom plugin configs ([#9502](https://github.com/tailwindlabs/tailwindcss/pull/9502), [#9545](https://github.com/tailwindlabs/tailwindcss/pull/9545))
59
112
  - Fix content path detection on Windows ([#9569](https://github.com/tailwindlabs/tailwindcss/pull/9569))
60
113
  - Ensure `--content` is used in the CLI when passed ([#9587](https://github.com/tailwindlabs/tailwindcss/pull/9587))
61
- - Increase strictness when using `applyVariant` on illegale candidates ([#9599](https://github.com/tailwindlabs/tailwindcss/pull/9599))
62
114
 
63
115
  ## [3.1.8] - 2022-08-05
64
116
 
@@ -155,7 +207,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
155
207
  - Move `important` selector to the front when `@apply`-ing selector-modifying variants in custom utilities ([#8313](https://github.com/tailwindlabs/tailwindcss/pull/8313))
156
208
  - Error when registering an invalid custom variant ([#8345](https://github.com/tailwindlabs/tailwindcss/pull/8345))
157
209
  - Create tailwind.config.cjs file in ESM package when running init ([#8363](https://github.com/tailwindlabs/tailwindcss/pull/8363))
158
- - Fix `matchVariants` that use at-rules and placeholders ([#8392](https://github.com/tailwindlabs/tailwindcss/pull/8392))
210
+ - Fix `matchVariant` that use at-rules and placeholders ([#8392](https://github.com/tailwindlabs/tailwindcss/pull/8392))
159
211
  - Improve types of the `tailwindcss/plugin` ([#8400](https://github.com/tailwindlabs/tailwindcss/pull/8400))
160
212
  - Allow returning parallel variants from `addVariant` or `matchVariant` callback functions ([#8455](https://github.com/tailwindlabs/tailwindcss/pull/8455))
161
213
  - Try using local `postcss` installation first in the CLI ([#8270](https://github.com/tailwindlabs/tailwindcss/pull/8270))
@@ -2080,7 +2132,12 @@ No release notes
2080
2132
 
2081
2133
  - Everything!
2082
2134
 
2083
- [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.8...HEAD
2135
+ [unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.4...HEAD
2136
+ [3.2.4]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.3...v3.2.4
2137
+ [3.2.3]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.2...v3.2.3
2138
+ [3.2.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.1...v3.2.2
2139
+ [3.2.1]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.0...v3.2.1
2140
+ [3.2.0]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.8...v3.2.0
2084
2141
  [3.1.8]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.7...v3.1.8
2085
2142
  [3.1.7]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.6...v3.1.7
2086
2143
  [3.1.6]: https://github.com/tailwindlabs/tailwindcss/compare/v3.1.5...v3.1.6
package/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  <p align="center">
2
- <a href="https://tailwindcss.com/#gh-light-mode-only" target="_blank">
3
- <img src="./.github/logo-light.svg" alt="Tailwind CSS" width="350" height="70">
4
- </a>
5
- <a href="https://tailwindcss.com/#gh-dark-mode-only" target="_blank">
6
- <img src="./.github/logo-dark.svg" alt="Tailwind CSS" width="350" height="70">
2
+ <a href="https://tailwindcss.com" target="_blank">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-dark.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg">
6
+ <img alt="Tailwind CSS" src="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg" width="350" height="70" style="max-width: 100%;">
7
+ </picture>
7
8
  </a>
8
9
  </p>
9
10
 
@@ -35,7 +35,11 @@ async function build(args, configs) {
35
35
  let configPath = args["--config"] ? args["--config"] : ((defaultPath)=>_fs.default.existsSync(defaultPath) ? defaultPath : null)(_path.default.resolve(`./${configs.tailwind}`));
36
36
  let processor = await (0, _pluginJs.createProcessor)(args, configPath);
37
37
  if (shouldWatch) {
38
- /* Abort the watcher if stdin is closed to avoid zombie processes */ process.stdin.on("end", ()=>process.exit(0));
38
+ // Abort the watcher if stdin is closed to avoid zombie processes
39
+ // You can disable this behavior with --watch=always
40
+ if (args["--watch"] !== "always") {
41
+ process.stdin.on("end", ()=>process.exit(0));
42
+ }
39
43
  process.stdin.resume();
40
44
  await processor.watch();
41
45
  } else {
@@ -170,9 +170,9 @@ let state = {
170
170
  let rawContent = this.config.content.files.filter((file)=>{
171
171
  return file !== null && typeof file === "object";
172
172
  });
173
- for (let { raw: content1 , extension ="html" } of rawContent){
174
- content1.push({
175
- content: content1,
173
+ for (let { raw: htmlContent , extension ="html" } of rawContent){
174
+ content.push({
175
+ content: htmlContent,
176
176
  extension
177
177
  });
178
178
  }
@@ -283,18 +283,45 @@ async function createProcessor(args, cliConfigPath) {
283
283
  from: input,
284
284
  to: output
285
285
  })).then((result)=>{
286
+ if (!state.watcher) {
287
+ return result;
288
+ }
289
+ _shared.env.DEBUG && console.time("Recording PostCSS dependencies");
290
+ for (let message of result.messages){
291
+ if (message.type === "dependency") {
292
+ state.contextDependencies.add(message.file);
293
+ }
294
+ }
295
+ _shared.env.DEBUG && console.timeEnd("Recording PostCSS dependencies");
296
+ // TODO: This needs to be in a different spot
297
+ _shared.env.DEBUG && console.time("Watch new files");
298
+ state.watcher.refreshWatchedFiles();
299
+ _shared.env.DEBUG && console.timeEnd("Watch new files");
300
+ return result;
301
+ }).then((result)=>{
286
302
  if (!output) {
287
303
  process.stdout.write(result.css);
288
304
  return;
289
305
  }
290
306
  return Promise.all([
291
- (0, _utils.outputFile)(output, result.css),
292
- result.map && (0, _utils.outputFile)(output + ".map", result.map.toString())
307
+ (0, _utils.outputFile)(result.opts.to, result.css),
308
+ result.map && (0, _utils.outputFile)(result.opts.to + ".map", result.map.toString())
293
309
  ]);
294
310
  }).then(()=>{
295
311
  let end = process.hrtime.bigint();
296
312
  console.error();
297
313
  console.error("Done in", (end - start) / BigInt(1e6) + "ms.");
314
+ }).then(()=>{}, (err)=>{
315
+ // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
316
+ // that were collected before the error occurred
317
+ // The result is not stored on the error so we have to store it externally
318
+ // and pull the messages off of it here somehow
319
+ // This results in a less than ideal DX because the watcher will not pick up
320
+ // changes to imported CSS if one of them caused an error during the initial build
321
+ // If you fix it and then save the main CSS file so there's no error
322
+ // The watcher will start watching the imported CSS files and will be
323
+ // resilient to future errors.
324
+ console.error(err);
298
325
  });
299
326
  }
300
327
  /**
@@ -37,22 +37,70 @@ function createWatcher(args, { state , rebuild }) {
37
37
  pollInterval: pollInterval
38
38
  } : false
39
39
  });
40
+ // A queue of rebuilds, file reads, etc… to run
40
41
  let chain = Promise.resolve();
41
- let pendingRebuilds = new Set();
42
- let changedContent = [];
42
+ /**
43
+ * A list of files that have been changed since the last rebuild
44
+ *
45
+ * @type {{file: string, content: () => Promise<string>, extension: string}[]}
46
+ */ let changedContent = [];
47
+ /**
48
+ * A list of files for which a rebuild has already been queued.
49
+ * This is used to prevent duplicate rebuilds when multiple events are fired for the same file.
50
+ * The rebuilt file is cleared from this list when it's associated rebuild has _started_
51
+ * This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should
52
+ **/ let pendingRebuilds = new Set();
53
+ let _timer;
54
+ let _reject;
55
+ /**
56
+ * Rebuilds the changed files and resolves when the rebuild is
57
+ * complete regardless of whether it was successful or not
58
+ */ async function rebuildAndContinue() {
59
+ let changes = changedContent.splice(0);
60
+ // There are no changes to rebuild so we can just do nothing
61
+ if (changes.length === 0) {
62
+ return Promise.resolve();
63
+ }
64
+ // Clear all pending rebuilds for the about-to-be-built files
65
+ changes.forEach((change)=>pendingRebuilds.delete(change.file));
66
+ // Resolve the promise even when the rebuild fails
67
+ return rebuild(changes).then(()=>{}, ()=>{});
68
+ }
43
69
  /**
44
70
  *
45
71
  * @param {*} file
46
72
  * @param {(() => Promise<string>) | null} content
47
- */ function recordChangedFile(file, content = null) {
73
+ * @param {boolean} skipPendingCheck
74
+ * @returns {Promise<void>}
75
+ */ function recordChangedFile(file, content = null, skipPendingCheck = false) {
48
76
  file = _path.default.resolve(file);
49
- content = content !== null && content !== void 0 ? content : async ()=>await _fs.default.promises.readFile(file, "utf8");
77
+ // Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
78
+ // In that case rebuild has already been queued by rename, so can be skipped in change
79
+ if (pendingRebuilds.has(file) && !skipPendingCheck) {
80
+ return Promise.resolve();
81
+ }
82
+ // Mark that a rebuild of this file is going to happen
83
+ // It MUST happen synchronously before the rebuild is queued for this to be effective
84
+ pendingRebuilds.add(file);
50
85
  changedContent.push({
51
86
  file,
52
- content,
87
+ content: content !== null && content !== void 0 ? content : ()=>_fs.default.promises.readFile(file, "utf8"),
53
88
  extension: _path.default.extname(file).slice(1)
54
89
  });
55
- chain = chain.then(()=>rebuild(changedContent));
90
+ if (_timer) {
91
+ clearTimeout(_timer);
92
+ _reject();
93
+ }
94
+ // If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired
95
+ chain = chain.then(()=>new Promise((resolve, reject)=>{
96
+ _timer = setTimeout(resolve, 10);
97
+ _reject = reject;
98
+ }));
99
+ // Resolves once this file has been rebuilt (or the rebuild for this file has failed)
100
+ // This queues as many rebuilds as there are changed files
101
+ // But those rebuilds happen after some delay
102
+ // And will immediately resolve if there are no changes
103
+ chain = chain.then(rebuildAndContinue, rebuildAndContinue);
56
104
  return chain;
57
105
  }
58
106
  watcher.on("change", (file)=>recordChangedFile(file));
@@ -91,15 +139,32 @@ function createWatcher(args, { state , rebuild }) {
91
139
  if (pendingRebuilds.has(filePath)) {
92
140
  return;
93
141
  }
142
+ // We'll go ahead and add the file to the pending rebuilds list here
143
+ // It'll be removed when the rebuild starts unless the read fails
144
+ // which will be taken care of as well
94
145
  pendingRebuilds.add(filePath);
95
- chain = chain.then(async ()=>{
96
- let content;
146
+ async function enqueue() {
97
147
  try {
98
- content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath));
99
- } finally{
100
- pendingRebuilds.delete(filePath);
148
+ // We need to read the file as early as possible outside of the chain
149
+ // because it may be gone by the time we get to it. doing the read
150
+ // immediately increases the chance that the file is still there
151
+ let content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath));
152
+ if (content === undefined) {
153
+ return;
154
+ }
155
+ // This will push the rebuild onto the chain
156
+ // We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
157
+ // This is because the order of events and timing is different on Linux
158
+ // @ts-ignore: TypeScript isn't picking up that content is a string here
159
+ await recordChangedFile(filePath, ()=>content, true);
160
+ } catch {
161
+ // If reading the file fails, it's was probably a deleted temporary file
162
+ // So we can ignore it and no rebuild is needed
101
163
  }
102
- return recordChangedFile(filePath, ()=>content);
164
+ }
165
+ enqueue().then(()=>{
166
+ // If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list
167
+ pendingRebuilds.delete(filePath);
103
168
  });
104
169
  });
105
170
  return {
package/lib/cli.js CHANGED
@@ -72,7 +72,7 @@ let commands = {
72
72
  description: "Output file"
73
73
  },
74
74
  "--watch": {
75
- type: Boolean,
75
+ type: oneOf(String, Boolean),
76
76
  description: "Watch for changes and rebuild as needed"
77
77
  },
78
78
  "--poll": {
@@ -171,8 +171,8 @@ let args = (()=>{
171
171
  for(let i = result["_"].length - 1; i >= 0; --i){
172
172
  let flag = result["_"][i];
173
173
  if (!flag.startsWith("-")) continue;
174
- let flagName = flag;
175
- let handler = flags[flag];
174
+ let [flagName, flagValue] = flag.split("=");
175
+ let handler = flags[flagName];
176
176
  // Resolve flagName & handler
177
177
  while(typeof handler === "string"){
178
178
  flagName = handler;
@@ -181,14 +181,24 @@ let args = (()=>{
181
181
  if (!handler) continue;
182
182
  let args = [];
183
183
  let offset = i + 1;
184
- // Parse args for current flag
185
- while(result["_"][offset] && !result["_"][offset].startsWith("-")){
186
- args.push(result["_"][offset++]);
184
+ // --flag value syntax was used so we need to pull `value` from `args`
185
+ if (flagValue === undefined) {
186
+ // Parse args for current flag
187
+ while(result["_"][offset] && !result["_"][offset].startsWith("-")){
188
+ args.push(result["_"][offset++]);
189
+ }
190
+ // Cleanup manually parsed flags + args
191
+ result["_"].splice(i, 1 + args.length);
192
+ // No args were provided, use default value defined in handler
193
+ // One arg was provided, use that directly
194
+ // Multiple args were provided so pass them all in an array
195
+ flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
196
+ } else {
197
+ // Remove the whole flag from the args array
198
+ result["_"].splice(i, 1);
187
199
  }
188
- // Cleanup manually parsed flags + args
189
- result["_"].splice(i, 1 + args.length);
190
200
  // Set the resolved value in the `result` object
191
- result[flagName] = handler.type(args.length === 0 ? undefined : args.length === 1 ? args[0] : args, flagName);
201
+ result[flagName] = handler.type(flagValue, flagName);
192
202
  }
193
203
  // Ensure that the `command` is always the first argument in the `args`.
194
204
  // This is important so that we don't have to check if a default command
@@ -228,12 +228,6 @@ let variantPlugins = {
228
228
  };
229
229
  for (let [name, fn] of Object.entries(variants)){
230
230
  matchVariant(name, (value = "", extra)=>{
231
- if (extra.modifier) {
232
- _log.default.warn(`modifier-${name}-experimental`, [
233
- `The ${name} variant modifier feature in Tailwind CSS is currently in preview.`,
234
- "Preview features are not covered by semver, and may be improved in breaking ways at any time."
235
- ]);
236
- }
237
231
  let result = (0, _dataTypes.normalize)(typeof value === "function" ? value(extra) : value);
238
232
  if (!result.includes("&")) result = "&" + result;
239
233
  let [a, b] = fn("", extra);
@@ -352,17 +346,17 @@ let variantPlugins = {
352
346
  return (value)=>{
353
347
  if (!areSimpleScreens) {
354
348
  _log.default.warn("complex-screen-config", [
355
- "The min and max variants are not supported with a screen configuration containing objects."
349
+ "The `min-*` and `max-*` variants are not supported with a `screens` configuration containing objects."
356
350
  ]);
357
351
  return [];
358
352
  } else if (!screensUseConsistentUnits) {
359
353
  _log.default.warn("mixed-screen-units", [
360
- "The min and max variants are not supported with a screen configuration containing mixed units."
354
+ "The `min-*` and `max-*` variants are not supported with a `screens` configuration containing mixed units."
361
355
  ]);
362
356
  return [];
363
357
  } else if (typeof value === "string" && !canUseUnits(value)) {
364
358
  _log.default.warn("minmax-have-mixed-units", [
365
- "The min and max variants are not supported with a screen configuration containing mixed units."
359
+ "The `min-*` and `max-*` variants are not supported with a `screens` configuration containing mixed units."
366
360
  ]);
367
361
  return [];
368
362
  }
@@ -2878,10 +2872,16 @@ let corePlugins = {
2878
2872
  },
2879
2873
  fontSize: ({ matchUtilities , theme })=>{
2880
2874
  matchUtilities({
2881
- text: (value)=>{
2875
+ text: (value, { modifier })=>{
2882
2876
  let [fontSize, options] = Array.isArray(value) ? value : [
2883
2877
  value
2884
2878
  ];
2879
+ if (modifier) {
2880
+ return {
2881
+ "font-size": fontSize,
2882
+ "line-height": modifier
2883
+ };
2884
+ }
2885
2885
  let { lineHeight , letterSpacing , fontWeight } = (0, _isPlainObject.default)(options) ? options : {
2886
2886
  lineHeight: options
2887
2887
  };
@@ -2900,6 +2900,7 @@ let corePlugins = {
2900
2900
  }
2901
2901
  }, {
2902
2902
  values: theme("fontSize"),
2903
+ modifiers: theme("lineHeight"),
2903
2904
  type: [
2904
2905
  "absolute-size",
2905
2906
  "relative-size",
@@ -22,6 +22,7 @@
22
22
  2. Prevent adjustments of font size after orientation changes in iOS.
23
23
  3. Use a more readable tab size.
24
24
  4. Use the user's configured `sans` font-family by default.
25
+ 5. Use the user's configured `sans` font-feature-settings by default.
25
26
  */
26
27
 
27
28
  html {
@@ -30,6 +31,7 @@ html {
30
31
  -moz-tab-size: 4; /* 3 */
31
32
  tab-size: 4; /* 3 */
32
33
  font-family: theme('fontFamily.sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); /* 4 */
34
+ font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings', normal); /* 5 */
33
35
  }
34
36
 
35
37
  /*
@@ -73,13 +73,16 @@ function parseCandidateFiles(context, tailwindConfig) {
73
73
  * @param {ContentPath} contentPath
74
74
  * @returns {ContentPath}
75
75
  */ function resolveGlobPattern(contentPath) {
76
- contentPath.pattern = contentPath.glob ? `${contentPath.base}/${contentPath.glob}` : contentPath.base;
77
- contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern;
78
76
  // This is required for Windows support to properly pick up Glob paths.
79
77
  // Afaik, this technically shouldn't be needed but there's probably
80
78
  // some internal, direct path matching with a normalized path in
81
79
  // a package which can't handle mixed directory separators
82
- contentPath.pattern = (0, _normalizePath.default)(contentPath.pattern);
80
+ let base = (0, _normalizePath.default)(contentPath.base);
81
+ // If the user's file path contains any special characters (like parens) for instance fast-glob
82
+ // is like "OOOH SHINY" and treats them as such. So we have to escape the base path to fix this
83
+ base = _fastGlob.default.escapePath(base);
84
+ contentPath.pattern = contentPath.glob ? `${base}/${contentPath.glob}` : base;
85
+ contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern;
83
86
  return contentPath;
84
87
  }
85
88
  /**
@@ -157,7 +160,14 @@ function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
157
160
  for (let file of files){
158
161
  let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity;
159
162
  let modified = _fs.default.statSync(file).mtimeMs;
160
- if (modified > prevModified) {
163
+ // This check is intentionally >= because we track the last modified time of context dependencies
164
+ // earier in the process and we want to make sure we don't miss any changes that happen
165
+ // when a context dependency is also a content dependency
166
+ // Ideally, we'd do all this tracking at one time but that is a larger refactor
167
+ // than we want to commit to right now, so this is a decent compromise.
168
+ // This should be sufficient because file modification times will be off by at least
169
+ // 1ms (the precision of fstat in Node) in most cases if they exist and were changed.
170
+ if (modified >= prevModified) {
161
171
  changedFiles.add(file);
162
172
  fileModifiedMap.set(file, modified);
163
173
  }
@@ -72,7 +72,7 @@ function* buildRegExps(context) {
72
72
  ])) : "";
73
73
  let utility = _regex.any([
74
74
  // Arbitrary properties
75
- /\[[^\s:'"`]+:[^\s\]]+\]/,
75
+ /\[[^\s:'"`]+:[^\s]+\]/,
76
76
  // Utilities
77
77
  _regex.pattern([
78
78
  // Utility Name / Group Name
@@ -306,21 +306,40 @@ function processApply(root, context, localCache) {
306
306
  hasReplaced = true;
307
307
  });
308
308
  });
309
- // Sort tag names before class names
309
+ // Sort tag names before class names (but only sort each group (separated by a combinator)
310
+ // separately and not in total)
310
311
  // This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
311
- for (const sel1 of replaced){
312
- sel1.sort((a, b)=>{
313
- if (a.type === "tag" && b.type === "class") {
314
- return -1;
315
- } else if (a.type === "class" && b.type === "tag") {
316
- return 1;
317
- } else if (a.type === "class" && b.type === "pseudo") {
318
- return -1;
319
- } else if (a.type === "pseudo" && b.type === "class") {
320
- return 1;
312
+ for (let sel1 of replaced){
313
+ let groups = [
314
+ []
315
+ ];
316
+ for (let node of sel1.nodes){
317
+ if (node.type === "combinator") {
318
+ groups.push(node);
319
+ groups.push([]);
320
+ } else {
321
+ let last = groups[groups.length - 1];
322
+ last.push(node);
321
323
  }
322
- return sel1.index(a) - sel1.index(b);
323
- });
324
+ }
325
+ sel1.nodes = [];
326
+ for (let group of groups){
327
+ if (Array.isArray(group)) {
328
+ group.sort((a, b)=>{
329
+ if (a.type === "tag" && b.type === "class") {
330
+ return -1;
331
+ } else if (a.type === "class" && b.type === "tag") {
332
+ return 1;
333
+ } else if (a.type === "class" && b.type === "pseudo" && b.value.startsWith("::")) {
334
+ return -1;
335
+ } else if (a.type === "pseudo" && a.value.startsWith("::") && b.type === "class") {
336
+ return 1;
337
+ }
338
+ return 0;
339
+ });
340
+ }
341
+ sel1.nodes = sel1.nodes.concat(group);
342
+ }
324
343
  }
325
344
  sel.replaceWith(...replaced);
326
345
  });
@@ -340,7 +359,7 @@ function processApply(root, context, localCache) {
340
359
  let [applyCandidates1, important] = extractApplyCandidates(apply.params);
341
360
  if (apply.parent.type === "atrule") {
342
361
  if (apply.parent.name === "screen") {
343
- const screenType = apply.parent.params;
362
+ let screenType = apply.parent.params;
344
363
  throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates1.map((c)=>`${screenType}:${c}`).join(" ")} instead.`);
345
364
  }
346
365
  throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`);
@@ -364,7 +383,7 @@ function processApply(root, context, localCache) {
364
383
  ]);
365
384
  }
366
385
  }
367
- for (const [parent, [candidates1, atApplySource]] of perParentApplies){
386
+ for (let [parent, [candidates1, atApplySource]] of perParentApplies){
368
387
  let siblings = [];
369
388
  for (let [applyCandidate1, important1, rules1] of candidates1){
370
389
  let potentialApplyCandidates = [
@@ -169,7 +169,7 @@ function expandTailwindAtRules(context) {
169
169
  ], context);
170
170
  }
171
171
  env.DEBUG && console.timeEnd("Build stylesheet");
172
- let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes , } = context.stylesheetCache;
172
+ let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes } = context.stylesheetCache;
173
173
  // ---
174
174
  // Replace any Tailwind directives with generated CSS
175
175
  if (layerNodes.base) {