Welcome, and thank you for your interest in contributing to iTwin.js!
There are many ways to contribute. The goal of this document is to provide a high-level overview of how you can get involved.
- Contributing to iTwin.js
- Repo Setup
- Source Code Edit Workflow
- Asking Questions
- Providing Feedback
- Reporting Issues
- Contributing Guidelines
- Frequently Asked Questions
- Rush commands take too long, is there a way to speed up my contribution workflow?
- Do I have to rebuild all packages in the repo, even those I didn't work on?
- A subdirectory can not find a node_modules file or directory
- Updating dependencies/devDependencies on packages within the monorepo
- Updating dependencies/devDependencies on packages external to monorepo
This repository is a monorepo that holds the source code for multiple iTwin.js npm packages. It is built using Rush.
Each package has its own node_modules directory that contains symbolic links to common dependencies managed by Rush.
- Install dependencies:
rush install - Build source:
rush build - Run tests:
rush cover
The above commands iterate and perform their action against each package in the monorepo.
Once you've set up the repo, you can move on to making changes to the source code by following the steps within:
- Create your own branch by running
git checkout -b "<your-branch-name>". See Branch Naming Policy - Make source code changes.
- Rebuild the repo by running
rush build. - Ensure unit tests pass when run locally:
rush cover. - Ensure linting passes when run locally:
rush lint. - Locally commit changes:
git commit(or use the Visual Studio Code user interface). - Repeat steps 1-4 until ready to push changes.
- Check for API signature changes:
rush extract-api. This will update the signature files, located incommon/api. Note: before doing this, first do the following:- Be sure that your branch is up to date with the target branch (i.e.
git merge origin/master). - Clean up your build output:
rush clean. - Rebuild the project:
rush build.
- Be sure that your branch is up to date with the target branch (i.e.
- Review any diffs to the API signature files in the
common/apidirectory to ensure they are compatible with the intended release of the package.- If any differences are in packages not modified on this branch, revert the changes before committing.
- Add changelog entry (which could potentially cover several commits):
rush change. - Follow prompts to enter a change description or press ENTER if the change does not warrant a changelog entry. If multiple packages have changed, multiple sets of prompts will be presented. If the changes are only to non-published packages (like display-test-app), then
rush changewill indicate that a changelog entry is not needed. - Completing the
rush changeprompts will cause new changelog entry JSON files to be created. - Add and commit the changelog JSON files and any API signature updates.
- Publish changes on the branch and open a pull request.
If executing scripts from
package.jsonfiles in any of the subdirectories, we recommend usingrushxovernpm.
The CI build will break if changes are pushed without running
rush changeandrush extract-api(if the API was changed). The fix will be to complete steps 6 through 11.
Here is a sample changelog to demonstrate the level of detail expected. Changelogs are user facing, so less verbosity is encouraged, and should avoid unnecessary details.
- Build TypeDoc documentation for all packages:
rush docs - Build TypeDoc documentation for a single package:
cd core\backendand thenrushx docs
Documentation code snippets are extracted from actively tested code to ensure they stay up-to-date and working. To add documentation snippets to a package:
- Create the test file: Place testable documentation snippets in
src/test/example-code/directory within the package - Mark extraction regions: Wrap code to be extracted with comment markers:
// __PUBLISH_EXTRACT_START__ SnippetName // Your code here that will be extracted // __PUBLISH_EXTRACT_END__
- Add extraction script: In
package.json, add:"extract": "betools extract --fileExt=ts --extractFrom=./src/test/example-code --recursive --out=../../generated-docs/extract"
- Update docs script: Chain extraction with documentation generation:
"docs": "betools docs --json=../../generated-docs/{package}/file.json --tsIndexFile=./{package}.ts --onlyJson && npm run -s extract"
- Reference in documentation: In markdown files, reference the snippets using:
```ts [[include:SnippetName]] ```
This pattern separates documentation examples from unit tests, emphasizing code that a user should adopt, and keeps documentation synchronized with working code.
Custom VSCode tasks are found in launch.json to make debugging easier for contributors. Navigate to the Run and Debug panel in VSCode and you can select one of many custom tasks to run, which will attach a debugger to the process, and stop at a breakpoint you've set up.
The custom scripts above run all tests found in their respective package. This monorepo contains packages using either mocha or vitest. Below is guidance for running specific tests using filters in either test library.
Filtering Mocha tests
Add a .only to a describe() or it() test function. Afterwards, run the custom VSCode task for the package through the Run and Debug panel, and mocha will run only that test suite. Example:
// Both Car and Plane test suites are found in the same test file. Mocha detects the use of `.only()` and will ignore all other test files.
describe.only("Car", () => { // Mocha will only run the Car test suite.
it("should drive", () => ...);
it.only("should stop", () => ...); // Mocha will only run this test case and not the first one.
});
describe("Plane", () => {
it("should fly", () => ...)
});Filtering Vitest tests
There are 2 ways to filter Vitest tests:
- The Vitest Explorer is a Visual Studio Code extension that enables running and debugging individual test cases. If unexpected behavior occurs after editing a test or source code, click the "Refresh Tests" button in the Testing view to reload your test suite and reflect any changes.
The Vitest Explorer is not compatible with tests running in a browser environment. The method below is the only viable way to debug browser-based tests.
- Edit the
vitest.config.mtsfound in a package's root folder and add an include property to filter out tests. Afterwards, run the custom VSCode task for the package through theRun and Debugpanel. For example, to test theViewRectclass in core-frontend (corresponding to theViewRect.test.tstest), one would edit thevitest.config.mtsfor core-frontend as demonstrated below. By adding.onlyto adescribe()orit()test function inViewRect.test.ts, you can filter out tests in more detail.
export default defineConfig({
esbuild: {
target: "es2022",
},
test: {
dir: "src",
setupFiles: "./src/test/setupTests.ts",
include: ["**/ViewRect.test.ts"], // Added here - the include property accepts a regex pattern.
browser: {
...
},
...
}
...
})To distinguish whether a package is using vitest or mocha, look at the package.json devDependencies.
Have a question? Rather than opening an issue, please ask away on the Github discussions page.
The community will be eager to assist you. Your well-worded question will serve as a resource to others searching for help.
Your comments and feedback are welcome. For general comments or discussion please click here to contribute via GitHub issues using the discussion label.
Have you identified a reproducible problem in iTwin.js? Have a feature request? We want to hear about it! Here's how you can make reporting your issue as effective as possible.
Before you create a new issue, please do a search in open issues to see if the issue or feature request has already been filed.
If you find that your issue already exists, please add relevant comments and your reaction. Use a reaction in place of a "+1" comment:
- 👍 - upvote
- 👎 - downvote
If you cannot find an existing issue that describes your bug or feature, create a new issue using the guidelines below.
File a single issue per problem and feature request. Do not enumerate multiple bugs or feature requests in the same issue.
Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
Please include the following with each issue:
- A short description of the issue that becomes the title
- Versions of relevant iTwin.js packages
- Minimal steps to reproduce the issue or a code snippet that demonstrates the issue
- What you expected to see, versus what you actually saw
- Images that help explain the issue
- Any relevant error messages, logs, or other details
- Impact of the issue
- Use the
bugorenhancementlabel to identify the type of issue you are filing
Don't feel bad if the developers can't reproduce the issue right away. They will simply ask for more information!
You may be asked to clarify things or try different approaches, so please follow your issue and be responsive.
We'd love to accept your contributions to iTwin.js. There are just a few guidelines you need to follow.
We recommend putting your github username, followed by a succinct branch name that reflects the changes you want to make. Eg. git checkout -b "<gh_username>/cleanup-docs"
Branch names should be all lowercase to avoid potential issues with non-case-sensitive systems and words should be separated by a dash. Eg: my-itwin-changes
A Contribution License Agreement with Bentley must be signed before your contributions will be accepted. Upon opening a pull request, you will be prompted to use cla-assistant for a one-time acceptance applicable for all Bentley projects. You can read more about Contributor License Agreements on Wikipedia.
All submissions go through a review process. We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.
When bug fixes or critical changes need to be applied to release branches (e.g., release/5.1.x), follow these best practices for backporting:
Best Practices:
- Master First Approach: Changes should always go into
masterfirst, then be backported to release branches if required for future releases. Avoid backporting from release branches tomasterwhenever possible to maintain clean commit history and reduce conflicts - PR Naming Convention: Always wrap the target branch name in square brackets in your PR title
- Example:
[release/5.1.x] Fix critical bug in geometry calculations
- Example:
- Use @Mergifyio: For backporting PRs from
masterto release branches, we recommend using@Mergifyioto automate the process- Comment
@Mergifyio backport release/X.X.xon the original PR to create an automatic backport. Use the release branch you want to target - Note:
@Mergifyioautomatically cherry-picks commits, but may encounter merge conflicts. If conflicts occur, you must resolve them manually and then remove theconflictslabel from your PR to proceed
- Comment
- Cherry-pick Carefully: When manually backporting, ensure all dependencies and related changes are included
- Minimal Changes: Keep backports focused and avoid unnecessary refactoring or feature additions
Example Workflow:
- Identify the commits that need to be backported from
master - Create a new branch from the target release branch (e.g.,
release/5.1.x) - Cherry-pick or manually apply the necessary changes
- Create a PR with the branch name in square brackets in the title
- Ensure all tests pass and the change is compatible with the release version
We welcome contributions, large or small, including:
- Bug fixes
- New features
- Documentation corrections or additions
- Example code snippets
- Sample data
If you would like to contribute new APIs, create a new issue and explain what these new APIs aim to accomplish. If possible check the CODEOWNERS file and tag the owners of the package you plan on introducing the new APIs into.
Thank you for taking the time to contribute to open source and making great projects like iTwin.js possible!
If your source code change only impacts the subdirectory you are working on, you can use rushx to run local commands, without affecting other packages.
Eg. I add a new method within core/frontend, also adding a relevant unit test in that folder's src/test. I can navigate to the root of that subdirectory, and run rushx build, followed by rushx test or rushx cover.
No. For incremental builds, the rush build command can be used to only build packages that have changes versus rush rebuild which always rebuilds all packages.
It is a good idea to
rush installafter eachgit pullas dependencies may have changed.
If you get an error similar to the following:
[Error: ENOENT: no such file or directory, stat '/.../itwinjs-core/test-apps/display-test-app/node_modules/@bentley/react-scripts']This means that the repo has stopped making use of an npm package that was used in the past:
To fix this build error, you should completely remove the node_modules directory and reinstall your dependencies. rush update --purge is a one-line solution for the above.
The version numbers of internal dependencies (see example) should not be manually edited. These will be automatically updated by our internal CI pipelines. Note that the packages are published by CI builds only.
Use these instructions to update dependencies and devDependencies on external packages (ones that live outside of this monorepo).
- Go into the appropriate
package.jsonfile and update the semantic version range of the dependency you want to update. - Run
rush checkto make sure that you are specifying consistent versions across the repository - Run
rush updateto make sure the newer version of the module specified in #1 is installed
