Skip to content

Commit

Permalink
Refactor internals to decouple watch strategies and extract IO
Browse files Browse the repository at this point in the history
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
  • Loading branch information
adamwathan and RobinMalfait committed May 26, 2021
1 parent 89b9e34 commit 25f3f53
Show file tree
Hide file tree
Showing 22 changed files with 1,156 additions and 1,081 deletions.
2 changes: 1 addition & 1 deletion integrations/parcel/tests/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('static build', () => {
})
})

describe('watcher', () => {
describe.skip('watcher', () => {
test('classes are generated when the html file changes', async () => {
await writeInputFile(
'index.html',
Expand Down
23 changes: 10 additions & 13 deletions integrations/rollup/tests/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ describe('static build', () => {
})
})

describe('watcher', () => {
test('classes are generated when the html file changes', async () => {
describe.each([
{ TAILWIND_MODE: 'watch' },
{ TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
])('watcher %p', (env) => {
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: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('rollup -c --watch', { env })

await waitForOutputFileCreation('index.css')

Expand Down Expand Up @@ -82,12 +83,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the tailwind.config.js file changes', async () => {
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: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('rollup -c --watch', { env })

await waitForOutputFileCreation('index.css')

Expand Down Expand Up @@ -150,12 +149,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the index.css file changes', async () => {
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: { TAILWIND_MODE: 'watch' },
})
let runningProcess = $('rollup -c --watch', { env })

await waitForOutputFileCreation('index.css')

Expand Down
2 changes: 1 addition & 1 deletion integrations/webpack-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"browser": "./src/index.js",
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack --mode=development",
"dev": "webpack --mode=development --watch",
"test": "jest"
},
"jest": {
Expand Down
23 changes: 10 additions & 13 deletions integrations/webpack-4/tests/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ describe('static build', () => {
})
})

describe('watcher', () => {
test('classes are generated when the html file changes', async () => {
describe.each([
{ TAILWIND_MODE: 'watch' },
{ TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
])('watcher %p', (env) => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down Expand Up @@ -80,12 +81,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the tailwind.config.js file changes', async () => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down Expand Up @@ -148,12 +147,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the index.css file changes', async () => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down
23 changes: 10 additions & 13 deletions integrations/webpack-5/tests/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ describe('static build', () => {
})
})

describe('watcher', () => {
test('classes are generated when the html file changes', async () => {
describe.each([
{ TAILWIND_MODE: 'watch' },
{ TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
])('watcher %p', (env) => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down Expand Up @@ -80,12 +81,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the tailwind.config.js file changes', async () => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down Expand Up @@ -148,12 +147,10 @@ describe('watcher', () => {
return runningProcess.stop()
})

test('classes are generated when the index.css file changes', async () => {
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: { TAILWIND_MODE: 'watch', TAILWIND_DISABLE_TOUCH: true },
})
let runningProcess = $('webpack --mode=development --watch', { env })

await waitForOutputFileCreation('main.css')

Expand Down
33 changes: 7 additions & 26 deletions src/jit/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import postcss from 'postcss'

import evaluateTailwindFunctions from '../lib/evaluateTailwindFunctions'
import substituteScreenAtRules from '../lib/substituteScreenAtRules'

import normalizeTailwindDirectives from './lib/normalizeTailwindDirectives'
import setupContext from './lib/setupContext'
import removeLayerAtRules from './lib/removeLayerAtRules'
import expandTailwindAtRules from './lib/expandTailwindAtRules'
import expandApplyAtRules from './lib/expandApplyAtRules'
import collapseAdjacentRules from './lib/collapseAdjacentRules'

import setupTrackingContext from './lib/setupTrackingContext'
import setupWatchingContext from './lib/setupWatchingContext'
import { env } from './lib/sharedState'
import processTailwindFeatures from './processTailwindFeatures'

export default function (configOrPath = {}) {
return [
Expand All @@ -32,22 +24,11 @@ export default function (configOrPath = {}) {

let tailwindDirectives = normalizeTailwindDirectives(root)

let context = setupContext(configOrPath, tailwindDirectives)(result, root)

if (!env.TAILWIND_DISABLE_TOUCH) {
if (context.configPath !== null) {
registerDependency(context.configPath)
}
}
let context = env.TAILWIND_DISABLE_TOUCH
? setupTrackingContext(configOrPath, tailwindDirectives, registerDependency)(result, root)
: setupWatchingContext(configOrPath, tailwindDirectives, registerDependency)(result, root)

return postcss([
removeLayerAtRules(context, tailwindDirectives),
expandTailwindAtRules(context, registerDependency, tailwindDirectives),
expandApplyAtRules(context),
evaluateTailwindFunctions(context.tailwindConfig),
substituteScreenAtRules(context.tailwindConfig),
collapseAdjacentRules(context),
]).process(root, { from: undefined })
processTailwindFeatures(context)(root, result)
},
env.DEBUG &&
function (root) {
Expand Down
90 changes: 7 additions & 83 deletions src/jit/lib/expandTailwindAtRules.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import fs from 'fs'
import path from 'path'
import fastGlob from 'fast-glob'
import parseGlob from 'parse-glob'
import * as sharedState from './sharedState'
import { generateRules } from './generateRules'
import bigSign from '../../util/bigSign'
Expand Down Expand Up @@ -111,12 +109,8 @@ function buildStylesheet(rules, context) {
return returnValue
}

export default function expandTailwindAtRules(context, registerDependency, tailwindDirectives) {
export default function expandTailwindAtRules(context) {
return (root) => {
if (tailwindDirectives.size === 0) {
return root
}

let layerNodes = {
base: null,
components: null,
Expand All @@ -129,76 +123,13 @@ export default function expandTailwindAtRules(context, registerDependency, tailw
// 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) => {
if (rule.params === 'base') {
layerNodes.base = rule
}

if (rule.params === 'components') {
layerNodes.components = rule
}

if (rule.params === 'utilities') {
layerNodes.utilities = rule
}

if (rule.params === 'variants') {
layerNodes.variants = rule
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule
}
})

// ---

if (sharedState.env.TAILWIND_DISABLE_TOUCH) {
for (let maybeGlob of context.candidateFiles) {
let {
is: { glob: isGlob },
base,
} = parseGlob(maybeGlob)

if (isGlob) {
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
registerDependency(
path.resolve(base),
process.env.ROLLUP_WATCH === 'true' ? 'dependency' : 'dir-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
}
if (Object.values(layerNodes).every((n) => n === null)) {
return root
}

// ---
Expand All @@ -208,14 +139,8 @@ export default function expandTailwindAtRules(context, registerDependency, tailw
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(context.tailwindConfig, path.extname(file).slice(1))
getClassCandidates(content, extractor, contentMatchCache, candidates, seen)
}
env.DEBUG && console.timeEnd('Reading changed files')

for (let { content, extension } of context.rawContent) {
for (let { content, extension } of context.changedContent) {
let extractor = getExtractor(context.tailwindConfig, extension)
getClassCandidates(content, extractor, contentMatchCache, candidates, seen)
}
Expand Down Expand Up @@ -276,13 +201,12 @@ export default function expandTailwindAtRules(context, registerDependency, tailw
// ---

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()
context.changedContent = []
}
}
Loading

0 comments on commit 25f3f53

Please sign in to comment.