Merge c9a445ee82 into fa81d697fe
This commit is contained in:
commit
f4e83c834e
2 changed files with 147 additions and 27 deletions
92
integrations/vite/build-watch.test.ts
Normal file
92
integrations/vite/build-watch.test.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import path from 'node:path'
|
||||
import { candidate, css, html, js, json, test } from '../utils'
|
||||
|
||||
test(
|
||||
'build watch ignores a custom output directory',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "6.2.3"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'vite.config.js': js`
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss()],
|
||||
build: {
|
||||
outDir: './assets',
|
||||
emptyOutDir: false,
|
||||
minify: false,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
app: './resources/js/app.js',
|
||||
styles: './resources/css/app.css',
|
||||
},
|
||||
output: {
|
||||
dir: './assets',
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].css',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
`,
|
||||
'resources/js/app.js': js`
|
||||
import '../css/app.css'
|
||||
|
||||
document.body.innerHTML = '<div class="underline">Hello</div>'
|
||||
`,
|
||||
'resources/css/app.css': css`
|
||||
@import 'tailwindcss';
|
||||
@source '../../assets/source.html';
|
||||
`,
|
||||
'assets/app.js': js` console.log('previous build') `,
|
||||
'assets/source.html': html` <div class="font-black"></div> `,
|
||||
'assets/styles.css': css`
|
||||
.previous-build {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ root, spawn, exec, fs, expect }) => {
|
||||
let version = await exec('pnpm vite --version')
|
||||
expect(version).toContain('vite/6.2.3')
|
||||
|
||||
let process = await spawn('pnpm vite build --watch')
|
||||
await process.onStdout((message) => message.includes('built in'))
|
||||
|
||||
let output = path.join(root, 'assets/styles.css')
|
||||
await fs.expectFileToContain(output, [candidate`font-black`, candidate`underline`])
|
||||
|
||||
process.flush()
|
||||
let result = await Promise.race([
|
||||
process.onStdout((message) => message.includes('built in')).then(() => 'rebuilt'),
|
||||
new Promise<'idle'>((resolve) => setTimeout(() => resolve('idle'), 1_500)),
|
||||
])
|
||||
expect(result).toBe('idle')
|
||||
|
||||
process.flush()
|
||||
await fs.write(
|
||||
'resources/js/app.js',
|
||||
js`
|
||||
import '../css/app.css'
|
||||
|
||||
document.body.innerHTML = '<div class="font-bold underline">Hello</div>'
|
||||
`,
|
||||
)
|
||||
await process.onStdout((message) => message.includes('built in'))
|
||||
await fs.expectFileToContain(output, candidate`font-bold`)
|
||||
},
|
||||
)
|
||||
|
|
@ -166,6 +166,7 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
|
|||
return new Root(
|
||||
id,
|
||||
config!.root,
|
||||
config!.command === 'build' ? path.resolve(config!.root, config!.build.outDir) : null,
|
||||
// Currently, Vite only supports CSS source maps in development and they
|
||||
// are off by default. Check to see if we need them or not.
|
||||
config?.css.devSourcemap ?? false,
|
||||
|
|
@ -338,6 +339,10 @@ class Root {
|
|||
// The lazily-initialized Tailwind scanner.
|
||||
private scanner?: Scanner
|
||||
|
||||
// A scanner for explicit `@source` paths that can opt back into paths which
|
||||
// are excluded from automatic source detection.
|
||||
private explicitScanner?: Scanner
|
||||
|
||||
// List of all candidates that were being returned by the root scanner during
|
||||
// the lifetime of the root.
|
||||
private candidates: Set<string> = new Set<string>()
|
||||
|
|
@ -350,6 +355,7 @@ class Root {
|
|||
constructor(
|
||||
private id: string,
|
||||
private base: string,
|
||||
private buildOutputDirectory: string | null,
|
||||
|
||||
private enableSourceMaps: boolean,
|
||||
private customCssResolver: (id: string, base: string) => Promise<string | false | undefined>,
|
||||
|
|
@ -431,7 +437,21 @@ class Root {
|
|||
return [{ ...this.compiler.root, negated: false }]
|
||||
})().concat(this.compiler.sources)
|
||||
|
||||
if (this.buildOutputDirectory !== null && this.compiler.root === null) {
|
||||
// Watching files emitted by Vite would trigger another build every time
|
||||
// the output is written.
|
||||
sources.push({
|
||||
base: this.buildOutputDirectory,
|
||||
pattern: '**/*',
|
||||
negated: true,
|
||||
})
|
||||
}
|
||||
|
||||
this.scanner = new Scanner({ sources })
|
||||
this.explicitScanner =
|
||||
this.compiler.sources.length > 0
|
||||
? new Scanner({ sources: this.compiler.sources })
|
||||
: undefined
|
||||
DEBUG && I.end('Setup scanner')
|
||||
} else {
|
||||
for (let buildDependency of this.buildDependencies.keys()) {
|
||||
|
|
@ -457,47 +477,55 @@ class Root {
|
|||
// setup a new scanner and compiler every time we request the CSS file
|
||||
// (regardless whether it actually changed or not).
|
||||
DEBUG && I.start('Scan for candidates')
|
||||
for (let candidate of this.scanner.scan()) {
|
||||
this.candidates.add(candidate)
|
||||
for (let scanner of [this.scanner, this.explicitScanner]) {
|
||||
if (!scanner) continue
|
||||
|
||||
for (let candidate of scanner.scan()) {
|
||||
this.candidates.add(candidate)
|
||||
}
|
||||
}
|
||||
DEBUG && I.end('Scan for candidates')
|
||||
}
|
||||
|
||||
if (this.compiler.features & Features.Utilities) {
|
||||
DEBUG && I.start('Register dependency messages')
|
||||
// Watch individual files found via custom `@source` paths
|
||||
for (let file of this.scanner.files) {
|
||||
addWatchFile(file)
|
||||
}
|
||||
for (let scanner of [this.scanner, this.explicitScanner]) {
|
||||
if (!scanner) continue
|
||||
|
||||
// Watch globs found via custom `@source` paths
|
||||
for (let glob of this.scanner.globs) {
|
||||
if (glob.pattern[0] === '!') continue
|
||||
|
||||
let relative = path.relative(this.base, glob.base)
|
||||
if (relative[0] !== '.') {
|
||||
relative = './' + relative
|
||||
// Watch individual files found via custom `@source` paths
|
||||
for (let file of scanner.files) {
|
||||
addWatchFile(file)
|
||||
}
|
||||
// Ensure relative is a posix style path since we will merge it with the
|
||||
// glob.
|
||||
relative = normalizePath(relative)
|
||||
|
||||
addWatchFile(path.posix.join(relative, glob.pattern))
|
||||
// Watch globs found via custom `@source` paths
|
||||
for (let glob of scanner.globs) {
|
||||
if (glob.pattern[0] === '!') continue
|
||||
|
||||
let root = this.compiler.root
|
||||
let relative = path.relative(this.base, glob.base)
|
||||
if (relative[0] !== '.') {
|
||||
relative = './' + relative
|
||||
}
|
||||
// Ensure relative is a posix style path since we will merge it with the
|
||||
// glob.
|
||||
relative = normalizePath(relative)
|
||||
|
||||
if (root !== 'none' && root !== null) {
|
||||
let basePath = normalizePath(path.resolve(root.base, root.pattern))
|
||||
addWatchFile(path.posix.join(relative, glob.pattern))
|
||||
|
||||
let isDir = await fs.stat(basePath).then(
|
||||
(stats) => stats.isDirectory(),
|
||||
() => false,
|
||||
)
|
||||
let root = this.compiler.root
|
||||
|
||||
if (!isDir) {
|
||||
throw new Error(
|
||||
`The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`,
|
||||
if (root !== 'none' && root !== null) {
|
||||
let basePath = normalizePath(path.resolve(root.base, root.pattern))
|
||||
|
||||
let isDir = await fs.stat(basePath).then(
|
||||
(stats) => stats.isDirectory(),
|
||||
() => false,
|
||||
)
|
||||
|
||||
if (!isDir) {
|
||||
throw new Error(
|
||||
`The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue