From 87f6742b05af275000dd1706bf489002d55c9ff7 Mon Sep 17 00:00:00 2001 From: Rolando Bosch Date: Fri, 27 Feb 2026 15:06:17 -0800 Subject: [PATCH 1/2] chore: replace fs-extra with native Node.js fs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace fs-extra with native Node.js fs APIs (node:fs/promises, node:fs). All replacements are available on the supported Node >= 18: - fs.pathExists() → fs.access() with boolean resolution - fs.outputFile() → fs.mkdir({ recursive: true }) + fs.writeFile() - fs.copy() → fs.copyFile() (glob ensures file-only results) - fs.emptyDir() → fs.rm({ recursive, force }) + fs.mkdir({ recursive }) - fs.remove() → fs.rm({ recursive, force }) - fs.createReadStream() → named import from node:fs This removes 1 runtime dependency (fs-extra + 3 transitive deps). Co-Authored-By: Claude Opus 4.6 --- index.js | 10 +++++++--- package.json | 1 - test/ext.js | 16 +++++++++++++--- test/helpers/clean.js | 8 +++++--- test/helpers/env.js | 24 +++++++++++++++--------- test/helpers/read.js | 2 +- test/map.js | 9 +++++++-- test/replace.js | 7 ++++--- test/stdin.js | 4 ++-- test/stdout.js | 4 ++-- test/unchanged.js | 2 +- test/watch.js | 2 +- 12 files changed, 58 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index 266c912..c7a0cd8 100755 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -import fs from 'fs-extra' +import fs from 'node:fs/promises' import path from 'path' import prettyHrtime from 'pretty-hrtime' @@ -286,10 +286,14 @@ function css(css, file) { }) async function outputFile(file, string) { - const fileExists = await fs.pathExists(file) + const fileExists = await fs.access(file).then( + () => true, + () => false, + ) const currentValue = fileExists ? await fs.readFile(file, 'utf8') : null if (currentValue === string) return - return fs.outputFile(file, string) + await fs.mkdir(path.dirname(file), { recursive: true }) + return fs.writeFile(file, string) } } diff --git a/package.json b/package.json index 6e5981a..ccde399 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "dependencies": { "chokidar": "^3.3.0", "dependency-graph": "^1.0.0", - "fs-extra": "^11.0.0", "picocolors": "^1.0.0", "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", diff --git a/test/ext.js b/test/ext.js index 329f2c4..675939d 100644 --- a/test/ext.js +++ b/test/ext.js @@ -1,6 +1,6 @@ import test from 'ava' -import fs from 'fs-extra' +import fs from 'node:fs/promises' import path from 'path' import cli from './helpers/cli.js' @@ -20,7 +20,12 @@ test('--ext works', async (t) => { ]) t.falsy(error, stderr) - t.truthy(await fs.pathExists(path.join(dir, 'a.css'))) + t.truthy( + await fs.access(path.join(dir, 'a.css')).then( + () => true, + () => false, + ), + ) }) test('--ext works with no leading dot', async (t) => { @@ -37,5 +42,10 @@ test('--ext works with no leading dot', async (t) => { ]) t.falsy(error, stderr) - t.truthy(await fs.pathExists(path.join(dir, 'a.css'))) + t.truthy( + await fs.access(path.join(dir, 'a.css')).then( + () => true, + () => false, + ), + ) }) diff --git a/test/helpers/clean.js b/test/helpers/clean.js index 73bb191..7591d7b 100644 --- a/test/helpers/clean.js +++ b/test/helpers/clean.js @@ -1,8 +1,10 @@ -import fs from 'fs-extra' +import fs from 'node:fs/promises' Promise.all([ - fs.emptyDir('./test/fixtures/.tmp/'), - fs.remove('./coverage'), + fs + .rm('./test/fixtures/.tmp/', { recursive: true, force: true }) + .then(() => fs.mkdir('./test/fixtures/.tmp/', { recursive: true })), + fs.rm('./coverage', { recursive: true, force: true }), ]).catch((err) => { console.error(err) process.exit(1) diff --git a/test/helpers/env.js b/test/helpers/env.js index 017df87..84c3fe2 100644 --- a/test/helpers/env.js +++ b/test/helpers/env.js @@ -1,4 +1,4 @@ -import fs from 'fs-extra' +import fs from 'node:fs/promises' import path from 'path' import { glob } from 'tinyglobby' @@ -7,12 +7,18 @@ import tmp from './tmp.js' export default function (config, fixtures = '**/*', extension = 'cjs') { const dir = tmp() - return Promise.all([ - glob(fixtures, { cwd: 'test/fixtures' }).then((list) => { - return list.map((item) => { - return fs.copy(path.join('test/fixtures', item), path.join(dir, item)) - }) - }), - fs.outputFile(path.join(dir, `postcss.config.${extension}`), config), - ]).then(() => dir) + return fs.mkdir(dir, { recursive: true }).then(() => + Promise.all([ + glob(fixtures, { cwd: 'test/fixtures' }).then((list) => { + return Promise.all( + list.map(async (item) => { + const dest = path.join(dir, item) + await fs.mkdir(path.dirname(dest), { recursive: true }) + return fs.copyFile(path.join('test/fixtures', item), dest) + }), + ) + }), + fs.writeFile(path.join(dir, `postcss.config.${extension}`), config), + ]).then(() => dir), + ) } diff --git a/test/helpers/read.js b/test/helpers/read.js index e9939aa..17d969f 100644 --- a/test/helpers/read.js +++ b/test/helpers/read.js @@ -1,4 +1,4 @@ -import fs from 'fs-extra' +import fs from 'node:fs/promises' export default function (path) { return fs.readFile(path, 'utf8').then( diff --git a/test/map.js b/test/map.js index 4783010..a3febb9 100644 --- a/test/map.js +++ b/test/map.js @@ -1,5 +1,5 @@ import test from 'ava' -import fs from 'fs-extra' +import fs from 'node:fs/promises' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' @@ -35,7 +35,12 @@ test('--map generates external sourcemaps', async (t) => { t.falsy(error, stderr) - t.truthy(await fs.pathExists(output.replace('.css', '.css.map'))) + t.truthy( + await fs.access(output.replace('.css', '.css.map')).then( + () => true, + () => false, + ), + ) }) test('--no-map disables internal sourcemaps', async (t) => { diff --git a/test/replace.js b/test/replace.js index dd24b98..7032493 100644 --- a/test/replace.js +++ b/test/replace.js @@ -1,6 +1,6 @@ import test from 'ava' -import fs from 'fs-extra' +import fs from 'node:fs/promises' import path from 'path' import cli from './helpers/cli.js' @@ -12,9 +12,10 @@ test('--replace works', async (t) => { const output = path.join(dir, 'output.css') + await fs.mkdir(dir, { recursive: true }) await Promise.all([ - fs.copy('test/fixtures/import.css', output), - fs.copy('test/fixtures/a.css', path.join(dir, 'a.css')), + fs.copyFile('test/fixtures/import.css', output), + fs.copyFile('test/fixtures/a.css', path.join(dir, 'a.css')), ]) const { error, stderr } = await cli([ diff --git a/test/stdin.js b/test/stdin.js index a682436..9cdf928 100644 --- a/test/stdin.js +++ b/test/stdin.js @@ -1,6 +1,6 @@ import test from 'ava' -import fs from 'fs-extra' +import { createReadStream } from 'node:fs' import path from 'path' import { exec } from 'child_process' @@ -24,5 +24,5 @@ test.cb('reads from stdin', (t) => { }, ) - fs.createReadStream('test/fixtures/a.css').pipe(cp.stdin) + createReadStream('test/fixtures/a.css').pipe(cp.stdin) }) diff --git a/test/stdout.js b/test/stdout.js index 260180f..b53de43 100644 --- a/test/stdout.js +++ b/test/stdout.js @@ -1,6 +1,6 @@ import test from 'ava' -import fs from 'fs-extra' +import { createReadStream } from 'node:fs' import path from 'path' import { exec } from 'child_process' @@ -23,5 +23,5 @@ test.cb('writes to stdout', (t) => { }, ) - fs.createReadStream('./test/fixtures/a.sss').pipe(cp.stdin) + createReadStream('./test/fixtures/a.sss').pipe(cp.stdin) }) diff --git a/test/unchanged.js b/test/unchanged.js index 4598530..beabdb1 100644 --- a/test/unchanged.js +++ b/test/unchanged.js @@ -1,4 +1,4 @@ -import fs from 'fs-extra' +import fs from 'node:fs/promises' import test from 'ava' import cli from './helpers/cli.js' diff --git a/test/watch.js b/test/watch.js index 357174a..ed0e873 100644 --- a/test/watch.js +++ b/test/watch.js @@ -1,6 +1,6 @@ import test from 'ava' -import fs from 'fs-extra' +import fs from 'node:fs/promises' import path from 'path' import { exec, spawn } from 'child_process' import chokidar from 'chokidar' From 0c9da903b4bee06aee920fe573bf7c36b615207e Mon Sep 17 00:00:00 2001 From: Rolando Bosch Date: Tue, 3 Mar 2026 10:07:14 -0800 Subject: [PATCH 2/2] refactor: convert env helper to async/await per review feedback --- test/helpers/env.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/helpers/env.js b/test/helpers/env.js index 84c3fe2..0fd9549 100644 --- a/test/helpers/env.js +++ b/test/helpers/env.js @@ -4,21 +4,21 @@ import { glob } from 'tinyglobby' import tmp from './tmp.js' -export default function (config, fixtures = '**/*', extension = 'cjs') { +export default async function (config, fixtures = '**/*', extension = 'cjs') { const dir = tmp() - return fs.mkdir(dir, { recursive: true }).then(() => - Promise.all([ - glob(fixtures, { cwd: 'test/fixtures' }).then((list) => { - return Promise.all( - list.map(async (item) => { - const dest = path.join(dir, item) - await fs.mkdir(path.dirname(dest), { recursive: true }) - return fs.copyFile(path.join('test/fixtures', item), dest) - }), - ) - }), - fs.writeFile(path.join(dir, `postcss.config.${extension}`), config), - ]).then(() => dir), - ) + await fs.mkdir(dir, { recursive: true }) + + const list = await glob(fixtures, { cwd: 'test/fixtures' }) + + await Promise.all([ + ...list.map(async (item) => { + const dest = path.join(dir, item) + await fs.mkdir(path.dirname(dest), { recursive: true }) + await fs.copyFile(path.join('test/fixtures', item), dest) + }), + fs.writeFile(path.join(dir, `postcss.config.${extension}`), config), + ]) + + return dir }