Skip to content

Commit

Permalink
feat: custom path labels (#194)
Browse files Browse the repository at this point in the history
  • Loading branch information
LironEr authored Jan 29, 2024
1 parent eed6989 commit 05dbcd0
Show file tree
Hide file tree
Showing 18 changed files with 372 additions and 78 deletions.
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ BundleMon helps you achieve that by constantly monitoring your bundle size on ev
## Setup

```
npm install bundlemon@next --save-dev
npm install bundlemon --save-dev
# or
yarn add bundlemon@next --dev
yarn add bundlemon --dev
```

Add `bundlemon` property to your `package.json`
Expand All @@ -64,16 +64,17 @@ Add `bundlemon` property to your `package.json`

BundleMon config can be placed in other places like: `.bundlemonrc`, `.bundlemonrc.json`, `bundlemon.config.js` exporting a JS object, more forms can be found [here](https://github.com/davidtheclark/cosmiconfig)

| Name | Description | Type | Default |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | --------------- |
| baseDir | Relative/absolute path to the directory | `string` | `process.cwd()` |
| files | [Files config](./docs/types.md#File) | `FileConfig[]` | - |
| groups | Sum all file sizes matching the pattern, rules applies to the sum of the files [Groups config](./docs/types.md#File) | `FileConfig[]` | - |
| defaultCompression | Use compression before calculating file size | `"none"` \| `"gzip"` \| `"brotli"` | `"gzip"` |
| reportOutput | [Output options](./docs/output.md) | `(string \| [string, object])[]` | [] |
| verbose | Print more details | `boolean` | `false` |
| subProject | By setting sub project you can use the same project id for multiple projects. This can be useful for monorepos. Can be set/overwrite with `BUNDLEMON_SUB_PROJECT` env var | `string` | `undefined` |
| includeCommitMessage | Include commit message when saving records | `boolean` | `false` |
| Name | Description | Type | Default |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------- |
| baseDir | Relative/absolute path to the directory | `string` | `process.cwd()` |
| files | [Files config](./docs/types.md#File) | `FileConfig[]` | - |
| groups | Sum all file sizes matching the pattern, rules applies to the sum of the files [Groups config](./docs/types.md#File) | `FileConfig[]` | - |
| defaultCompression | Use compression before calculating file size | `"none"` \| `"gzip"` \| `"brotli"` | `"gzip"` |
| reportOutput | [Output options](./docs/output.md) | `(string \| [string, object])[]` | [] |
| verbose | Print more details | `boolean` | `false` |
| subProject | By setting sub project you can use the same project id for multiple projects. This can be useful for monorepos. Can be set/overwrite with `BUNDLEMON_SUB_PROJECT` env var | `string` | `undefined` |
| includeCommitMessage | Include commit message when saving records | `boolean` | `false` |
| pathLabels | More info [here](#path-labels) | `Record<string, string>` | `{ "hash": "[a-zA-Z0-9]+" }` |

## CLI usage

Expand All @@ -85,7 +86,7 @@ bundlemon --config my-custom-config-path.json

[CLI flags docs](./docs/cli-flags.md)

## Using hash in file names?
## Path labels

When using hash in file names the file name can be changed every build.

Expand All @@ -102,7 +103,7 @@ bundle.ea45e578.js

Config:

```
```json
"bundlemon": {
"baseDir": "./build",
"files": [
Expand All @@ -124,6 +125,9 @@ Output:
[PASS] login.(hash).chunk.js: 3.37KB < 50KB
```

> [!TIP]
> You can customize the default labels and add more labels, more info [here](docs/customPathLabels.md)
## BundleMon Project

In order to save history and get differences from your main branches BundleMon will need a project id.
Expand Down
52 changes: 52 additions & 0 deletions docs/customPathLabels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Custom Path Labels

By default path labels replace only `<hash>`, but you can customize it and add more labels by defining `pathLabels` in your config.

### Default labels:

```json
{
"pathLabels": {
"hash": "[a-zA-Z0-9]+"
}
}
```

### Adding more labels:

```json
{
"baseDir": "./build",
"pathLabels": {
"chunkId": "[\\w-]+"
},
"files": [
{
"path": "*.<hash>.chunk.<chunkId>.js"
},
{
"path": "*.<hash>.js"
}
]
}
```

### Customizing and adding more labels:

```json
{
"baseDir": "./build",
"pathLabels": {
"hash": "[a-z]+",
"chunkId": "[\\w-]+"
},
"files": [
{
"path": "*.<hash>.chunk.<chunkId>.js"
},
{
"path": "*.<hash>.js"
}
]
}
```
2 changes: 1 addition & 1 deletion packages/bundlemon/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bundlemon",
"version": "2.0.2",
"version": "2.1.0",
"description": "Monitor your bundle size",
"keywords": [
"bundle",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ exports[`consts default snapshot 1`] = `
"GithubActions": "GITHUB_ACTIONS",
"ProjectApiKey": "PROJECT_API_KEY",
},
"DEFAULT_PATH_LABELS": {
"hash": "[a-zA-Z0-9]+",
},
"EnvVar": {
"projectApiKey": "BUNDLEMON_PROJECT_APIKEY",
"projectId": "BUNDLEMON_PROJECT_ID",
Expand Down
6 changes: 6 additions & 0 deletions packages/bundlemon/src/common/consts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PathLabels } from '../main/types';

export enum EnvVar {
remoteFlag = 'BUNDLEMON_REMOTE',
projectId = 'BUNDLEMON_PROJECT_ID',
Expand All @@ -17,3 +19,7 @@ export enum CreateCommitRecordAuthType {
ProjectApiKey = 'PROJECT_API_KEY',
GithubActions = 'GITHUB_ACTIONS',
}

export const DEFAULT_PATH_LABELS: PathLabels = {
hash: '[a-zA-Z0-9]+',
};
30 changes: 22 additions & 8 deletions packages/bundlemon/src/main/__tests__/initializer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as fs from 'fs';
import { validateConfig } from '../utils/configUtils';
import { validateConfig, getNormalizedConfig } from '../utils/configUtils';
import { initializer } from '../initializer';
import { Config } from '../types';
import { initOutputs } from '../outputs';
Expand All @@ -20,49 +20,63 @@ describe('initializer', () => {
});

test('validate config failed', async () => {
const mockedValidateConfig = jest.mocked(validateConfig).mockResolvedValue(undefined);
const mockedValidateConfig = jest.mocked(validateConfig).mockReturnValue(undefined);

const result = await initializer(config);

expect(mockedValidateConfig).toHaveBeenCalledWith(config);
expect(result).toEqual(undefined);
});

test('get normalized config failed', async () => {
const mockedValidateConfig = jest.mocked(validateConfig).mockReturnValue(config);
const mockedGetNormalizedConfig = jest.mocked(getNormalizedConfig).mockResolvedValue(undefined);

const result = await initializer(config);

expect(mockedValidateConfig).toHaveBeenCalledWith(config);
expect(mockedGetNormalizedConfig).toHaveBeenCalledWith(config);
expect(result).toEqual(undefined);
});

test('base dir not found', async () => {
const expectedNormalizedConfig = generateNormalizedConfigRemoteOn();
const mockedValidateConfig = jest.mocked(validateConfig).mockResolvedValue(expectedNormalizedConfig);
jest.mocked(validateConfig).mockReturnValue(config);
const mockedGetNormalizedConfig = jest.mocked(getNormalizedConfig).mockResolvedValue(expectedNormalizedConfig);
const mockedExistsSync = jest.mocked(fs.existsSync).mockReturnValue(false);

const result = await initializer(config);

expect(mockedValidateConfig).toHaveBeenCalledWith(config);
expect(mockedGetNormalizedConfig).toHaveBeenCalledWith(config);
expect(mockedExistsSync).toHaveBeenCalledWith(expectedNormalizedConfig.baseDir);
expect(result).toEqual(undefined);
});

test('failed to initialize outputs', async () => {
const expectedNormalizedConfig = generateNormalizedConfigRemoteOn();
const mockedValidateConfig = jest.mocked(validateConfig).mockResolvedValue(expectedNormalizedConfig);
jest.mocked(validateConfig).mockReturnValue(config);
const mockedGetNormalizedConfig = jest.mocked(getNormalizedConfig).mockResolvedValue(expectedNormalizedConfig);
const mockedExistsSync = jest.mocked(fs.existsSync).mockReturnValue(true);
const mockedInitOutputs = jest.mocked(initOutputs).mockRejectedValue(new Error('error'));

const result = await initializer(config);

expect(mockedValidateConfig).toHaveBeenCalledWith(config);
expect(mockedGetNormalizedConfig).toHaveBeenCalledWith(config);
expect(mockedExistsSync).toHaveBeenCalledWith(expectedNormalizedConfig.baseDir);
expect(mockedInitOutputs).toHaveBeenCalledWith(expectedNormalizedConfig);
expect(result).toEqual(undefined);
});

test('success', async () => {
const expectedNormalizedConfig = generateNormalizedConfigRemoteOn();
const mockedValidateConfig = jest.mocked(validateConfig).mockResolvedValue(expectedNormalizedConfig);
jest.mocked(validateConfig).mockReturnValue(config);
const mockedGetNormalizedConfig = jest.mocked(getNormalizedConfig).mockResolvedValue(expectedNormalizedConfig);
const mockedExistsSync = jest.mocked(fs.existsSync).mockReturnValue(true);
const mockedInitOutputs = jest.mocked(initOutputs).mockResolvedValue();

const result = await initializer(config);

expect(mockedValidateConfig).toHaveBeenCalledWith(config);
expect(mockedGetNormalizedConfig).toHaveBeenCalledWith(config);
expect(mockedExistsSync).toHaveBeenCalledWith(expectedNormalizedConfig.baseDir);
expect(mockedInitOutputs).toHaveBeenCalledWith(expectedNormalizedConfig);
expect(result).toEqual(expectedNormalizedConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ exports[`getFiles getAllPaths empty directory 1`] = `[]`;

exports[`getFiles getRegexHash 1`] = `"(?<hash0>[a-zA-Z0-9]+)"`;
exports[`getFiles getRegexHash 2`] = `"(?<hash0>[a-zA-Z0-9]+)"`;
exports[`getFiles getRegexHash 2`] = `"(?<hash1>[a-zA-Z0-9]+)"`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getFilesDetails, groupFilesByPattern } from '../fileDetailsUtils';
import { NormalizedConfig, MatchFile } from '../../types';
import { NormalizedConfig, MatchFile, PathLabels } from '../../types';
import { getMatchFiles } from '../pathUtils';
import { getFileSize } from '../getFileSize';
import { Compression, FileDetails } from 'bundlemon-utils';
Expand All @@ -10,6 +10,10 @@ jest.mock('../../../common/logger');

describe('fileDetailsUtils', () => {
test('getFilesDetails', async () => {
const pathLabels: PathLabels = {
hash: '[a-zA-Z0-9]+',
};

const allFiles = ['css/a.css', 'some/path/a.hajdh22.js', 'some/path/b.hj23j2.js', 'logo.png'];
const matchFiles: Record<string, MatchFile[]> = {
'css/*.css': [{ fullPath: 'css/a.css', prettyPath: 'css/a.css' }],
Expand All @@ -35,7 +39,7 @@ describe('fileDetailsUtils', () => {
},
];

const result = await getFilesDetails({ baseDir, allFiles, config, stopOnMatch: true });
const result = await getFilesDetails({ baseDir, pathLabels, allFiles, config, stopOnMatch: true });

expect(mockedGetMatchFiles).toHaveBeenCalledTimes(1);
expect(mockedGetFileSize).toHaveBeenCalledTimes(3);
Expand Down
Loading

0 comments on commit 05dbcd0

Please sign in to comment.