diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 0d9dfdb241..9248ccb57c 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -17,8 +17,10 @@ let uno: UnoGenerator const fileCache = new Map() +const getAbsolutePath = (file: string) => resolve(process.cwd(), file) + export async function generate(options: ResolvedCliOptions) { - const outFile = options.outFile ?? resolve(process.cwd(), 'uno.css') + const outFile = options.outFile ?? getAbsolutePath('uno.css') const { css, matched } = await uno.generate([...fileCache].join('\n')) const dir = dirname(outFile) @@ -57,7 +59,8 @@ export async function build(_options: CliOptions) { const files = await fg(options.patterns) await Promise.all( files.map(async (file) => { - fileCache.set(file, await fs.readFile(file, 'utf8')) + const absolutePath = getAbsolutePath(file) + fileCache.set(absolutePath, await fs.readFile(absolutePath, 'utf8')) }), ) @@ -103,10 +106,11 @@ export async function build(_options: CliOptions) { else { consola.log(`${green(type)} ${dim(file)}`) + const absolutePath = getAbsolutePath(file) if (type.startsWith('unlink')) - fileCache.delete(file) + fileCache.delete(absolutePath) else - fileCache.set(file, await fs.readFile(file, 'utf8')) + fileCache.set(absolutePath, await fs.readFile(absolutePath, 'utf8')) } debouncedBuild() diff --git a/test/__snapshots__/cli.test.ts.snap b/test/__snapshots__/cli.test.ts.snap index b5d70d2137..e4dd63bc9d 100644 --- a/test/__snapshots__/cli.test.ts.snap +++ b/test/__snapshots__/cli.test.ts.snap @@ -14,3 +14,10 @@ exports[`cli > supports unocss.config.js 1`] = ` /* layer: shortcuts */ .box{margin-left:auto;margin-right:auto;max-width:80rem;border-radius:0.375rem;--un-bg-opacity:1;background-color:rgba(243,244,246,var(--un-bg-opacity));padding:1rem;--un-shadow:var(--un-shadow-inset) 0 1px 2px 0 var(--un-shadow-color, rgba(0,0,0,0.05));box-shadow:var(--un-ring-offset-shadow, 0 0 #0000), var(--un-ring-shadow, 0 0 #0000), var(--un-shadow);}" `; + +exports[`cli > uno.css exclude initialized class after changing file 1`] = ` +"/* layer: preflights */ +*,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));--un-pan-x:var(--un-empty,/*!*/ /*!*/);--un-pan-y:var(--un-empty,/*!*/ /*!*/);--un-pinch-zoom:var(--un-empty,/*!*/ /*!*/);--un-touch-action:var(--un-pan-x) var(--un-pan-y) var(--un-pinch-zoom);--un-scroll-snap-strictness:proximity;--un-ordinal:var(--un-empty,/*!*/ /*!*/);--un-slashed-zero:var(--un-empty,/*!*/ /*!*/);--un-numeric-figure:var(--un-empty,/*!*/ /*!*/);--un-numeric-spacing:var(--un-empty,/*!*/ /*!*/);--un-numeric-fraction:var(--un-empty,/*!*/ /*!*/);--un-font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 #0000;--un-ring-shadow:0 0 #0000;--un-shadow-inset:var(--un-empty,/*!*/ /*!*/);--un-shadow:0 0 #0000;--un-ring-inset:var(--un-empty,/*!*/ /*!*/);--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,0.5);--un-blur:var(--un-empty,/*!*/ /*!*/);--un-brightness:var(--un-empty,/*!*/ /*!*/);--un-contrast:var(--un-empty,/*!*/ /*!*/);--un-drop-shadow:var(--un-empty,/*!*/ /*!*/);--un-grayscale:var(--un-empty,/*!*/ /*!*/);--un-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-invert:var(--un-empty,/*!*/ /*!*/);--un-saturate:var(--un-empty,/*!*/ /*!*/);--un-sepia:var(--un-empty,/*!*/ /*!*/);--un-filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);--un-backdrop-blur:var(--un-empty,/*!*/ /*!*/);--un-backdrop-brightness:var(--un-empty,/*!*/ /*!*/);--un-backdrop-contrast:var(--un-empty,/*!*/ /*!*/);--un-backdrop-grayscale:var(--un-empty,/*!*/ /*!*/);--un-backdrop-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-invert:var(--un-empty,/*!*/ /*!*/);--un-backdrop-opacity:var(--un-empty,/*!*/ /*!*/);--un-backdrop-saturate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-sepia:var(--un-empty,/*!*/ /*!*/);--un-backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);} +/* layer: default */ +.bg-blue{--un-bg-opacity:1;background-color:rgba(96,165,250,var(--un-bg-opacity));}" +`; diff --git a/test/cli.test.ts b/test/cli.test.ts index 17d7a73fb2..0aa52c3424 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -6,6 +6,29 @@ import { execa } from 'execa' export const tempDir = resolve('.temp') export const cli = resolve(__dirname, '../packages/cli/src/cli.ts') +function createWaiting() { + const loop = () => { } + let $resolve = loop + let $reject = loop + const waiting = new Promise((resolve, reject) => { + $resolve = resolve + $reject = reject + }) + return { + waiting, + $resolve, + $reject, + } +} + +function sleep(time = 300) { + return new Promise((resolve) => { + setTimeout(() => { + resolve() + }, time) + }) +} + beforeAll(async () => { await fs.remove(tempDir) }) @@ -23,6 +46,28 @@ describe('cli', () => { expect(output).toMatchSnapshot() }) + it('uno.css exclude initialized class after changing file', async () => { + const fileName = 'views/index.html' + const initializedContent = '
' + const changedContent = '
' + const testDir = getTestDir() + const absolutePathOfFile = resolve(testDir, fileName) + await fs.outputFile(absolutePathOfFile, initializedContent) + const subProcess = runAsyncChildProcess(testDir, './views/**/*', '-w') + const { stdout } = subProcess + const { waiting, $resolve } = createWaiting() + stdout!.on('data', (data) => { + if (data.toString().includes('[info] Watching for changes')) + $resolve() + }) + await waiting + await fs.writeFile(absolutePathOfFile, changedContent) + await sleep(2022) + subProcess.cancel() + const output = await readUnocssFile(testDir) + expect(output).toMatchSnapshot() + }) + it('supports unocss.config.js', async () => { const { output } = await runCli({ 'views/index.html': '
', @@ -38,25 +83,41 @@ export default defineConfig({ }) }) -async function runCli(files: Record) { - const testDir = resolve(tempDir, Math.round(Math.random() * 100000).toString()) +function getTestDir() { + return resolve(tempDir, Math.round(Math.random() * 100000).toString()) +} - await Promise.all( +function initalOutputFiles(testDir: string, files: Record) { + return Promise.all( Object.entries(files).map(([path, content]) => fs.outputFile(resolve(testDir, path), content, 'utf8'), ), ) +} - const { exitCode, stdout, stderr } = await execa('npx', ['esno', cli, 'views/**/*'], { - cwd: testDir, +function runAsyncChildProcess(cwd: string, ...args: string[]) { + return execa('npx', ['esno', cli, ...args], { + cwd, // stdio: 'inherit', }) +} + +function readUnocssFile(testDir: string) { + return fs.readFile(resolve(testDir, 'uno.css'), 'utf8') +} + +async function runCli(files: Record) { + const testDir = getTestDir() + + await initalOutputFiles(testDir, files) + + const { exitCode, stdout, stderr } = await runAsyncChildProcess(testDir, 'views/**/*') const logs = stdout + stderr if (exitCode !== 0) throw new Error(logs) - const output = await fs.readFile(resolve(testDir, 'uno.css'), 'utf8') + const output = await readUnocssFile(testDir) return { output,