tailwindcss 0.0.0-insiders.ea10bb9 → 0.0.0-insiders.ea4e1cd

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 (184) hide show
  1. package/README.md +1 -1
  2. package/lib/cli/build/deps.js +17 -9
  3. package/lib/cli/build/index.js +20 -10
  4. package/lib/cli/build/plugin.js +86 -70
  5. package/lib/cli/build/utils.js +18 -8
  6. package/lib/cli/build/watching.js +16 -12
  7. package/lib/cli/help/index.js +6 -4
  8. package/lib/cli/index.js +222 -10
  9. package/lib/cli/init/index.js +29 -12
  10. package/lib/cli-peer-dependencies.js +12 -4
  11. package/lib/cli.js +4 -226
  12. package/lib/corePluginList.js +7 -1
  13. package/lib/corePlugins.js +348 -75
  14. package/lib/css/preflight.css +2 -0
  15. package/lib/featureFlags.js +27 -15
  16. package/lib/index.js +1 -47
  17. package/lib/lib/cacheInvalidation.js +7 -5
  18. package/lib/lib/collapseAdjacentRules.js +5 -3
  19. package/lib/lib/collapseDuplicateDeclarations.js +12 -10
  20. package/lib/lib/content.js +34 -30
  21. package/lib/lib/defaultExtractor.js +15 -8
  22. package/lib/lib/detectNesting.js +10 -2
  23. package/lib/lib/evaluateTailwindFunctions.js +22 -20
  24. package/lib/lib/expandApplyAtRules.js +43 -35
  25. package/lib/lib/expandTailwindAtRules.js +46 -19
  26. package/lib/lib/findAtConfigPath.js +9 -7
  27. package/lib/lib/generateRules.js +157 -92
  28. package/lib/lib/getModuleDependencies.js +85 -37
  29. package/lib/lib/load-config.js +42 -0
  30. package/lib/lib/normalizeTailwindDirectives.js +5 -3
  31. package/lib/lib/offsets.js +93 -4
  32. package/lib/lib/partitionApplyAtRules.js +3 -1
  33. package/lib/lib/regex.js +21 -7
  34. package/lib/lib/remap-bitfield.js +89 -0
  35. package/lib/lib/resolveDefaultsAtRules.js +28 -24
  36. package/lib/lib/setupContextUtils.js +190 -131
  37. package/lib/lib/setupTrackingContext.js +49 -26
  38. package/lib/lib/sharedState.js +37 -10
  39. package/lib/lib/substituteScreenAtRules.js +5 -3
  40. package/lib/oxide/cli/build/deps.js +89 -0
  41. package/lib/oxide/cli/build/index.js +53 -0
  42. package/lib/oxide/cli/build/plugin.js +375 -0
  43. package/lib/oxide/cli/build/utils.js +87 -0
  44. package/lib/oxide/cli/build/watching.js +179 -0
  45. package/lib/oxide/cli/help/index.js +72 -0
  46. package/lib/oxide/cli/index.js +214 -0
  47. package/lib/oxide/cli/init/index.js +52 -0
  48. package/lib/oxide/cli.js +5 -0
  49. package/lib/oxide/postcss-plugin.js +2 -0
  50. package/lib/plugin.js +98 -0
  51. package/lib/postcss-plugins/nesting/index.js +3 -1
  52. package/lib/postcss-plugins/nesting/plugin.js +10 -8
  53. package/lib/processTailwindFeatures.js +14 -12
  54. package/lib/public/colors.js +49 -25
  55. package/lib/public/create-plugin.js +5 -3
  56. package/lib/public/default-config.js +6 -4
  57. package/lib/public/default-theme.js +6 -4
  58. package/lib/public/load-config.js +12 -0
  59. package/lib/public/resolve-config.js +6 -4
  60. package/lib/util/applyImportantSelector.js +36 -0
  61. package/lib/util/bigSign.js +3 -1
  62. package/lib/util/buildMediaQuery.js +3 -1
  63. package/lib/util/cloneDeep.js +3 -1
  64. package/lib/util/cloneNodes.js +5 -3
  65. package/lib/util/color.js +30 -12
  66. package/lib/util/colorNames.js +752 -0
  67. package/lib/util/configurePlugins.js +3 -1
  68. package/lib/util/createPlugin.js +3 -1
  69. package/lib/util/createUtilityPlugin.js +7 -5
  70. package/lib/util/dataTypes.js +74 -17
  71. package/lib/util/defaults.js +9 -7
  72. package/lib/util/escapeClassName.js +10 -8
  73. package/lib/util/escapeCommas.js +3 -1
  74. package/lib/util/flattenColorPalette.js +3 -1
  75. package/lib/util/formatVariantSelector.js +138 -160
  76. package/lib/util/getAllConfigs.js +8 -6
  77. package/lib/util/hashConfig.js +6 -4
  78. package/lib/util/isKeyframeRule.js +3 -1
  79. package/lib/util/isPlainObject.js +3 -1
  80. package/lib/util/isSyntacticallyValidPropertyValue.js +3 -1
  81. package/lib/util/log.js +8 -4
  82. package/lib/util/nameClass.js +12 -6
  83. package/lib/util/negateValue.js +4 -2
  84. package/lib/util/normalizeConfig.js +28 -27
  85. package/lib/util/normalizeScreens.js +12 -4
  86. package/lib/util/parseAnimationValue.js +3 -1
  87. package/lib/util/parseBoxShadowValue.js +6 -2
  88. package/lib/util/parseDependency.js +3 -1
  89. package/lib/util/parseGlob.js +6 -4
  90. package/lib/util/parseObjectStyles.js +9 -7
  91. package/lib/util/pluginUtils.js +54 -54
  92. package/lib/util/prefixSelector.js +27 -11
  93. package/lib/util/pseudoElements.js +229 -0
  94. package/lib/util/removeAlphaVariables.js +3 -1
  95. package/lib/util/resolveConfig.js +17 -15
  96. package/lib/util/resolveConfigPath.js +26 -10
  97. package/lib/util/responsive.js +6 -4
  98. package/lib/util/splitAtTopLevelOnly.js +10 -2
  99. package/lib/util/tap.js +3 -1
  100. package/lib/util/toColorValue.js +3 -1
  101. package/lib/util/toPath.js +3 -1
  102. package/lib/util/transformThemeValue.js +6 -4
  103. package/lib/util/validateConfig.js +16 -3
  104. package/lib/util/validateFormalSyntax.js +3 -1
  105. package/lib/util/withAlphaVariable.js +6 -2
  106. package/loadConfig.d.ts +4 -0
  107. package/loadConfig.js +2 -0
  108. package/package.json +45 -37
  109. package/peers/index.js +63324 -46417
  110. package/resolveConfig.d.ts +11 -2
  111. package/scripts/swap-engines.js +40 -0
  112. package/src/cli/build/index.js +13 -9
  113. package/src/cli/build/plugin.js +42 -32
  114. package/src/cli/build/watching.js +4 -2
  115. package/src/cli/index.js +216 -3
  116. package/src/cli/init/index.js +37 -8
  117. package/src/cli.js +4 -220
  118. package/src/corePluginList.js +1 -1
  119. package/src/corePlugins.js +207 -32
  120. package/src/css/preflight.css +2 -0
  121. package/src/featureFlags.js +6 -0
  122. package/src/index.js +1 -47
  123. package/src/lib/content.js +12 -17
  124. package/src/lib/defaultExtractor.js +9 -3
  125. package/src/lib/detectNesting.js +9 -1
  126. package/src/lib/expandApplyAtRules.js +8 -1
  127. package/src/lib/expandTailwindAtRules.js +36 -7
  128. package/src/lib/generateRules.js +124 -42
  129. package/src/lib/getModuleDependencies.js +70 -30
  130. package/src/lib/load-config.ts +31 -0
  131. package/src/lib/offsets.js +104 -1
  132. package/src/lib/remap-bitfield.js +82 -0
  133. package/src/lib/setupContextUtils.js +103 -54
  134. package/src/lib/setupTrackingContext.js +36 -11
  135. package/src/lib/sharedState.js +15 -4
  136. package/src/oxide/cli/build/deps.ts +91 -0
  137. package/src/oxide/cli/build/index.ts +47 -0
  138. package/src/oxide/cli/build/plugin.ts +442 -0
  139. package/src/oxide/cli/build/utils.ts +74 -0
  140. package/src/oxide/cli/build/watching.ts +225 -0
  141. package/src/oxide/cli/help/index.ts +69 -0
  142. package/src/oxide/cli/index.ts +204 -0
  143. package/src/oxide/cli/init/index.ts +59 -0
  144. package/src/oxide/cli.ts +1 -0
  145. package/src/oxide/postcss-plugin.ts +1 -0
  146. package/src/plugin.js +107 -0
  147. package/src/public/colors.js +22 -0
  148. package/src/public/default-config.js +1 -1
  149. package/src/public/default-theme.js +2 -2
  150. package/src/public/load-config.js +2 -0
  151. package/src/util/applyImportantSelector.js +27 -0
  152. package/src/util/color.js +18 -3
  153. package/src/util/colorNames.js +150 -0
  154. package/src/util/dataTypes.js +33 -4
  155. package/src/util/formatVariantSelector.js +160 -163
  156. package/src/util/getAllConfigs.js +2 -2
  157. package/src/util/negateValue.js +1 -1
  158. package/src/util/normalizeConfig.js +2 -1
  159. package/src/util/pluginUtils.js +16 -31
  160. package/src/util/prefixSelector.js +28 -10
  161. package/src/util/pseudoElements.js +170 -0
  162. package/src/util/resolveConfigPath.js +12 -1
  163. package/src/util/splitAtTopLevelOnly.js +8 -1
  164. package/src/util/validateConfig.js +13 -0
  165. package/stubs/.gitignore +1 -0
  166. package/stubs/.prettierrc.json +6 -0
  167. package/stubs/{defaultConfig.stub.js → config.full.js} +183 -146
  168. package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -1
  169. package/stubs/postcss.config.js +6 -0
  170. package/stubs/tailwind.config.cjs +2 -0
  171. package/stubs/tailwind.config.js +2 -0
  172. package/stubs/tailwind.config.ts +3 -0
  173. package/types/config.d.ts +15 -9
  174. package/types/generated/colors.d.ts +22 -0
  175. package/types/generated/corePluginList.d.ts +1 -1
  176. package/types/generated/default-theme.d.ts +108 -79
  177. package/CHANGELOG.md +0 -2336
  178. package/lib/cli/shared.js +0 -12
  179. package/lib/constants.js +0 -44
  180. package/scripts/install-integrations.js +0 -27
  181. package/scripts/rebuildFixtures.js +0 -68
  182. package/src/cli/shared.js +0 -5
  183. package/src/constants.js +0 -17
  184. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
@@ -0,0 +1,82 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * We must remap all the old bits to new bits for each set variant
5
+ * Only arbitrary variants are considered as those are the only
6
+ * ones that need to be re-sorted at this time
7
+ *
8
+ * An iterated process that removes and sets individual bits simultaneously
9
+ * will not work because we may have a new bit that is also a later old bit
10
+ * This means that we would be removing a previously set bit which we don't
11
+ * want to do
12
+ *
13
+ * For example (assume `bN` = `1<<N`)
14
+ * Given the "total" mapping `[[b1, b3], [b2, b4], [b3, b1], [b4, b2]]`
15
+ * The mapping is "total" because:
16
+ * 1. Every input and output is accounted for
17
+ * 2. All combinations are unique
18
+ * 3. No one input maps to multiple outputs and vice versa
19
+ * And, given an offset with all bits set:
20
+ * V = b1 | b2 | b3 | b4
21
+ *
22
+ * Let's explore the issue with removing and setting bits simultaneously:
23
+ * V & ~b1 | b3 = b2 | b3 | b4
24
+ * V & ~b2 | b4 = b3 | b4
25
+ * V & ~b3 | b1 = b1 | b4
26
+ * V & ~b4 | b2 = b1 | b2
27
+ *
28
+ * As you can see, we end up with the wrong result.
29
+ * This is because we're removing a bit that was previously set.
30
+ * And, thus the final result is missing b3 and b4.
31
+ *
32
+ * Now, let's explore the issue with removing the bits first:
33
+ * V & ~b1 = b2 | b3 | b4
34
+ * V & ~b2 = b3 | b4
35
+ * V & ~b3 = b4
36
+ * V & ~b4 = 0
37
+ *
38
+ * And then setting the bits:
39
+ * V | b3 = b3
40
+ * V | b4 = b3 | b4
41
+ * V | b1 = b1 | b3 | b4
42
+ * V | b2 = b1 | b2 | b3 | b4
43
+ *
44
+ * We get the correct result because we're not removing any bits that were
45
+ * previously set thus properly remapping the bits to the new order
46
+ *
47
+ * To collect this into a single operation that can be done simultaneously
48
+ * we must first create a mask for the old bits that are set and a mask for
49
+ * the new bits that are set. Then we can remove the old bits and set the new
50
+ * bits simultaneously in a "single" operation like so:
51
+ * OldMask = b1 | b2 | b3 | b4
52
+ * NewMask = b3 | b4 | b1 | b2
53
+ *
54
+ * So this:
55
+ * V & ~oldMask | newMask
56
+ *
57
+ * Expands to this:
58
+ * V & ~b1 & ~b2 & ~b3 & ~b4 | b3 | b4 | b1 | b2
59
+ *
60
+ * Which becomes this:
61
+ * b1 | b2 | b3 | b4
62
+ *
63
+ * Which is the correct result!
64
+ *
65
+ * @param {bigint} num
66
+ * @param {[bigint, bigint][]} mapping
67
+ */
68
+ export function remapBitfield(num, mapping) {
69
+ // Create masks for the old and new bits that are set
70
+ let oldMask = 0n
71
+ let newMask = 0n
72
+ for (let [oldBit, newBit] of mapping) {
73
+ if (num & oldBit) {
74
+ oldMask = oldMask | oldBit
75
+ newMask = newMask | newBit
76
+ }
77
+ }
78
+
79
+ // Remove all old bits
80
+ // Set all new bits
81
+ return (num & ~oldMask) | newMask
82
+ }
@@ -54,32 +54,50 @@ function normalizeOptionTypes({ type = 'any', ...options }) {
54
54
  }
55
55
 
56
56
  function parseVariantFormatString(input) {
57
- if (input.includes('{')) {
58
- if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
59
-
60
- return input
61
- .split(/{(.*)}/gim)
62
- .flatMap((line) => parseVariantFormatString(line))
63
- .filter(Boolean)
64
- }
65
-
66
- return [input.trim()]
67
- }
68
-
69
- function isBalanced(input) {
70
- let count = 0
71
-
72
- for (let char of input) {
73
- if (char === '{') {
74
- count++
57
+ /** @type {string[]} */
58
+ let parts = []
59
+
60
+ // When parsing whitespace around special characters are insignificant
61
+ // However, _inside_ of a variant they could be
62
+ // Because the selector could look like this
63
+ // @media { &[data-name="foo bar"] }
64
+ // This is why we do not skip whitespace
65
+
66
+ let current = ''
67
+ let depth = 0
68
+
69
+ for (let idx = 0; idx < input.length; idx++) {
70
+ let char = input[idx]
71
+
72
+ if (char === '\\') {
73
+ // Escaped characters are not special
74
+ current += '\\' + input[++idx]
75
+ } else if (char === '{') {
76
+ // Nested rule: start
77
+ ++depth
78
+ parts.push(current.trim())
79
+ current = ''
75
80
  } else if (char === '}') {
76
- if (--count < 0) {
77
- return false // unbalanced
81
+ // Nested rule: end
82
+ if (--depth < 0) {
83
+ throw new Error(`Your { and } are unbalanced.`)
78
84
  }
85
+
86
+ parts.push(current.trim())
87
+ current = ''
88
+ } else {
89
+ // Normal character
90
+ current += char
79
91
  }
80
92
  }
81
93
 
82
- return count === 0
94
+ if (current.length > 0) {
95
+ parts.push(current.trim())
96
+ }
97
+
98
+ parts = parts.filter((part) => part !== '')
99
+
100
+ return parts
83
101
  }
84
102
 
85
103
  function insertInto(list, value, { before = [] } = {}) {
@@ -253,25 +271,18 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
253
271
  }
254
272
 
255
273
  function resolveThemeValue(path, defaultValue, opts = {}) {
256
- const [pathRoot, ...subPaths] = toPath(path)
257
- const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
258
- return transformThemeValue(pathRoot)(value, opts)
274
+ let parts = toPath(path)
275
+ let value = getConfigValue(['theme', ...parts], defaultValue)
276
+ return transformThemeValue(parts[0])(value, opts)
259
277
  }
260
278
 
261
- const theme = Object.assign(
262
- (path, defaultValue = undefined) => resolveThemeValue(path, defaultValue),
263
- {
264
- withAlpha: (path, opacityValue) => resolveThemeValue(path, undefined, { opacityValue }),
265
- }
266
- )
267
-
268
279
  let variantIdentifier = 0
269
280
  let api = {
270
281
  postcss,
271
282
  prefix: applyConfiguredPrefix,
272
283
  e: escapeClassName,
273
284
  config: getConfigValue,
274
- theme,
285
+ theme: resolveThemeValue,
275
286
  corePlugins: (path) => {
276
287
  if (Array.isArray(tailwindConfig.corePlugins)) {
277
288
  return tailwindConfig.corePlugins.includes(path)
@@ -639,6 +650,7 @@ export function getFileModifiedMap(context) {
639
650
 
640
651
  function trackModified(files, fileModifiedMap) {
641
652
  let changed = false
653
+ let mtimesToCommit = new Map()
642
654
 
643
655
  for (let file of files) {
644
656
  if (!file) continue
@@ -659,10 +671,10 @@ function trackModified(files, fileModifiedMap) {
659
671
  changed = true
660
672
  }
661
673
 
662
- fileModifiedMap.set(file, newModified)
674
+ mtimesToCommit.set(file, newModified)
663
675
  }
664
676
 
665
- return changed
677
+ return [changed, mtimesToCommit]
666
678
  }
667
679
 
668
680
  function extractVariantAtRules(node) {
@@ -919,12 +931,19 @@ function registerPlugins(plugins, context) {
919
931
  prefix(context, 'peer'),
920
932
  ]
921
933
  context.getClassOrder = function getClassOrder(classes) {
934
+ // Sort classes so they're ordered in a deterministic manner
935
+ let sorted = [...classes].sort((a, z) => {
936
+ if (a === z) return 0
937
+ if (a < z) return -1
938
+ return 1
939
+ })
940
+
922
941
  // Non-util classes won't be generated, so we default them to null
923
- let sortedClassNames = new Map(classes.map((className) => [className, null]))
942
+ let sortedClassNames = new Map(sorted.map((className) => [className, null]))
924
943
 
925
944
  // Sort all classes in order
926
945
  // Non-tailwind classes won't be generated and will be left as `null`
927
- let rules = generateRules(new Set(classes), context)
946
+ let rules = generateRules(new Set(sorted), context)
928
947
  rules = context.offsets.sort(rules)
929
948
 
930
949
  let idx = BigInt(parasiteUtilities.length)
@@ -950,23 +969,35 @@ function registerPlugins(plugins, context) {
950
969
 
951
970
  // Generate a list of strings for autocompletion purposes, e.g.
952
971
  // ['uppercase', 'lowercase', ...]
953
- context.getClassList = function getClassList() {
972
+ context.getClassList = function getClassList(options = {}) {
954
973
  let output = []
955
974
 
956
975
  for (let util of classList) {
957
976
  if (Array.isArray(util)) {
958
- let [utilName, options] = util
977
+ let [utilName, utilOptions] = util
959
978
  let negativeClasses = []
960
979
 
961
- for (let [key, value] of Object.entries(options?.values ?? {})) {
980
+ let modifiers = Object.keys(utilOptions?.modifiers ?? {})
981
+
982
+ if (utilOptions?.types?.some(({ type }) => type === 'color')) {
983
+ modifiers.push(...Object.keys(context.tailwindConfig.theme.opacity ?? {}))
984
+ }
985
+
986
+ let metadata = { modifiers }
987
+ let includeMetadata = options.includeMetadata && modifiers.length > 0
988
+
989
+ for (let [key, value] of Object.entries(utilOptions?.values ?? {})) {
962
990
  // Ignore undefined and null values
963
991
  if (value == null) {
964
992
  continue
965
993
  }
966
994
 
967
- output.push(formatClass(utilName, key))
968
- if (options?.supportsNegativeValues && negateValue(value)) {
969
- negativeClasses.push(formatClass(utilName, `-${key}`))
995
+ let cls = formatClass(utilName, key)
996
+ output.push(includeMetadata ? [cls, metadata] : cls)
997
+
998
+ if (utilOptions?.supportsNegativeValues && negateValue(value)) {
999
+ let cls = formatClass(utilName, `-${key}`)
1000
+ negativeClasses.push(includeMetadata ? [cls, metadata] : cls)
970
1001
  }
971
1002
  }
972
1003
 
@@ -1087,20 +1118,38 @@ function registerPlugins(plugins, context) {
1087
1118
  })
1088
1119
  }
1089
1120
 
1090
- let result = formatStrings.map((formatString) =>
1091
- finalizeSelector(formatVariantSelector('&', ...formatString), {
1092
- selector: `.${candidate}`,
1093
- candidate,
1094
- context,
1095
- isArbitraryVariant: !(value in (options.values ?? {})),
1096
- })
1121
+ let isArbitraryVariant = !(value in (options.values ?? {}))
1122
+
1123
+ formatStrings = formatStrings.map((format) =>
1124
+ format.map((str) => ({
1125
+ format: str,
1126
+ isArbitraryVariant,
1127
+ }))
1128
+ )
1129
+
1130
+ manualFormatStrings = manualFormatStrings.map((format) => ({
1131
+ format,
1132
+ isArbitraryVariant,
1133
+ }))
1134
+
1135
+ let opts = {
1136
+ candidate,
1137
+ context,
1138
+ }
1139
+
1140
+ let result = formatStrings.map((formats) =>
1141
+ finalizeSelector(`.${candidate}`, formatVariantSelector(formats, opts), opts)
1097
1142
  .replace(`.${candidate}`, '&')
1098
1143
  .replace('{ & }', '')
1099
1144
  .trim()
1100
1145
  )
1101
1146
 
1102
1147
  if (manualFormatStrings.length > 0) {
1103
- result.push(formatVariantSelector('&', ...manualFormatStrings))
1148
+ result.push(
1149
+ formatVariantSelector(manualFormatStrings, opts)
1150
+ .toString()
1151
+ .replace(`.${candidate}`, '&')
1152
+ )
1104
1153
  }
1105
1154
 
1106
1155
  return result
@@ -1219,12 +1268,12 @@ export function getContext(
1219
1268
  // If there's already a context in the cache and we don't need to
1220
1269
  // reset the context, return the cached context.
1221
1270
  if (existingContext) {
1222
- let contextDependenciesChanged = trackModified(
1271
+ let [contextDependenciesChanged, mtimesToCommit] = trackModified(
1223
1272
  [...contextDependencies],
1224
1273
  getFileModifiedMap(existingContext)
1225
1274
  )
1226
1275
  if (!contextDependenciesChanged && !cssDidChange) {
1227
- return [existingContext, false]
1276
+ return [existingContext, false, mtimesToCommit]
1228
1277
  }
1229
1278
  }
1230
1279
 
@@ -1259,7 +1308,7 @@ export function getContext(
1259
1308
  userConfigPath,
1260
1309
  })
1261
1310
 
1262
- trackModified([...contextDependencies], getFileModifiedMap(context))
1311
+ let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context))
1263
1312
 
1264
1313
  // ---
1265
1314
 
@@ -1274,5 +1323,5 @@ export function getContext(
1274
1323
 
1275
1324
  contextSourcesMap.get(context).add(sourcePath)
1276
1325
 
1277
- return [context, true]
1326
+ return [context, true, mtimesToCommit]
1278
1327
  }
@@ -1,14 +1,17 @@
1
+ // @ts-check
2
+
1
3
  import fs from 'fs'
2
- import LRU from 'quick-lru'
4
+ import LRU from '@alloc/quick-lru'
3
5
 
4
6
  import hash from '../util/hashConfig'
5
- import getModuleDependencies from '../lib/getModuleDependencies'
6
7
  import resolveConfig from '../public/resolve-config'
7
8
  import resolveConfigPath from '../util/resolveConfigPath'
8
9
  import { getContext, getFileModifiedMap } from './setupContextUtils'
9
10
  import parseDependency from '../util/parseDependency'
10
11
  import { validateConfig } from '../util/validateConfig.js'
11
12
  import { parseCandidateFiles, resolvedChangedContent } from './content.js'
13
+ import { loadConfig } from '../lib/load-config'
14
+ import getModuleDependencies from './getModuleDependencies'
12
15
 
13
16
  let configPathCache = new LRU({ maxSize: 100 })
14
17
 
@@ -32,7 +35,7 @@ function getTailwindConfig(configOrPath) {
32
35
  let [prevConfig, prevConfigHash, prevDeps, prevModified] =
33
36
  configPathCache.get(userConfigPath) || []
34
37
 
35
- let newDeps = getModuleDependencies(userConfigPath).map((dep) => dep.file)
38
+ let newDeps = getModuleDependencies(userConfigPath)
36
39
 
37
40
  let modified = false
38
41
  let newModified = new Map()
@@ -53,8 +56,7 @@ function getTailwindConfig(configOrPath) {
53
56
  for (let file of newDeps) {
54
57
  delete require.cache[file]
55
58
  }
56
- let newConfig = resolveConfig(require(userConfigPath))
57
- newConfig = validateConfig(newConfig)
59
+ let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath)))
58
60
  let newHash = hash(newConfig)
59
61
  configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified])
60
62
  return [newConfig, userConfigPath, newHash, newDeps]
@@ -101,7 +103,7 @@ export default function setupTrackingContext(configOrPath) {
101
103
  }
102
104
  }
103
105
 
104
- let [context] = getContext(
106
+ let [context, , mTimesToCommit] = getContext(
105
107
  root,
106
108
  result,
107
109
  tailwindConfig,
@@ -110,6 +112,8 @@ export default function setupTrackingContext(configOrPath) {
110
112
  contextDependencies
111
113
  )
112
114
 
115
+ let fileModifiedMap = getFileModifiedMap(context)
116
+
113
117
  let candidateFiles = getCandidateFiles(context, tailwindConfig)
114
118
 
115
119
  // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
@@ -118,8 +122,6 @@ export default function setupTrackingContext(configOrPath) {
118
122
  // because it's impossible for a layer in one file to end up in the actual @tailwind rule
119
123
  // in another file since independent sources are effectively isolated.
120
124
  if (tailwindDirectives.size > 0) {
121
- let fileModifiedMap = getFileModifiedMap(context)
122
-
123
125
  // Add template paths as postcss dependencies.
124
126
  for (let contentPath of candidateFiles) {
125
127
  for (let dependency of parseDependency(contentPath)) {
@@ -127,12 +129,28 @@ export default function setupTrackingContext(configOrPath) {
127
129
  }
128
130
  }
129
131
 
130
- for (let changedContent of resolvedChangedContent(
132
+ let [changedContent, contentMTimesToCommit] = resolvedChangedContent(
131
133
  context,
132
134
  candidateFiles,
133
135
  fileModifiedMap
134
- )) {
135
- context.changedContent.push(changedContent)
136
+ )
137
+
138
+ for (let content of changedContent) {
139
+ context.changedContent.push(content)
140
+ }
141
+
142
+ // Add the mtimes of the content files to the commit list
143
+ // We can overwrite the existing values because unconditionally
144
+ // This is because:
145
+ // 1. Most of the files here won't be in the map yet
146
+ // 2. If they are that means it's a context dependency
147
+ // and we're reading this after the context. This means
148
+ // that the mtime we just read is strictly >= the context
149
+ // mtime. Unless the user / os is doing something weird
150
+ // in which the mtime would be going backwards. If that
151
+ // happens there's already going to be problems.
152
+ for (let [path, mtime] of contentMTimesToCommit.entries()) {
153
+ mTimesToCommit.set(path, mtime)
136
154
  }
137
155
  }
138
156
 
@@ -140,6 +158,13 @@ export default function setupTrackingContext(configOrPath) {
140
158
  registerDependency({ type: 'dependency', file })
141
159
  }
142
160
 
161
+ // "commit" the new modified time for all context deps
162
+ // We do this here because we want content tracking to
163
+ // read the "old" mtime even when it's a context dependency.
164
+ for (let [path, mtime] of mTimesToCommit.entries()) {
165
+ fileModifiedMap.set(path, mtime)
166
+ }
167
+
143
168
  return context
144
169
  }
145
170
  }
@@ -1,7 +1,18 @@
1
- export const env = {
2
- NODE_ENV: process.env.NODE_ENV,
3
- DEBUG: resolveDebug(process.env.DEBUG),
4
- }
1
+ import pkg from '../../package.json'
2
+
3
+ export const env =
4
+ typeof process !== 'undefined'
5
+ ? {
6
+ NODE_ENV: process.env.NODE_ENV,
7
+ DEBUG: resolveDebug(process.env.DEBUG),
8
+ ENGINE: pkg.tailwindcss.engine,
9
+ }
10
+ : {
11
+ NODE_ENV: 'production',
12
+ DEBUG: false,
13
+ ENGINE: pkg.tailwindcss.engine,
14
+ }
15
+
5
16
  export const contextMap = new Map()
6
17
  export const configContextMap = new Map()
7
18
  export const contextSourcesMap = new Map()
@@ -0,0 +1,91 @@
1
+ import packageJson from '../../../../package.json'
2
+ import browserslist from 'browserslist'
3
+ import { Result } from 'postcss'
4
+
5
+ import {
6
+ // @ts-ignore
7
+ lazyPostcss,
8
+
9
+ // @ts-ignore
10
+ lazyPostcssImport,
11
+
12
+ // @ts-ignore
13
+ lazyCssnano,
14
+
15
+ // @ts-ignore
16
+ } from '../../../../peers/index'
17
+
18
+ export function lazyLightningCss() {
19
+ // TODO: Make this lazy/bundled
20
+ return require('lightningcss')
21
+ }
22
+
23
+ let lightningCss
24
+
25
+ function loadLightningCss() {
26
+ if (lightningCss) {
27
+ return lightningCss
28
+ }
29
+
30
+ // Try to load a local version first
31
+ try {
32
+ return (lightningCss = require('lightningcss'))
33
+ } catch {}
34
+
35
+ return (lightningCss = lazyLightningCss())
36
+ }
37
+
38
+ export async function lightningcss(shouldMinify: boolean, result: Result) {
39
+ let css = loadLightningCss()
40
+
41
+ try {
42
+ let transformed = css.transform({
43
+ filename: result.opts.from || 'input.css',
44
+ code: Buffer.from(result.css, 'utf-8'),
45
+ minify: shouldMinify,
46
+ sourceMap: !!result.map,
47
+ inputSourceMap: result.map ? result.map.toString() : undefined,
48
+ targets: css.browserslistToTargets(browserslist(packageJson.browserslist)),
49
+ drafts: {
50
+ nesting: true,
51
+ },
52
+ })
53
+
54
+ return Object.assign(result, {
55
+ css: transformed.code.toString('utf8'),
56
+ map: result.map
57
+ ? Object.assign(result.map, {
58
+ toString() {
59
+ return transformed.map.toString()
60
+ },
61
+ })
62
+ : result.map,
63
+ })
64
+ } catch (err) {
65
+ console.error('Unable to use Lightning CSS. Using raw version instead.')
66
+ console.error(err)
67
+
68
+ return result
69
+ }
70
+ }
71
+
72
+ /**
73
+ * @returns {import('postcss')}
74
+ */
75
+ export function loadPostcss() {
76
+ // Try to load a local `postcss` version first
77
+ try {
78
+ return require('postcss')
79
+ } catch {}
80
+
81
+ return lazyPostcss()
82
+ }
83
+
84
+ export function loadPostcssImport() {
85
+ // Try to load a local `postcss-import` version first
86
+ try {
87
+ return require('postcss-import')
88
+ } catch {}
89
+
90
+ return lazyPostcssImport()
91
+ }
@@ -0,0 +1,47 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import { resolveDefaultConfigPath } from '../../../util/resolveConfigPath'
4
+ import { createProcessor } from './plugin'
5
+
6
+ export async function build(args) {
7
+ let input = args['--input']
8
+ let shouldWatch = args['--watch']
9
+
10
+ // TODO: Deprecate this in future versions
11
+ if (!input && args['_'][1]) {
12
+ console.error('[deprecation] Running tailwindcss without -i, please provide an input file.')
13
+ input = args['--input'] = args['_'][1]
14
+ }
15
+
16
+ if (input && input !== '-' && !fs.existsSync((input = path.resolve(input)))) {
17
+ console.error(`Specified input file ${args['--input']} does not exist.`)
18
+ process.exit(9)
19
+ }
20
+
21
+ if (args['--config'] && !fs.existsSync((args['--config'] = path.resolve(args['--config'])))) {
22
+ console.error(`Specified config file ${args['--config']} does not exist.`)
23
+ process.exit(9)
24
+ }
25
+
26
+ // TODO: Reference the @config path here if exists
27
+ let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath()
28
+
29
+ let processor = await createProcessor(args, configPath)
30
+
31
+ if (shouldWatch) {
32
+ // Abort the watcher if stdin is closed to avoid zombie processes
33
+ // You can disable this behavior with --watch=always
34
+ if (args['--watch'] !== 'always') {
35
+ process.stdin.on('end', () => process.exit(0))
36
+ }
37
+
38
+ process.stdin.resume()
39
+
40
+ await processor.watch()
41
+ } else {
42
+ await processor.build().catch((e) => {
43
+ console.error(e)
44
+ process.exit(1)
45
+ })
46
+ }
47
+ }