%PDF- %PDF-
Direktori : /home/forge/takeaseat.eco-n-tech.co.uk/node_modules/tailwindcss/jit/lib/ |
Current File : //home/forge/takeaseat.eco-n-tech.co.uk/node_modules/tailwindcss/jit/lib/expandTailwindAtRules.js |
const fs = require('fs') const path = require('path') const fastGlob = require('fast-glob') const parseGlob = require('parse-glob') const sharedState = require('./sharedState') const { generateRules } = require('./generateRules') const { bigSign, cloneNodes } = require('./utils') let env = sharedState.env let contentMatchCache = sharedState.contentMatchCache const BROAD_MATCH_GLOBAL_REGEXP = /[^<>"'`\s]*[^<>"'`\s:]/g const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g function getDefaultExtractor(fileExtension) { return function (content) { if (fileExtension === 'svelte') { content = content.replace(/\sclass:/g, ' ') } 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 const fileExtension = path.extname(fileName).slice(1) if (!purgeOptions) { return getDefaultExtractor(fileExtension) } const fileSpecificExtractor = (purgeOptions.extractors || []).find((extractor) => extractor.extensions.includes(fileExtension) ) if (fileSpecificExtractor) { return fileSpecificExtractor.extractor } return purgeOptions.defaultExtractor || getDefaultExtractor(fileExtension) } // 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, extractor, contentMatchCache, candidates, seen) { for (let line of content.split('\n')) { line = line.trim() if (seen.has(line)) { continue } seen.add(line) if (contentMatchCache.has(line)) { for (let match of contentMatchCache.get(line)) { candidates.add(match) } } else { let extractorMatches = extractor(line) let lineMatchesSet = new Set(extractorMatches) for (let match of lineMatchesSet) { candidates.add(match) } contentMatchCache.set(line, lineMatchesSet) } } } function buildStylesheet(rules, context) { let sortedRules = rules.sort(([a], [z]) => bigSign(a - z)) let returnValue = { base: new Set(), components: new Set(), utilities: new Set(), screens: new Set(), } for (let [sort, rule] of sortedRules) { if (sort >= context.minimumScreen) { returnValue.screens.add(rule) continue } if (sort & context.layerOrder.base) { returnValue.base.add(rule) continue } if (sort & context.layerOrder.components) { returnValue.components.add(rule) continue } if (sort & context.layerOrder.utilities) { returnValue.utilities.add(rule) continue } } return returnValue } function expandTailwindAtRules(context, registerDependency) { return (root) => { let foundTailwind = false let layerNodes = { base: null, components: null, utilities: null, screens: null, } // Make sure this file contains Tailwind directives. If not, we can save // a lot of work and bail early. Also we don't have to register our touch // file as a dependency since the output of this CSS does not depend on // the source of any templates. Think Vue <style> blocks for example. root.walkAtRules('tailwind', (rule) => { foundTailwind = true if (rule.params === 'base') { layerNodes.base = rule } if (rule.params === 'components') { layerNodes.components = rule } if (rule.params === 'utilities') { layerNodes.utilities = rule } if (rule.params === 'screens') { layerNodes.screens = rule } }) if (!foundTailwind) { return root } // --- if (sharedState.env.TAILWIND_DISABLE_TOUCH) { for (let maybeGlob of context.candidateFiles) { let { is: { glob: isGlob }, base, } = parseGlob(maybeGlob) if (isGlob) { // register base dir as `dependency` _and_ `context-dependency` for // increased compatibility registerDependency(path.resolve(base)) registerDependency(path.resolve(base), 'context-dependency') } else { registerDependency(path.resolve(maybeGlob)) } } env.DEBUG && console.time('Finding changed files') let files = fastGlob.sync(context.candidateFiles) for (let file of files) { let prevModified = context.fileModifiedMap.has(file) ? context.fileModifiedMap.get(file) : -Infinity let modified = fs.statSync(file).mtimeMs if (!context.scannedContent || modified > prevModified) { context.changedFiles.add(file) context.fileModifiedMap.set(file, modified) } } context.scannedContent = true env.DEBUG && console.timeEnd('Finding changed files') } else { // Register our temp file as a dependency — we write to this file // to trigger rebuilds. if (context.touchFile) { registerDependency(context.touchFile) } // If we're not set up and watching files ourselves, we need to do // the work of grabbing all of the template files for candidate // detection. if (!context.scannedContent) { let files = fastGlob.sync(context.candidateFiles) for (let file of files) { context.changedFiles.add(file) } context.scannedContent = true } } // --- // Find potential rules in changed files let candidates = new Set(['*']) let seen = new Set() env.DEBUG && console.time('Reading changed files') for (let file of context.changedFiles) { let content = fs.readFileSync(file, 'utf8') let extractor = getExtractor(file, context.tailwindConfig) getClassCandidates(content, extractor, contentMatchCache, candidates, seen) } env.DEBUG && console.timeEnd('Reading changed files') // --- // Generate the actual CSS let classCacheCount = context.classCache.size env.DEBUG && console.time('Generate rules') let rules = generateRules(candidates, context) env.DEBUG && console.timeEnd('Generate rules') // We only ever add to the classCache, so if it didn't grow, there is nothing new. env.DEBUG && console.time('Build stylesheet') if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) { for (let rule of rules) { context.ruleCache.add(rule) } context.stylesheetCache = buildStylesheet([...context.ruleCache], context) } env.DEBUG && console.timeEnd('Build stylesheet') let { base: baseNodes, components: componentNodes, utilities: utilityNodes, screens: screenNodes, } = context.stylesheetCache // --- // Replace any Tailwind directives with generated CSS if (layerNodes.base) { layerNodes.base.before(cloneNodes([...baseNodes])) layerNodes.base.remove() } if (layerNodes.components) { layerNodes.components.before(cloneNodes([...componentNodes])) layerNodes.components.remove() } if (layerNodes.utilities) { layerNodes.utilities.before(cloneNodes([...utilityNodes])) layerNodes.utilities.remove() } if (layerNodes.screens) { layerNodes.screens.before(cloneNodes([...screenNodes])) layerNodes.screens.remove() } else { root.append(cloneNodes([...screenNodes])) } // --- if (env.DEBUG) { console.log('Changed files: ', context.changedFiles.size) console.log('Potential classes: ', candidates.size) console.log('Active contexts: ', sharedState.contextSourcesMap.size) console.log('Content match entries', contentMatchCache.size) } // Clear the cache for the changed files context.changedFiles.clear() } } module.exports = expandTailwindAtRules