Skip to content

Commit 77f613f

Browse files
committed
perf(worker): avoid accessing panda context to scan all files
1 parent 76c59c4 commit 77f613f

File tree

4 files changed

+57
-27
lines changed

4 files changed

+57
-27
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
"dependencies": {
2828
"@changesets/changelog-github": "^0.5.0",
2929
"@changesets/cli": "^2.27.1",
30+
"@types/micromatch": "^4.0.10",
3031
"@typescript-eslint/utils": "^8.21.0",
3132
"esbuild": "0.25.0",
33+
"micromatch": "^4.0.8",
3234
"tsup": "^8.0.1",
3335
"typescript": "^5.3.3"
3436
},

plugin/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@
3939
"@pandacss/shared": "^0.53.2",
4040
"@typescript-eslint/utils": "^8.21.0",
4141
"hookable": "^5.5.3",
42+
"micromatch": "^4.0.8",
4243
"synckit": "^0.9.0"
4344
},
4445
"peerDependencies": {
4546
"eslint": "*"
4647
},
4748
"devDependencies": {
49+
"@types/micromatch": "^4.0.10",
4850
"typescript": "^5.7.2"
4951
}
5052
}

plugin/src/utils/worker.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
1-
import { PandaContext, loadConfigAndCreateContext } from '@pandacss/node'
1+
import { Generator } from '@pandacss/generator'
22
import { runAsWorker } from 'synckit'
33
import { createContext } from 'fixture'
44
import { resolveTsPathPattern } from '@pandacss/config/ts-path'
5-
import { findConfig } from '@pandacss/config'
5+
import { findConfig, loadConfig } from '@pandacss/config'
66
import path from 'path'
7+
import micromatch from 'micromatch'
78
import type { ImportResult } from '.'
89

910
type Opts = {
1011
currentFile: string
1112
configPath?: string
1213
}
1314

14-
const contextCache: { [configPath: string]: Promise<PandaContext> } = {}
15+
const contextCache: { [configPath: string]: Promise<Generator> } = {}
1516

1617
async function _getContext(configPath: string | undefined) {
1718
if (!configPath) throw new Error('Invalid config path')
1819

1920
const cwd = path.dirname(configPath)
2021

21-
const ctx = await loadConfigAndCreateContext({ configPath, cwd })
22+
const conf = await loadConfig({ file: configPath, cwd })
23+
const ctx = new Generator(conf)
2224
return ctx
2325
}
2426

2527
export async function getContext(opts: Opts) {
2628
if (process.env.NODE_ENV === 'test') {
27-
const ctx = createContext() as unknown as PandaContext
28-
ctx.getFiles = () => ['App.tsx']
29+
const ctx = createContext() as unknown as Generator
30+
31+
// Store cwd on the context for use in isValidFile
32+
// @ts-expect-error - adding custom property
33+
ctx._cwd = cwd
2934
return ctx
3035
} else {
3136
const configPath = findConfig({ cwd: opts.configPath ?? opts.currentFile })
@@ -39,7 +44,7 @@ export async function getContext(opts: Opts) {
3944
}
4045
}
4146

42-
async function filterInvalidTokens(ctx: PandaContext, paths: string[]): Promise<string[]> {
47+
async function filterInvalidTokens(ctx: Generator, paths: string[]): Promise<string[]> {
4348
return paths.filter((path) => !ctx.utility.tokens.view.get(path))
4449
}
4550

@@ -50,45 +55,44 @@ export type DeprecatedToken =
5055
value: string
5156
}
5257

53-
async function filterDeprecatedTokens(ctx: PandaContext, tokens: DeprecatedToken[]): Promise<DeprecatedToken[]> {
58+
async function filterDeprecatedTokens(ctx: Generator, tokens: DeprecatedToken[]): Promise<DeprecatedToken[]> {
5459
return tokens.filter((token) => {
5560
const value = typeof token === 'string' ? token : token.category + '.' + token.value
5661
return ctx.utility.tokens.isDeprecated(value)
5762
})
5863
}
5964

60-
async function isColorToken(ctx: PandaContext, value: string): Promise<boolean> {
65+
async function isColorToken(ctx: Generator, value: string): Promise<boolean> {
6166
return !!ctx.utility.tokens.view.categoryMap.get('colors')?.get(value)
6267
}
6368

64-
async function getPropCategory(ctx: PandaContext, _attr: string) {
69+
async function getPropCategory(ctx: Generator, _attr: string) {
6570
const longhand = await resolveLongHand(ctx, _attr)
6671
const attr = longhand || _attr
6772
const attrConfig = ctx.utility.config[attr]
6873
return typeof attrConfig?.values === 'string' ? attrConfig.values : undefined
6974
}
7075

71-
async function isColorAttribute(ctx: PandaContext, _attr: string): Promise<boolean> {
76+
async function isColorAttribute(ctx: Generator, _attr: string): Promise<boolean> {
7277
const category = await getPropCategory(ctx, _attr)
7378
return category === 'colors'
7479
}
7580

76-
const arePathsEqual = (path1: string, path2: string) => {
77-
const normalizedPath1 = path.resolve(path1)
78-
const normalizedPath2 = path.resolve(path2)
81+
async function isValidFile(ctx: Generator, fileName: string): Promise<boolean> {
82+
const { include, exclude } = ctx.config
83+
// @ts-expect-error - using custom property
84+
const cwd = ctx._cwd || ctx.config.cwd || process.cwd()
7985

80-
return normalizedPath1 === normalizedPath2
81-
}
86+
const relativePath = path.isAbsolute(fileName) ? path.relative(cwd, fileName) : fileName
8287

83-
async function isValidFile(ctx: PandaContext, fileName: string): Promise<boolean> {
84-
return ctx.getFiles().some((file) => arePathsEqual(file, fileName))
88+
return micromatch.isMatch(relativePath, include, { ignore: exclude, dot: true })
8589
}
8690

87-
async function resolveShorthands(ctx: PandaContext, name: string): Promise<string[] | undefined> {
91+
async function resolveShorthands(ctx: Generator, name: string): Promise<string[] | undefined> {
8892
return ctx.utility.getPropShorthandsMap().get(name)
8993
}
9094

91-
async function resolveLongHand(ctx: PandaContext, name: string): Promise<string | undefined> {
95+
async function resolveLongHand(ctx: Generator, name: string): Promise<string | undefined> {
9296
const reverseShorthandsMap = new Map()
9397

9498
for (const [key, values] of ctx.utility.getPropShorthandsMap()) {
@@ -100,7 +104,7 @@ async function resolveLongHand(ctx: PandaContext, name: string): Promise<string
100104
return reverseShorthandsMap.get(name)
101105
}
102106

103-
async function isValidProperty(ctx: PandaContext, name: string, patternName?: string) {
107+
async function isValidProperty(ctx: Generator, name: string, patternName?: string) {
104108
if (ctx.isValidProperty(name)) return true
105109
if (!patternName) return
106110

@@ -110,7 +114,7 @@ async function isValidProperty(ctx: PandaContext, name: string, patternName?: st
110114
return Object.keys(pattern).includes(name)
111115
}
112116

113-
async function matchFile(ctx: PandaContext, name: string, imports: ImportResult[]) {
117+
async function matchFile(ctx: Generator, name: string, imports: ImportResult[]) {
114118
const file = ctx.imports.file(imports)
115119

116120
return file.match(name)
@@ -121,7 +125,7 @@ type MatchImportResult = {
121125
alias: string
122126
mod: string
123127
}
124-
async function matchImports(ctx: PandaContext, result: MatchImportResult) {
128+
async function matchImports(ctx: Generator, result: MatchImportResult) {
125129
return ctx.imports.match(result, (mod) => {
126130
const { tsOptions } = ctx.parserOptions
127131
if (!tsOptions?.pathMappings) return

pnpm-lock.yaml

Lines changed: 26 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)