diff --git a/examples/bundlesize/bundlesize.config.js b/examples/bundlesize/bundlesize.config.js index dd6b097f..e8ad1b04 100644 --- a/examples/bundlesize/bundlesize.config.js +++ b/examples/bundlesize/bundlesize.config.js @@ -1,6 +1,6 @@ +// @ts-check +/** @type {import('@node-cli/bundlesize').BundlesizeConfig} */ export default { - $schema: - "https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json", report: { // header: "## My custom header", // footer: (limitReached, diff) => diff --git a/packages/bundlesize/README.md b/packages/bundlesize/README.md index ee42a44e..452bc1ec 100644 --- a/packages/bundlesize/README.md +++ b/packages/bundlesize/README.md @@ -14,14 +14,16 @@ A configuration file must be provided via the `-c` parameter. -### JSON Schema Support +### Type-Safe Configuration -For IDE autocompletion and validation, you can add a `$schema` property to your configuration file: +For IDE autocompletion and validation, you can use either JSDoc type hints or the `defineConfig` helper function. + +#### Using JSDoc (recommended for JavaScript configs) ```js +// @ts-check +/** @type {import('@node-cli/bundlesize').BundlesizeConfig} */ export default { - $schema: - "https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json", sizes: [ { path: "dist/bundle.js", @@ -31,19 +33,29 @@ export default { }; ``` -This provides: +#### Using defineConfig helper -- Autocompletion for configuration options -- Inline documentation for each property -- Validation of configuration values - -**Note**: For a specific version of the schema, use: +```js +// @ts-check +import { defineConfig } from "@node-cli/bundlesize"; -``` -https://cdn.jsdelivr.net/npm/@node-cli/bundlesize@VERSION/schemas/bundlesize.config.schema.json +export default defineConfig({ + sizes: [ + { + path: "dist/bundle.js", + limit: "10 kB" + } + ] +}); ``` -### Configuration Options +Both approaches provide: + +- Autocompletion for configuration options +- Inline documentation for each property +- Type validation in your IDE + +**Note**: The `// @ts-check` comment enables TypeScript checking for the file, which is required for validation errors to appear. ### Configuration Options diff --git a/packages/bundlesize/bundlesize.config.js b/packages/bundlesize/bundlesize.config.js index 98cde0c0..28d5cc55 100644 --- a/packages/bundlesize/bundlesize.config.js +++ b/packages/bundlesize/bundlesize.config.js @@ -1,6 +1,6 @@ +// @ts-check +/** @type {import('./src/config.ts').BundlesizeConfig} */ export default { - $schema: - "https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json", sizes: [ { path: "dist/bundlesize.js", diff --git a/packages/bundlesize/package.json b/packages/bundlesize/package.json index 708ecac7..be8cfd1d 100644 --- a/packages/bundlesize/package.json +++ b/packages/bundlesize/package.json @@ -6,11 +6,15 @@ "description": "Simple CLI tool that checks file(s) size and report if limits have been reached", "type": "module", "types": "./dist/index.d.ts", - "exports": "./dist/bundlesize.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/config.js" + } + }, "bin": "dist/bundlesize.js", "files": [ "dist", - "schemas", "README.md" ], "node": ">=18", diff --git a/packages/bundlesize/schemas/bundlesize.config.schema.json b/packages/bundlesize/schemas/bundlesize.config.schema.json deleted file mode 100644 index c17e9605..00000000 --- a/packages/bundlesize/schemas/bundlesize.config.schema.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json", - "title": "Bundlesize Configuration", - "description": "Configuration schema for @node-cli/bundlesize - a CLI tool that checks file(s) size and reports if limits have been reached", - "type": "object", - "properties": { - "$schema": { - "type": "string", - "description": "Path to the JSON Schema for this configuration file" - }, - "sizes": { - "type": "array", - "description": "Array of file size entries to check", - "items": { - "oneOf": [ - { - "$ref": "#/$defs/SizeEntry" - }, - { - "$ref": "#/$defs/HeaderEntry" - } - ] - } - }, - "report": { - "$ref": "#/$defs/ReportConfiguration" - } - }, - "additionalProperties": false, - "$defs": { - "SizeEntry": { - "type": "object", - "description": "A file size entry to check", - "properties": { - "path": { - "type": "string", - "description": "Path to the file to check. Supports glob patterns and special placeholders: for content hashes, for semantic versions" - }, - "limit": { - "type": "string", - "description": "Maximum allowed size for the file (gzipped). Examples: '1.5 kB', '500 B', '2 MB'", - "pattern": "^[0-9]+(\\.[0-9]+)?\\s*(B|kB|KB|MB|GB|TB|PB)$" - }, - "alias": { - "type": "string", - "description": "Optional alias for the file in reports. Useful when using dynamic path patterns" - } - }, - "required": ["path", "limit"], - "additionalProperties": false - }, - "HeaderEntry": { - "type": "object", - "description": "A header entry for grouping files in reports", - "properties": { - "header": { - "type": "string", - "description": "Header text for a group of files in the report (e.g., '### Main Bundle')" - } - }, - "required": ["header"], - "additionalProperties": false - }, - "ColumnDefinition": { - "type": "object", - "description": "A column definition for the report table", - "minProperties": 1, - "maxProperties": 1, - "additionalProperties": { - "type": "string", - "description": "Column header text" - } - }, - "ReportConfiguration": { - "type": "object", - "description": "Configuration for generating size comparison reports", - "properties": { - "current": { - "type": "string", - "description": "Path to the current stats JSON file (relative to config file)" - }, - "previous": { - "type": "string", - "description": "Path to the previous stats JSON file for comparison (relative to config file)" - }, - "header": { - "type": "string", - "description": "Custom header for the report. Defaults to '## Bundle Size'" - }, - "threshold": { - "type": "number", - "description": "Minimum byte difference to report as a change. Differences below this threshold are treated as no change. Defaults to 0", - "minimum": 0 - }, - "columns": { - "type": "array", - "description": "Custom column definitions for the report table. Default columns: status, file, size, limits", - "items": { - "$ref": "#/$defs/ColumnDefinition" - }, - "examples": [ - [ - { "status": "Status" }, - { "file": "File" }, - { "size": "Size (Gzip)" }, - { "limits": "Limits" } - ] - ] - } - }, - "required": ["current", "previous"], - "additionalProperties": true - } - }, - "examples": [ - { - "sizes": [ - { - "path": "dist/index.js", - "limit": "10 kB" - }, - { - "path": "dist/vendor..js", - "limit": "50 kB", - "alias": "vendor" - } - ] - }, - { - "sizes": [ - { "header": "### Core" }, - { - "path": "dist/core.js", - "limit": "5 kB" - }, - { "header": "### Plugins" }, - { - "path": "dist/plugins/*.js", - "limit": "2 kB" - } - ], - "report": { - "current": "stats/current.json", - "previous": "stats/previous.json", - "header": "## Bundle Size Report", - "threshold": 100 - } - } - ] -} diff --git a/packages/bundlesize/src/config.ts b/packages/bundlesize/src/config.ts new file mode 100644 index 00000000..9c0a9404 --- /dev/null +++ b/packages/bundlesize/src/config.ts @@ -0,0 +1,111 @@ +import type { FooterProperties } from "./utilities.js"; + +/** + * Configuration for a single file size entry. + */ +export interface SizeEntry { + /** + * Path to the file to check. Supports glob patterns. + * Special placeholders: + * - ``: matches content hashes (e.g., `bundle-.js`) + * - ``: matches semantic versions (e.g., `lib-.js`) + */ + path: string; + /** + * Maximum allowed size for the file (gzipped). + * Format: number followed by unit (B, kB, KB, MB, GB, TB, PB) + * @example "10 kB", "1.5 MB", "500 B" + */ + limit: string; + /** + * Optional alias for the file in reports. + * Useful for giving meaningful names to files with hash patterns. + */ + alias?: string; +} + +/** + * Configuration for a header entry (group separator in reports). + */ +export interface HeaderEntry { + /** + * Header text to display as a group separator in reports. + */ + header: string; +} + +/** + * Column definition for the report table. + */ +export interface ColumnDefinition { + [key: string]: string; +} + +/** + * Configuration for generating comparison reports. + */ +export interface ReportConfiguration { + /** + * Path to the current stats JSON file (relative to config file). + */ + current: string; + /** + * Path to the previous stats JSON file for comparison (relative to config file). + */ + previous: string; + /** + * Custom header text for the report. + * @default "## Bundle Size" + */ + header?: string; + /** + * Custom footer function for the report. + * Receives an object with limitReached, overallDiff, and totalGzipSize. + */ + footer?: (args: FooterProperties) => string; + /** + * Column definitions for the report table. + * @default [{ status: "Status" }, { file: "File" }, { size: "Size (Gzip)" }, { limits: "Limits" }] + */ + columns?: ColumnDefinition[]; + /** + * Minimum gzip size change in bytes to consider as a change. + * Changes below this threshold are treated as no change. + * @default 0 + */ + threshold?: number; +} + +/** + * Bundlesize configuration object. + */ +export interface BundlesizeConfig { + /** + * Array of file size entries to check. + * Each entry can be either a SizeEntry (file to check) or HeaderEntry (group separator). + */ + sizes?: (SizeEntry | HeaderEntry)[]; + /** + * Configuration for generating comparison reports. + */ + report?: ReportConfiguration; +} + +/** + * Helper function to define bundlesize configuration with full type support. + * Provides IntelliSense and type checking for configuration files. + * + * @example + * ```js + * import { defineConfig } from "@node-cli/bundlesize"; + * + * export default defineConfig({ + * sizes: [ + * { path: "dist/bundle.js", limit: "10 kB" } + * ] + * }); + * ``` + */ +export function defineConfig(config: BundlesizeConfig): BundlesizeConfig { + return config; +}