{"id":19489375,"url":"https://github.com/salute-developers/perftool","last_synced_at":"2025-04-25T19:30:29.981Z","repository":{"id":65652542,"uuid":"593083767","full_name":"salute-developers/perftool","owner":"salute-developers","description":"Performance Testing Tool for React Components","archived":false,"fork":false,"pushed_at":"2024-12-30T09:42:10.000Z","size":3265,"stargazers_count":16,"open_issues_count":11,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-17T18:16:10.667Z","etag":null,"topics":["benchmark","github-actions","performance","performance-monitoring","performance-testing","react","testing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salute-developers.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-01-25T07:34:20.000Z","updated_at":"2025-04-09T10:23:50.000Z","dependencies_parsed_at":"2023-05-28T10:15:27.842Z","dependency_job_id":"1f831de2-1f15-4666-8303-8bb3967583ac","html_url":"https://github.com/salute-developers/perftool","commit_stats":{"total_commits":20,"total_committers":3,"mean_commits":6.666666666666667,"dds":0.55,"last_synced_commit":"031816c5b5af266634fdba2baef8bf2ec8fc9484"},"previous_names":[],"tags_count":72,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salute-developers%2Fperftool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salute-developers%2Fperftool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salute-developers%2Fperftool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salute-developers%2Fperftool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salute-developers","download_url":"https://codeload.github.com/salute-developers/perftool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250882380,"owners_count":21502300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmark","github-actions","performance","performance-monitoring","performance-testing","react","testing"],"created_at":"2024-11-10T21:08:20.263Z","updated_at":"2025-04-25T19:30:29.635Z","avatar_url":"https://github.com/salute-developers.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Performance Monitoring System for React Components\n\n[![NPM version](https://badge.fury.io/js/@salutejs%2Fperftool.svg)](https://www.npmjs.com/package/@salutejs/perftool)\n[![@salutejs/perftool](https://snyk.io/advisor/npm-package/@salutejs/perftool/badge.svg)](https://snyk.io/advisor/npm-package/@salutejs/perftool)\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](/LICENSE)\n\nKeep your components blazingly fast and ship your React app with no doubt.\n\n**🍌 Native Env**: benchmark your components in the environment they usually run in.\n\n**🎰 CI Ready**: get it to work in your Pull Requests, it's really built for that.\n\n**🎯 Stable Results** even in unsteady envs like GitHub runners and other virtual machines.\n\n## Table of Contents\n\n-   [Getting Started](#getting-started)\n-   [Configuration](#configuration)\n-   [Documentation](#documentation)\n-   [Supported environments](#supported-environments)\n-   [Contributing](#contributing)\n-   [License](#license)\n\n## Getting Started\n\nInstall Perftool using preferred package manager.\n\n```bash\n# Yarn\nyarn add --dev @salutejs/perftool\n```\n\n```bash\n# NPM\nnpm i -D @salutejs/perftool\n```\n\n```bash\n# PNPM\npnpm add -D @salutejs/perftool\n```\n\nLet's get started by writing a test for a component. First, create a `Component.tsx` module:\n\n```tsx\nimport React from 'react';\n\nconst Component = ({ prop }) =\u003e \u003cdiv style=\"color: red;\"\u003e{prop}\u003c/div\u003e;\n\nexport default Component;\n```\n\nThen, create a module `Component.perf.tsx`. This is an entrypoint for Perftool to obtain the component:\n\n```tsx\nimport React from 'react';\nimport Component from './Component';\n\nexport function Default() {\n    return \u003cComponent prop=\"value\" /\u003e;\n}\n```\n\nNow run Perftool in preview mode to test the build and check if the component renders correctly.\n\n```bash\nnpx perftool --preview *.perf.tsx\n```\n\nThen, we can proceed to the actual run with following command:\n\n```bash\nnpx perftool -o base.json *.perf.tsx\n```\n\nAfter Perftool finishes the run, `base.json` report file will appear in the current directory.\nNow let's change our component, so it takes noticeably more amount of time to render it:\n\n```tsx\nimport React from 'react';\n\nconst Component = ({ prop }) =\u003e (\n    \u003cdiv\u003e\n        {[...Array(1000)].map(() =\u003e (\n            \u003cdiv style=\"color: red;\"\u003e{prop}\u003c/div\u003e\n        ))}\n    \u003c/div\u003e\n);\n\nexport default Component;\n```\n\nRun Perftool one more time with changed output filename:\n\n```bash\nnpx perftool -o changed.json *.perf.tsx\n```\n\nAfter Perftool finishes the run, `changed.json` report file will appear in the current directory.\nFinally, let's do the comparison of our reports:\n\n```bash\nnpx perftool-compare -o result.json changed.json base.json\n```\n\nAfter Perftool does the comparison, `result.json` report file will appear in the current directory and an error will be thrown owing to bad significant change in the reported metrics.\n\n**🎉 Well done! You just successfully done your first performance test with Perftool!**\n\n## Configuration\n\nTo make an additional configuration, create `perftool.config.mts` file in the root of your project, or provide a config file path with `-c \u003cpath\u003e` option when running Perftool. Here's example config:\n\n```typescript\nimport type { Config } from '@salutejs/perftool';\n\nconst config: Config = {\n    retries: 30,\n    include: ['src/**/*.perf.tsx'],\n    displayIntermediateCalculations: false,\n    failOnSignificantChanges: false,\n    modifyWebpackConfig(conf) {\n        /**\n         * Customize the build if needed\n         */\n        return conf;\n    },\n};\n\nexport default config;\n```\n\nCheck out all the config settings and description [here](/packages/perftool/lib/config/common.ts).\n\nHere's [example config](https://github.com/salute-developers/plasma/blob/master/perftool.config.mts).\n\n## Documentation\n\nThere are no fancy-github-hosted docs right now, so this section consists of useful links and some nice perftool feature specs.\n\n### beforeTest\n\nYou can run code before Perftool renders the component. This code will be run in the browser, so at this stage you can mock data through the global object.\n\n```tsx\nimport React from 'react';\nimport Component from './Component';\n\nexport function Default() {\n    return \u003cComponent prop=\"value\" propX={window.mock} /\u003e;\n}\n\nDefault.beforeTest = () =\u003e {\n    window.mock = 123;\n};\n```\n\n#### intercept\n\nUsing the intercept method, you can intercept requests and return prepared data. Useful if you need to mock some endpoint, image or file, or cancel some request (see [typings](/packages/perftool/lib/api/intercept.ts)).\n\n```tsx\nimport React from 'react';\nimport { intercept } from '@salutejs/perftool';\nimport Component from './Component';\n\nexport function Default() {\n    return \u003cComponent prop=\"value\" /\u003e;\n}\n\nDefault.beforeTest = async () =\u003e {\n    await intercept({\n        method: 'POST',\n        source: '**/api/foo*', // glob-pattern\n        response: 'src/utils/perftool/fixtures/foo.json', // file path\n    });\n    await intercept({\n        method: 'GET',\n        responseType: 'json',\n        source: '**/api/bar*',\n        response: { foo: 'bar' },\n    });\n    await intercept({\n        // any http method\n        responseType: 'abort',\n        source: '**/api/baz*',\n    });\n};\n```\n\n#### setViewport\n\nUsing the setViewport method, you can specify the size of the viewport for rendering the current component. See [typings](/packages/perftool/lib/api/viewport.ts)\n\n```tsx\nimport React from 'react';\nimport { setViewport } from '@salutejs/perftool';\nimport Component from './Component';\n\nexport function Default() {\n    return \u003cComponent prop=\"value\" /\u003e;\n}\n\nDefault.beforeTest = async () =\u003e {\n    await setViewport('desktop'); // 'desktop' and 'touch' are built-in presets\n};\n```\n\n### Results interpretation\n\nMost often the following situation will occur: everything is fine, no degradation.\nIn this case, there is no need to do anything - we will assume that nothing bad happened.\nNow let's look at the case when perftool-compare threw an error.\nThe result of the performance test is a comparison of the results of runs in the base and feature branches.\nHere is an example of such a report, most of the fields have been omitted for readability:\n\n```json\n{\n    \"hasSignificantNegativeChanges\": true,\n    \"result\": {\n        \"Component.perf.tsx#Default\": {\n            \"render\": {\n                \"mean\": {\n                    \"old\": [10, 2],\n                    \"new\": [20, 4],\n                    \"change\": {\n                        \"difference\": 10,\n                        \"percentage\": 100,\n                        \"significanceRank\": \"high\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nThe top-level part of the report is a field with the boolean data type **hasSignificantNegativeChanges**, which means whether there are components in the report with statistically significant negative changes. Its value is determined based on the comparison results for each component and metric. In the config you can specify which specific metrics will be aggregated in **hasSignificantNegativeChanges**.\n\nIn this case, we detect **hasSignificantNegativeChanges: true**, and now we need to find the reason. We are looking for a metric with `change.significanceRank === 'high'` and `difference \u003e 0`. This can be one or more components/metrics. Once we have found all the candidates for degradation, we move on to the next step.\n\nNow you need to check whether the component that failed the test has actually changed. If the component was not directly or indirectly affected in this branch, then the result is false-positive and can be ignored - sometimes on machines where jobs are run, a load change occurs, which can lead to incorrect results.\n\nAt this stage, you can begin searching for degradation in the changed component. If you are not sure if degradation actually happened, you can run a check one more time.\n\n### Example of CI job\n\nSee [here](https://github.com/salute-developers/plasma/blob/master/.github/workflows/performance-test-pr.yml).\n\n## Supported environments\n\nWe follow Node maintenance cycle.\n\n| Node | 14  | 16  | 18  | 20  |\n| :--: | :-: | :-: | :-: | :-: |\n|      | ❌  | ✅  | ✅  | ✅  |\n\n| React | \u003c= 16.8 | ^16.8 | ^17 | ^18 |\n| :---: | :-----: | :---: | :-: | :-: |\n|       |   ❌    |  ✅   | ✅  | ✅  |\n\nWindows support is not currently planned.\n\n| OS  | Windows | MacOS | Linux |\n| :-: | :-----: | :---: | :---: |\n|     |   ❌    |  ✅   |  ✅   |\n\n## Contributing\n\nCheck out [Contribution guide](/CONTRIBUTING.md). All types of contributions are encouraged and valued.\n\n## License\n\nPerftool is [MIT licensed](/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalute-developers%2Fperftool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalute-developers%2Fperftool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalute-developers%2Fperftool/lists"}