Welcome to the Strapi Client repository. This guide walks you through the steps to get started with contributing to the project, whether you're a maintainer or an external contributor.
- 📋 Prerequisites
- 🛠 Setting Up the Project
- 🏗️ Compiling the Changes
- 🧪 Testing the Changes
- 🔎 Verifying Your Contribution
- 📝 Commit Messages
- 🎉 You're Ready to Contribute!
- 🔐 Pull Request Reviews
- 📚 Releases
Before you get started, ensure you have the following installed:
-
Node.js: >=20.18.2 <=22.x.x. You can check your Node.js version using:
node -v
-
pnpm: the project requires
pnpm
as the package manager.To install
pnpm
, follow the official documentation.You can check if pnpm is correctly installed using:
pnpm -v
-
Git: ensure Git is installed and properly configured.
Follow these steps to set up the repository locally:
Clone the Strapi Client repository to your local machine:
Using git
git clone https://github.com/strapi/client.git
cd client
Using the GitHub command-line tool
gh repo clone strapi/client
cd client
Install all required dependencies using pnpm
:
pnpm install
Both commands rely on the project's rollup configuration.
Run the following command to build the source code:
pnpm build
To automatically rebuild the project when changes are detected:
pnpm watch
Now, any changes you make to the src
folder will trigger a rebuild.
The build process outputs the generated artifacts to the dist
folder. These include:
- Type Definitions: TypeScript type definitions (
*.d.ts
files). - Bundles: JavaScript bundles in the following formats:
- CommonJS (
cjs
): useful for Node.js applications or environments requiring CJS modules. - ES Modules (
mjs
): ideal for modern JavaScript, TypeScript, and bundlers like Rollup or Webpack. - Browser (
iife
): minified bundle for direct consumption in browser environments (for use in<script>
tags).
- CommonJS (
Unit tests ensure the reliability and correctness of the features. The project uses Jest as the testing framework.
The project is configured for at least 95% of coverage on branches, functions, lines, and statement, but the project aims to stay at 100% as long as possible.
When writing tests, aim to fully validate the features and reliability of the code. Coverage is just a baseline metric to ensure all paths are considered, but the focus should be on comprehensively testing each scenario—including common usage, edge cases, and unexpected events. Effective tests help ensure the project remains robust and maintainable over time.
To run all unit tests:
pnpm test
Run all the tests and generate a test coverage report with:
pnpm test:cov
Note: you can pass any jest argument at the end of both commands, this can be useful to specific run tests based on their path or name
The Jest configuration file for the project is located at jest.config.js
, it covers aspects like:
- Pattern matching for test files
- Coverage threshold requirements
- Handling of TypeScript and module paths
In the unlikely event you need to customize the test behavior, you can modify the file as needed.
To be picked up by jest, test files should be located in the ./tests/unit/
directory with filenames ending in
.test.ts
.
Use the following structure as a template for a unit test:
// example.test.ts
import { ExampleClass } from '../src/example';
describe('Example Class', () => {
it('should return the expected result when calling action', () => {
// Arrange
const input = 'inputValue';
const expected = 'smth';
const instance = new ExampleClass();
const spy = jest.spyOn(instance, 'sideEffect');
// Act
const result = instance.action(input);
// Assert
expect(result).toBe(expected);
expect(spy).toHaveBeenCalledWith(input);
});
});
Note: keep the Arrange/Act/Assert comments, they help scan through tests quicker and are part of the style convention for this project.
Ensure each test covers a specific function or component and includes edge cases where applicable.
Mocks are used to simulate external dependencies and provide deterministic behavior.
To use a mock, import it from the tests/unit/mocks
folder and use it as a dependency for other objects/classes in your
test.
Here is an example of a mock representing a flaky URL validator instance
import { URLValidator } from '../../../src/validators';
/**
* Class representing a FlakyURLValidator which extends URLValidator.
*
* This validator is designed to throw an error unexpectedly upon validation and should only be used in test suites.
*/
export class MockFlakyURLValidator extends URLValidator {
validate() {
throw new Error('Unexpected error');
}
}
Feel free to create your own mocks based on your needs and export them from the folder's index.ts.
The repository includes demo projects to allow you to test your changes in different real-world scenarios.
From the project's root, set up the demo apps
pnpm demo setup
This installs the demos dependencies, builds them if needed, and sets up the Strapi app used by the different demos.
To test your changes in the demo projects, start by running the Strapi app:
pnpm demo app:start
Then navigate to any of the example in the ./demo folder, and refer to their respective package.json
for
instructions on how to run them.
Note: feel free to locally modify the demos to test your changes but avoid commiting them unless they provide fixes or additional functionality.
Before submitting a PR (pull request), verify that all checks pass:
- Run Linting
pnpm lint
- Format Code
pnpm prettier:check
- TypeScript Checks
pnpm ts:check
- Unit Tests
pnpm test:cov
- Production Build Check
NODE_ENV=production pnpm build:clean
When making commits, ensure they follow the project's commit message conventions.
These conventions are enforced using commitlint and are based on the Conventional Commits specification.
Example:
feat: added a new example feature
You can find the exact configuration used as well as the list of available commit types here.
Once your changes are ready and have been thoroughly tested, it is time to submit a new Pull Request.
When creating your PR, make sure the description is clear and provides enough details about the changes. Be sure to include:
- Purpose: explain what the changes do and why they're needed.
- Implementation Details: mention any key decisions, the approach taken, and anything specific the reviewer should focus on.
- Screenshots or Examples: share anything that helps illustrate the results or how the changes should work.
Providing a well-written description helps reviewers understand the context and makes the review process smoother.
For more information about what is expected in a pull request, check the template.
For additional guidance, refer to the official documentation or join the discussion on Strapi's Discord.
Happy contributing! 🚀
This section is targeted to maintainers only
When reviewing a PR, maintainers should pay close attention to several key points.
First, ensure the code adheres to the project's code style, conventions, and builds correctly.
While GitHub Actions typically handle these checks, you can manually verify with the following commands:
-
Linting: checks for code style issues.
pnpm lint
-
Formatting: verifies if the code adheres to
Prettier
formatting rules.pnpm prettier:check
-
TypeScript Validation: ensures TypeScript types are valid and there is no type-related breaking error.
pnpm ts:check
-
Unit Tests: runs all tests and checks if test coverage meets the required threshold.
pnpm test:cov
-
Build Check (Production): confirms that the client can successfully build for production.
NODE_ENV=production pnpm build:clean
Next, thoroughly analyze the changes to ensure they're safe and well-implemented. Keep the following considerations in mind:
- Does the PR introduce breaking changes to the public API?
- Is the logic clear and efficient, or does it need improvement?
- Are complex sections of code adequately documented with comments?
- Are there any potential security issues, such as weak input validation or unsafe dependency usage?
- Could the performance be negatively impacted by heavy operations or unnecessary computations?
- Are the unit tests comprehensive and sufficient for any new features?
- Does the code follow formatting and style guidelines?
- Are there opportunities to simplify overly complex or redundant code?
- Are edge cases and error handling adequately covered to prevent unexpected behavior?
- Do variable and function names enhance code readability, or are they vague and unclear?
- Does the change significantly increase the bundles' size, and if so, is the impact justified?
Note: if you're uncertain about a particular change, its purpose, or its potential impact, don't hesitate to consult with other maintainers.
Finally, check out the branch locally and manually test the proposed changes.
A PR can only be merged into main
by a maintainer if:
- All CI checks pass.
- The PR has been reviewed and approved by another maintainer.
- It is up to date with the target branch.
Any maintainer may merge a PR once all these conditions are met.
This section is targeted to maintainers only
To safely release a new version, maintainers must follow these steps:
-
Create a release branch from
main
and ensure it is up to date.The branch name should follow the format:
releases/<major>.<minor>.<patch>
. -
Install the latest dependencies with
pnpm install
. -
Update the package version in the root package.json:
{ "name": "@strapi/client", - "version": "1.0.0", + "version": "1.0.1", // ... }
-
Perform a dry-run publication with
pnpm publish --dry-run --tag latest
. -
If the dry run succeeds, commit the version update with the message
release: <major>.<minor>.<patch>
. If it fails, resolve the issues before proceeding. -
Create a version tag with
git tag v<major>.<minor>.<patch>
. -
Push the tag to the remote repository:
git push origin v<major>.<minor>.<patch>
. -
Publish the new version to NPM:
pnpm publish --tag latest
. -
Draft a new release on GitHub.
-
Select the newly created tag under the
Choose a tag
dropdown, leaving theTarget
asauto
. -
Click
Generate release notes
, review the content (for example, remove PRs related to the release process), and make necessary corrections. -
Ensure the
Set as the latest release
option is selected, then clickPublish release
. -
Push the release branch to the remote and create a pull request named
release: <major>.<minor>.<patch>
targeting themain
branch.
Note: in the long term, the goal will be to rely on a script or GitHub action to handle all the steps automatically