diff --git a/README.md b/README.md index 898ff286..8cc85309 100644 --- a/README.md +++ b/README.md @@ -591,6 +591,12 @@ npm install --save-dev @size-limit/file npx size-limit --limit "10 kB" dist/bundle.js ``` +Additionally, you can specify a custom path to your configuration file when running the CLI: + +```sh +npx size-limit --config src/configs/your-config.{m,c}?{js,ts,json} +``` + [Statoscope docs]: https://github.com/statoscope/statoscope/tree/master/packages/webpack-plugin#optionsreports-report [pattern]: https://github.com/SuperchupuDev/tinyglobby diff --git a/fixtures/config-file-from-arg/index.js b/fixtures/config-file-from-arg/index.js new file mode 100644 index 00000000..d1bdfc55 --- /dev/null +++ b/fixtures/config-file-from-arg/index.js @@ -0,0 +1,5 @@ +const first = 'first' + +const second = 'second' + +export { first, second } diff --git a/fixtures/config-file-from-arg/package.json b/fixtures/config-file-from-arg/package.json new file mode 100644 index 00000000..c8a12af8 --- /dev/null +++ b/fixtures/config-file-from-arg/package.json @@ -0,0 +1,17 @@ +{ + "private": true, + "name": "config-file-from-arg", + "devDependencies": { + "@size-limit/file": ">= 0.0.0", + "size-limit": ">= 0.0.0" + }, + "size-limit": [ + { + "path": [ + "a.js", + "b.js" + ], + "import": "a" + } + ] +} diff --git a/fixtures/config-file-from-arg/src/configs/my-size-limit.config.js b/fixtures/config-file-from-arg/src/configs/my-size-limit.config.js new file mode 100644 index 00000000..737046b9 --- /dev/null +++ b/fixtures/config-file-from-arg/src/configs/my-size-limit.config.js @@ -0,0 +1,12 @@ +export default [ + { + path: '../../index.js', + limit: 10, + name: 'index' + }, + { + path: '../main.js', + limit: 20, + name: 'main' + } +] diff --git a/fixtures/config-file-from-arg/src/main.js b/fixtures/config-file-from-arg/src/main.js new file mode 100644 index 00000000..371fdfb1 --- /dev/null +++ b/fixtures/config-file-from-arg/src/main.js @@ -0,0 +1 @@ +console.log('hello') diff --git a/packages/size-limit/get-config.js b/packages/size-limit/get-config.js index 872eccf2..22c8415f 100644 --- a/packages/size-limit/get-config.js +++ b/packages/size-limit/get-config.js @@ -1,7 +1,7 @@ import bytes from 'bytes-iec' import { lilconfig } from 'lilconfig' import { createRequire } from 'node:module' -import { dirname, isAbsolute, join, relative } from 'node:path' +import { dirname, isAbsolute, join, relative, resolve } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import { glob } from 'tinyglobby' @@ -147,7 +147,9 @@ export default async function getConfig(plugins, process, args, pkg) { '.size-limit.cts' ] }) - let result = await explorer.search(process.cwd()) + let result = args.config?.trim() + ? await explorer.load(resolve(args.config.trim())) + : await explorer.search(process.cwd()) if (result === null) throw new SizeLimitError('noConfig') checkChecks(plugins, result.config) diff --git a/packages/size-limit/parse-args.js b/packages/size-limit/parse-args.js index 3848e69e..b02d4b4c 100644 --- a/packages/size-limit/parse-args.js +++ b/packages/size-limit/parse-args.js @@ -63,6 +63,12 @@ export default function parseArgs(plugins, argv) { throw new SizeLimitError('argWithoutParameter', 'compare-with', 'FILE') } args.compareWith = nextArg + } else if (arg === '--config') { + let nextArg = argv[++i] + if (!nextArg || nextArg.startsWith('--')) { + throw new SizeLimitError('argWithoutParameter', 'config', 'FILE') + } + args.config = nextArg } else if (arg === '--watch') { /* c8 ignore next */ args.watch = true diff --git a/packages/size-limit/test/__snapshots__/run.test.js.snap b/packages/size-limit/test/__snapshots__/run.test.js.snap index 9bb7e6b4..1cb1f668 100644 --- a/packages/size-limit/test/__snapshots__/run.test.js.snap +++ b/packages/size-limit/test/__snapshots__/run.test.js.snap @@ -397,6 +397,16 @@ exports[`throws on --compare-with argument without webpack 1`] = ` " `; +exports[`throws on --config argument without FILE parameter 1`] = ` +" ERROR  Missing parameter FILE for --config argument +" +`; + +exports[`throws on --config argument without FILE parameter 2`] = ` +" ERROR  Missing parameter FILE for --config argument +" +`; + exports[`throws on --save-bundle argument without DIR parameter 1`] = ` " ERROR  Missing parameter DIR for --save-bundle argument " diff --git a/packages/size-limit/test/get-config.test.js b/packages/size-limit/test/get-config.test.js index 0b287cb1..43a9182c 100644 --- a/packages/size-limit/test/get-config.test.js +++ b/packages/size-limit/test/get-config.test.js @@ -1,4 +1,4 @@ -import { join } from 'node:path' +import { dirname, join } from 'node:path' import { beforeEach, describe, expect, it, vi } from 'vitest' import calc from '../calc' @@ -429,6 +429,31 @@ it('normalizes import', async () => { }) }) +it('takes config from CLI config argument', async () => { + let cwd = 'config-file-from-arg' + let configPath = 'src/configs/my-size-limit.config.js' + expect(await check(cwd, ['--config', fixture(cwd, configPath)])).toEqual({ + checks: [ + { + files: [fixture(cwd, 'index.js')], + limit: 10, + name: 'index', + path: '../../index.js', + sizeLimit: 10 + }, + { + files: [fixture(cwd, 'src/main.js')], + limit: 20, + name: 'main', + path: '../main.js', + sizeLimit: 20 + } + ], + configPath, + cwd: fixture(cwd, dirname(configPath)) + }) +}) + const allConfigFileExtensions = ['mjs', 'js', 'cjs', 'ts', 'mts', 'cts'] const exportTypes = [ { exportSyntax: 'export default', moduleType: 'esm' }, diff --git a/packages/size-limit/test/run.test.js b/packages/size-limit/test/run.test.js index ce5b6b21..5f9d449f 100644 --- a/packages/size-limit/test/run.test.js +++ b/packages/size-limit/test/run.test.js @@ -200,6 +200,23 @@ it('throws on --compare-with argument without value', async () => { expect(await error('webpack', ['--why', '--compare-with'])).toMatchSnapshot() }) +it('throws on --config argument without FILE parameter', async () => { + expect(await error('file', ['--config'])).toMatchSnapshot() + expect(await error('file', ['--config', '--why'])).toMatchSnapshot() +}) + +it('throws on --config argument with invalid FILE parameter', async () => { + expect(await error('file', ['--config', 'invalid/config/path'])).toContain( + 'no such file or directory' + ) +}) + +it('throws on --config argument with invalid FILE extension', async () => { + expect( + await error('file', ['--config', 'invalid/config/path.extension']) + ).toContain('No loader specified for extension') +}) + it('throws on no config', async () => { expect(await error('file')).toMatchSnapshot() })