Skip to content

Commit

Permalink
refactor(cli): panda analyze minor changes (#2679)
Browse files Browse the repository at this point in the history
* refactor(cli): rename `panda analyze` --json -> --outfile

* feat(cli): rm box in favor of range for each report item + add lightningCss timings/css file size

* chore: rename/restructure a bunch of things

* chore: add componentName

* chore: rename "name" to "componentName"

* chore: lint & typecheck
  • Loading branch information
astahmer committed Jun 19, 2024
1 parent adb2484 commit 19c3a2c
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 296 deletions.
8 changes: 8 additions & 0 deletions .changeset/famous-rockets-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@pandacss/extractor': patch
'@pandacss/types': patch
'@pandacss/node': patch
'@pandacss/dev': patch
---

Minor changes in the `panda analyze --output coverage.json` file
10 changes: 5 additions & 5 deletions packages/cli/src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ export async function main() {

cli
.command('analyze [glob]', 'Analyze design token usage in glob')
.option('--json [filepath]', 'Output analyze report in JSON')
.option('--outfile [filepath]', 'Output analyze report in JSON')
.option('--silent', "Don't print any logs")
.option('-c, --config <path>', 'Path to panda config file')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
Expand All @@ -385,13 +385,13 @@ export async function main() {
},
})

if (flags?.json && typeof flags.json === 'string') {
await writeAnalyzeJSON(flags.json, result, ctx)
logger.info('cli', `JSON report saved to ${flags.json}`)
if (flags?.outfile && typeof flags.outfile === 'string') {
await writeAnalyzeJSON(flags.outfile, result, ctx)
logger.info('cli', `JSON report saved to ${resolve(flags.outfile)}`)
return
}

logger.info('cli', `Found ${result.details.byId.size} token used in ${result.details.byFilePathMaps.size} files`)
logger.info('cli', `Found ${result.propByIndex.size} token used in ${result.derived.byFilePathMaps.size} files`)
})

cli
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface StudioCommandFlags extends Pick<Config, 'cwd'> {

export interface AnalyzeCommandFlags {
silent?: boolean
json?: string
outfile?: string
cwd?: string
config?: string
}
Expand Down
1 change: 1 addition & 0 deletions packages/extractor/src/box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const box = {
value: undefined,
getNode: () => node.getNode(),
getStack: () => node.getStack(),
getRange: () => node.getRange(),
}
},
/**
Expand Down
113 changes: 75 additions & 38 deletions packages/node/src/analyze-tokens.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { logger } from '@pandacss/logger'
import type { ParserResultInterface } from '@pandacss/types'
import type { ParserResultInterface, ReportSnapshot } from '@pandacss/types'
import { filesize } from 'filesize'
import { writeFile } from 'fs/promises'
import path from 'node:path'
import zlib from 'zlib'
import { version } from '../package.json'
import { classifyTokens } from './classify'
import type { PandaContext } from './create-context'

Expand All @@ -12,50 +14,86 @@ interface Options {
onResult?: (file: string, result: ParserResultInterface) => void
}

export function analyzeTokens(ctx: PandaContext, options: Options = {}) {
export function analyzeTokens(ctx: PandaContext, options: Options = {}): ReportSnapshot {
const filesMap = new Map<string, ParserResultInterface>()
const timesMap = new Map<string, number>()

const files = ctx.getFiles()
const sheet = ctx.createSheet()
ctx.appendLayerParams(sheet)
ctx.appendBaselineCss(sheet)

files.forEach((file) => {
const start = performance.now()
const result = ctx.project.parseSourceFile(file)

const extractMs = performance.now() - start
timesMap.set(file, extractMs)
const relativePath = path.relative(ctx.config.cwd, file)
timesMap.set(relativePath, extractMs)
logger.debug('analyze', `Parsed ${file} in ${extractMs}ms`)

if (result) {
filesMap.set(file, result)
filesMap.set(relativePath, result)
options.onResult?.(file, result)
}
})

const totalMs = Array.from(timesMap.values()).reduce((a, b) => a + b, 0)
logger.debug('analyze', `Analyzed ${files.length} files in ${totalMs.toFixed(2)}ms`)

const minify = ctx.config.minify
ctx.appendParserCss(sheet)

ctx.config.optimize = true
const cssStart = performance.now()
ctx.config.minify = false

// TODO
const css = ''
const minifiedCss = ''

// restore minify config
ctx.config.minify = minify
const css = ctx.getCss(sheet)
const cssMs = performance.now() - cssStart

const cssMinifyStart = performance.now()
ctx.config.minify = true
const minifiedCss = ctx.getCss(sheet)
const cssMinifyMs = performance.now() - cssMinifyStart

let lightningCss = ''
let lightningCssMs: number | undefined
let lightningCssMinifiedCss = ''
let lightningCssMinifiedMs: number | undefined

const isUsingLightningCss = ctx.config.lightningcss
if (!isUsingLightningCss) {
sheet['context'].lightningcss = true

ctx.config.minify = false
const lightningcssStart = performance.now()
lightningCss = ctx.getCss(sheet)
lightningCssMs = performance.now() - lightningcssStart

ctx.config.minify = true
const lightningcssMinifyStart = performance.now()
lightningCssMinifiedCss = ctx.getCss(sheet)
lightningCssMinifiedMs = performance.now() - lightningcssMinifyStart
}

const start = performance.now()
const analysis = classifyTokens(ctx, filesMap)
const classifyMs = performance.now() - start

return Object.assign(
const details = Object.assign(
{
duration: {
extractTimeByFiles: Object.fromEntries(timesMap.entries()),
extractTotal: totalMs,
classify: classifyMs,
//
cssMs,
cssMinifyMs,
//
...(!isUsingLightningCss
? {
lightningCssMs,
lightningCssMinifiedMs,
}
: {}),
//
extractTotal: totalMs,
extractTimeByFiles: Object.fromEntries(timesMap.entries()),
},
fileSizes: {
lineCount: css.split('\n').length,
Expand All @@ -65,10 +103,27 @@ export function analyzeTokens(ctx: PandaContext, options: Options = {}) {
normal: filesize(gzipSizeSync(css)),
minified: filesize(gzipSizeSync(minifiedCss)),
},
lightningCss: !isUsingLightningCss
? {
normal: filesize(Buffer.byteLength(lightningCss, 'utf-8')),
minified: filesize(Buffer.byteLength(lightningCssMinifiedCss, 'utf-8')),
}
: undefined,
},
},
analysis,
)
analysis.details,
) satisfies ReportSnapshot['details']

const { globalCss, ...config } = ctx.config

return {
schemaVersion: version,
details,
propByIndex: analysis.propById,
componentByIndex: analysis.componentById,
derived: analysis.derived,
config,
}
}

const analyzeResultSerializer = (_key: string, value: any) => {
Expand All @@ -83,27 +138,9 @@ const analyzeResultSerializer = (_key: string, value: any) => {
return value
}

export const writeAnalyzeJSON = (filePath: string, result: ReturnType<typeof analyzeTokens>, ctx: PandaContext) => {
// prevent writing twice the same BoxNode in the output (already serialized in the `byId` map)
result.details.byInstanceId.forEach((item) => {
item.box = item.box.toJSON() as any
})

export const writeAnalyzeJSON = (filePath: string, result: ReportSnapshot, ctx: PandaContext) => {
const dirname = ctx.runtime.path.dirname(filePath)
ctx.runtime.fs.ensureDirSync(dirname)

return writeFile(
filePath,
JSON.stringify(
Object.assign(result, {
cwd: ctx.config.cwd,
theme: ctx.config.theme,
utilities: ctx.config.utilities,
conditions: ctx.config.conditions,
shorthands: ctx.utility.shorthands,
}),
analyzeResultSerializer,
2,
),
)
return writeFile(filePath, JSON.stringify(result, analyzeResultSerializer, 2))
}
Loading

0 comments on commit 19c3a2c

Please sign in to comment.