From 0f0b4b205df201e9cdd047764868dd2619a528b0 Mon Sep 17 00:00:00 2001 From: Superchupu <53496941+SuperchupuDev@users.noreply.github.com> Date: Fri, 19 Jul 2024 15:56:33 +0100 Subject: [PATCH] refactor: replace `globby` with faster alternative (#1158) --- package.json | 4 +++- pnpm-lock.yaml | 35 ++++++++++++++++++++++++++++++++--- src/index.ts | 10 ++++++++-- src/utils.ts | 26 ++++++++++++++++++++++---- test/utils.ts | 10 ++++++---- 5 files changed, 71 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 3668bd8e1..7c73c557c 100644 --- a/package.json +++ b/package.json @@ -57,9 +57,10 @@ "debug": "^4.3.5", "esbuild": "^0.23.0", "execa": "^5.1.1", - "globby": "^11.1.0", + "fdir": "^6.1.1", "joycon": "^3.1.1", "picocolors": "^1.0.1", + "picomatch": "^4.0.2", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.18.1", @@ -74,6 +75,7 @@ "@types/debug": "4.1.12", "@types/fs-extra": "11.0.4", "@types/node": "20.14.11", + "@types/picomatch": "^3.0.0", "@types/resolve": "1.20.6", "flat": "6.0.1", "fs-extra": "11.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec678e411..32def7819 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,15 +29,18 @@ importers: execa: specifier: ^5.1.1 version: 5.1.1 - globby: - specifier: ^11.1.0 - version: 11.1.0 + fdir: + specifier: ^6.1.1 + version: 6.1.1(picomatch@4.0.2) joycon: specifier: ^3.1.1 version: 3.1.1 picocolors: specifier: ^1.0.1 version: 1.0.1 + picomatch: + specifier: ^4.0.2 + version: 4.0.2 postcss-load-config: specifier: ^6.0.1 version: 6.0.1(jiti@1.21.6)(postcss@8.4.39)(yaml@2.4.5) @@ -75,6 +78,9 @@ importers: '@types/node': specifier: 20.14.11 version: 20.14.11 + '@types/picomatch': + specifier: ^3.0.0 + version: 3.0.0 '@types/resolve': specifier: 1.20.6 version: 1.20.6 @@ -700,6 +706,9 @@ packages: '@types/node@20.14.11': resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + '@types/picomatch@3.0.0': + resolution: {integrity: sha512-iX/Qwk9vU17N/5Q7QrV46wzciloTdCqTRt6z8A7uFFADM2+Sy5oQh9ldZhAiTXH+l0sM/EkXatEhJIs8FUyOBQ==} + '@types/pug@2.0.10': resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} @@ -941,6 +950,14 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fdir@6.1.1: + resolution: {integrity: sha512-QfKBVg453Dyn3mr0Q0O+Tkr1r79lOTAKSi9f/Ot4+qVEwxWhav2Z+SudrG9vQjM2aYRMQQZ2/Q1zdA8ACM1pDg==} + peerDependencies: + picomatch: 3.x + peerDependenciesMeta: + picomatch: + optional: true + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1258,6 +1275,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -2108,6 +2129,8 @@ snapshots: dependencies: undici-types: 5.26.5 + '@types/picomatch@3.0.0': {} + '@types/pug@2.0.10': {} '@types/resolve@1.20.6': {} @@ -2404,6 +2427,10 @@ snapshots: dependencies: reusify: 1.0.4 + fdir@6.1.1(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -2673,6 +2700,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + pirates@4.0.6: {} postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.39)(yaml@2.4.5): diff --git a/src/index.ts b/src/index.ts index e3ec00721..c9af0fd20 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,10 @@ import path from 'node:path' import fs from 'node:fs' import { Worker } from 'node:worker_threads' -import glob from 'globby' import { loadTsConfig } from 'bundle-require' import execa from 'execa' +import { fdir } from 'fdir' +import picomatch from 'picomatch' import kill from 'tree-kill' import { version } from '../package.json' import { PrettyError, handleError } from './errors' @@ -118,7 +119,12 @@ const normalizeOptions = async ( } if (Array.isArray(entry)) { - options.entry = await glob(entry) + const matcher = picomatch(entry, { windows: process.platform === 'win32' }) + options.entry = await new fdir() + .withRelativePaths() + .filter((file) => matcher(file)) + .crawl(process.cwd()) + .withPromise() // Ensure entry exists if (!options.entry || options.entry.length === 0) { throw new PrettyError(`Cannot find ${entry}`) diff --git a/src/utils.ts b/src/utils.ts index 08314658c..04c08a4ec 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,7 @@ import fs from 'node:fs' import path from 'node:path' -import glob from 'globby' +import { fdir } from 'fdir' +import picomatch from 'picomatch' import resolveFrom from 'resolve-from' import strip from 'strip-json-comments' import type { Entry, Format } from './options' @@ -65,10 +66,27 @@ export function pathExists(p: string) { } export async function removeFiles(patterns: string[], dir: string) { - const files = await glob(patterns, { - cwd: dir, - absolute: true, + const matchPatterns: string[] = [] + const ignorePatterns: string[] = [] + for (const pattern of patterns) { + if (pattern.startsWith('!') && pattern[1] !== '(') { + ignorePatterns.push(pattern.slice(1)) + } else { + matchPatterns.push(pattern) + } + } + + const matcher = picomatch(matchPatterns, { + dot: true, + ignore: ignorePatterns, + windows: process.platform === 'win32', }) + + const files = await new fdir() + .withFullPaths() + .filter((file) => matcher(file)) + .crawl(dir) + .withPromise() files.forEach((file) => fs.existsSync(file) && fs.unlinkSync(file)) } diff --git a/test/utils.ts b/test/utils.ts index d928d9874..2b60ffb1a 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -2,8 +2,8 @@ import path from 'node:path' import { fileURLToPath } from 'node:url' import { expect } from 'vitest' import execa from 'execa' +import { fdir } from 'fdir' import fs from 'fs-extra' -import glob from 'globby' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const cacheDir = path.resolve(__dirname, '.cache') @@ -57,9 +57,11 @@ export async function run( } // Get output - const outFiles = await glob('**/*', { - cwd: path.resolve(testDir, 'dist'), - }).then((res) => res.sort()) + const outFiles = await new fdir() + .withRelativePaths() + .crawl(path.resolve(testDir, 'dist')) + .withPromise() + .then((res) => res.map((f) => f.replaceAll('\\', '/')).sort()) return { get output() {