@tailwindcss/jit
Advanced tools
Comparing version 0.1.7 to 0.1.8
@@ -12,2 +12,14 @@ # Changelog | ||
## [0.1.8] - 2021-03-24 | ||
### Added | ||
- Direct support for @import 'tailwindcss/{layer}' syntax ([#145](https://github.com/tailwindlabs/tailwindcss-jit/pull/145)) | ||
- Support for custom extractors ([#125](https://github.com/tailwindlabs/tailwindcss-jit/pull/125)) | ||
### Fixed | ||
- Fix `@apply` with animation utilities stripping keyframe names ([#150](https://github.com/tailwindlabs/tailwindcss-jit/pull/150)) | ||
- Fix using `@apply` multiple times within a single rule ([#151](https://github.com/tailwindlabs/tailwindcss-jit/pull/151)) | ||
## [0.1.7] - 2021-03-22 | ||
@@ -74,3 +86,4 @@ | ||
[unreleased]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.7...HEAD | ||
[unreleased]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.8...HEAD | ||
[0.1.8]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.7...v0.1.8 | ||
[0.1.7]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.6...v0.1.7 | ||
@@ -77,0 +90,0 @@ [0.1.6]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.5...v0.1.6 |
{ | ||
"name": "@tailwindcss/jit", | ||
"version": "0.1.7", | ||
"version": "0.1.8", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -6,2 +6,3 @@ const postcss = require('postcss') | ||
const rewriteTailwindImports = require('./lib/rewriteTailwindImports') | ||
const setupContext = require('./lib/setupContext') | ||
@@ -35,2 +36,4 @@ const removeLayerAtRules = require('./lib/removeLayerAtRules') | ||
rewriteTailwindImports(root) | ||
let context = setupContext(configOrPath)(result, root) | ||
@@ -37,0 +40,0 @@ |
@@ -105,4 +105,11 @@ const postcss = require('postcss') | ||
/** @type {Map<import('postcss').Node, [string, boolean, import('postcss').Node[]][]>} */ | ||
let perParentApplies = new Map() | ||
// Collect all apply candidates and their rules | ||
for (let apply of applies) { | ||
let siblings = [] | ||
let candidates = perParentApplies.get(apply.parent) || [] | ||
perParentApplies.set(apply.parent, candidates) | ||
let [applyCandidates, important] = extractApplyCandidates(apply.params) | ||
@@ -119,11 +126,24 @@ | ||
candidates.push([applyCandidate, important, rules]) | ||
} | ||
} | ||
for (const [parent, candidates] of perParentApplies) { | ||
let siblings = [] | ||
for (let [applyCandidate, important, rules] of candidates) { | ||
for (let [meta, node] of rules) { | ||
let root = postcss.root({ nodes: [node.clone()] }) | ||
let canRewriteSelector = | ||
node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes') | ||
root.walkRules((rule) => { | ||
rule.selector = replaceSelector(apply.parent.selector, rule.selector, applyCandidate) | ||
rule.walkDecls((d) => { | ||
d.important = important | ||
if (canRewriteSelector) { | ||
root.walkRules((rule) => { | ||
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate) | ||
rule.walkDecls((d) => { | ||
d.important = important | ||
}) | ||
}) | ||
}) | ||
} | ||
@@ -135,7 +155,9 @@ siblings.push([meta, root.nodes[0]]) | ||
// Inject the rules, sorted, correctly | ||
for (let [, sibling] of siblings.sort(([a], [z]) => bigSign(z.sort - a.sort))) { | ||
// `apply.parent` is referring to the node at `.abc` in: .abc { @apply mt-2 } | ||
apply.parent.after(sibling) | ||
} | ||
const nodes = siblings.sort(([a], [z]) => bigSign(a.sort - z.sort)).map((s) => s[1]) | ||
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 } | ||
parent.after(nodes) | ||
} | ||
for (let apply of applies) { | ||
// If there are left-over declarations, just remove the @apply | ||
@@ -142,0 +164,0 @@ if (apply.parent.nodes.length > 1) { |
const fs = require('fs') | ||
const path = require('path') | ||
const fastGlob = require('fast-glob') | ||
@@ -10,6 +11,35 @@ const sharedState = require('./sharedState') | ||
const BROAD_MATCH_GLOBAL_REGEXP = /[^<>"'`\s]*[^<>"'`\s:]/g | ||
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g | ||
function defaultJitExtractor(content) { | ||
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [] | ||
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [] | ||
return [...broadMatches, ...innerMatches] | ||
} | ||
function getExtractor(fileName, tailwindConfig) { | ||
const purgeOptions = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.options | ||
if (!purgeOptions) { | ||
return defaultJitExtractor | ||
} | ||
const fileExtension = path.extname(fileName).slice(1) | ||
const fileSpecificExtractor = (purgeOptions.extractors || []).find((extractor) => | ||
extractor.extensions.includes(fileExtension) | ||
) | ||
if (fileSpecificExtractor) { | ||
return fileSpecificExtractor.extractor | ||
} | ||
return purgeOptions.defaultExtractor || defaultJitExtractor | ||
} | ||
// Scans template contents for possible classes. This is a hot path on initial build but | ||
// not too important for subsequent builds. The faster the better though — if we can speed | ||
// up these regexes by 50% that could cut initial build time by like 20%. | ||
function getClassCandidates(content, contentMatchCache, candidates, seen) { | ||
function getClassCandidates(content, extractor, contentMatchCache, candidates, seen) { | ||
for (let line of content.split('\n')) { | ||
@@ -28,16 +58,10 @@ line = line.trim() | ||
} else { | ||
let allMatches = new Set() | ||
let broadMatches = line.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [] | ||
let innerMatches = line.match(/[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g) || [] | ||
let extractorMatches = extractor(line) | ||
let lineMatchesSet = new Set(extractorMatches) | ||
for (let match of broadMatches) { | ||
allMatches.add(match) | ||
for (let match of lineMatchesSet) { | ||
candidates.add(match) | ||
} | ||
for (let match of innerMatches) { | ||
allMatches.add(match) | ||
candidates.add(match) | ||
} | ||
contentMatchCache.set(line, allMatches) | ||
contentMatchCache.set(line, lineMatchesSet) | ||
} | ||
@@ -148,3 +172,4 @@ } | ||
let content = fs.readFileSync(file, 'utf8') | ||
getClassCandidates(content, contentMatchCache, candidates, seen) | ||
let extractor = getExtractor(file, context.tailwindConfig) | ||
getClassCandidates(content, extractor, contentMatchCache, candidates, seen) | ||
} | ||
@@ -151,0 +176,0 @@ env.DEBUG && console.timeEnd('Reading changed files') |
@@ -91,4 +91,2 @@ const postcss = require('postcss') | ||
* | ||
* NOTE: Only clone the nodes you pass to root.append() | ||
* | ||
* @param {import('postcss').Node[]} nodes | ||
@@ -95,0 +93,0 @@ * */ |
@@ -102,2 +102,11 @@ const postcss = require('postcss') | ||
} | ||
h1 { | ||
@apply text-2xl lg:text-2xl sm:text-3xl; | ||
} | ||
h2 { | ||
@apply text-2xl; | ||
@apply lg:text-2xl; | ||
@apply sm:text-2xl; | ||
} | ||
} | ||
@@ -109,2 +118,10 @@ | ||
} | ||
.foo { | ||
@apply animate-spin; | ||
} | ||
.bar { | ||
@apply animate-pulse !important; | ||
} | ||
} | ||
@@ -111,0 +128,0 @@ ` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
255128
4865
184
7338
25