@zealakit/css-doctor-rsbuild 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +24 -9
- package/dist/index.js.map +1 -1
- package/package.json +25 -3
package/dist/index.js
CHANGED
|
@@ -118,17 +118,20 @@ var DEFAULT_MIN_PAGE_RATIO = 0.5;
|
|
|
118
118
|
var DEFAULT_MAX_CHUNK_SIZE = 60 * 1024;
|
|
119
119
|
var CssDoctorRspackPlugin = class {
|
|
120
120
|
options;
|
|
121
|
+
configurationWarnings = [];
|
|
121
122
|
constructor(options = {}) {
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
const configuredMinPageRatio = options.pageCoverage?.minPageRatio ?? DEFAULT_MIN_PAGE_RATIO;
|
|
124
|
+
const configuredMaxChunkSize = options.sizeBudget?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;
|
|
125
|
+
const minPageRatio = Number.isFinite(configuredMinPageRatio) && configuredMinPageRatio >= 0 && configuredMinPageRatio <= 1 ? configuredMinPageRatio : DEFAULT_MIN_PAGE_RATIO;
|
|
126
|
+
const maxChunkSize = Number.isInteger(configuredMaxChunkSize) && configuredMaxChunkSize > 0 ? configuredMaxChunkSize : DEFAULT_MAX_CHUNK_SIZE;
|
|
127
|
+
if (minPageRatio !== configuredMinPageRatio) {
|
|
128
|
+
this.configurationWarnings.push(
|
|
129
|
+
"minPageRatio must be a number between 0 and 1; using 0.5"
|
|
127
130
|
);
|
|
128
131
|
}
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
"
|
|
132
|
+
if (maxChunkSize !== configuredMaxChunkSize) {
|
|
133
|
+
this.configurationWarnings.push(
|
|
134
|
+
"maxChunkSize must be a positive integer; using 61440"
|
|
132
135
|
);
|
|
133
136
|
}
|
|
134
137
|
this.options = {
|
|
@@ -172,6 +175,9 @@ var CssDoctorRspackPlugin = class {
|
|
|
172
175
|
async process(compiler, compilation) {
|
|
173
176
|
const startedAt = performance.now();
|
|
174
177
|
const logger = compilation.getLogger(PLUGIN_NAME);
|
|
178
|
+
for (const warning of this.configurationWarnings) {
|
|
179
|
+
logger.warn(`[css-doctor] ${warning}`);
|
|
180
|
+
}
|
|
175
181
|
const pagesResult = await collectPages(compilation);
|
|
176
182
|
const pageNames = pagesResult.pages.map((page) => page.name);
|
|
177
183
|
const allPages = new Set(pageNames);
|
|
@@ -658,13 +664,22 @@ function scanClasses(source, classes) {
|
|
|
658
664
|
continue;
|
|
659
665
|
}
|
|
660
666
|
for (const token of value.split(/\s+/)) {
|
|
661
|
-
if (
|
|
667
|
+
if (isClassToken(token)) {
|
|
662
668
|
classes.add(token.toLowerCase());
|
|
663
669
|
}
|
|
664
670
|
}
|
|
665
671
|
}
|
|
666
672
|
}
|
|
667
673
|
}
|
|
674
|
+
function isClassToken(token) {
|
|
675
|
+
if (!token || token.length > 256) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
if (/[`${}]/.test(token)) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
return /[A-Za-z_]/.test(token);
|
|
682
|
+
}
|
|
668
683
|
function injectPageCssLoaders(compilation, cssByPage, pageByName, RawSource) {
|
|
669
684
|
const publicPath = compilation.options.output.publicPath;
|
|
670
685
|
const base = typeof publicPath === "string" && publicPath.length > 0 ? publicPath : "/";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rspack-plugin.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { posix } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { analyzeCss, optimizeCss } from \"@zealakit/css-doctor-binding\";\nimport type {\n JsChunkOutput,\n JsSelectorStat,\n} from \"@zealakit/css-doctor-binding\";\nimport type { Compilation, Compiler } from \"@rspack/core\";\n\nimport { printReport } from \"./reporter\";\nimport type {\n ChunkInfo,\n CssAssetDiagnostic,\n CssDoctorRsbuildDiagnostics,\n CssDoctorRsbuildOptions,\n EmittedCssChunk,\n PageCoverageOptions,\n SizeBudgetOptions,\n} from \"./types\";\n\nconst PLUGIN_NAME = \"css-doctor:rsbuild\";\nconst DEFAULT_MIN_PAGE_RATIO = 0.5;\nconst DEFAULT_MAX_CHUNK_SIZE = 60 * 1_024;\n\ntype RspackChunkLike = {\n name?: string;\n files?: Iterable<string>;\n auxiliaryFiles?: Iterable<string>;\n};\n\ntype RspackEntrypointLike = {\n name?: string;\n chunks?: Iterable<RspackChunkLike>;\n getFiles?: () => Iterable<string>;\n};\n\ntype RspackModuleLike = {\n resource?: string;\n modules?: Iterable<RspackModuleLike>;\n originalSource?: () => { source: () => unknown } | null;\n};\n\ntype PageInfo = {\n name: string;\n classes: Set<string>;\n cssFiles: Set<string>;\n jsFiles: Set<string>;\n};\n\ntype PagesResult = {\n pages: PageInfo[];\n pagesByCss: Map<string, Set<string>>;\n};\n\ntype ResolvedOptions = {\n pageCoverage: Required<PageCoverageOptions> & { forceCommon: string[] };\n sizeBudget: Required<SizeBudgetOptions>;\n minify: boolean;\n report: boolean;\n include: Array<string | RegExp>;\n exclude: Array<string | RegExp>;\n};\n\n/**\n * Rspack compilation plugin that runs the css-doctor two-tier pipeline for\n * global CSS assets. CSS Modules assets are deliberately skipped.\n */\nexport class CssDoctorRspackPlugin {\n private readonly options: ResolvedOptions;\n\n constructor(options: CssDoctorRsbuildOptions = {}) {\n const minPageRatio =\n options.pageCoverage?.minPageRatio ?? DEFAULT_MIN_PAGE_RATIO;\n const maxChunkSize =\n options.sizeBudget?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\n if (\n !Number.isFinite(minPageRatio) ||\n minPageRatio < 0 ||\n minPageRatio > 1\n ) {\n throw new RangeError(\n \"css-doctor: minPageRatio must be a number between 0 and 1\",\n );\n }\n\n if (!Number.isInteger(maxChunkSize) || maxChunkSize <= 0) {\n throw new RangeError(\n \"css-doctor: maxChunkSize must be a positive integer\",\n );\n }\n\n this.options = {\n pageCoverage: {\n enabled: options.pageCoverage?.enabled ?? true,\n minPageRatio,\n forceCommon: options.pageCoverage?.forceCommon ?? [],\n },\n sizeBudget: {\n enabled: options.sizeBudget?.enabled ?? true,\n maxChunkSize,\n isolateVariables: options.sizeBudget?.isolateVariables ?? true,\n },\n minify: options.minify ?? true,\n report: options.report ?? true,\n include: options.include ?? [],\n exclude: options.exclude ?? [],\n };\n }\n\n apply(compiler: Compiler): void {\n compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {\n compilation.hooks.processAssets.tapPromise(\n {\n name: PLUGIN_NAME,\n stage: compiler.rspack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,\n },\n async () => {\n try {\n await this.process(compiler, compilation);\n } catch (error) {\n compilation\n .getLogger(PLUGIN_NAME)\n .warn(\n `[css-doctor] diagnostics failed without interrupting the build: ${describeError(\n error,\n )}`,\n );\n }\n },\n );\n });\n }\n\n private async process(\n compiler: Compiler,\n compilation: Compilation,\n ): Promise<void> {\n const startedAt = performance.now();\n const logger = compilation.getLogger(PLUGIN_NAME);\n const pagesResult = await collectPages(compilation);\n const pageNames = pagesResult.pages.map((page) => page.name);\n const allPages = new Set(pageNames);\n const pageUsage: Record<string, string[]> = {};\n const pageUsageCounts: Record<string, number> = {};\n\n for (const page of pagesResult.pages) {\n const classes = [...page.classes].sort();\n pageUsage[page.name] = classes;\n pageUsageCounts[page.name] = classes.length;\n }\n\n const hasPageClasses = pagesResult.pages.some(\n (page) => page.classes.size > 0,\n );\n const pageCoverageApplied =\n this.options.pageCoverage.enabled && hasPageClasses;\n const diagnostics: CssDoctorRsbuildDiagnostics = {\n plugin: PLUGIN_NAME,\n generatedAt: new Date().toISOString(),\n durationMs: 0,\n totalOriginalSize: 0,\n totalOptimizedSize: 0,\n deadCodeSelectorsCount: 0,\n chunks: [],\n minify: this.options.minify,\n pages: pageNames,\n pageUsage: pageUsageCounts,\n splitApplied: pageCoverageApplied,\n totalCssAssets: 0,\n analyzedCssAssets: 0,\n skippedCssAssets: 0,\n failedCssAssets: 0,\n totalSelectors: 0,\n totalRules: 0,\n commonCssBytes: 0,\n pageSpecificCssBytes: 0,\n emittedPageChunks: [],\n emittedCssChunks: [],\n sizeBudget: {\n enabled: this.options.sizeBudget.enabled,\n maxChunkSize: this.options.sizeBudget.maxChunkSize,\n isolateVariables: this.options.sizeBudget.isolateVariables,\n splitChunks: 0,\n oversizedChunks: 0,\n },\n usageMatrix: [],\n files: [],\n errors: [],\n };\n\n const matrix = new Map<string, JsSelectorStat>();\n const pageFiles = new Map<string, string[]>();\n const usedAssetNames = new Set(\n compilation.getAssets().map((asset) => asset.name),\n );\n const RawSource = compiler.rspack.sources.RawSource;\n\n const emitCssChunk = (chunk: JsChunkOutput): string => {\n const hash = createHash(\"sha256\")\n .update(chunk.css)\n .digest(\"hex\")\n .slice(0, 8);\n const safeName =\n chunk.name\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"chunk\";\n let fileName = `static/css/${safeName}.${hash}.css`;\n let index = 2;\n\n while (usedAssetNames.has(fileName)) {\n fileName = `static/css/${safeName}.${hash}-${index}.css`;\n index += 1;\n }\n\n compilation.emitAsset(fileName, new RawSource(chunk.css));\n usedAssetNames.add(fileName);\n return fileName;\n };\n\n for (const asset of compilation.getAssets()) {\n if (!asset.name.endsWith(\".css\")) {\n continue;\n }\n\n diagnostics.totalCssAssets += 1;\n\n if (\n this.shouldSkipAsset(asset.name, sourceToString(asset.source.source()))\n ) {\n diagnostics.skippedCssAssets += 1;\n continue;\n }\n\n const associatedPages = [\n ...(pagesResult.pagesByCss.get(asset.name) ?? allPages),\n ].sort();\n const originalCss = sourceToString(asset.source.source());\n const file = createDiagnostic(asset.name, originalCss, associatedPages);\n\n try {\n const analysis = analyzeCss(originalCss);\n file.selectorCount = analysis.stats.selectorCount;\n file.ruleCount = analysis.stats.ruleCount;\n const moduleClasses = collectCssModuleClasses(originalCss);\n const assetPageUsage =\n moduleClasses.length > 0\n ? withCommonClasses(pageUsage, moduleClasses)\n : pageUsage;\n const pipeline = optimizeCss({\n cssContent: originalCss,\n pageUsage: assetPageUsage,\n pageCoverage: {\n enabled: pageCoverageApplied,\n minPageRatio: this.options.pageCoverage.minPageRatio,\n forceCommon: this.options.pageCoverage.forceCommon,\n },\n sizeBudget: {\n enabled: this.options.sizeBudget.enabled,\n maxChunkSize: this.options.sizeBudget.maxChunkSize,\n isolateVariables: this.options.sizeBudget.isolateVariables,\n },\n minify: this.options.minify,\n });\n\n const commonChunks = pipeline.chunks.filter(\n (chunk) => chunk.page === undefined && chunk.sourceChunk === \"common\",\n );\n const pageChunks = pipeline.chunks.filter(\n (chunk) =>\n chunk.page !== undefined &&\n (associatedPages.includes(chunk.page) ||\n !pagesResult.pagesByCss.has(asset.name)),\n );\n const commonWasSplit =\n commonChunks.length > 1 ||\n commonChunks.some((chunk) => chunk.splitDueToSize);\n const embeddedCommon = commonWasSplit ? undefined : commonChunks[0];\n const commonFileNames: string[] = [];\n let commonSize = 0;\n\n for (const chunk of commonChunks) {\n const embedded = chunk === embeddedCommon;\n const fileName = embedded ? asset.name : emitCssChunk(chunk);\n commonSize += chunk.sizeBytes;\n commonFileNames.push(fileName);\n\n diagnostics.emittedCssChunks.push(\n toEmittedChunk(chunk, fileName, embedded),\n );\n\n if (chunk.splitDueToSize) {\n diagnostics.sizeBudget.splitChunks += 1;\n }\n\n if (chunk.oversized) {\n diagnostics.sizeBudget.oversizedChunks += 1;\n }\n }\n\n if (commonWasSplit) {\n const imports = commonFileNames\n .map((fileName) => {\n const relativePath = posix.relative(\n posix.dirname(asset.name),\n fileName,\n );\n return `@import \"./${relativePath}\";`;\n })\n .join(\"\\n\");\n compilation.updateAsset(asset.name, new RawSource(imports));\n } else {\n compilation.updateAsset(\n asset.name,\n new RawSource(embeddedCommon?.css ?? \"\"),\n );\n }\n\n let pageSpecificSize = 0;\n\n for (const chunk of pageChunks) {\n if (!chunk.page) {\n continue;\n }\n\n const fileName = emitCssChunk(chunk);\n pageSpecificSize += chunk.sizeBytes;\n const files = pageFiles.get(chunk.page) ?? [];\n files.push(fileName);\n pageFiles.set(chunk.page, files);\n\n diagnostics.emittedPageChunks.push({\n page: chunk.page,\n fileName,\n sizeBytes: chunk.sizeBytes,\n });\n diagnostics.emittedCssChunks.push(\n toEmittedChunk(chunk, fileName, false),\n );\n\n if (chunk.splitDueToSize) {\n diagnostics.sizeBudget.splitChunks += 1;\n }\n\n if (chunk.oversized) {\n diagnostics.sizeBudget.oversizedChunks += 1;\n }\n }\n\n file.sizeAfterBytes = commonWasSplit\n ? commonSize\n : Buffer.byteLength(embeddedCommon?.css ?? \"\", \"utf8\");\n file.deadCodeCount = pipeline.deadCodeCount;\n diagnostics.deadCodeSelectorsCount += pipeline.deadCodeCount;\n diagnostics.commonCssBytes += commonSize;\n diagnostics.pageSpecificCssBytes += pageSpecificSize;\n diagnostics.totalOriginalSize += file.sizeBeforeBytes;\n diagnostics.totalOptimizedSize += commonSize + pageSpecificSize;\n\n for (const stat of pipeline.stats) {\n const previous = matrix.get(stat.selector);\n\n if (!previous || stat.totalOccurrences > previous.totalOccurrences) {\n matrix.set(stat.selector, stat);\n }\n }\n } catch (error) {\n file.error = describeError(error);\n diagnostics.failedCssAssets += 1;\n diagnostics.errors.push(`${asset.name}: ${file.error}`);\n logger.warn(`[css-doctor] ${asset.name}: ${file.error}`);\n }\n\n diagnostics.analyzedCssAssets += 1;\n diagnostics.totalSelectors += file.selectorCount;\n diagnostics.totalRules += file.ruleCount;\n diagnostics.files.push(file);\n }\n\n if (pageFiles.size > 0) {\n injectPageCssLoaders(\n compilation,\n pageFiles,\n new Map(pagesResult.pages.map((page) => [page.name, page])),\n RawSource,\n );\n }\n\n diagnostics.chunks = diagnostics.emittedCssChunks.map(toChunkInfo);\n diagnostics.usageMatrix = [...matrix.values()].sort((left, right) =>\n left.selector.localeCompare(right.selector),\n );\n diagnostics.durationMs = roundMs(performance.now() - startedAt);\n\n if (\n this.options.report &&\n (diagnostics.totalCssAssets > 0 || diagnostics.errors.length > 0)\n ) {\n try {\n printReport(diagnostics);\n } catch (error) {\n logger.warn(`[css-doctor] reporter failed: ${describeError(error)}`);\n }\n }\n }\n\n private shouldSkipAsset(assetName: string, source: string): boolean {\n if (/\\.module\\.(css|scss|sass|less|styl|stylus)$/i.test(assetName)) {\n return true;\n }\n\n // Rspack may hash CSS Modules assets so the original `.module.css` name is\n // no longer present. Next/Rsbuild default local identifiers use `_local__hash`.\n if (/\\.[A-Za-z0-9_-]+_[A-Za-z0-9_-]+__[A-Za-z0-9_-]+/.test(source)) {\n return true;\n }\n\n // Rsbuild/Rspack default CSS Modules local identifiers are\n // `<local>-<6-char-hash>`, e.g. `.card-Glm32v`.\n if (hasRsbuildCssModuleClass(source)) {\n return true;\n }\n\n if (this.options.include.length > 0) {\n if (!matchesPatterns(assetName, this.options.include)) {\n return true;\n }\n }\n\n return (\n this.options.exclude.length > 0 &&\n matchesPatterns(assetName, this.options.exclude)\n );\n }\n}\n\nfunction createDiagnostic(\n fileName: string,\n css: string,\n associatedPages: string[],\n): CssAssetDiagnostic {\n return {\n fileName,\n sizeBeforeBytes: Buffer.byteLength(css, \"utf8\"),\n sizeAfterBytes: Buffer.byteLength(css, \"utf8\"),\n selectorCount: 0,\n ruleCount: 0,\n associatedPages,\n deadCodeCount: 0,\n };\n}\n\nfunction toEmittedChunk(\n chunk: JsChunkOutput,\n fileName: string,\n embedded: boolean,\n): EmittedCssChunk {\n return {\n name: chunk.name,\n fileName,\n sourceChunk: chunk.sourceChunk,\n kind: chunk.kind as EmittedCssChunk[\"kind\"],\n page: chunk.page,\n size: chunk.sizeBytes,\n isVariableChunk: chunk.variables,\n isPartChunk: chunk.part !== undefined,\n embedded,\n oversized: chunk.oversized,\n splitDueToSize: chunk.splitDueToSize,\n };\n}\n\nfunction toChunkInfo(chunk: EmittedCssChunk): ChunkInfo {\n return {\n name: chunk.name,\n size: chunk.size,\n isVariableChunk: chunk.isVariableChunk,\n isPartChunk: chunk.isPartChunk,\n };\n}\n\nasync function collectPages(compilation: Compilation): Promise<PagesResult> {\n const pages: PageInfo[] = [];\n const pagesByCss = new Map<string, Set<string>>();\n const sourceCache = new Map<string, Promise<string | undefined>>();\n const entrypoints = compilation.entrypoints as ReadonlyMap<\n string,\n RspackEntrypointLike\n >;\n\n for (const [entryName, entry] of entrypoints) {\n const pageName = normalizePageName(entryName);\n const page: PageInfo = {\n name: pageName,\n classes: new Set<string>(),\n cssFiles: new Set<string>(),\n jsFiles: new Set<string>(),\n };\n\n const files = entryFiles(entry);\n for (const file of files) {\n if (file.endsWith(\".css\")) {\n if (!/\\.module\\.(css|scss|sass|less|styl|stylus)$/i.test(file)) {\n page.cssFiles.add(file);\n }\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const chunk of entry.chunks ?? []) {\n for (const file of chunk.files ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const module of chunkModules(compilation, chunk)) {\n await scanModule(module, page.classes, sourceCache);\n }\n }\n\n for (const cssFile of page.cssFiles) {\n const owners = pagesByCss.get(cssFile) ?? new Set<string>();\n owners.add(pageName);\n pagesByCss.set(cssFile, owners);\n }\n\n pages.push(page);\n }\n\n if (pages.length === 0) {\n pages.push({\n name: \"main\",\n classes: new Set<string>(),\n cssFiles: new Set<string>(),\n jsFiles: new Set<string>(),\n });\n }\n\n // Rsbuild SPA apps have one entrypoint and route pages in async chunks.\n // Replace the shell-only page with page chunks when they are discoverable.\n if (entrypoints.size === 1 && pages.length === 1) {\n const shell = pages[0];\n const entryChunks = new Set<RspackChunkLike>();\n\n for (const [, entry] of entrypoints) {\n for (const chunk of entry.chunks ?? []) {\n entryChunks.add(chunk);\n }\n }\n\n const pageChunks = findPageChunks(compilation, entryChunks);\n\n if (pageChunks.length > 0 && shell) {\n pages.length = 0;\n pagesByCss.clear();\n\n for (const { chunk: pageChunk, name: pageName } of pageChunks) {\n const page: PageInfo = {\n name: pageName,\n classes: new Set(shell.classes),\n cssFiles: new Set(shell.cssFiles),\n jsFiles: new Set<string>(),\n };\n\n for (const file of pageChunk.files ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const file of pageChunk.auxiliaryFiles ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n }\n }\n\n for (const module of chunkModules(compilation, pageChunk)) {\n await scanModule(module, page.classes, sourceCache);\n }\n\n for (const cssFile of page.cssFiles) {\n const owners = pagesByCss.get(cssFile) ?? new Set<string>();\n owners.add(pageName);\n pagesByCss.set(cssFile, owners);\n }\n\n pages.push(page);\n }\n }\n }\n\n return { pages, pagesByCss };\n}\n\ntype PageChunk = {\n chunk: RspackChunkLike;\n name: string;\n};\n\nfunction findPageChunks(\n compilation: Compilation,\n entryChunks: Set<RspackChunkLike>,\n): PageChunk[] {\n const pages = new Map<RspackChunkLike, string>();\n const chunkGraph = compilation.chunkGraph as unknown as {\n getModuleChunksIterable: (\n module: RspackModuleLike,\n ) => Iterable<RspackChunkLike>;\n };\n const modules = compilation.modules as unknown as Iterable<RspackModuleLike>;\n\n for (const module of modules) {\n const pageName = pageNameFromModule(module);\n\n if (!pageName) {\n continue;\n }\n\n for (const chunk of chunkGraph.getModuleChunksIterable(module)) {\n if (!entryChunks.has(chunk) && !pages.has(chunk)) {\n pages.set(chunk, pageName);\n }\n }\n }\n\n const chunks = compilation.chunks as unknown as Iterable<RspackChunkLike>;\n\n for (const chunk of chunks) {\n if (entryChunks.has(chunk) || pages.has(chunk)) {\n continue;\n }\n\n const pageName = findPageName(compilation, chunk);\n\n if (pageName) {\n pages.set(chunk, pageName);\n }\n }\n\n return [...pages].map(([chunk, name]) => ({ chunk, name }));\n}\n\nfunction pageNameFromModule(module: RspackModuleLike): string | null {\n const resource = module.resource?.split(\"?\")[0] ?? module.resource;\n const match = resource?.match(/\\/pages\\/([^/]+?)\\.(?:tsx?|jsx?)$/i);\n\n if (match?.[1]) {\n return normalizePageName(match[1]).replace(/^page-/i, \"\") || \"page\";\n }\n\n for (const child of module.modules ?? []) {\n const pageName = pageNameFromModule(child);\n\n if (pageName) {\n return pageName;\n }\n }\n\n return null;\n}\nfunction findPageName(\n compilation: Compilation,\n chunk: RspackChunkLike,\n): string | null {\n for (const module of chunkModules(compilation, chunk)) {\n const pageName = pageNameFromModule(module);\n\n if (pageName) {\n return pageName;\n }\n }\n\n const name = chunk.name;\n\n if (name && /^page-/i.test(name)) {\n return normalizePageName(name).replace(/^page-/i, \"\") || \"page\";\n }\n\n return null;\n}\n\nfunction entryFiles(entry: RspackEntrypointLike): Set<string> {\n const files = new Set<string>();\n\n if (typeof entry.getFiles === \"function\") {\n for (const file of entry.getFiles()) {\n files.add(file);\n }\n }\n\n return files;\n}\n\nfunction chunkModules(\n compilation: Compilation,\n chunk: RspackChunkLike,\n): Iterable<RspackModuleLike> {\n const chunkGraph = compilation.chunkGraph as unknown as {\n getChunkModulesIterable: (chunk: unknown) => Iterable<RspackModuleLike>;\n };\n\n try {\n return chunkGraph.getChunkModulesIterable(chunk);\n } catch {\n return [];\n }\n}\n\nasync function scanModule(\n module: RspackModuleLike,\n classes: Set<string>,\n sourceCache: Map<string, Promise<string | undefined>>,\n): Promise<void> {\n const nested = module.modules;\n\n if (nested) {\n for (const child of nested) {\n await scanModule(child, classes, sourceCache);\n }\n }\n\n const resource = module.resource;\n\n if (resource && isStyleFile(resource)) {\n return;\n }\n\n const source = readModuleSource(module);\n\n if (source) {\n scanClasses(source, classes);\n return;\n }\n\n if (!resource) {\n return;\n }\n\n const filePath = resource.split(\"?\")[0];\n\n if (!filePath) {\n return;\n }\n\n let pending = sourceCache.get(filePath);\n\n if (!pending) {\n pending = readFile(filePath, \"utf8\").catch(() => undefined);\n sourceCache.set(filePath, pending);\n }\n\n const fresh = await pending;\n\n if (fresh) {\n scanClasses(fresh, classes);\n }\n}\n\nfunction readModuleSource(module: RspackModuleLike): string | undefined {\n try {\n const source = module.originalSource?.();\n\n if (!source) {\n return undefined;\n }\n\n return sourceToString(source.source());\n } catch {\n return undefined;\n }\n}\n\nfunction scanClasses(source: string, classes: Set<string>): void {\n const patterns = [\n /(?:class|className)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n /(?:^|[,{;\\s])(?:class|className)\\s*:\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n /classList\\.(?:add|remove|toggle|contains)\\(\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n ];\n\n for (const pattern of patterns) {\n for (const match of source.matchAll(pattern)) {\n const value = match[1] ?? match[2] ?? match[3];\n\n if (!value) {\n continue;\n }\n\n for (const token of value.split(/\\s+/)) {\n if (/^-?[_a-zA-Z][\\w-]*$/.test(token)) {\n classes.add(token.toLowerCase());\n }\n }\n }\n }\n}\n\nfunction injectPageCssLoaders(\n compilation: Compilation,\n cssByPage: Map<string, string[]>,\n pageByName: Map<string, PageInfo>,\n RawSource: new (source: string) => unknown,\n): void {\n const publicPath = compilation.options.output.publicPath;\n const base =\n typeof publicPath === \"string\" && publicPath.length > 0 ? publicPath : \"/\";\n const normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n\n for (const [page, files] of cssByPage) {\n const jsFiles = pageByName.get(page)?.jsFiles;\n\n if (!jsFiles || files.length === 0) {\n continue;\n }\n\n const hrefs = files.map((file) => `${normalizedBase}${file}`);\n const snippet = `(()=>{const __cssDoctorPageStyles=${JSON.stringify(hrefs)};if(typeof document!==\"undefined\"){for(const __cssDoctorPageHref of __cssDoctorPageStyles){if(!Array.from(document.querySelectorAll(\"link[data-css-doctor-page]\")).some((link)=>link.dataset.cssDoctorPage===__cssDoctorPageHref)){const __cssDoctorPageLink=document.createElement(\"link\");__cssDoctorPageLink.rel=\"stylesheet\";__cssDoctorPageLink.href=__cssDoctorPageHref;__cssDoctorPageLink.dataset.cssDoctorPage=__cssDoctorPageHref;document.head.append(__cssDoctorPageLink);}}}})();\\n`;\n\n for (const jsFile of jsFiles) {\n const asset = compilation.getAsset(jsFile);\n\n if (!asset) {\n continue;\n }\n\n compilation.updateAsset(\n jsFile,\n new RawSource(snippet + sourceToString(asset.source.source())) as never,\n );\n }\n }\n}\n\nfunction normalizePageName(name: string): string {\n const normalized = name.trim();\n\n if (!normalized) {\n return \"main\";\n }\n\n return (\n normalized\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"main\"\n );\n}\n\nfunction isStyleFile(filePath: string): boolean {\n return /\\.(css|scss|sass|less|styl|stylus)(\\?|$)/i.test(filePath);\n}\n\nfunction hasRsbuildCssModuleClass(css: string): boolean {\n const pattern =\n /\\.([A-Za-z_][A-Za-z0-9_-]*-[A-Za-z0-9]{6})(?=[\\s,{:.#>+~[])/g;\n\n for (const match of css.matchAll(pattern)) {\n const className = match[1];\n\n if (className && isRsbuildCssModuleClass(className)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction isRsbuildCssModuleClass(className: string): boolean {\n const hash = className.split(\"-\").at(-1) ?? \"\";\n\n return hash.length === 6 && /[A-Z]/.test(hash) && /[0-9]/.test(hash);\n}\n\nfunction collectCssModuleClasses(css: string): string[] {\n const classes = new Set<string>();\n const pattern =\n /\\.([A-Za-z_][A-Za-z0-9_-]*-[A-Za-z0-9]{6})(?=[\\s,{:.#>+~[])/g;\n\n for (const match of css.matchAll(pattern)) {\n const className = match[1];\n\n if (className && isRsbuildCssModuleClass(className)) {\n classes.add(className.toLowerCase());\n }\n }\n\n return [...classes];\n}\n\nfunction withCommonClasses(\n pageUsage: Record<string, string[]>,\n classes: string[],\n): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n\n for (const [page, pageClasses] of Object.entries(pageUsage)) {\n result[page] = [...new Set([...pageClasses, ...classes])];\n }\n\n return result;\n}\n\nfunction matchesPatterns(\n value: string,\n patterns: Array<string | RegExp>,\n): boolean {\n return patterns.some((pattern) =>\n typeof pattern === \"string\" ? value.includes(pattern) : pattern.test(value),\n );\n}\n\nfunction sourceToString(source: unknown): string {\n if (typeof source === \"string\") {\n return source;\n }\n\n if (source instanceof Uint8Array) {\n return Buffer.from(source).toString(\"utf8\");\n }\n\n return String(source);\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction roundMs(value: number): number {\n return Math.round(value * 10) / 10;\n}\n","import pc from \"picocolors\";\n\nimport type { CssDoctorRsbuildDiagnostics } from \"./types\";\n\nexport function printReport(diagnostics: CssDoctorRsbuildDiagnostics): void {\n const status = diagnostics.minify\n ? pc.green(\"Minified: YES\")\n : pc.yellow(\"Minified: NO\");\n const lines = [\n \"\",\n `${pc.cyan(pc.bold(\"[css-doctor]\"))} ${pc.bold(\"Rsbuild\")} ${pc.dim(\"·\")} ${\n diagnostics.pages.length\n } pages ${pc.dim(\"·\")} ${diagnostics.analyzedCssAssets}/${\n diagnostics.totalCssAssets\n } CSS assets ${pc.dim(\"·\")} ${formatBytes(\n diagnostics.totalOriginalSize,\n )} ${pc.dim(\"→\")} ${formatBytes(diagnostics.totalOptimizedSize)} ${pc.dim(\n \"·\",\n )} ${formatDuration(diagnostics.durationMs)} ${pc.dim(\"·\")} ${status}`,\n ];\n\n for (const file of diagnostics.files) {\n if (file.error) {\n lines.push(\n ` ${pc.red(\"✗\")} ${pc.magenta(file.fileName)} ${pc.red(file.error)}`,\n );\n continue;\n }\n\n lines.push(\n ` ${pc.green(\"✓\")} ${pc.magenta(file.fileName)} ${pc.dim(\n `${formatBytes(file.sizeBeforeBytes)} → ${formatBytes(\n file.sizeAfterBytes,\n )}`,\n )} ${pc.dim(\"·\")} ${file.selectorCount} selectors ${pc.dim(\n \"·\",\n )} pages: ${file.associatedPages.join(\", \") || \"none\"}`,\n );\n lines.push(\n ` split common ${formatBytes(\n file.sizeAfterBytes,\n )} ${pc.dim(\"·\")} dead ${file.deadCodeCount}`,\n );\n }\n\n if (diagnostics.emittedPageChunks.length > 0) {\n lines.push(\"\");\n lines.push(\n ` ${pc.bold(`Emitted page chunks (${diagnostics.emittedPageChunks.length})`)}`,\n );\n\n for (const chunk of diagnostics.emittedPageChunks) {\n lines.push(\n ` ${pc.magenta(chunk.fileName)} ${pc.dim(formatBytes(chunk.sizeBytes))}`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n ` ${pc.bold(\"Size budget\")} ${pc.dim(\n `(max ${formatBytes(diagnostics.sizeBudget.maxChunkSize)} · variables ${\n diagnostics.sizeBudget.isolateVariables ? \"isolated\" : \"inline\"\n })`,\n )}`,\n );\n\n if (diagnostics.emittedCssChunks.length === 0) {\n lines.push(` ${pc.dim(\"No CSS chunks were emitted.\")}`);\n } else {\n for (const chunk of diagnostics.emittedCssChunks) {\n const markers: string[] = [];\n\n if (chunk.isVariableChunk) {\n markers.push(\"vars\");\n }\n\n if (chunk.isPartChunk) {\n markers.push(\"part\");\n }\n\n if (chunk.embedded) {\n markers.push(\"embedded\");\n }\n\n if (chunk.splitDueToSize) {\n markers.push(pc.yellow(\"split\"));\n }\n\n if (chunk.oversized) {\n markers.push(pc.red(\"oversized\"));\n }\n\n lines.push(\n ` ${pc.magenta(chunk.fileName)} ${pc.dim(\n formatBytes(chunk.size),\n )}${markers.length > 0 ? ` ${pc.dim(\"·\")} ${markers.join(\" · \")}` : \"\"}`,\n );\n }\n }\n\n if (diagnostics.deadCodeSelectorsCount > 0) {\n lines.push(\"\");\n lines.push(\n ` ${pc.yellow(\n `⚠ Dead code eliminated: ${diagnostics.deadCodeSelectorsCount} selector occurrences`,\n )}`,\n );\n }\n\n if (diagnostics.errors.length > 0) {\n lines.push(\"\");\n for (const error of diagnostics.errors) {\n lines.push(` ${pc.red(`✗ ${error}`)}`);\n }\n }\n\n console.log(lines.join(\"\\n\"));\n}\n\nfunction formatDuration(milliseconds: number): string {\n if (milliseconds < 1) {\n return \"<1 ms\";\n }\n\n return `${milliseconds.toFixed(1)} ms`;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n\n return `${(bytes / 1024).toFixed(1)} KB`;\n}\n","import type { RsbuildPlugin } from \"@rsbuild/core\";\n\nimport { CssDoctorRspackPlugin } from \"./rspack-plugin\";\nimport type { CssDoctorRsbuildOptions } from \"./types\";\n\n/**\n * Adds the css-doctor Rspack plugin to production Rsbuild builds.\n */\nexport const pluginCssDoctor = (\n options: CssDoctorRsbuildOptions = {},\n): RsbuildPlugin => ({\n name: \"css-doctor:rsbuild\",\n apply: \"build\",\n setup(api) {\n if (api.context.bundlerType !== \"rspack\") {\n return;\n }\n\n api.modifyRspackConfig((config, { isProd }) => {\n if (!isProd || process.env.NODE_ENV !== \"production\") {\n return;\n }\n\n config.plugins ??= [];\n config.plugins.push(new CssDoctorRspackPlugin(options));\n });\n },\n});\n\nexport type * from \"./types\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/rspack-plugin.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { posix } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { analyzeCss, optimizeCss } from \"@zealakit/css-doctor-binding\";\nimport type {\n JsChunkOutput,\n JsSelectorStat,\n} from \"@zealakit/css-doctor-binding\";\nimport type { Compilation, Compiler } from \"@rspack/core\";\n\nimport { printReport } from \"./reporter\";\nimport type {\n ChunkInfo,\n CssAssetDiagnostic,\n CssDoctorRsbuildDiagnostics,\n CssDoctorRsbuildOptions,\n EmittedCssChunk,\n PageCoverageOptions,\n SizeBudgetOptions,\n} from \"./types\";\n\nconst PLUGIN_NAME = \"css-doctor:rsbuild\";\nconst DEFAULT_MIN_PAGE_RATIO = 0.5;\nconst DEFAULT_MAX_CHUNK_SIZE = 60 * 1_024;\n\ntype RspackChunkLike = {\n name?: string;\n files?: Iterable<string>;\n auxiliaryFiles?: Iterable<string>;\n};\n\ntype RspackEntrypointLike = {\n name?: string;\n chunks?: Iterable<RspackChunkLike>;\n getFiles?: () => Iterable<string>;\n};\n\ntype RspackModuleLike = {\n resource?: string;\n modules?: Iterable<RspackModuleLike>;\n originalSource?: () => { source: () => unknown } | null;\n};\n\ntype PageInfo = {\n name: string;\n classes: Set<string>;\n cssFiles: Set<string>;\n jsFiles: Set<string>;\n};\n\ntype PagesResult = {\n pages: PageInfo[];\n pagesByCss: Map<string, Set<string>>;\n};\n\ntype ResolvedOptions = {\n pageCoverage: Required<PageCoverageOptions> & { forceCommon: string[] };\n sizeBudget: Required<SizeBudgetOptions>;\n minify: boolean;\n report: boolean;\n include: Array<string | RegExp>;\n exclude: Array<string | RegExp>;\n};\n\n/**\n * Rspack compilation plugin that runs the css-doctor two-tier pipeline for\n * global CSS assets. CSS Modules assets are deliberately skipped.\n */\nexport class CssDoctorRspackPlugin {\n private readonly options: ResolvedOptions;\n private readonly configurationWarnings: string[] = [];\n\n constructor(options: CssDoctorRsbuildOptions = {}) {\n const configuredMinPageRatio =\n options.pageCoverage?.minPageRatio ?? DEFAULT_MIN_PAGE_RATIO;\n const configuredMaxChunkSize =\n options.sizeBudget?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\n const minPageRatio =\n Number.isFinite(configuredMinPageRatio) &&\n configuredMinPageRatio >= 0 &&\n configuredMinPageRatio <= 1\n ? configuredMinPageRatio\n : DEFAULT_MIN_PAGE_RATIO;\n const maxChunkSize =\n Number.isInteger(configuredMaxChunkSize) && configuredMaxChunkSize > 0\n ? configuredMaxChunkSize\n : DEFAULT_MAX_CHUNK_SIZE;\n\n if (minPageRatio !== configuredMinPageRatio) {\n this.configurationWarnings.push(\n \"minPageRatio must be a number between 0 and 1; using 0.5\",\n );\n }\n\n if (maxChunkSize !== configuredMaxChunkSize) {\n this.configurationWarnings.push(\n \"maxChunkSize must be a positive integer; using 61440\",\n );\n }\n\n this.options = {\n pageCoverage: {\n enabled: options.pageCoverage?.enabled ?? true,\n minPageRatio,\n forceCommon: options.pageCoverage?.forceCommon ?? [],\n },\n sizeBudget: {\n enabled: options.sizeBudget?.enabled ?? true,\n maxChunkSize,\n isolateVariables: options.sizeBudget?.isolateVariables ?? true,\n },\n minify: options.minify ?? true,\n report: options.report ?? true,\n include: options.include ?? [],\n exclude: options.exclude ?? [],\n };\n }\n\n apply(compiler: Compiler): void {\n compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {\n compilation.hooks.processAssets.tapPromise(\n {\n name: PLUGIN_NAME,\n stage: compiler.rspack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,\n },\n async () => {\n try {\n await this.process(compiler, compilation);\n } catch (error) {\n compilation\n .getLogger(PLUGIN_NAME)\n .warn(\n `[css-doctor] diagnostics failed without interrupting the build: ${describeError(\n error,\n )}`,\n );\n }\n },\n );\n });\n }\n\n private async process(\n compiler: Compiler,\n compilation: Compilation,\n ): Promise<void> {\n const startedAt = performance.now();\n const logger = compilation.getLogger(PLUGIN_NAME);\n for (const warning of this.configurationWarnings) {\n logger.warn(`[css-doctor] ${warning}`);\n }\n const pagesResult = await collectPages(compilation);\n const pageNames = pagesResult.pages.map((page) => page.name);\n const allPages = new Set(pageNames);\n const pageUsage: Record<string, string[]> = {};\n const pageUsageCounts: Record<string, number> = {};\n\n for (const page of pagesResult.pages) {\n const classes = [...page.classes].sort();\n pageUsage[page.name] = classes;\n pageUsageCounts[page.name] = classes.length;\n }\n\n const hasPageClasses = pagesResult.pages.some(\n (page) => page.classes.size > 0,\n );\n const pageCoverageApplied =\n this.options.pageCoverage.enabled && hasPageClasses;\n const diagnostics: CssDoctorRsbuildDiagnostics = {\n plugin: PLUGIN_NAME,\n generatedAt: new Date().toISOString(),\n durationMs: 0,\n totalOriginalSize: 0,\n totalOptimizedSize: 0,\n deadCodeSelectorsCount: 0,\n chunks: [],\n minify: this.options.minify,\n pages: pageNames,\n pageUsage: pageUsageCounts,\n splitApplied: pageCoverageApplied,\n totalCssAssets: 0,\n analyzedCssAssets: 0,\n skippedCssAssets: 0,\n failedCssAssets: 0,\n totalSelectors: 0,\n totalRules: 0,\n commonCssBytes: 0,\n pageSpecificCssBytes: 0,\n emittedPageChunks: [],\n emittedCssChunks: [],\n sizeBudget: {\n enabled: this.options.sizeBudget.enabled,\n maxChunkSize: this.options.sizeBudget.maxChunkSize,\n isolateVariables: this.options.sizeBudget.isolateVariables,\n splitChunks: 0,\n oversizedChunks: 0,\n },\n usageMatrix: [],\n files: [],\n errors: [],\n };\n\n const matrix = new Map<string, JsSelectorStat>();\n const pageFiles = new Map<string, string[]>();\n const usedAssetNames = new Set(\n compilation.getAssets().map((asset) => asset.name),\n );\n const RawSource = compiler.rspack.sources.RawSource;\n\n const emitCssChunk = (chunk: JsChunkOutput): string => {\n const hash = createHash(\"sha256\")\n .update(chunk.css)\n .digest(\"hex\")\n .slice(0, 8);\n const safeName =\n chunk.name\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"chunk\";\n let fileName = `static/css/${safeName}.${hash}.css`;\n let index = 2;\n\n while (usedAssetNames.has(fileName)) {\n fileName = `static/css/${safeName}.${hash}-${index}.css`;\n index += 1;\n }\n\n compilation.emitAsset(fileName, new RawSource(chunk.css));\n usedAssetNames.add(fileName);\n return fileName;\n };\n\n for (const asset of compilation.getAssets()) {\n if (!asset.name.endsWith(\".css\")) {\n continue;\n }\n\n diagnostics.totalCssAssets += 1;\n\n if (\n this.shouldSkipAsset(asset.name, sourceToString(asset.source.source()))\n ) {\n diagnostics.skippedCssAssets += 1;\n continue;\n }\n\n const associatedPages = [\n ...(pagesResult.pagesByCss.get(asset.name) ?? allPages),\n ].sort();\n const originalCss = sourceToString(asset.source.source());\n const file = createDiagnostic(asset.name, originalCss, associatedPages);\n\n try {\n const analysis = analyzeCss(originalCss);\n file.selectorCount = analysis.stats.selectorCount;\n file.ruleCount = analysis.stats.ruleCount;\n const moduleClasses = collectCssModuleClasses(originalCss);\n const assetPageUsage =\n moduleClasses.length > 0\n ? withCommonClasses(pageUsage, moduleClasses)\n : pageUsage;\n const pipeline = optimizeCss({\n cssContent: originalCss,\n pageUsage: assetPageUsage,\n pageCoverage: {\n enabled: pageCoverageApplied,\n minPageRatio: this.options.pageCoverage.minPageRatio,\n forceCommon: this.options.pageCoverage.forceCommon,\n },\n sizeBudget: {\n enabled: this.options.sizeBudget.enabled,\n maxChunkSize: this.options.sizeBudget.maxChunkSize,\n isolateVariables: this.options.sizeBudget.isolateVariables,\n },\n minify: this.options.minify,\n });\n\n const commonChunks = pipeline.chunks.filter(\n (chunk) => chunk.page === undefined && chunk.sourceChunk === \"common\",\n );\n const pageChunks = pipeline.chunks.filter(\n (chunk) =>\n chunk.page !== undefined &&\n (associatedPages.includes(chunk.page) ||\n !pagesResult.pagesByCss.has(asset.name)),\n );\n const commonWasSplit =\n commonChunks.length > 1 ||\n commonChunks.some((chunk) => chunk.splitDueToSize);\n const embeddedCommon = commonWasSplit ? undefined : commonChunks[0];\n const commonFileNames: string[] = [];\n let commonSize = 0;\n\n for (const chunk of commonChunks) {\n const embedded = chunk === embeddedCommon;\n const fileName = embedded ? asset.name : emitCssChunk(chunk);\n commonSize += chunk.sizeBytes;\n commonFileNames.push(fileName);\n\n diagnostics.emittedCssChunks.push(\n toEmittedChunk(chunk, fileName, embedded),\n );\n\n if (chunk.splitDueToSize) {\n diagnostics.sizeBudget.splitChunks += 1;\n }\n\n if (chunk.oversized) {\n diagnostics.sizeBudget.oversizedChunks += 1;\n }\n }\n\n if (commonWasSplit) {\n const imports = commonFileNames\n .map((fileName) => {\n const relativePath = posix.relative(\n posix.dirname(asset.name),\n fileName,\n );\n return `@import \"./${relativePath}\";`;\n })\n .join(\"\\n\");\n compilation.updateAsset(asset.name, new RawSource(imports));\n } else {\n compilation.updateAsset(\n asset.name,\n new RawSource(embeddedCommon?.css ?? \"\"),\n );\n }\n\n let pageSpecificSize = 0;\n\n for (const chunk of pageChunks) {\n if (!chunk.page) {\n continue;\n }\n\n const fileName = emitCssChunk(chunk);\n pageSpecificSize += chunk.sizeBytes;\n const files = pageFiles.get(chunk.page) ?? [];\n files.push(fileName);\n pageFiles.set(chunk.page, files);\n\n diagnostics.emittedPageChunks.push({\n page: chunk.page,\n fileName,\n sizeBytes: chunk.sizeBytes,\n });\n diagnostics.emittedCssChunks.push(\n toEmittedChunk(chunk, fileName, false),\n );\n\n if (chunk.splitDueToSize) {\n diagnostics.sizeBudget.splitChunks += 1;\n }\n\n if (chunk.oversized) {\n diagnostics.sizeBudget.oversizedChunks += 1;\n }\n }\n\n file.sizeAfterBytes = commonWasSplit\n ? commonSize\n : Buffer.byteLength(embeddedCommon?.css ?? \"\", \"utf8\");\n file.deadCodeCount = pipeline.deadCodeCount;\n diagnostics.deadCodeSelectorsCount += pipeline.deadCodeCount;\n diagnostics.commonCssBytes += commonSize;\n diagnostics.pageSpecificCssBytes += pageSpecificSize;\n diagnostics.totalOriginalSize += file.sizeBeforeBytes;\n diagnostics.totalOptimizedSize += commonSize + pageSpecificSize;\n\n for (const stat of pipeline.stats) {\n const previous = matrix.get(stat.selector);\n\n if (!previous || stat.totalOccurrences > previous.totalOccurrences) {\n matrix.set(stat.selector, stat);\n }\n }\n } catch (error) {\n file.error = describeError(error);\n diagnostics.failedCssAssets += 1;\n diagnostics.errors.push(`${asset.name}: ${file.error}`);\n logger.warn(`[css-doctor] ${asset.name}: ${file.error}`);\n }\n\n diagnostics.analyzedCssAssets += 1;\n diagnostics.totalSelectors += file.selectorCount;\n diagnostics.totalRules += file.ruleCount;\n diagnostics.files.push(file);\n }\n\n if (pageFiles.size > 0) {\n injectPageCssLoaders(\n compilation,\n pageFiles,\n new Map(pagesResult.pages.map((page) => [page.name, page])),\n RawSource,\n );\n }\n\n diagnostics.chunks = diagnostics.emittedCssChunks.map(toChunkInfo);\n diagnostics.usageMatrix = [...matrix.values()].sort((left, right) =>\n left.selector.localeCompare(right.selector),\n );\n diagnostics.durationMs = roundMs(performance.now() - startedAt);\n\n if (\n this.options.report &&\n (diagnostics.totalCssAssets > 0 || diagnostics.errors.length > 0)\n ) {\n try {\n printReport(diagnostics);\n } catch (error) {\n logger.warn(`[css-doctor] reporter failed: ${describeError(error)}`);\n }\n }\n }\n\n private shouldSkipAsset(assetName: string, source: string): boolean {\n if (/\\.module\\.(css|scss|sass|less|styl|stylus)$/i.test(assetName)) {\n return true;\n }\n\n // Rspack may hash CSS Modules assets so the original `.module.css` name is\n // no longer present. Next/Rsbuild default local identifiers use `_local__hash`.\n if (/\\.[A-Za-z0-9_-]+_[A-Za-z0-9_-]+__[A-Za-z0-9_-]+/.test(source)) {\n return true;\n }\n\n // Rsbuild/Rspack default CSS Modules local identifiers are\n // `<local>-<6-char-hash>`, e.g. `.card-Glm32v`.\n if (hasRsbuildCssModuleClass(source)) {\n return true;\n }\n\n if (this.options.include.length > 0) {\n if (!matchesPatterns(assetName, this.options.include)) {\n return true;\n }\n }\n\n return (\n this.options.exclude.length > 0 &&\n matchesPatterns(assetName, this.options.exclude)\n );\n }\n}\n\nfunction createDiagnostic(\n fileName: string,\n css: string,\n associatedPages: string[],\n): CssAssetDiagnostic {\n return {\n fileName,\n sizeBeforeBytes: Buffer.byteLength(css, \"utf8\"),\n sizeAfterBytes: Buffer.byteLength(css, \"utf8\"),\n selectorCount: 0,\n ruleCount: 0,\n associatedPages,\n deadCodeCount: 0,\n };\n}\n\nfunction toEmittedChunk(\n chunk: JsChunkOutput,\n fileName: string,\n embedded: boolean,\n): EmittedCssChunk {\n return {\n name: chunk.name,\n fileName,\n sourceChunk: chunk.sourceChunk,\n kind: chunk.kind as EmittedCssChunk[\"kind\"],\n page: chunk.page,\n size: chunk.sizeBytes,\n isVariableChunk: chunk.variables,\n isPartChunk: chunk.part !== undefined,\n embedded,\n oversized: chunk.oversized,\n splitDueToSize: chunk.splitDueToSize,\n };\n}\n\nfunction toChunkInfo(chunk: EmittedCssChunk): ChunkInfo {\n return {\n name: chunk.name,\n size: chunk.size,\n isVariableChunk: chunk.isVariableChunk,\n isPartChunk: chunk.isPartChunk,\n };\n}\n\nasync function collectPages(compilation: Compilation): Promise<PagesResult> {\n const pages: PageInfo[] = [];\n const pagesByCss = new Map<string, Set<string>>();\n const sourceCache = new Map<string, Promise<string | undefined>>();\n const entrypoints = compilation.entrypoints as ReadonlyMap<\n string,\n RspackEntrypointLike\n >;\n\n for (const [entryName, entry] of entrypoints) {\n const pageName = normalizePageName(entryName);\n const page: PageInfo = {\n name: pageName,\n classes: new Set<string>(),\n cssFiles: new Set<string>(),\n jsFiles: new Set<string>(),\n };\n\n const files = entryFiles(entry);\n for (const file of files) {\n if (file.endsWith(\".css\")) {\n if (!/\\.module\\.(css|scss|sass|less|styl|stylus)$/i.test(file)) {\n page.cssFiles.add(file);\n }\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const chunk of entry.chunks ?? []) {\n for (const file of chunk.files ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const module of chunkModules(compilation, chunk)) {\n await scanModule(module, page.classes, sourceCache);\n }\n }\n\n for (const cssFile of page.cssFiles) {\n const owners = pagesByCss.get(cssFile) ?? new Set<string>();\n owners.add(pageName);\n pagesByCss.set(cssFile, owners);\n }\n\n pages.push(page);\n }\n\n if (pages.length === 0) {\n pages.push({\n name: \"main\",\n classes: new Set<string>(),\n cssFiles: new Set<string>(),\n jsFiles: new Set<string>(),\n });\n }\n\n // Rsbuild SPA apps have one entrypoint and route pages in async chunks.\n // Replace the shell-only page with page chunks when they are discoverable.\n if (entrypoints.size === 1 && pages.length === 1) {\n const shell = pages[0];\n const entryChunks = new Set<RspackChunkLike>();\n\n for (const [, entry] of entrypoints) {\n for (const chunk of entry.chunks ?? []) {\n entryChunks.add(chunk);\n }\n }\n\n const pageChunks = findPageChunks(compilation, entryChunks);\n\n if (pageChunks.length > 0 && shell) {\n pages.length = 0;\n pagesByCss.clear();\n\n for (const { chunk: pageChunk, name: pageName } of pageChunks) {\n const page: PageInfo = {\n name: pageName,\n classes: new Set(shell.classes),\n cssFiles: new Set(shell.cssFiles),\n jsFiles: new Set<string>(),\n };\n\n for (const file of pageChunk.files ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n } else if (file.endsWith(\".js\")) {\n page.jsFiles.add(file);\n }\n }\n\n for (const file of pageChunk.auxiliaryFiles ?? []) {\n if (file.endsWith(\".css\")) {\n page.cssFiles.add(file);\n }\n }\n\n for (const module of chunkModules(compilation, pageChunk)) {\n await scanModule(module, page.classes, sourceCache);\n }\n\n for (const cssFile of page.cssFiles) {\n const owners = pagesByCss.get(cssFile) ?? new Set<string>();\n owners.add(pageName);\n pagesByCss.set(cssFile, owners);\n }\n\n pages.push(page);\n }\n }\n }\n\n return { pages, pagesByCss };\n}\n\ntype PageChunk = {\n chunk: RspackChunkLike;\n name: string;\n};\n\nfunction findPageChunks(\n compilation: Compilation,\n entryChunks: Set<RspackChunkLike>,\n): PageChunk[] {\n const pages = new Map<RspackChunkLike, string>();\n const chunkGraph = compilation.chunkGraph as unknown as {\n getModuleChunksIterable: (\n module: RspackModuleLike,\n ) => Iterable<RspackChunkLike>;\n };\n const modules = compilation.modules as unknown as Iterable<RspackModuleLike>;\n\n for (const module of modules) {\n const pageName = pageNameFromModule(module);\n\n if (!pageName) {\n continue;\n }\n\n for (const chunk of chunkGraph.getModuleChunksIterable(module)) {\n if (!entryChunks.has(chunk) && !pages.has(chunk)) {\n pages.set(chunk, pageName);\n }\n }\n }\n\n const chunks = compilation.chunks as unknown as Iterable<RspackChunkLike>;\n\n for (const chunk of chunks) {\n if (entryChunks.has(chunk) || pages.has(chunk)) {\n continue;\n }\n\n const pageName = findPageName(compilation, chunk);\n\n if (pageName) {\n pages.set(chunk, pageName);\n }\n }\n\n return [...pages].map(([chunk, name]) => ({ chunk, name }));\n}\n\nfunction pageNameFromModule(module: RspackModuleLike): string | null {\n const resource = module.resource?.split(\"?\")[0] ?? module.resource;\n const match = resource?.match(/\\/pages\\/([^/]+?)\\.(?:tsx?|jsx?)$/i);\n\n if (match?.[1]) {\n return normalizePageName(match[1]).replace(/^page-/i, \"\") || \"page\";\n }\n\n for (const child of module.modules ?? []) {\n const pageName = pageNameFromModule(child);\n\n if (pageName) {\n return pageName;\n }\n }\n\n return null;\n}\nfunction findPageName(\n compilation: Compilation,\n chunk: RspackChunkLike,\n): string | null {\n for (const module of chunkModules(compilation, chunk)) {\n const pageName = pageNameFromModule(module);\n\n if (pageName) {\n return pageName;\n }\n }\n\n const name = chunk.name;\n\n if (name && /^page-/i.test(name)) {\n return normalizePageName(name).replace(/^page-/i, \"\") || \"page\";\n }\n\n return null;\n}\n\nfunction entryFiles(entry: RspackEntrypointLike): Set<string> {\n const files = new Set<string>();\n\n if (typeof entry.getFiles === \"function\") {\n for (const file of entry.getFiles()) {\n files.add(file);\n }\n }\n\n return files;\n}\n\nfunction chunkModules(\n compilation: Compilation,\n chunk: RspackChunkLike,\n): Iterable<RspackModuleLike> {\n const chunkGraph = compilation.chunkGraph as unknown as {\n getChunkModulesIterable: (chunk: unknown) => Iterable<RspackModuleLike>;\n };\n\n try {\n return chunkGraph.getChunkModulesIterable(chunk);\n } catch {\n return [];\n }\n}\n\nasync function scanModule(\n module: RspackModuleLike,\n classes: Set<string>,\n sourceCache: Map<string, Promise<string | undefined>>,\n): Promise<void> {\n const nested = module.modules;\n\n if (nested) {\n for (const child of nested) {\n await scanModule(child, classes, sourceCache);\n }\n }\n\n const resource = module.resource;\n\n if (resource && isStyleFile(resource)) {\n return;\n }\n\n const source = readModuleSource(module);\n\n if (source) {\n scanClasses(source, classes);\n return;\n }\n\n if (!resource) {\n return;\n }\n\n const filePath = resource.split(\"?\")[0];\n\n if (!filePath) {\n return;\n }\n\n let pending = sourceCache.get(filePath);\n\n if (!pending) {\n pending = readFile(filePath, \"utf8\").catch(() => undefined);\n sourceCache.set(filePath, pending);\n }\n\n const fresh = await pending;\n\n if (fresh) {\n scanClasses(fresh, classes);\n }\n}\n\nfunction readModuleSource(module: RspackModuleLike): string | undefined {\n try {\n const source = module.originalSource?.();\n\n if (!source) {\n return undefined;\n }\n\n return sourceToString(source.source());\n } catch {\n return undefined;\n }\n}\n\nfunction scanClasses(source: string, classes: Set<string>): void {\n const patterns = [\n /(?:class|className)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n /(?:^|[,{;\\s])(?:class|className)\\s*:\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n /classList\\.(?:add|remove|toggle|contains)\\(\\s*(?:\"([^\"]*)\"|'([^']*)'|`([^`]*)`)/g,\n ];\n\n for (const pattern of patterns) {\n for (const match of source.matchAll(pattern)) {\n const value = match[1] ?? match[2] ?? match[3];\n\n if (!value) {\n continue;\n }\n\n for (const token of value.split(/\\s+/)) {\n if (isClassToken(token)) {\n classes.add(token.toLowerCase());\n }\n }\n }\n }\n}\n\n/** Accept Tailwind-style tokens (`md:flex`, `w-1/2`, `w-[10px]`, `!p-2`). */\nfunction isClassToken(token: string): boolean {\n if (!token || token.length > 256) {\n return false;\n }\n\n if (/[`${}]/.test(token)) {\n return false;\n }\n\n return /[A-Za-z_]/.test(token);\n}\n\nfunction injectPageCssLoaders(\n compilation: Compilation,\n cssByPage: Map<string, string[]>,\n pageByName: Map<string, PageInfo>,\n RawSource: new (source: string) => unknown,\n): void {\n const publicPath = compilation.options.output.publicPath;\n const base =\n typeof publicPath === \"string\" && publicPath.length > 0 ? publicPath : \"/\";\n const normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n\n for (const [page, files] of cssByPage) {\n const jsFiles = pageByName.get(page)?.jsFiles;\n\n if (!jsFiles || files.length === 0) {\n continue;\n }\n\n const hrefs = files.map((file) => `${normalizedBase}${file}`);\n const snippet = `(()=>{const __cssDoctorPageStyles=${JSON.stringify(hrefs)};if(typeof document!==\"undefined\"){for(const __cssDoctorPageHref of __cssDoctorPageStyles){if(!Array.from(document.querySelectorAll(\"link[data-css-doctor-page]\")).some((link)=>link.dataset.cssDoctorPage===__cssDoctorPageHref)){const __cssDoctorPageLink=document.createElement(\"link\");__cssDoctorPageLink.rel=\"stylesheet\";__cssDoctorPageLink.href=__cssDoctorPageHref;__cssDoctorPageLink.dataset.cssDoctorPage=__cssDoctorPageHref;document.head.append(__cssDoctorPageLink);}}}})();\\n`;\n\n for (const jsFile of jsFiles) {\n const asset = compilation.getAsset(jsFile);\n\n if (!asset) {\n continue;\n }\n\n compilation.updateAsset(\n jsFile,\n new RawSource(snippet + sourceToString(asset.source.source())) as never,\n );\n }\n }\n}\n\nfunction normalizePageName(name: string): string {\n const normalized = name.trim();\n\n if (!normalized) {\n return \"main\";\n }\n\n return (\n normalized\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"main\"\n );\n}\n\nfunction isStyleFile(filePath: string): boolean {\n return /\\.(css|scss|sass|less|styl|stylus)(\\?|$)/i.test(filePath);\n}\n\nfunction hasRsbuildCssModuleClass(css: string): boolean {\n const pattern =\n /\\.([A-Za-z_][A-Za-z0-9_-]*-[A-Za-z0-9]{6})(?=[\\s,{:.#>+~[])/g;\n\n for (const match of css.matchAll(pattern)) {\n const className = match[1];\n\n if (className && isRsbuildCssModuleClass(className)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction isRsbuildCssModuleClass(className: string): boolean {\n const hash = className.split(\"-\").at(-1) ?? \"\";\n\n return hash.length === 6 && /[A-Z]/.test(hash) && /[0-9]/.test(hash);\n}\n\nfunction collectCssModuleClasses(css: string): string[] {\n const classes = new Set<string>();\n const pattern =\n /\\.([A-Za-z_][A-Za-z0-9_-]*-[A-Za-z0-9]{6})(?=[\\s,{:.#>+~[])/g;\n\n for (const match of css.matchAll(pattern)) {\n const className = match[1];\n\n if (className && isRsbuildCssModuleClass(className)) {\n classes.add(className.toLowerCase());\n }\n }\n\n return [...classes];\n}\n\nfunction withCommonClasses(\n pageUsage: Record<string, string[]>,\n classes: string[],\n): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n\n for (const [page, pageClasses] of Object.entries(pageUsage)) {\n result[page] = [...new Set([...pageClasses, ...classes])];\n }\n\n return result;\n}\n\nfunction matchesPatterns(\n value: string,\n patterns: Array<string | RegExp>,\n): boolean {\n return patterns.some((pattern) =>\n typeof pattern === \"string\" ? value.includes(pattern) : pattern.test(value),\n );\n}\n\nfunction sourceToString(source: unknown): string {\n if (typeof source === \"string\") {\n return source;\n }\n\n if (source instanceof Uint8Array) {\n return Buffer.from(source).toString(\"utf8\");\n }\n\n return String(source);\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction roundMs(value: number): number {\n return Math.round(value * 10) / 10;\n}\n","import pc from \"picocolors\";\n\nimport type { CssDoctorRsbuildDiagnostics } from \"./types\";\n\nexport function printReport(diagnostics: CssDoctorRsbuildDiagnostics): void {\n const status = diagnostics.minify\n ? pc.green(\"Minified: YES\")\n : pc.yellow(\"Minified: NO\");\n const lines = [\n \"\",\n `${pc.cyan(pc.bold(\"[css-doctor]\"))} ${pc.bold(\"Rsbuild\")} ${pc.dim(\"·\")} ${\n diagnostics.pages.length\n } pages ${pc.dim(\"·\")} ${diagnostics.analyzedCssAssets}/${\n diagnostics.totalCssAssets\n } CSS assets ${pc.dim(\"·\")} ${formatBytes(\n diagnostics.totalOriginalSize,\n )} ${pc.dim(\"→\")} ${formatBytes(diagnostics.totalOptimizedSize)} ${pc.dim(\n \"·\",\n )} ${formatDuration(diagnostics.durationMs)} ${pc.dim(\"·\")} ${status}`,\n ];\n\n for (const file of diagnostics.files) {\n if (file.error) {\n lines.push(\n ` ${pc.red(\"✗\")} ${pc.magenta(file.fileName)} ${pc.red(file.error)}`,\n );\n continue;\n }\n\n lines.push(\n ` ${pc.green(\"✓\")} ${pc.magenta(file.fileName)} ${pc.dim(\n `${formatBytes(file.sizeBeforeBytes)} → ${formatBytes(\n file.sizeAfterBytes,\n )}`,\n )} ${pc.dim(\"·\")} ${file.selectorCount} selectors ${pc.dim(\n \"·\",\n )} pages: ${file.associatedPages.join(\", \") || \"none\"}`,\n );\n lines.push(\n ` split common ${formatBytes(\n file.sizeAfterBytes,\n )} ${pc.dim(\"·\")} dead ${file.deadCodeCount}`,\n );\n }\n\n if (diagnostics.emittedPageChunks.length > 0) {\n lines.push(\"\");\n lines.push(\n ` ${pc.bold(`Emitted page chunks (${diagnostics.emittedPageChunks.length})`)}`,\n );\n\n for (const chunk of diagnostics.emittedPageChunks) {\n lines.push(\n ` ${pc.magenta(chunk.fileName)} ${pc.dim(formatBytes(chunk.sizeBytes))}`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n ` ${pc.bold(\"Size budget\")} ${pc.dim(\n `(max ${formatBytes(diagnostics.sizeBudget.maxChunkSize)} · variables ${\n diagnostics.sizeBudget.isolateVariables ? \"isolated\" : \"inline\"\n })`,\n )}`,\n );\n\n if (diagnostics.emittedCssChunks.length === 0) {\n lines.push(` ${pc.dim(\"No CSS chunks were emitted.\")}`);\n } else {\n for (const chunk of diagnostics.emittedCssChunks) {\n const markers: string[] = [];\n\n if (chunk.isVariableChunk) {\n markers.push(\"vars\");\n }\n\n if (chunk.isPartChunk) {\n markers.push(\"part\");\n }\n\n if (chunk.embedded) {\n markers.push(\"embedded\");\n }\n\n if (chunk.splitDueToSize) {\n markers.push(pc.yellow(\"split\"));\n }\n\n if (chunk.oversized) {\n markers.push(pc.red(\"oversized\"));\n }\n\n lines.push(\n ` ${pc.magenta(chunk.fileName)} ${pc.dim(\n formatBytes(chunk.size),\n )}${markers.length > 0 ? ` ${pc.dim(\"·\")} ${markers.join(\" · \")}` : \"\"}`,\n );\n }\n }\n\n if (diagnostics.deadCodeSelectorsCount > 0) {\n lines.push(\"\");\n lines.push(\n ` ${pc.yellow(\n `⚠ Dead code eliminated: ${diagnostics.deadCodeSelectorsCount} selector occurrences`,\n )}`,\n );\n }\n\n if (diagnostics.errors.length > 0) {\n lines.push(\"\");\n for (const error of diagnostics.errors) {\n lines.push(` ${pc.red(`✗ ${error}`)}`);\n }\n }\n\n console.log(lines.join(\"\\n\"));\n}\n\nfunction formatDuration(milliseconds: number): string {\n if (milliseconds < 1) {\n return \"<1 ms\";\n }\n\n return `${milliseconds.toFixed(1)} ms`;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n\n return `${(bytes / 1024).toFixed(1)} KB`;\n}\n","import type { RsbuildPlugin } from \"@rsbuild/core\";\n\nimport { CssDoctorRspackPlugin } from \"./rspack-plugin\";\nimport type { CssDoctorRsbuildOptions } from \"./types\";\n\n/**\n * Adds the css-doctor Rspack plugin to production Rsbuild builds.\n */\nexport const pluginCssDoctor = (\n options: CssDoctorRsbuildOptions = {},\n): RsbuildPlugin => ({\n name: \"css-doctor:rsbuild\",\n apply: \"build\",\n setup(api) {\n if (api.context.bundlerType !== \"rspack\") {\n return;\n }\n\n api.modifyRspackConfig((config, { isProd }) => {\n if (!isProd || process.env.NODE_ENV !== \"production\") {\n return;\n }\n\n config.plugins ??= [];\n config.plugins.push(new CssDoctorRspackPlugin(options));\n });\n },\n});\n\nexport type * from \"./types\";\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zealakit/css-doctor-rsbuild",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Rsbuild/Rspack integration for css-doctor page-coverage and size-budget CSS splitting",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css",
|
|
7
|
+
"css-doctor",
|
|
8
|
+
"rsbuild",
|
|
9
|
+
"rspack",
|
|
10
|
+
"rsbuild-plugin",
|
|
11
|
+
"rspack-plugin",
|
|
12
|
+
"webpack",
|
|
13
|
+
"bundler",
|
|
14
|
+
"css-analysis",
|
|
15
|
+
"css-optimizer",
|
|
16
|
+
"dead-code-elimination",
|
|
17
|
+
"unused-css",
|
|
18
|
+
"purgecss",
|
|
19
|
+
"css-splitting",
|
|
20
|
+
"page-coverage",
|
|
21
|
+
"size-budget",
|
|
22
|
+
"performance",
|
|
23
|
+
"web-performance",
|
|
24
|
+
"frontend",
|
|
25
|
+
"build-tool"
|
|
26
|
+
],
|
|
5
27
|
"author": "nqhed - Huy Edward Nguyen",
|
|
6
28
|
"type": "module",
|
|
7
29
|
"license": "MIT",
|
|
@@ -21,8 +43,8 @@
|
|
|
21
43
|
"README_CN.md"
|
|
22
44
|
],
|
|
23
45
|
"dependencies": {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
46
|
+
"@zealakit/css-doctor-binding": "1.1.0",
|
|
47
|
+
"picocolors": "^1.1.1"
|
|
26
48
|
},
|
|
27
49
|
"peerDependencies": {
|
|
28
50
|
"@rsbuild/core": ">=1.0.0"
|