source: frontend/node_modules/tailwindcss/src/lib/setupTrackingContext.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 6.3 KB
Line 
1// @ts-check
2
3import fs from 'fs'
4import LRU from '@alloc/quick-lru'
5
6import hash from '../util/hashConfig'
7import resolveConfig from '../public/resolve-config'
8import resolveConfigPath from '../util/resolveConfigPath'
9import { getContext, getFileModifiedMap } from './setupContextUtils'
10import parseDependency from '../util/parseDependency'
11import { validateConfig } from '../util/validateConfig.js'
12import { parseCandidateFiles, resolvedChangedContent } from './content.js'
13import { loadConfig } from '../lib/load-config'
14import getModuleDependencies from './getModuleDependencies'
15
16let configPathCache = new LRU({ maxSize: 100 })
17
18let candidateFilesCache = new WeakMap()
19
20function getCandidateFiles(context, tailwindConfig) {
21 if (candidateFilesCache.has(context)) {
22 return candidateFilesCache.get(context)
23 }
24
25 let candidateFiles = parseCandidateFiles(context, tailwindConfig)
26
27 return candidateFilesCache.set(context, candidateFiles).get(context)
28}
29
30// Get the config object based on a path
31function getTailwindConfig(configOrPath) {
32 let userConfigPath = resolveConfigPath(configOrPath)
33
34 if (userConfigPath !== null) {
35 let [prevConfig, prevConfigHash, prevDeps, prevModified] =
36 configPathCache.get(userConfigPath) || []
37
38 let newDeps = getModuleDependencies(userConfigPath)
39
40 let modified = false
41 let newModified = new Map()
42 for (let file of newDeps) {
43 let time = fs.statSync(file).mtimeMs
44 newModified.set(file, time)
45 if (!prevModified || !prevModified.has(file) || time > prevModified.get(file)) {
46 modified = true
47 }
48 }
49
50 // It hasn't changed (based on timestamps)
51 if (!modified) {
52 return [prevConfig, userConfigPath, prevConfigHash, prevDeps]
53 }
54
55 // It has changed (based on timestamps), or first run
56 for (let file of newDeps) {
57 // When loaded transitively through a TypeScript file `require.cache`
58 // may be undefined. Happens in Node 22.18+.
59 if (!require.cache) continue
60 delete require.cache[file]
61 }
62 let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath)))
63 let newHash = hash(newConfig)
64 configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified])
65 return [newConfig, userConfigPath, newHash, newDeps]
66 }
67
68 // It's a plain object, not a path
69 let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {})
70
71 newConfig = validateConfig(newConfig)
72
73 return [newConfig, null, hash(newConfig), []]
74}
75
76// DISABLE_TOUCH = TRUE
77
78// Retrieve an existing context from cache if possible (since contexts are unique per
79// source path), or set up a new one (including setting up watchers and registering
80// plugins) then return it
81export default function setupTrackingContext(configOrPath) {
82 return ({ tailwindDirectives, registerDependency }) => {
83 return (root, result) => {
84 let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] =
85 getTailwindConfig(configOrPath)
86
87 let contextDependencies = new Set(configDependencies)
88
89 // If there are no @tailwind or @apply rules, we don't consider this CSS
90 // file or its dependencies to be dependencies of the context. Can reuse
91 // the context even if they change. We may want to think about `@layer`
92 // being part of this trigger too, but it's tough because it's impossible
93 // for a layer in one file to end up in the actual @tailwind rule in
94 // another file since independent sources are effectively isolated.
95 if (tailwindDirectives.size > 0) {
96 // Add current css file as a context dependencies.
97 contextDependencies.add(result.opts.from)
98
99 // Add all css @import dependencies as context dependencies.
100 for (let message of result.messages) {
101 if (message.type === 'dependency') {
102 contextDependencies.add(message.file)
103 }
104 }
105 }
106
107 let [context, , mTimesToCommit] = getContext(
108 root,
109 result,
110 tailwindConfig,
111 userConfigPath,
112 tailwindConfigHash,
113 contextDependencies
114 )
115
116 let fileModifiedMap = getFileModifiedMap(context)
117
118 let candidateFiles = getCandidateFiles(context, tailwindConfig)
119
120 // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
121 // dependencies to be dependencies of the context. Can reuse the context even if they change.
122 // We may want to think about `@layer` being part of this trigger too, but it's tough
123 // because it's impossible for a layer in one file to end up in the actual @tailwind rule
124 // in another file since independent sources are effectively isolated.
125 if (tailwindDirectives.size > 0) {
126 // Add template paths as postcss dependencies.
127 for (let contentPath of candidateFiles) {
128 for (let dependency of parseDependency(contentPath)) {
129 registerDependency(dependency)
130 }
131 }
132
133 let [changedContent, contentMTimesToCommit] = resolvedChangedContent(
134 context,
135 candidateFiles,
136 fileModifiedMap
137 )
138
139 for (let content of changedContent) {
140 context.changedContent.push(content)
141 }
142
143 // Add the mtimes of the content files to the commit list
144 // We can overwrite the existing values because unconditionally
145 // This is because:
146 // 1. Most of the files here won't be in the map yet
147 // 2. If they are that means it's a context dependency
148 // and we're reading this after the context. This means
149 // that the mtime we just read is strictly >= the context
150 // mtime. Unless the user / os is doing something weird
151 // in which the mtime would be going backwards. If that
152 // happens there's already going to be problems.
153 for (let [path, mtime] of contentMTimesToCommit.entries()) {
154 mTimesToCommit.set(path, mtime)
155 }
156 }
157
158 for (let file of configDependencies) {
159 registerDependency({ type: 'dependency', file })
160 }
161
162 // "commit" the new modified time for all context deps
163 // We do this here because we want content tracking to
164 // read the "old" mtime even when it's a context dependency.
165 for (let [path, mtime] of mTimesToCommit.entries()) {
166 fileModifiedMap.set(path, mtime)
167 }
168
169 return context
170 }
171 }
172}
Note: See TracBrowser for help on using the repository browser.