Remove the watching context (#6858)

* remove watching context

* update changelog
This commit is contained in:
Robin Malfait 2022-01-03 17:45:31 +01:00 committed by GitHub
parent b9af5a916b
commit 1cbb29faeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 62 additions and 396 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Validate `theme()` works in arbitrary values ([#6852](https://github.com/tailwindlabs/tailwindcss/pull/6852))
- Properly detect `theme()` value usage in arbitrary properties ([#6854](https://github.com/tailwindlabs/tailwindcss/pull/6854))
- Improve collapsing of duplicate declarations ([#6856](https://github.com/tailwindlabs/tailwindcss/pull/6856))
- Remove the watching context ([#6858](https://github.com/tailwindlabs/tailwindcss/pull/6858))
## [3.0.8] - 2021-12-28

View File

@ -43,9 +43,7 @@ describe.skip('watcher', () => {
`
)
let runningProcess = $('parcel watch ./src/index.html --no-cache', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('parcel watch ./src/index.html --no-cache')
await waitForOutputFileCreation(/index\.\w+\.css$/)
@ -103,9 +101,7 @@ describe.skip('watcher', () => {
`
)
let runningProcess = $('parcel watch ./src/index.html --no-cache', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('parcel watch ./src/index.html --no-cache')
await waitForOutputFileCreation(/index\.\w+\.css$/)
@ -172,9 +168,7 @@ describe.skip('watcher', () => {
`
)
let runningProcess = $('parcel watch ./src/index.html --no-cache', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('parcel watch ./src/index.html --no-cache')
await waitForOutputFileCreation(/index\.\w+\.css$/)

View File

@ -32,9 +32,7 @@ describe('watcher', () => {
test('classes are generated when the html file changes', async () => {
await writeInputFile('index.html', html`<div class="font-bold"></div>`)
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose')
await runningProcess.onStderr(ready)
expect(await readOutputFile('main.css')).toIncludeCss(
@ -83,9 +81,7 @@ describe('watcher', () => {
test('classes are generated when the tailwind.config.js file changes', async () => {
await writeInputFile('index.html', html`<div class="font-bold md:font-medium"></div>`)
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose')
await runningProcess.onStderr(ready)
@ -145,9 +141,7 @@ describe('watcher', () => {
test('classes are generated when the index.css file changes', async () => {
await writeInputFile('index.html', html`<div class="font-bold btn"></div>`)
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose', {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('postcss ./src/index.css -o ./dist/main.css -w --verbose')
await runningProcess.onStderr(ready)

View File

@ -28,11 +28,11 @@ describe('static build', () => {
})
})
describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watcher %p', (env) => {
describe('watcher', () => {
test(`classes are generated when the html file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold"></div>`)
let runningProcess = $('rollup -c --watch', { env })
let runningProcess = $('rollup -c --watch')
await runningProcess.onStderr(ready)
expect(await readOutputFile('index.css')).toIncludeCss(
@ -81,7 +81,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the tailwind.config.js file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold md:font-medium"></div>`)
let runningProcess = $('rollup -c --watch', { env })
let runningProcess = $('rollup -c --watch')
await runningProcess.onStderr(ready)
expect(await readOutputFile('index.css')).toIncludeCss(
@ -140,7 +140,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the index.css file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold btn"></div>`)
let runningProcess = $('rollup -c --watch', { env })
let runningProcess = $('rollup -c --watch')
await runningProcess.onStderr(ready)
expect(await readOutputFile('index.css')).toIncludeCss(

View File

@ -53,9 +53,7 @@ describe('watcher', () => {
`
)
let runningProcess = $(`vite --port ${PORT}`, {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $(`vite --port ${PORT}`)
await runningProcess.onStdout((message) => message.includes('ready in'))
expect(await fetchCSS()).toIncludeCss(
@ -110,9 +108,7 @@ describe('watcher', () => {
`
)
let runningProcess = $(`vite --port ${PORT}`, {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $(`vite --port ${PORT}`)
await runningProcess.onStdout((message) => message.includes('ready in'))
expect(await fetchCSS()).toIncludeCss(
@ -177,9 +173,7 @@ describe('watcher', () => {
`
)
let runningProcess = $(`vite --port ${PORT}`, {
env: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $(`vite --port ${PORT}`)
await runningProcess.onStdout((message) => message.includes('ready in'))
expect(await fetchCSS()).toIncludeCss(

View File

@ -25,11 +25,11 @@ describe('static build', () => {
})
})
describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watcher %p', (env) => {
describe('watcher', () => {
test(`classes are generated when the html file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')
@ -81,7 +81,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the tailwind.config.js file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold md:font-medium"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')
@ -142,7 +142,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the index.css file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold btn"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')

View File

@ -25,11 +25,11 @@ describe('static build', () => {
})
})
describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watcher %p', (env) => {
describe('watcher', () => {
test(`classes are generated when the html file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')
@ -81,7 +81,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the tailwind.config.js file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold md:font-medium"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')
@ -142,7 +142,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
test(`classes are generated when the index.css file changes`, async () => {
await writeInputFile('index.html', html`<div class="font-bold btn"></div>`)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')
@ -245,7 +245,7 @@ describe.each([{ TAILWIND_MODE: 'watch' }, { TAILWIND_MODE: undefined }])('watch
`
)
let runningProcess = $('webpack --mode=development --watch', { env })
let runningProcess = $('webpack --mode=development --watch')
await waitForOutputFileCreation('main.css')

68
package-lock.json generated
View File

@ -28,8 +28,7 @@
"postcss-selector-parser": "^6.0.7",
"postcss-value-parser": "^4.2.0",
"quick-lru": "^5.1.1",
"resolve": "^1.20.0",
"tmp": "^0.2.1"
"resolve": "^1.20.0"
},
"bin": {
"tailwind": "lib/cli.js",
@ -1784,7 +1783,8 @@
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.2.0",
@ -1804,6 +1804,7 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2087,7 +2088,8 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/convert-source-map": {
"version": "1.8.0",
@ -3408,7 +3410,8 @@
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.2",
@ -3489,6 +3492,7 @@
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -3727,6 +3731,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@ -3735,7 +3740,8 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-arrayish": {
"version": "0.2.1",
@ -4948,6 +4954,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -5075,6 +5082,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"dependencies": {
"wrappy": "1"
}
@ -5215,6 +5223,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -6084,6 +6093,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"dependencies": {
"glob": "^7.1.3"
},
@ -6435,17 +6445,6 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"node_modules/tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
"dependencies": {
"rimraf": "^3.0.0"
},
"engines": {
"node": ">=8.17.0"
}
},
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@ -6702,7 +6701,8 @@
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"node_modules/write-file-atomic": {
"version": "3.0.3",
@ -8079,7 +8079,8 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"binary-extensions": {
"version": "2.2.0",
@ -8096,6 +8097,7 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -8316,7 +8318,8 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"convert-source-map": {
"version": "1.8.0",
@ -9250,7 +9253,8 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"fsevents": {
"version": "2.3.2",
@ -9303,6 +9307,7 @@
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -9476,6 +9481,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@ -9484,7 +9490,8 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
@ -10435,6 +10442,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -10529,6 +10537,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
@ -10631,7 +10640,8 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-key": {
"version": "3.1.1",
@ -11185,6 +11195,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
@ -11443,14 +11454,6 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
"requires": {
"rimraf": "^3.0.0"
}
},
"tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@ -11654,7 +11657,8 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"write-file-atomic": {
"version": "3.0.3",

View File

@ -25,7 +25,7 @@
"prepublishOnly": "npm install --force && npm run swcify",
"style": "eslint .",
"pretest": "npm run generate:plugin-list",
"test": "cross-env TAILWIND_MODE=build jest",
"test": "jest",
"test:integrations": "npm run test --prefix ./integrations",
"install:integrations": "node scripts/install-integrations.js",
"posttest": "npm run style",
@ -85,8 +85,7 @@
"postcss-selector-parser": "^6.0.7",
"postcss-value-parser": "^4.2.0",
"quick-lru": "^5.1.1",
"resolve": "^1.20.0",
"tmp": "^0.2.1"
"resolve": "^1.20.0"
},
"browserslist": [
"> 1%",

View File

@ -1,5 +1,4 @@
import setupTrackingContext from './lib/setupTrackingContext'
import setupWatchingContext from './lib/setupWatchingContext'
import processTailwindFeatures from './processTailwindFeatures'
import { env } from './lib/sharedState'
@ -14,12 +13,7 @@ module.exports = function tailwindcss(configOrPath) {
return root
},
function (root, result) {
let setupContext =
env.TAILWIND_MODE === 'watch'
? setupWatchingContext(configOrPath)
: setupTrackingContext(configOrPath)
processTailwindFeatures(setupContext)(root, result)
processTailwindFeatures(setupTrackingContext(configOrPath))(root, result)
},
env.DEBUG &&
function (root) {

View File

@ -1,311 +0,0 @@
import fs from 'fs'
import path from 'path'
import tmp from 'tmp'
import chokidar from 'chokidar'
import fastGlob from 'fast-glob'
import LRU from 'quick-lru'
import normalizePath from 'normalize-path'
import hash from '../util/hashConfig'
import log from '../util/log'
import getModuleDependencies from '../lib/getModuleDependencies'
import resolveConfig from '../public/resolve-config'
import resolveConfigPath from '../util/resolveConfigPath'
import { getContext } from './setupContextUtils'
// This is used to trigger rebuilds. Just updating the timestamp
// is significantly faster than actually writing to the file (10x).
function touch(filename) {
let time = new Date()
try {
fs.utimesSync(filename, time, time)
} catch (err) {
fs.closeSync(fs.openSync(filename, 'w'))
}
}
let watchers = new WeakMap()
function getWatcher(context) {
if (watchers.has(context)) {
return watchers.get(context)
}
return null
}
function setWatcher(context, watcher) {
return watchers.set(context, watcher)
}
let touchFiles = new WeakMap()
function getTouchFile(context) {
if (touchFiles.has(context)) {
return touchFiles.get(context)
}
return null
}
function setTouchFile(context, touchFile) {
return touchFiles.set(context, touchFile)
}
let configPaths = new WeakMap()
function getConfigPath(context, configOrPath) {
if (!configPaths.has(context)) {
configPaths.set(context, resolveConfigPath(configOrPath))
}
return configPaths.get(context)
}
function rebootWatcher(context, configPath, configDependencies, candidateFiles) {
let touchFile = getTouchFile(context)
if (touchFile === null) {
touchFile = tmp.fileSync().name
setTouchFile(context, touchFile)
touch(touchFile)
}
let watcher = getWatcher(context)
Promise.resolve(watcher ? watcher.close() : null).then(() => {
log.info([
'Tailwind CSS is watching for changes...',
'https://tailwindcss.com/docs/just-in-time-mode#watch-mode-and-one-off-builds',
])
watcher = chokidar.watch([...candidateFiles, ...configDependencies], {
ignoreInitial: true,
awaitWriteFinish:
process.platform === 'win32'
? {
stabilityThreshold: 50,
pollInterval: 10,
}
: false,
})
setWatcher(context, watcher)
watcher.on('add', (file) => {
let changedFile = path.resolve('.', file)
let content = fs.readFileSync(changedFile, 'utf8')
let extension = path.extname(changedFile).slice(1)
context.changedContent.push({ content, extension })
touch(touchFile)
})
watcher.on('change', (file) => {
// If it was a config dependency, touch the config file to trigger a new context.
// This is not really that clean of a solution but it's the fastest, because we
// can do a very quick check on each build to see if the config has changed instead
// of having to get all of the module dependencies and check every timestamp each
// time.
if (configDependencies.has(file)) {
for (let dependency of configDependencies) {
delete require.cache[require.resolve(dependency)]
}
touch(configPath)
} else {
let changedFile = path.resolve('.', file)
let content = fs.readFileSync(changedFile, 'utf8')
let extension = path.extname(changedFile).slice(1)
context.changedContent.push({ content, extension })
touch(touchFile)
}
})
watcher.on('unlink', (file) => {
// Touch the config file if any of the dependencies are deleted.
if (configDependencies.has(file)) {
for (let dependency of configDependencies) {
delete require.cache[require.resolve(dependency)]
}
touch(configPath)
}
})
})
}
let configPathCache = new LRU({ maxSize: 100 })
let configDependenciesCache = new WeakMap()
function getConfigDependencies(context) {
if (!configDependenciesCache.has(context)) {
configDependenciesCache.set(context, new Set())
}
return configDependenciesCache.get(context)
}
let candidateFilesCache = new WeakMap()
function getCandidateFiles(context, tailwindConfig) {
if (candidateFilesCache.has(context)) {
return candidateFilesCache.get(context)
}
let candidateFiles = tailwindConfig.content.files
.filter((item) => typeof item === 'string')
.map((contentPath) => normalizePath(contentPath))
return candidateFilesCache.set(context, candidateFiles).get(context)
}
// Get the config object based on a path
function getTailwindConfig(configOrPath) {
let userConfigPath = resolveConfigPath(configOrPath)
if (userConfigPath !== null) {
let [prevConfig, prevModified = -Infinity, prevConfigHash] =
configPathCache.get(userConfigPath) || []
let modified = fs.statSync(userConfigPath).mtimeMs
// It hasn't changed (based on timestamp)
if (modified <= prevModified) {
return [prevConfig, userConfigPath, prevConfigHash, [userConfigPath]]
}
// It has changed (based on timestamp), or first run
delete require.cache[userConfigPath]
let newConfig = resolveConfig(require(userConfigPath))
let newHash = hash(newConfig)
configPathCache.set(userConfigPath, [newConfig, modified, newHash])
return [newConfig, userConfigPath, newHash, [userConfigPath]]
}
// It's a plain object, not a path
let newConfig = resolveConfig(
configOrPath.config === undefined ? configOrPath : configOrPath.config
)
return [newConfig, null, hash(newConfig), []]
}
function resolvedChangedContent(context, candidateFiles) {
let changedContent = context.tailwindConfig.content.files
.filter((item) => typeof item.raw === 'string')
.map(({ raw, extension = 'html' }) => ({ content: raw, extension }))
for (let changedFile of resolveChangedFiles(context, candidateFiles)) {
let content = fs.readFileSync(changedFile, 'utf8')
let extension = path.extname(changedFile).slice(1)
changedContent.push({ content, extension })
}
return changedContent
}
let scannedContentCache = new WeakMap()
function resolveChangedFiles(context, candidateFiles) {
let changedFiles = new Set()
// 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 (!scannedContentCache.has(context)) {
let files = fastGlob.sync(candidateFiles)
for (let file of files) {
changedFiles.add(file)
}
scannedContentCache.set(context, true)
}
return changedFiles
}
// DISABLE_TOUCH = FALSE
// Retrieve an existing context from cache if possible (since contexts are unique per
// source path), or set up a new one (including setting up watchers and registering
// plugins) then return it
export default function setupWatchingContext(configOrPath) {
return ({ tailwindDirectives, registerDependency }) => {
return (root, result) => {
let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] =
getTailwindConfig(configOrPath)
let contextDependencies = new Set(configDependencies)
// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
// to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
// in another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {
// Add current css file as a context dependencies.
contextDependencies.add(result.opts.from)
// Add all css @import dependencies as context dependencies.
for (let message of result.messages) {
if (message.type === 'dependency') {
contextDependencies.add(message.file)
}
}
}
let [context, isNewContext] = getContext(
root,
result,
tailwindConfig,
userConfigPath,
tailwindConfigHash,
contextDependencies
)
let candidateFiles = getCandidateFiles(context, tailwindConfig)
let contextConfigDependencies = getConfigDependencies(context)
for (let file of configDependencies) {
registerDependency({ type: 'dependency', file })
}
context.disposables.push((oldContext) => {
let watcher = getWatcher(oldContext)
if (watcher !== null) {
watcher.close()
}
})
let configPath = getConfigPath(context, configOrPath)
if (configPath !== null) {
for (let dependency of getModuleDependencies(configPath)) {
if (dependency.file === configPath) {
continue
}
contextConfigDependencies.add(dependency.file)
}
}
if (isNewContext) {
rebootWatcher(context, configPath, contextConfigDependencies, candidateFiles)
}
// Register our temp file as a dependency — we write to this file
// to trigger rebuilds.
let touchFile = getTouchFile(context)
if (touchFile) {
registerDependency({ type: 'dependency', file: touchFile })
}
if (tailwindDirectives.size > 0) {
for (let changedContent of resolvedChangedContent(context, candidateFiles)) {
context.changedContent.push(changedContent)
}
}
return context
}
}
}

View File

@ -1,9 +1,6 @@
export const env = {
TAILWIND_MODE: process.env.TAILWIND_MODE,
NODE_ENV: process.env.NODE_ENV,
DEBUG: resolveDebug(process.env.DEBUG),
TAILWIND_DISABLE_TOUCH: process.env.TAILWIND_DISABLE_TOUCH !== undefined,
TAILWIND_TOUCH_DIR: process.env.TAILWIND_TOUCH_DIR,
}
export const contextMap = new Map()
export const configContextMap = new Map()