|
|
|
|
|
import fs from 'fs' |
|
import LRU from '@alloc/quick-lru' |
|
|
|
import hash from '../util/hashConfig' |
|
import resolveConfig from '../public/resolve-config' |
|
import resolveConfigPath from '../util/resolveConfigPath' |
|
import { getContext, getFileModifiedMap } from './setupContextUtils' |
|
import parseDependency from '../util/parseDependency' |
|
import { validateConfig } from '../util/validateConfig.js' |
|
import { parseCandidateFiles, resolvedChangedContent } from './content.js' |
|
import { loadConfig } from '../lib/load-config' |
|
import getModuleDependencies from './getModuleDependencies' |
|
|
|
let configPathCache = new LRU({ maxSize: 100 }) |
|
|
|
let candidateFilesCache = new WeakMap() |
|
|
|
function getCandidateFiles(context, tailwindConfig) { |
|
if (candidateFilesCache.has(context)) { |
|
return candidateFilesCache.get(context) |
|
} |
|
|
|
let candidateFiles = parseCandidateFiles(context, tailwindConfig) |
|
|
|
return candidateFilesCache.set(context, candidateFiles).get(context) |
|
} |
|
|
|
|
|
function getTailwindConfig(configOrPath) { |
|
let userConfigPath = resolveConfigPath(configOrPath) |
|
|
|
if (userConfigPath !== null) { |
|
let [prevConfig, prevConfigHash, prevDeps, prevModified] = |
|
configPathCache.get(userConfigPath) || [] |
|
|
|
let newDeps = getModuleDependencies(userConfigPath) |
|
|
|
let modified = false |
|
let newModified = new Map() |
|
for (let file of newDeps) { |
|
let time = fs.statSync(file).mtimeMs |
|
newModified.set(file, time) |
|
if (!prevModified || !prevModified.has(file) || time > prevModified.get(file)) { |
|
modified = true |
|
} |
|
} |
|
|
|
|
|
if (!modified) { |
|
return [prevConfig, userConfigPath, prevConfigHash, prevDeps] |
|
} |
|
|
|
|
|
for (let file of newDeps) { |
|
delete require.cache[file] |
|
} |
|
let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath))) |
|
let newHash = hash(newConfig) |
|
configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified]) |
|
return [newConfig, userConfigPath, newHash, newDeps] |
|
} |
|
|
|
|
|
let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {}) |
|
|
|
newConfig = validateConfig(newConfig) |
|
|
|
return [newConfig, null, hash(newConfig), []] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function setupTrackingContext(configOrPath) { |
|
return ({ tailwindDirectives, registerDependency }) => { |
|
return (root, result) => { |
|
let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = |
|
getTailwindConfig(configOrPath) |
|
|
|
let contextDependencies = new Set(configDependencies) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tailwindDirectives.size > 0) { |
|
|
|
contextDependencies.add(result.opts.from) |
|
|
|
|
|
for (let message of result.messages) { |
|
if (message.type === 'dependency') { |
|
contextDependencies.add(message.file) |
|
} |
|
} |
|
} |
|
|
|
let [context, , mTimesToCommit] = getContext( |
|
root, |
|
result, |
|
tailwindConfig, |
|
userConfigPath, |
|
tailwindConfigHash, |
|
contextDependencies |
|
) |
|
|
|
let fileModifiedMap = getFileModifiedMap(context) |
|
|
|
let candidateFiles = getCandidateFiles(context, tailwindConfig) |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tailwindDirectives.size > 0) { |
|
|
|
for (let contentPath of candidateFiles) { |
|
for (let dependency of parseDependency(contentPath)) { |
|
registerDependency(dependency) |
|
} |
|
} |
|
|
|
let [changedContent, contentMTimesToCommit] = resolvedChangedContent( |
|
context, |
|
candidateFiles, |
|
fileModifiedMap |
|
) |
|
|
|
for (let content of changedContent) { |
|
context.changedContent.push(content) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (let [path, mtime] of contentMTimesToCommit.entries()) { |
|
mTimesToCommit.set(path, mtime) |
|
} |
|
} |
|
|
|
for (let file of configDependencies) { |
|
registerDependency({ type: 'dependency', file }) |
|
} |
|
|
|
|
|
|
|
|
|
for (let [path, mtime] of mTimesToCommit.entries()) { |
|
fileModifiedMap.set(path, mtime) |
|
} |
|
|
|
return context |
|
} |
|
} |
|
} |
|
|