# Table of Contents - [Rush](#rush) - [PNPM Compatibility DB | Rush](#pnpm-compatibility-db-rush) - [Search the documentation | Rush](#search-the-documentation-rush) - [Incremental builds | Rush](#incremental-builds-rush) - [Injected dependencies | Rush](#injected-dependencies-rush) - [Installation variants | Rush](#installation-variants-rush) - [NPM doppelgangers | Rush](#npm-doppelgangers-rush) - [Phantom dependencies | Rush](#phantom-dependencies-rush) - [Preferred versions | Rush](#preferred-versions-rush) - [pnpm-issue-5132 | Rush](#pnpm-issue-5132-rush) - [upgrading | Rush](#upgrading-rush) - [api | Rush](#api-rush) - [config_files | Rush](#config-files-rush) - [pinned_versions | Rush](#pinned-versions-rush) - [upgrading | Rush](#upgrading-rush) - [pinned_versions | Rush](#pinned-versions-rush) - [使用 Rush 库的 API | Rush](#-rush-api-rush) - [配置文件参考 | Rush](#-rush) - [Search the documentation | Rush](#search-the-documentation-rush) - [command_line_json | Rush](#command-line-json-rush) - [common_versions_json | Rush](#common-versions-json-rush) - [version_policies_json | Rush](#version-policies-json-rush) - [Rush](#rush) - [What's new | Rush](#what-s-new-rush) - [Contributing | Rush](#contributing-rush) - [pnpm-issue-5132 | Rush](#pnpm-issue-5132-rush) - [Rush files and folders | Rush](#rush-files-and-folders-rush) - [Rush subspaces | Rush](#rush-subspaces-rush) - [Agent context files | Rush](#agent-context-files-rush) - [rush add | Rush](#rush-add-rush) - [PNPM Compatibility DB | Rush](#pnpm-compatibility-db-rush) - [Authoring change logs | Rush](#authoring-change-logs-rush) - [Enabling a merge queue | Rush](#enabling-a-merge-queue-rush) - [Using watch mode | Rush](#using-watch-mode-rush) - [增量构建 | Rush](#-rush) - [Welcome to Rush! | Rush](#welcome-to-rush-rush) - [优先版本 | Rush](#-rush) - [幻影依赖 | Rush](#-rush) - [NPM 分身 | Rush](#npm-rush) - [注入依赖 | Rush](#-rush) - [安装变种 | Rush](#-rush) - [Rush MCP plugins | Rush](#rush-mcp-plugins-rush) - [rush init-autoinstaller | Rush](#rush-init-autoinstaller-rush) - [rush init-deploy | Rush](#rush-init-deploy-rush) - [rush change | Rush](#rush-change-rush) - [rush build | Rush](#rush-build-rush) - [rush init | Rush](#rush-init-rush) - [rush install-autoinstaller | Rush](#rush-install-autoinstaller-rush) - [rush link | Rush](#rush-link-rush) - [rush purge | Rush](#rush-purge-rush) - [rush setup | Rush](#rush-setup-rush) - [rush remove | Rush](#rush-remove-rush) - [rush scan | Rush](#rush-scan-rush) - [rush tab-complete | Rush](#rush-tab-complete-rush) - [rush unlink | Rush](#rush-unlink-rush) - [rush update-autoinstaller | Rush](#rush-update-autoinstaller-rush) - [rush update-cloud-credentials | Rush](#rush-update-cloud-credentials-rush) - [rush upgrade-interactive | Rush](#rush-upgrade-interactive-rush) - [rush-pnpm | Rush](#rush-pnpm-rush) - [rush version | Rush](#rush-version-rush) - [cobuild.json (experimental) | Rush](#cobuild-json-experimental-rush) - [custom-tips.json (experimental) | Rush](#custom-tips-json-experimental-rush) - [.npmrc-publish | Rush](#-npmrc-publish-rush) - [.pnpmfile.cjs | Rush](#-pnpmfile-cjs-rush) - [rush-plugins.json (experimental) | Rush](#rush-plugins-json-experimental-rush) - [rush check | Rush](#rush-check-rush) - [rush deploy | Rush](#rush-deploy-rush) - [rush list | Rush](#rush-list-rush) - [Rush MCP server | Rush](#rush-mcp-server-rush) - [rush update | Rush](#rush-update-rush) - [rush publish | Rush](#rush-publish-rush) - [rushx | Rush](#rushx-rush) - [.npmrc | Rush](#-npmrc-rush) - [common-versions.json | Rush](#common-versions-json-rush) - [rush-plugin-manifest.json (experimental) | Rush](#rush-plugin-manifest-json-experimental-rush) - [Modifying package.json | Rush](#modifying-package-json-rush) - [Getting started as a developer | Rush](#getting-started-as-a-developer-rush) - [Other helpful commands | Rush](#other-helpful-commands-rush) - [Why one big repo⁈ | Rush](#why-one-big-repo-rush) - [Getting support | Rush](#getting-support-rush) - [Getting started | Rush](#getting-started-rush) - [rush install | Rush](#rush-install-rush) - [rush rebuild | Rush](#rush-rebuild-rush) - [artifactory.json | Rush](#artifactory-json-rush) - [experiments.json | Rush](#experiments-json-rush) - [rush-project.json | Rush](#rush-project-json-rush) - [Everyday commands | Rush](#everyday-commands-rush) - [Using project tags | Rush](#using-project-tags-rush) - [version-policies.json | Rush](#version-policies-json-rush) - [Configuring tab completion | Rush](#configuring-tab-completion-rush) - [subspaces.json | Rush](#subspaces-json-rush) - [Installing Git hooks | Rush](#installing-git-hooks-rush) - [Recommended settings | Rush](#recommended-settings-rush) - [Autoinstallers | Rush](#autoinstallers-rush) - [Environment variables | Rush](#environment-variables-rush) - [build-cache.json | Rush](#build-cache-json-rush) - [deploy.json | Rush](#deploy-json-rush) - [The "rush-lib" API | Rush](#the-rush-lib-api-rush) - [Speed up Git with Sparo | Rush](#speed-up-git-with-sparo-rush) - [rush-alerts.json (experimental) | Rush](#rush-alerts-json-experimental-rush) - [Setting up a new repo | Rush](#setting-up-a-new-repo-rush) - [Using Mergify with Rush | Rush](#using-mergify-with-rush-rush) - [NPM vs PNPM vs Yarn | Rush](#npm-vs-pnpm-vs-yarn-rush) - [Frequently Asked Questions (FAQ) | Rush](#frequently-asked-questions-faq-rush) - [Enabling CI builds | Rush](#enabling-ci-builds-rush) - [Custom tips (experimental) | Rush](#custom-tips-experimental-rush) - [Publishing packages | Rush](#publishing-packages-rush) - [Using Rush plugins (experimental) | Rush](#using-rush-plugins-experimental-rush) - [Creating Rush plugins (experimental) | Rush](#creating-rush-plugins-experimental-rush) - [NPM registry authentication | Rush](#npm-registry-authentication-rush) - [Adding projects to a repo | Rush](#adding-projects-to-a-repo-rush) - [Selecting subsets of projects | Rush](#selecting-subsets-of-projects-rush) - [Deploying projects | Rush](#deploying-projects-rush) - [Custom commands | Rush](#custom-commands-rush) - [Enabling phased builds | Rush](#enabling-phased-builds-rush) - [Enabling the build cache | Rush](#enabling-the-build-cache-rush) - [Enabling Prettier | Rush](#enabling-prettier-rush) - [Enabling policies | Rush](#enabling-policies-rush) - [pnpm-config.json | Rush](#pnpm-config-json-rush) - [command-line.json | Rush](#command-line-json-rush) - [rush.json | Rush](#rush-json-rush) - [Cobuilds (experimental) | Rush](#cobuilds-experimental-rush) - [Rush files and folders | Rush](#rush-files-and-folders-rush) - [Rush 子空间 | Rush](#rush-rush) - [代理上下文文件 | Rush](#-rush) - [rush add | Rush](#rush-add-rush) - [编写变更日志 | Rush](#-rush) - [启用合并队列 | Rush](#-rush) - [使用监听模式 | Rush](#-rush) - [Rush MCP 插件 | Rush](#rush-mcp-rush) - [最新动态 | Rush](#-rush) - [贡献 | Rush](#-rush) - [欢迎使用 Rush | Rush](#-rush-rush) - [rush init-autoinstaller | Rush](#rush-init-autoinstaller-rush) - [rush init-deploy | Rush](#rush-init-deploy-rush) - [rush change | Rush](#rush-change-rush) - [rush build | Rush](#rush-build-rush) - [rush init | Rush](#rush-init-rush) - [rush install-autoinstaller | Rush](#rush-install-autoinstaller-rush) - [rush link | Rush](#rush-link-rush) - [rush purge | Rush](#rush-purge-rush) - [rush setup | Rush](#rush-setup-rush) - [rush remove | Rush](#rush-remove-rush) - [rush scan | Rush](#rush-scan-rush) - [rush tab-complete | Rush](#rush-tab-complete-rush) - [rush unlink | Rush](#rush-unlink-rush) - [command_line_json | Rush](#command-line-json-rush) - [common_versions_json | Rush](#common-versions-json-rush) - [version_policies_json | Rush](#version-policies-json-rush) - [rush update-autoinstaller | Rush](#rush-update-autoinstaller-rush) - [rush update-cloud-credentials | Rush](#rush-update-cloud-credentials-rush) - [rush upgrade-interactive | Rush](#rush-upgrade-interactive-rush) - [rush-pnpm | Rush](#rush-pnpm-rush) - [rush version | Rush](#rush-version-rush) - [cobuild.json (experimental) | Rush](#cobuild-json-experimental-rush) - [custom-tips.json (实验性功能) | Rush](#custom-tips-json-rush) - [.npmrc-publish | Rush](#-npmrc-publish-rush) - [.pnpmfile.cjs | Rush](#-pnpmfile-cjs-rush) - [rush-plugins.json (experimental) | Rush](#rush-plugins-json-experimental-rush) - [rush check | Rush](#rush-check-rush) - [rush deploy | Rush](#rush-deploy-rush) - [rush list | Rush](#rush-list-rush) - [Rush MCP 服务器 | Rush](#rush-mcp-rush) - [rush update | Rush](#rush-update-rush) - [rushx | Rush](#rushx-rush) - [rush publish | Rush](#rush-publish-rush) - [.npmrc | Rush](#-npmrc-rush) - [common-versions.json | Rush](#common-versions-json-rush) - [以开发者的身份开始 | Rush](#-rush) - [修改 package.json | Rush](#-package-json-rush) - [rush-plugin-manifest.json (experimental) | Rush](#rush-plugin-manifest-json-experimental-rush) - [其他有用的指令 | Rush](#-rush) - [获取支持 | Rush](#-rush) - [为什么使用一个大仓库?! | Rush](#-rush) - [rush rebuild | Rush](#rush-rebuild-rush) - [快速开始 | Rush](#-rush) - [experiments.json | Rush](#experiments-json-rush) - [rush install | Rush](#rush-install-rush) - [rush-project.json | Rush](#rush-project-json-rush) - [artifactory.json | Rush](#artifactory-json-rush) - [日常用到的指令 | Rush](#-rush) - [使用项目标签 | Rush](#-rush) - [version-policies.json | Rush](#version-policies-json-rush) - [subspaces.json | Rush](#subspaces-json-rush) - [配置 tab 补全 | Rush](#-tab-rush) - [推荐设定 | Rush](#-rush) - [Autoinstallers | Rush](#autoinstallers-rush) - [安装 Git 钩子 | Rush](#-git-rush) - [build-cache.json | Rush](#build-cache-json-rush) - [环境变量 | Rush](#-rush) - [The "rush-lib" API | Rush](#the-rush-lib-api-rush) - [deploy.json | Rush](#deploy-json-rush) - [rush-alerts_json | Rush](#rush-alerts-json-rush) - [使用 Sparo 加速 Git | Rush](#-sparo-git-rush) - [在 Rush 中使用 Mergify | Rush](#-rush-mergify-rush) - [创建一个新的仓库 | Rush](#-rush) - [常见问题回答 | Rush](#-rush) - [启用 CI | Rush](#-ci-rush) - [Custom tips (实验性功能) | Rush](#custom-tips-rush) - [Using Rush plugins (experimental) | Rush](#using-rush-plugins-experimental-rush) - [NPM 仓库认证 | Rush](#npm-rush) - [发布包 | Rush](#-rush) - [仓库中添加项目 | Rush](#-rush) - [Creating Rush plugins (experimental) | Rush](#creating-rush-plugins-experimental-rush) - [选择部分项目 | Rush](#-rush) - [自定义指令 | Rush](#-rush) - [NPM vs PNPM vs Yarn | Rush](#npm-vs-pnpm-vs-yarn-rush) - [部署项目 | Rush](#-rush) - [Enabling phased builds | Rush](#enabling-phased-builds-rush) - [启用构建缓存(实验性) | Rush](#-rush) - [启用一些策略 | Rush](#-rush) - [启用 Prettier | Rush](#-prettier-rush) - [pnpm-config.json | Rush](#pnpm-config-json-rush) - [command-line.json | Rush](#command-line-json-rush) - [Cobuilds (experimental) | Rush](#cobuilds-experimental-rush) - [rush.json | Rush](#rush-json-rush) - [未找到页面 | Rush](#-rush) --- # Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/#docusaurus_skipToContent_fallback) Rush makes life easier for JavaScript developers who build and publish many packages from a common Git repo. If you're looking to break up your giant application into smaller pieces, and you already realized [why it doesn't work](https://rushjs.io/pages/intro/why_mono/) to put each package in a separate repo... then Rush is for you! ![monorepo diagram](https://rushjs.io/images/home/mono-concept-h.svg) ![monorepo diagram](https://rushjs.io/images/home/mono-concept-v.svg) The Rush difference =================== These days many different tools can run "npm install" and "npm run build" in 20 different folders. What's so great about Rush? ![Git repositories](https://rushjs.io/images/home/card-repo.svg) Ready for large repos --------------------- Rush is built by professional engineers who maintain large production monorepos. Our job is to provide the best developer experience for our colleagues, not to convert you into a customer for a paid consulting or hosting service. The repositories we maintain contain hundreds of apps with many years of Git history. To manage this scale, Rush offers parallel builds, subset builds, incremental builds, and distributed builds. ![large team](https://rushjs.io/images/home/card-people.svg) Designed for large teams ------------------------ Rush provides many mechanisms for onboarding newcomers and coordinating collaboration between teams. Repo policies allow new package dependencies to be reviewed before they are accepted. Rush can enforce consistent dependency versions across your repo. Different subsets of projects can publish separately with lockstep or independent versioning strategies. ![NPM phantom dependency](https://rushjs.io/images/home/card-phantom.svg) Reliable NPM installations -------------------------- Rush's installation model leverages the PNPM package manager to eliminate the [phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/) and [NPM doppelgangers](https://rushjs.io/pages/advanced/npm_doppelgangers/) that frustrate large scale installations. You can visualize and troubleshoot version conflicts using our [Lockfile Explorer](https://lfx.rushstack.io/) companion tool. ![motorbike and tricycle](https://rushjs.io/images/home/card-trike.svg) Easy to administer ------------------ When you maintain a large repo, you don't want developers opening support tickets that can't be reproduced on any other computer. Rush helps to ensure that installs and builds are completely deterministic. Even the Rush engine version is automatically installed according to your Git branch. If you define custom commands or options, they are strictly validated and documented as part of Rush's command-line help. ![army knife](https://rushjs.io/images/home/card-knife.svg) Turnkey solution ---------------- Tired of cobbling together your developer experience from multiple tools that never seem to integrate properly? Rush is a unified orchestrator that can install, link, build, generate change logs, publish, and bump versions. These features are designed to integrate with the broader [Rush Stack](https://rushstack.io/) suite of tools and practices. ![free price tag](https://rushjs.io/images/home/card-free.svg) Open model ---------- The Rush software is free and open source. Community contributions are welcome! We're also open-minded about your toolchain: In a Rush repo, each project folder remains fully self-contained, individually installable, and easy to relocate if needed. Relatively little effort is required to enable/disable Rush for a given set of projects. Who's using Rush? ================= [![Azure SDK logo](https://rushjs.io/images/3rdparty/azure.png)\ \ Azure SDK](https://github.com/azure/azure-sdk-for-js) [![HBO Max logo](https://rushjs.io/images/3rdparty/hbomax.png)\ \ HBO Max](https://www.hbomax.com/) ![OneDrive logo](https://rushjs.io/images/3rdparty/onedrive.png) OneDrive ![SharePoint logo](https://rushjs.io/images/3rdparty/sharepoint.png) SharePoint ![Office 365 Small Business logo](https://rushjs.io/images/3rdparty/o365.png) Office 365 Small Business ![Windows Store logo](https://rushjs.io/images/3rdparty/windows_store.png) Windows Store ![Office Web Apps logo](https://rushjs.io/images/3rdparty/o365.png) Office Web Apps [![SimplrJS react-forms logo](https://rushjs.io/images/3rdparty/simplrjs.png)\ \ SimplrJS react-forms](https://github.com/SimplrJS/react-forms) [![Telia Company logo](https://rushjs.io/images/3rdparty/telia.png)\ \ Telia Company](https://www.telia.se/) [![Welbi logo](https://rushjs.io/images/3rdparty/welbi.png)\ \ Welbi](https://www.welbi.co/) [![Wix logo](https://rushjs.io/images/3rdparty/wix.png)\ \ Wix](https://www.wix.com/) --- # PNPM Compatibility DB | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/compatibility_db/#docusaurus_skipToContent_fallback) On this page Both Yarn and PNPM support a feature called the **Compatibility DB**, which is a public database of `package.json` fixups. These fixups solve known issues that the official maintainer of an NPM package may be unwilling to solve. (The best practice would be to avoid such packages, but often that is impractical.) Compatibility DB fixups are similar to user-authored rules found in `.pnpmfile.cjs`. They are maintained with the [@yarnpkg/extensions](https://www.npmjs.com/package/@yarnpkg/extensions) package. PNPM's feature protects small projects from common pitfalls, but the approach has some downsides for a large monorepo: * **Hidden magic:** The fixups are bundled into the PNPM binary. When trying to coordinate complex cross-project version dependencies, it is awkward for key inputs to be in a file with no Git diff, not even viewable in the GitHub website. * **Unnecessary coupling:** Different versions of the `@yarnpkg/extensions` rules are bundled into different PNPM releases. This may cause churn the lockfile when upgrading or downgrading the package manager. * **Applied last:** The fixups are applied after `.pnpmfile.cjs`. This means the fixed up versions aren't visible to the user's own transformations or logging, and `.pnpmfile.cjs` is no longer the final authority about version choices. To avoid these issues, `rush install` and `rush update` always disable the Compatibility DB feature when invoking PNPM. Details[​](https://rushjs.io/pages/advanced/compatibility_db/#details "Direct link to Details") ------------------------------------------------------------------------------------------------ * Compatibility DB is implemented by PNPM versions `>= 6.32.12`, `>= 7.0.1` (but not `7.0.0`) * The `ignore-compatibility-db` switch is implemented in newer PNPM releases: `>= 6.34.0 <7.0.01` and `>= 7.9.0` * Compatibility DB is disabled by Rush versions `>= 5.76.0` if possible... * ..otherwise, if the switch is missing, Rush prints a warning recommending to upgrade PNPM The Compatibility DB fixes are useful. To apply them in your Rush repo, it's recommended to copy these settings into a proper Git-tracked file such as `.pnpmfile.cjs`. > 💡 Feature idea: Propose an automated mechanism for syncing `@yarnpkg/extensions` into a Git-tracked file under `common/config/rush`. * [Details](https://rushjs.io/pages/advanced/compatibility_db/#details) --- # Search the documentation | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/search/#docusaurus_skipToContent_fallback) Search the documentation ======================== [](https://typesense.org/?utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch) --- # Incremental builds | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/incremental_builds/#docusaurus_skipToContent_fallback) On this page Rush's **incremental build** feature speeds things up by skipping projects that are already up to date. In this context, "already up to date" means: 1. the project has already been built locally, AND 2. its input files and NPM dependencies have not changed since then, AND 3. if the project depends on any other Rush projects, those projects are up to date as well, AND 4. the command line parameters haven't changed. (For example, invoking `rush build --production` after `rush build` would require rebuilding.) By default, the "input files" are all source files under the project folder, except for files that are excluded by `.gitignore`; the details can be customized using the [rush-project.json](https://rushjs.io/pages/configs/rush-project_json/) config file. This feature can be combined with [project selection parameters](https://rushjs.io/pages/developer/selecting_subsets/) , where a person explicitly tells Rush which projects to process. Incremental builds reuse existing outputs on your local disk. This can be contrasted with Rush's [build cache](https://rushjs.io/pages/maintainer/build_cache/) feature that can fetch previously built outputs from a cloud storage container. How to use it[​](https://rushjs.io/pages/advanced/incremental_builds/#how-to-use-it "Direct link to How to use it") -------------------------------------------------------------------------------------------------------------------- To see incremental builds in action, simply run the `rush build` command twice: rush install# This might take several minutes...rush build# ...but the second time it finishes in just a few seconds.rush build The native `rush build` is hard-wired to be incremental. (And `rush rebuild` is the non-incremental variant of this command.) If you define your own custom [bulk commands](https://rushjs.io/pages/maintainer/custom_commands/) , you can make them incremental as well by enabling the `"incremental"` option in the [command-line.json](https://rushjs.io/pages/configs/command-line_json/) config file. How does it work?[​](https://rushjs.io/pages/advanced/incremental_builds/#how-does-it-work "Direct link to How does it work?") ------------------------------------------------------------------------------------------------------------------------------- Your project's build script (as invoked by `rushx build` or `npm run build`) probably already implements its own incremental optimizations. For example, [Heft](https://rushstack.io/pages/heft/overview/) maintains multiple caches for various tasks. However, even when `rushx build` does no work for a project, there is still nontrivial overhead for spawning the Node.js process, evaluating JavaScript files, and comparing timestamps for individual files. Suppose all those things take only 500ms for one project. If your monorepo has 100 projects, this works out to 100 x 0.5 = **50 seconds** worth of computation required in the best case where everything is already up to date. Rush eliminates this overhead by performing its own global analysis of the repo, in a single pass -- this way build scripts are not invoked at all for projects that are up to date. As an additional optimization, Rush's incremental analysis relies on file hashes rather than timestamps. For example, if you switch to a different Git branch, then switch back, many files may get their timestamps bumped, but Rush's incremental analysis won't be impacted as long as the source file contents have not changed. The file hashes are managed by the [@rushstack/package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) library. The hashes are saved in a file such as `/.rush/temp/package-deps_.json`. Inspecting this file can provide some insight into what the algorithm is doing. There are actually three distinct behaviors for incremental analysis: * **No incremental optimization:** If the invoked Rush command is not incremental (`incremental: false` in **command-line.json**), then the operation is always redone every time. * **Output preservation:** If the Build Cache is disabled (`"buildCacheEnabled": false` in **build-cache.json**), then Rush checks to see whether the input files have changed since the previous build on the same local machine. If no files were modified, then Rush assumes that the output files under the project's folder are up-to-date, and the project is "skipped" without performing any work. Note that this assumption can be easily violated by manually tampering with the output files. * **Cache restoration:** If the [build cache](https://rushjs.io/pages/maintainer/build_cache/) is enabled (`"buildCacheEnabled": true` in **build-cache.json**), then Rush instead queries the cache provider to see if this project has been built before. The cache provider may be cloud storage or the local disk cache. For a cache hit, the project's output files are deleted and replaced by restoring from the cache. > **Possible future improvement:** In the current implementation, when the build cache is enabled, the **output preservation** strategy is never used. In other words, the project output folders are always cleaned and replaced by restoring from the cache, which seems inefficient in situations where the files on disk are already up to date. Would it be more efficient to combine **output preservation** and **cache restoration** approaches? > > The engineering challenge is that when the build cache is enabled, we also need to write to the cache, which requires a high degree of confidence in the correctness of the outputs. The **output preservation** algorithm currently does not validate hashes of the output files or check for extra/missing files. If such validation is implemented, its runtime must be faster than tarball extraction, which is already a very fast operation. Building changed projects only (unsafe)[​](https://rushjs.io/pages/advanced/incremental_builds/#building-changed-projects-only-unsafe "Direct link to Building changed projects only (unsafe)") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Suppose hypothetically that our monorepo has the following projects: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) In the above illustration, the circles represent local projects, not external NPM dependencies. The arrow from `D` to `C` indicates that `D` depends on `C`; this means that `C` must be built before `D` can be built. Suppose that after rebuilding everything, we make a change to a source file under project `B`. Projects `C` and `D` depend on `B`, so they need to be built as well: ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) We might invoke: # This command will rebuild B, C, and Drush build But what if you know that your change to `C` won't affect its API contract? For example, maybe you updated the color of a button control, or some text in an error message. The `--changed-projects-only` flag tells Rush to build only those projects where a file was changed: ![rush build --only B](https://rushjs.io/images/docs/selection-only.svg) We'd invoke it like this: # This command will rebuild B (but ignore the effects for C and D)rush build --changed-projects-only The `--changed-projects-only` is "unsafe" because errors might be encountered if the downstream projects actually did need to be rebuilt. This parameter saves time by assuming that you know better than Rush about what really needs to be built. If that assumption is incorrect, you can always do `rush build` to get back to a good state. See also[​](https://rushjs.io/pages/advanced/incremental_builds/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------------- * [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/) * [Using watch mode](https://rushjs.io/pages/advanced/watch_mode/) * [How to use it](https://rushjs.io/pages/advanced/incremental_builds/#how-to-use-it) * [How does it work?](https://rushjs.io/pages/advanced/incremental_builds/#how-does-it-work) * [Building changed projects only (unsafe)](https://rushjs.io/pages/advanced/incremental_builds/#building-changed-projects-only-unsafe) * [See also](https://rushjs.io/pages/advanced/incremental_builds/#see-also) --- # Injected dependencies | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/injected_deps/#docusaurus_skipToContent_fallback) On this page Injected dependencies are a PNPM feature allowing local project folders to be installed as if they were published to an NPM registry. Background: Conventional workspace symlinking[​](https://rushjs.io/pages/advanced/injected_deps/#background-conventional-workspace-symlinking "Direct link to Background: Conventional workspace symlinking") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush projects typically use the `workspace:` specifier to depend on other projects within the monorepo workspace. For example, suppose `my-project` and `my-library` are projects in the Rush workspace: **my-repo/apps/my-project/package.json** { "name": "my-project", "version": "1.2.3", "dependencies": { "react": "^18.3.1", "my-library": "workspace:*" }} In the above example, the `react` package will installed by downloading from the NPM registry and extracting into a `node_modules` subfolder. By contrast, the `workspace:*` specifier causes PNPM to create a `node_modules` symlink pointing to the source code folder where `my-library` is developed: **Symlink:** `my-repo/apps/my-project/node_modules/my-library` --> `my-repo/libraries/my-library/` In this way, `my-project` will always consume the latest locally built outputs for `my-library`. It may even be the case that `my-project` and `my-library` are never published to an NPM registry at all. Limitations of workspace symlinking[​](https://rushjs.io/pages/advanced/injected_deps/#limitations-of-workspace-symlinking "Direct link to Limitations of workspace symlinking") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Suppose however that `my-library` declares a peer dependency like this: **my-repo/libraries/my-library/package.json** { "name": "my-library", "version": "0.0.0", "peerDependencies": { "react": "^18.0.0 || ^17.0.0" }, "devDependencies": { "react": "17.0.0" }} The `my-library` project declares that it can use both React version 17 and 18. For local development, the `devDependencies` install the oldest supported version 17.0.0, a common practice to validate backwards compatibility. Why do we need `peerDependencies` instead of `dependencies`? With `dependencies`, the package manager would be free to choose any version of `react` matching `"^18.0.0 || ^17.0.0"`. For example, if our app is using React 17, then `my-library` could get React 18, which is wrong. The peer dependency avoids this possibility by stipulating that `my-library` must get the same `react` version as its consumer (and in fact the same installed disk folder). What if two different apps depend on `my-library`, and those apps have different versions of `react`? For external NPM packages, PNPM would normally solve this by installing two copies of (the same version of) `my-library` into two different subfolders of `node_modules`. These copies are called **"peer dependency doppelgangers".** They are needed because of a design constraint of the Node.js module resolvers: > _**Context-free resolution:** When a given file on disk imports an NPM package, the module resolver will always resolve the same way for that file._ In other words, the only way to cause `my-library/lib/index.js` to import React 17 for `app1` while importing React 18 for `app2` is for the two apps to import from two different (doppelganger) copies of `index.js`. The package manager creates doppelgangers automatically as needed when extracting NPM packages into the `node_modules` folder. However, in our example, `my-project` used `workspace:*` to create a symlink to the project folder for `my-library`, instead of extracting an NPM package into the `node_modules` folder. How will the peer dependency be satisfied? PNPM simply produces an incorrect installation in this situation: * When `my-project` imports React, it will get version 18 * When `my-project` imports `my-library` and `my-library` imports React, it will get version 17 (as installed from the `devDependencies`) The `peerDependencies` are ignored. Injected dependencies to the rescue[​](https://rushjs.io/pages/advanced/injected_deps/#injected-dependencies-to-the-rescue "Direct link to Injected dependencies to the rescue") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To solve this problem, PNPM supports [a package.json setting](https://pnpm.io/package_json#dependenciesmetainjected) called `injected` that will cause `my-library` to get installed as if it had been published to NPM. Here's how to enable it: **my-repo/apps/my-project/package.json** { "name": "my-project", "version": "1.2.3", "dependencies": { "react": "^18.3.1", "my-library": "workspace:*" }, "dependenciesMeta": { "my-library": { "injected": true } }} With this change, `pnpm install` (in our case `rush install` or `rush update`) will install `my-library` by copying the project contents into the `node_modules` folder of `my-project`. Because they are conventionally installed, injected dependencies can become doppelgangers and correctly satisfy peer dependencies. **A second benefit:** Injected installation honors publishing filters such as `.npmignore`, and so the copied contents accurately reflect what would happen if `my-library` had been published to an NPM registry. For this reason, a test project that consumes the library can set `injected: true` to catch mistakes in `.npmignore` filters -- misconfigurations that are often missed when using `workspace:` symlinking. Sounds great -- so why doesn't PNPM use injected install for every `workspace:` reference? Syncing injected dependencies[​](https://rushjs.io/pages/advanced/injected_deps/#syncing-injected-dependencies "Direct link to Syncing injected dependencies") --------------------------------------------------------------------------------------------------------------------------------------------------------------- We said that injected dependencies get copied into a `node_modules` folder during `rush install`. But what happens if we make changes to `my-library` and then run `rush build`? When `my-project` imports `my-library`, it will still find the old copy from `node_modules`. To get a correct result, we would need to redo `rush install` every time we rebuild `my-library`. More precisely, we would need to redo `rush install` _**after**_ building any injected project but _**before**_ the consumer gets built. In a worst case, that could mean redoing `rush install` hundreds of times during `rush build`. This is unrealistic. PNPM currently doesn't yet include a built-in solution for this problem, and as a result injected dependencies have not yet gained wide adoption. However, a new tool called [pnpm-sync](https://github.com/tiktok/pnpm-sync) provides a solution: Whenever `my-library` is rebuilt, `pnpm-sync` can copy its outputs to update the appropriate `node_modules` subfolders. Normally it would be up to each project to determine whether and how to invoke the `pnpm-sync` command, but Rush integrates this feature and manages it automatically. To use `pnpm-sync` with Rush, enable the `usePnpmSyncForInjectedDependencies` experiment: **common/config/rush/experiments.json** /** * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot * correctly satisfy versioning requirements without installing duplicate copies of a package inside the * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" * feature provides a model for copying the local project folder into node_modules, however copying * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. * The "pnpm-sync" tool manages this operation; see its documentation for details. * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies * by invoking "pnpm-sync" during the build. */ "usePnpmSyncForInjectedDependencies": true This will enable the following behaviors: * `rush install` and `rush update` will automatically invoke `pnpm-sync prepare` to configure copying of injected dependencies such as `my-library` * `rush build` (and other Rush custom commands and phases) will automatically invoke `pnpm-sync copy` to resync the installed folders whenever a project like `my-library` is rebuilt * `rushx` will automatically invoke `pnpm-sync copy` after any operation performed under the `my-library` folder Injected dependencies for subspaces[​](https://rushjs.io/pages/advanced/injected_deps/#injected-dependencies-for-subspaces "Direct link to Injected dependencies for subspaces") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- If you are using Rush subspaces, consider enabling `alwaysInjectDependenciesFromOtherSubspaces` as well: **common/config/subspaces//pnpm-config.json** /** * When a project uses `workspace:` to depend on another Rush project, PNPM normally installs * it by creating a symlink under `node_modules`. This generally works well, but in certain * cases such as differing `peerDependencies` versions, symlinking may cause trouble * such as incorrectly satisfied versions. For such cases, the dependency can be declared * as "injected", causing PNPM to copy its built output into `node_modules` like a real * install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/ * * When using Rush subspaces, these sorts of versioning problems are much more likely if * `workspace:` refers to a project from a different subspace. This is because the symlink * would point to a separate `node_modules` tree installed by a different PNPM lockfile. * A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`, * which automatically treats all projects from other subspaces as injected dependencies * without having to manually configure them. * * NOTE: Use carefully -- excessive file copying can slow down the `rush install` and * `pnpm-sync` operations if too many dependencies become injected. * * The default value is false. */ "alwaysInjectDependenciesFromOtherSubspaces": true See also[​](https://rushjs.io/pages/advanced/injected_deps/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------ * [pnpm-sync](https://github.com/tiktok/pnpm-sync) GitHub project * [dependenciesMeta.\*.injected](https://pnpm.io/package_json#dependenciesmetainjected) from PNPM documentation * [Rush subspaces](https://rushjs.io/pages/advanced/subspaces/) * [Background: Conventional workspace symlinking](https://rushjs.io/pages/advanced/injected_deps/#background-conventional-workspace-symlinking) * [Limitations of workspace symlinking](https://rushjs.io/pages/advanced/injected_deps/#limitations-of-workspace-symlinking) * [Injected dependencies to the rescue](https://rushjs.io/pages/advanced/injected_deps/#injected-dependencies-to-the-rescue) * [Syncing injected dependencies](https://rushjs.io/pages/advanced/injected_deps/#syncing-injected-dependencies) * [Injected dependencies for subspaces](https://rushjs.io/pages/advanced/injected_deps/#injected-dependencies-for-subspaces) * [See also](https://rushjs.io/pages/advanced/injected_deps/#see-also) --- # Installation variants | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/installation_variants/#docusaurus_skipToContent_fallback) On this page Sometimes you may want to build your entire monorepo using a modified set of dependencies. For example, suppose you just finished upgrading to a major new release of a framework, but you intend to maintain compatibility with the previous release during a transition period. Your developers should use the new variant for their everyday work, but for PR builds, you want your CI job to build the entire repo twice -- once with the old variant, and once with the new variant. It seems like you could solve this by writing a simple script to search+replace the versions in your **package.json** files, but you'll quickly encounter other files that are affected: * **shrinkwrap file**: builds won't be deterministic unless you maintain separate shrinkwrap files for the two variants * **common-versions.json**: the `preferredVersions` or `allowedAlternativeVersions` may need to be different for the two variants * **pnpmfile.js**: if you have workarounds for poorly behaved legacy packages, they may need to be different for the two variants This problem seems to requires a separate, parallel set of configuration files. Starting with Rush 5.4.0, there's now an out-of-box solution for this problem. Setting up a variant[​](https://rushjs.io/pages/advanced/installation_variants/#setting-up-a-variant "Direct link to Setting up a variant") -------------------------------------------------------------------------------------------------------------------------------------------- Suppose "**widget-sdk**" is a hypothetical library that just shipped a major new release 3, and we've upgraded to version 3, but we want to maintain compatibility with version 2. We can indicate this using a loose SemVer range our **package.json** file: **libraries/my-controls/package.json** { "name": "my-controls", "version": "1.0.0", "description": "An example library project", "license": "MIT", "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { "build": "node_modules/.bin/my-build" }, "dependencies": { "widget-sdk": "^2.3.4 || ^3.0.2" }, "devDependencies": { "my-toolchain": "^1.0.0", "typescript": "^3.0.3" }} The `"^2.3.4 || ^3.0.2"` range indicates that our library will accept **widget-sdk** version 2.x (but not older than 2.3.4) or version 3.x (but not older than 3.0.2). When you run `rush update`, you will normally get the latest compatible version. How to build and test with the older version 2? Let's set up a variant! **1. Define your variant.** In the rush.json config file, we add a definition like this: **\*rush.json** excerpt\* "variants": [ // { // /** // * The folder name for this variant. // */ // "variantName": "example-variant", // // /** // * An informative description // */ // "description": "Build this repo using the previous release of the SDK" // } { "variantName": "old-widget-sdk", "description": "Build this repo using version 2 of the widget-sdk" } ], **2. Copy the config files.** To get your variant started, copy your existing config files from **common/config/rush** to your variant folder **common/config/rush/variants/old-widget-sdk**. Three config files are currently supported (others may be added in the future): * **shrinkwrap.yaml**, **npm-shrinkwrap.json**, or **yarn.lock** depending on your package manager * **common-versions.json** * **pnpmfile.js** if you are using PNPM as your package manager Be sure to add the copied files to Git: git add .git commit -m "Creating a new variant" **3. Override the dependency versions for the variant.** For this example, we will downgrade **widget-sdk** to use version 2.x. This can be done by using Rush's [preferred versions](https://rushjs.io/pages/advanced/preferred_versions/) feature. We'll use a wildcard so that `rush update --full` still picks up minor/patch releases: **\*common-versions.json** excerpt\* /** * A table that specifies a "preferred version" for a dependency package. The "preferred version" * is typically used to hold an indirect dependency back to a specific version, however generally * it can be any SemVer range specifier (e.g. "~1.2.3"), and it will narrow any (compatible) * SemVer range specifier. See the Rush documentation for details about this feature. */ "preferredVersions": { /** * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, * instead of the latest version. */ // "some-library": "1.2.3" "widget-sdk": "^2.3.9" }, Note that `^2.3.9` satisfies the SemVer range `^2.3.4 || ^3.0.2` that we specified in **package.json** above. (If this was not true, then the preferred version would not have any effect!) **4. Install your variant and test it.** Let's start by running `rush update` to install the new set of dependency versions: rush update --full --variant old-widget-sdk This will update the file **common/config/rush/old-widget-sdk/shrinkwrap.yaml**, install those dependencies in **common/temp/node\_modules**, and link each project to use those dependencies. The `rush install` command also supports the `--variant` option. Your CI job can use this when it builds with the old **widget-sdk** release. Now you can build and test your variant: rush rebuild 👉 If you get tired of typing `--variant`, you can also use the [RUSH\_VARIANT](https://rushjs.io/pages/configs/environment_vars/) environment variable to specify the variant name. **5. Restoring the original state.** When you're done testing your variant, you can return to the original state by running `rush install` without the `--variant` option. We call this the "**default variant**", because it's the same default behavior as a repo that didn't define any variants: # Restore the original state by omitting "--variant":rush install > **Tip:** If you forget which variant is active, you can look in the **common/temp/current-variant.json** file. If you open this file in a text editor, you should see a line like this: > > { "variant": "old-widget-sdk"} * [Setting up a variant](https://rushjs.io/pages/advanced/installation_variants/#setting-up-a-variant) --- # NPM doppelgangers | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/npm_doppelgangers/#docusaurus_skipToContent_fallback) On this page _This article continues the discussion from the "[Phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/) " section. It's recommended to read that first._ How NPM doppelgangers arise[​](https://rushjs.io/pages/advanced/npm_doppelgangers/#how-npm-doppelgangers-arise "Direct link to How NPM doppelgangers arise") ------------------------------------------------------------------------------------------------------------------------------------------------------------- ![NPM doppelganger](https://rushjs.io/images/home/card-doppel.svg) Sometimes the **node\_modules** data structure is forced to install two copies of **_the same version of_** the same package. Really? How can that happen? Suppose we have a main project **A** like this: { "name": "library-a", "version": "1.0.0", "dependencies": { "library-b": "^1.0.0", "library-c": "^1.0.0", "library-d": "^1.0.0", "library-e": "^1.0.0" }} And then **B** and **C** both depend on **F1**: { "name": "library-b", "version": "1.0.0", "dependencies": { "library-f": "^1.0.0" }} { "name": "library-c", "version": "1.0.0", "dependencies": { "library-f": "^1.0.0" }} But **D** and **E** depend on **F2**: { "name": "library-d", "version": "1.0.0", "dependencies": { "library-f": "^2.0.0" }} { "name": "library-e", "version": "1.0.0", "dependencies": { "library-f": "^2.0.0" }} The **node\_modules** tree can share **F1** by putting it at the top of the tree, but then **F2** has to be duplicated in subfolders: - library-a/ - package.json - node_modules/ - library-b/ - package.json - library-c/ - package.json - library-d/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@2.0.0 - library-e/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@2.0.0 - library-f/ - package.json <-- library-f@1.0.0 Alternatively, the package manager could choose to put **F2** at the top, but then **F1** gets duplicated: - library-a/ - package.json - node_modules/ - library-b/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@1.0.0 - library-c/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@1.0.0 - library-d/ - package.json - library-e/ - package.json - library-f/ - package.json <-- library-f@2.0.0 Either way, we cannot arrange the tree without having two copies of the same version of **library-f**. We call these "doppelgangers". Traditional package managers from other programming languages don't encounter this issue; it's a peculiar aspect of NPM's **node\_modules** tree. It is inherent in the design and unavoidable. Consequences of doppelgangers[​](https://rushjs.io/pages/advanced/npm_doppelgangers/#consequences-of-doppelgangers "Direct link to Consequences of doppelgangers") ------------------------------------------------------------------------------------------------------------------------------------------------------------------- Small projects rarely encounter doppelgangers, but they are fairly common in a large scale monorepo. Here's some potential problems that can result: * **Slower installs:** Disk space isn't too expensive these days, but imagine you have 20 libraries that depend on **F1**, leading to 20 duplicated copies. Or suppose there's a post-install script that downloads and unzips large archive (e.g. PhantomJS) and this happens separately for each doppelganger. That could impact your install time significantly. * **Exploding bundle sizes:** Web projects commonly use a bundler such as [webpack](https://webpack.js.org/) that statically analyzes `require()` statements and collects code into a single bundle file for deployment. This file should be kept as small as possible, because it directly affects the load time for your web application. When a doppelganger appears unexpectedly (e.g. due to an `npm install` operation that rebalances the **node\_modules** tree), this can cause two copies of a library to be embedded in a bundle, greatly increasing its size. * **Non-single singletons:** Suppose **library-f** has an API which exposes a cache object that is intended to be a singleton instance shared by all consumers of the library. When two different components call `require("library-f")` they may get two different library instantiations, which means there will suddenly be two instances of the singleton (i.e. the underlying "global" variable gets allocated in two different closures). This can lead to very strange behavior that is difficult to debug. * **Duplicate types:** Suppose **library-f** is a TypeScript library. The compiler will encounter duplicate copies of all the \*.d.ts files for that library. For example, each class will have two copies of its declaration, which cannot be deduplicated by following symlink targets, since they are separate physical files. In general identical class declarations are not considered interchangeable by TypeScript and will cause compile errors when mixed. Typescript 2.x introduced a heuristic for detecting and equating these duplicates, but it involves additional complexity and processing. Other build tasks may not be so sophisticated. * **Semantically different doppelgangers:** Suppose **F** has a dependency **G** that is also consumed by other packages in the tree. In the tree, the first copy of **F1** starts its search for **G** under **B**, whereas the second copy of **F1** starts under **C**. The `require()` algorithm can find different versions of **G** from these two starting points. This means the runtime behavior of the two **F1** instances may be different. Or at compile time, if **F** exports a TypeScript class that inherits from a base class defined in **G**, we can end up with differing type signatures **_for the same class from the same version of the same package_**. This can lead to highly confusing compiler errors. **How Rush helps:** Rush's symlinking strategy eliminates doppelgangers only for dependencies that are local projects in the monorepo. If you're using NPM or Yarn as your package manager, unfortunately doppelgangers are still possible for any indirect dependencies. Whereas if you use PNPM with Rush, the doppelganger problem is fully solved (because PNPM's installation model accurately simulates a true directed acyclic graph). * [How NPM doppelgangers arise](https://rushjs.io/pages/advanced/npm_doppelgangers/#how-npm-doppelgangers-arise) * [Consequences of doppelgangers](https://rushjs.io/pages/advanced/npm_doppelgangers/#consequences-of-doppelgangers) --- # Phantom dependencies | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/phantom_deps/#docusaurus_skipToContent_fallback) On this page Rush's documentation occasionally mentions "phantoms" and "doppelgangers". Want to learn more about how JavaScript package managers work? Some history and some theory[​](https://rushjs.io/pages/advanced/phantom_deps/#some-history-and-some-theory "Direct link to Some history and some theory") ----------------------------------------------------------------------------------------------------------------------------------------------------------- Everyone knows that software **packages** can depend on other **packages**, and the resulting [dependency graph](https://en.wikipedia.org/wiki/Dependency_graph) is a kind of [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) in computer science. Unlike a tree data structure, a directed acyclic graph can have diamond-shaped branches that rejoin. For example, library **A** might import definitions from libraries **B** and **C**, but then **B** and **C** can both import from **D**, which creates a "**diamond dependency**" between these four packages. Conventionally the programming language's **module resolver** looks up imported packages by traversing edges of this graph, and (in other systems) the packages themselves are found in a central store that can be shared by many projects. For historical reasons, NodeJS and NPM took a different approach by representing this graph physically on disk: NPM models the graph vertexes using actual package folder copies, and the graph edges are implied by the subfolder relationships. But a folder tree's branches cannot rejoin to make diamonds. To handle this, NodeJS added a [special resolution rule](https://nodejs.org/api/modules.html#all-together) whose effect is to introduce extra graph edges (pointing to the immediate children of all parent folders). From a computer science perspective, this rule relaxes the file system's [tree data structure](https://en.wikipedia.org/wiki/Tree_(data_structure)) in two ways: (1) it can now represent some (but not all) directed acyclic graphs, and (2) we pick up some extra edges that do not correspond to any declared package dependency. These extra edges are called "**phantom dependencies**". NPM's approach has many unique characteristics that differ from traditional package managers: * Each (root-level) project gets its own **node\_modules** tree containing lots of package folder copies. Even a very small NodeJS project is likely to have more than 10,000 files copied under its folder. * In NPM 2.x, the **node\_modules** folder tree was very deep and duplicated, which minimized phantom dependencies. NPM 3.x improved the installation algorithm to flatten the tree, which eliminated a lot of duplication, at the expense of introducing even more phantom dependencies (extra graph edges). In some cases the new algorithm will also choose a slightly older version of a package (while still satisfying SemVer) to further reduce duplication of package folders. * The installed **node\_modules** tree is not unique. There are many possible ways to arrange package folders into a tree to approximate the directed acyclic graph, and there is no unique "normalized" arrangement. The tree you get depends on whatever heuristics your package manager chose to follow. NPM's own heuristics are even sensitive to [the order in which you add packages](http://npm.github.io/how-npm-works-docs/npm3/non-determinism.html) . The **node\_modules** tree is an unusual and theoretically interesting data structure. But let's focus on three consequences that can cause real trouble, and which can be particularly difficult to diagnose in a large and very active monorepo. We'll also show how Rush improves things -- mitigating these problems was one of the original motivations for creating the Rush tool! Phantom dependencies[​](https://rushjs.io/pages/advanced/phantom_deps/#phantom-dependencies "Direct link to Phantom dependencies") ----------------------------------------------------------------------------------------------------------------------------------- ![NPM phantom dependency](https://rushjs.io/images/home/card-phantom.svg) A "phantom dependency" occurs when a project uses a package that is not defined in its **package.json** file. Consider this example: **my-library/package.json** { "name": "my-library", "version": "1.0.0", "main": "lib/index.js", "dependencies": { "minimatch": "^3.0.4" }, "devDependencies": { "rimraf": "^2.6.2" }} But suppose that the code looks like this: **my-library/lib/index.js** var minimatch = require('minimatch');var expand = require('brace-expansion'); // ???var glob = require('glob'); // ???// (more code here that uses those libraries) Wait a sec -- two of these libraries are not declared as dependencies in the **package.json** file. How is this working at all!? It turns out that **brace-expansion** is a dependency of **minimatch**, and **glob** is a dependency of **rimraf**. During installation, NPM has flattened their folders to be under **my-library/node\_modules**. The NodeJS `require()` function finds them there because it probes for folders without considering the **package.json** files at all. This is perhaps counterintuitive, but it seems to work just fine. Maybe it's a feature and not a bug? Unfortunately this project's missing declarations are best considered a bug. It can lead to unexpected malfunctions or errors: * **Incompatible versions:** Although our library's **package.json** declared that it needs **minimatch** version 3, we don't have any say about the version of **brace-expansion** that we'll get. The [SemVer system](https://semver.org/) makes it perfectly legal for a PATCH release of **minimatch** to incorporate a MAJOR upgrade of the **brace-expansion** library, as long as it doesn't affect the API signature for **minimatch**. In practice we'll probably never encounter this as developers of **my-library** -- instead, it will be found by a poor victim who installs our published library later in some very different **node\_modules** arrangement that has newer (or older) version constraints than what we regularly test. * **Missing dependencies:** The **glob** package is coming from our `devDependencies`, which means it only gets installed for developers who work on the **my-library** project. For other consumers, `require("glob")` should fail immediately with an error because **glob** won't get installed at all for them. We should hear about it as soon as we publish the **my-library** package, right? Not exactly. In practice it's likely that most consumers will also have **glob** for some reason (e.g. using **rimraf** themselves), so it may appear to work. Only a small percentage of our consumers will encounter the failed import error, making it seem like they're reporting a weird issue that's difficult to repro. **How Rush helps:** Rush's symlinking strategy ensures that each project's **node\_modules** contains only its declared direct dependencies. This catches phantom dependencies immediately at build time. If you're using the PNPM package manager, the same protections are also applied to all indirect dependencies (with the ability to workaround any "bad" packages by using **pnpmfile.js**). Phantom node\_modules folders[​](https://rushjs.io/pages/advanced/phantom_deps/#phantom-node_modules-folders "Direct link to Phantom node_modules folders") ------------------------------------------------------------------------------------------------------------------------------------------------------------ Suppose we have a monorepo, and someone adds a root-level **package.json** file like this: **my-monorepo/package.json**: { "name": "my-monorepo", "version": "0.0.0", "scripts": { "deploy-app": "node ./deploy-app.js" }, "devDependencies": { "semver": "~5.6.0" }} This allows people to run `npm run deploy-app`, and our script will automatically deploy all the projects in the monorepo. (Don't do this if you're using Rush! Instead define a [custom command](https://rushjs.io/pages/maintainer/custom_commands/) .) Notice that this hypothetical script needs to use the **semver** library, so it was added to the `devDependencies` list. People are asked to run `npm install` in the repo root folder before `npm run deploy-app`. The resulting installed folders will look something like this: - my-monorepo/ - package.json - node_modules/ - semver/ - ... - my-library/ - package.json - lib/ - index.js - node_modules/ - brace-expansion - minimatch - ... But recall that NodeJS's module resolver probes for dependencies in parent folders. This means that our **my-library/lib/index.js** can call `require("semver")` and find the **semver** package, even if it doesn't appear anywhere under **my-library/node\_modules**. This is an even more insidious way to pick up accidental phantom dependencies -- it can sometimes find **node\_modules** folders that aren't even under your Git working directory! **How Rush helps:** Rush's got you covered. The `rush install` command scans all potential parent folders and issues a warning if any phantom **node\_modules** folders are found. * [Some history and some theory](https://rushjs.io/pages/advanced/phantom_deps/#some-history-and-some-theory) * [Phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/#phantom-dependencies) * [Phantom node\_modules folders](https://rushjs.io/pages/advanced/phantom_deps/#phantom-node_modules-folders) --- # Preferred versions | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/preferred_versions/#docusaurus_skipToContent_fallback) On this page Background[​](https://rushjs.io/pages/advanced/preferred_versions/#background "Direct link to Background") ----------------------------------------------------------------------------------------------------------- Rush performs a single install for all your projects by creating a fake **rush-common** project in your common folder that references tarballs containing the dependencies for each project. For example, suppose your **rush.json** has two projects "**project1**" and "**project2**". The generated file might look like this: **common/temp/package.json** { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz" }} The package manager considers each of these "**@rush-temp**" scoped projects to be a direct dependency for the **rush-common** project. In general NPM installs a project's direct dependencies first (at the root of the **node\_modules** tree), and only then proceed to download the indirect dependencies. But since your real project's direct dependencies are now indirect dependencies for the **rush-common** project, the `npm install` behavior could be different. Suppose **project-1/package.json** looks like this: { "name": "project-1", "version": "1.0.0", "dependencies": { "library-a": "1.0.1", "library-b": "1.1.3" }} And let's say **library-a** (from the internet) looks like this: { "name": "library-a", "version": "1.0.1", "dependencies": { "library-b": "^1.0.0" }} If you ran a normal `npm install` in for **project-1**, you would expect to have a **node\_modules** folder which looks like this, even if **[library-b@1.4.4](mailto:library-b@1.4.4) ** exists in the NPM registry: node_modules/ library-a/ (1.0.1) library-b/ (1.1.3) Even though **[library-b@1.4.4](mailto:library-b@1.4.4) ** matches the `"^1.0.0"` SemVer pattern, NPM doesn't install it because 1.1.3 (installed by `project-1`) already satisfies it. But the **common/temp/package.json** described above would not guarantee this. Instead, depending on the dependencies of **project-2**, you could end up with this: node_modules/ project-1/ library-b/ (1.1.3) library-a/ (1.0.1) library-b/ (1.4.4) ... which is also a valid solution to the SemVer equation. Similar problems can arise when using Rush with NPM's [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies/) . Preferred Versions[​](https://rushjs.io/pages/advanced/preferred_versions/#preferred-versions "Direct link to Preferred Versions") ----------------------------------------------------------------------------------------------------------------------------------- To control these effects Rush introduces a concept of "preferred versions", which are dependencies that get explicitly added to the top-level **common/temp/package.json**. You can "pin" a version by adding it to the config file **common-versions.json**. For example: **common/config/rush/common-versions.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", "preferredVersions": { "css-loader": "1.2.3" }} This will cause **css-loader** to be added to the **common/temp/package.json** from our above example, like this: { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "css-loader": "1.2.3", "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz" }} _Note: If you are publishing packages, you should be careful about adding preferred versions in a way that would produce a different result than a person who installs your library normally using NPM._ Implicitly Preferred Versions[​](https://rushjs.io/pages/advanced/preferred_versions/#implicitly-preferred-versions "Direct link to Implicitly Preferred Versions") -------------------------------------------------------------------------------------------------------------------------------------------------------------------- By default, Rush will automatically add all direct dependencies of all your projects to **common/temp/package.json**. In our original example, these "implicitly preferred versions" might appear like this: **common/temp/package.json** { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "css-loader": "1.2.3", // <---- preferred version that was specified above "library-a": "~1.0.0", // <---- implicitly preferred version "library-b": "1.1.3", // <---- implicitly preferred version "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz", }} Rush does this for you except in cases where different projects specify different version ranges for a given dependency. In that case, Rush wouldn't know which version should be implicitly preferred. For example, if **project1** and **project2** were requesting different versions of **library-b**, then you might need to get involved, and maybe use **common-versions.json** to resolve your issue. For older package managers, automatically adding these entries tended to reduce duplication of indirect dependencies. However, implicitly preferred versions can cause trouble for certain dependencies with incompatible `peerDependencies` ranges. If you're encountering installation errors involving peer dependencies, we recommend to disable this behavior by setting `implicitlyPreferredVersions` to `false` in the [common/config/rush/common-versions.json](https://rushjs.io/pages/configs/common-versions_json/) config file. * [Background](https://rushjs.io/pages/advanced/preferred_versions/#background) * [Preferred Versions](https://rushjs.io/pages/advanced/preferred_versions/#preferred-versions) * [Implicitly Preferred Versions](https://rushjs.io/pages/advanced/preferred_versions/#implicitly-preferred-versions) --- # pnpm-issue-5132 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/link/pnpm-issue-5132/#docusaurus_skipToContent_fallback) Redirecting... --- # upgrading | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/link/upgrading/#docusaurus_skipToContent_fallback) Redirecting... --- # api | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/api/#docusaurus_skipToContent_fallback) Redirecting... --- # config_files | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/config_files/#docusaurus_skipToContent_fallback) Redirecting... --- # pinned_versions | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/pinned_versions/#docusaurus_skipToContent_fallback) Redirecting... --- # upgrading | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/link/upgrading/#docusaurus_skipToContent_fallback) Redirecting... --- # pinned_versions | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/pinned_versions/#docusaurus_skipToContent_fallback) Redirecting... --- # 使用 Rush 库的 API | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/api/#docusaurus_skipToContent_fallback) On this page Rush 通过 API 提供了自动化脚本使用的接口。它在 Rush 工程中的竭诚 API 可以参考以下文档:      [接口手册: @microsoft/rush-lib package](https://api.rushstack.io/pages/rush-lib/) 下面是一些用法示例: > 虽然这些示例为 JavaScript 代码,但我们强烈建议使用 TypeScript. 起初需要花费些时间,但是长时间运行时,它可以节省时间和减少维护的工作。 读取 rush.json 配置[​](https://rushjs.io/zh-cn/pages/advanced/api/#%E8%AF%BB%E5%8F%96-rushjson-%E9%85%8D%E7%BD%AE "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- 建议使用提供了很多数据信息的 [RushConfiguration](https://api.rushstack.io/pages/rush-lib.rushconfiguration/) 类来读取 rush.json, 而不是直接读取 rush.json 文件。 例如,以下脚本展示了 Rush 内所有的项目和它们的文件夹: const rushLib = require('@microsoft/rush-lib');// loadFromDefaultLocation() 会搜索父亲文件来寻找 "rush.json", 之后会解析它并加载相关的配置文件。const rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});for (const project of rushConfiguration.projects) { console.log(project.packageName + ':'); console.log(' ' + project.projectRelativeFolder);} 修改 package.json 文件[​](https://rushjs.io/zh-cn/pages/advanced/api/#%E4%BF%AE%E6%94%B9-packagejson-%E6%96%87%E4%BB%B6 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------- 如果你想修改 **package.json** 文件,[PackageJsonEditor](https://api.rushstack.io/pages/rush-lib.packagejsoneditor/) 类提供了一些有用的校验和标准化方法: const rushLib = require('@microsoft/rush-lib');const rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});// 它将寻找在 rush.json 中的 "@rushstack/ts-command-line", 而不需要指定 NPM 包的作用域const project = rushConfiguration.findProjectByShorthandName('ts-command-line');// 将 lodash 作为一个可选依赖project.packageJsonEditor.addOrUpdateDependency('lodash', '4.17.15', 'optionalDependencies');// 保存修改过的 package.json 文件project.packageJsonEditor.saveIfModified(); 生成 README.md 摘要[​](https://rushjs.io/zh-cn/pages/advanced/api/#%E7%94%9F%E6%88%90-readmemd-%E6%91%98%E8%A6%81 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- 作为一个更实际的例子,[repo-toolbox/src/ReadmeAction.ts](https://github.com/microsoft/rushstack/blob/main/repo-scripts/repo-toolbox/src/ReadmeAction.ts) 展示了如何使用这些 API 来生成 Rush Stack 库的 [README.md](https://github.com/microsoft/rushstack/blob/main/README.md#published-packages) . * [读取 rush.json 配置](https://rushjs.io/zh-cn/pages/advanced/api/#%E8%AF%BB%E5%8F%96-rushjson-%E9%85%8D%E7%BD%AE) * [修改 package.json 文件](https://rushjs.io/zh-cn/pages/advanced/api/#%E4%BF%AE%E6%94%B9-packagejson-%E6%96%87%E4%BB%B6) * [生成 README.md 摘要](https://rushjs.io/zh-cn/pages/advanced/api/#%E7%94%9F%E6%88%90-readmemd-%E6%91%98%E8%A6%81) --- # 配置文件参考 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/config_files/#docusaurus_skipToContent_fallback) On this page 配置文件[​](https://rushjs.io/zh-cn/pages/advanced/config_files/#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------- | 文件列表 | 作用 | | --- | --- | | common/temp/install-run/... | 存储 **install-run.js** 和 **install-run-rush.js** 脚本。 可以查看[启用 CI 构建](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/)
一文。 | | common/temp/node\_modules/... | 安装的库,它只是 `npm install` 的输出,其中没有任何符号连接。 | | common/temp/npm-cache/... | 本地 NPM 的缓存,由于并发问题,Rush 不会使用全局的 NPM 缓存。 | | common/temp/npm-local/... | 基于 **npmVersion** 的配置,Rush 会在根目录安装 NPM 包,同时给每个项目创建符号链接。 | | common/temp/npm-tmp/... | NPM 安装时候创建的临时文件。 | | common/temp/projects/... | **common/temp/package.json** 引用的合成项目。 | | common/temp/rush-recycler/... | 用于加速递归删除。 | | common/temp/last-install.flag | 不必关心该文件,它追踪了上次 `rush install` 成功的时间戳。 | | common/temp/package.json | 公共文件的定义。 | | common/temp/rush-link.json | 不必关心该文件,当你执行 `rush link` 是它会创建,并被诸如 "rush build" 等命令读取。 | * [配置文件](https://rushjs.io/zh-cn/pages/advanced/config_files/#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) --- # Search the documentation | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/search/#docusaurus_skipToContent_fallback) Search the documentation ======================== [](https://typesense.org/?utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch) --- # command_line_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/command_line_json/#docusaurus_skipToContent_fallback) Redirecting... --- # common_versions_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/common_versions_json/#docusaurus_skipToContent_fallback) Redirecting... --- # version_policies_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/version_policies_json/#docusaurus_skipToContent_fallback) Redirecting... --- # Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/#docusaurus_skipToContent_fallback) Rush让那些从一个公共Git仓库构建和发布多个包的JavaScript开发者的生活变得更轻松。如果你正打算将你的大型应用程序分解为更小的部分,并且你已经意识到 [为什么这不可行](https://rushjs.io/zh-cn/pages/intro/why_mono/) 将每个包放在一个单独的仓库里... 那么Rush就是为你准备的! ![monorepo diagram](https://rushjs.io/images/home/mono-concept-h.svg) ![monorepo diagram](https://rushjs.io/images/home/mono-concept-v.svg) Rush的不同之处 ========= 现在许多不同的工具可以在20个不同的文件夹中运行"npm install"和"npm run build"。那么Rush有什么优点呢? ![Git repositories](https://rushjs.io/images/home/card-repo.svg) 适应大型仓库 ------ Rush是由维护大型生产单仓库的专业工程师构建的。我们的工作是为我们的同事提供最佳的开发者体验,而不是将你转变为付费咨询或托管服务的客户。我们维护的仓库包含有多年Git历史记录的数百个应用程序。为了管理这种规模,Rush提供并行构建、子集构建、增量构建和分布式构建。 ![large team](https://rushjs.io/images/home/card-people.svg) 为大型团队设计 ------- Rush提供了许多机制来引导新手和协调团队间的协作。仓库策略允许在接受新的包依赖关系之前对其进行审查。Rush可以在你的仓库中强制执行一致的依赖版本。不同的项目子集可以使用锁定步调或独立版本策略进行独立发布。 ![NPM phantom dependency](https://rushjs.io/images/home/card-phantom.svg) 可靠的NPM安装 -------- Rush的安装模型利用PNPM包管理器消除 [幽灵依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) 和 [NPM替身](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/) 这些使大规模安装受挫的问题。你可以使用我们的 [锁文件资源管理器](https://lfx.rushstack.io/) 配套工具来可视化和解决版本冲突。 ![motorbike and tricycle](https://rushjs.io/images/home/card-trike.svg) 易于管理 ---- 当你维护一个大型仓库时,你不希望开发者提出无法在任何其他计算机上复现的支持请求。Rush有助于确保安装和构建完全确定。甚至Rush引擎版本也会根据你的Git分支自动安装。如果你定义自定义命令或选项,它们会被严格验证,并作为Rush命令行帮助的一部分进行文档记录。 ![army knife](https://rushjs.io/images/home/card-knife.svg) 一站式解决方案 ------- 厌倦了从多个工具中拼凑出你的开发者体验,而这些工具似乎从未正确集成过吗?Rush是一个统一的协调器,可以安装、链接、构建、生成变更日志、发布和升级版本。这些功能旨在与更广泛的 [Rush Stack](https://rushstack.io/) 工具和实践套件集成。 ![free price tag](https://rushjs.io/images/home/card-free.svg) 开放模式 ---- Rush软件是免费和开源的。我们欢迎社区的贡献!我们也对你的工具链持开放态度:在Rush仓库中,每个项目文件夹都保持完全独立,可以单独安装,如果需要也易于迁移。只需要相对较少的努力就可以为一组特定的项目启用/禁用Rush。 谁在使用Rush? ========= [![Azure SDK logo](https://rushjs.io/images/3rdparty/azure.png)\ \ Azure SDK](https://github.com/azure/azure-sdk-for-js) [![HBO Max logo](https://rushjs.io/images/3rdparty/hbomax.png)\ \ HBO Max](https://www.hbomax.com/) ![OneDrive logo](https://rushjs.io/images/3rdparty/onedrive.png) OneDrive ![SharePoint logo](https://rushjs.io/images/3rdparty/sharepoint.png) SharePoint ![Office 365 Small Business logo](https://rushjs.io/images/3rdparty/o365.png) Office 365 Small Business ![Windows Store logo](https://rushjs.io/images/3rdparty/windows_store.png) Windows Store ![Office Web Apps logo](https://rushjs.io/images/3rdparty/o365.png) Office Web Apps [![SimplrJS react-forms logo](https://rushjs.io/images/3rdparty/simplrjs.png)\ \ SimplrJS react-forms](https://github.com/SimplrJS/react-forms) [![Telia Company logo](https://rushjs.io/images/3rdparty/telia.png)\ \ Telia Company](https://www.telia.se/) [![Welbi logo](https://rushjs.io/images/3rdparty/welbi.png)\ \ Welbi](https://www.welbi.co/) [![Wix logo](https://rushjs.io/images/3rdparty/wix.png)\ \ Wix](https://www.wix.com/) --- # What's new | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/news/#docusaurus_skipToContent_fallback) On this page To find out what's changed in the latest release, please see the Rush [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush/CHANGELOG.md) . Rush is maintained by the Rush Stack developer community. For roadmaps and updates from the team, please visit the [Rush Stack News](https://rushstack.io/pages/news/) page. The **Rush Hour** monthly video call is the easiest way to find out what's happening with Rush Stack: * Sign up using the [Events](https://rushstack.io/community/events/) page. * If you missed an event, the [Past Events](https://rushstack.io/community/past-events/) archive often includes a green **Meeting Notes** button with a summary of important points. Announcements[​](https://rushjs.io/pages/news/#announcements "Direct link to Announcements") --------------------------------------------------------------------------------------------- Follow us on [Mastodon (@rushstack@fosstodon.org)](https://fosstodon.org/@rushstack) or [Twitter (@rushstack)](https://twitter.com/rushstack) . Mastodon feed for [@rushstack@fosstodon.org](https://fosstodon.org/@rushstack) . . . [•   •   •](https://fosstodon.org/@rushstack) * [Announcements](https://rushjs.io/pages/news/#announcements) --- # Contributing | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/contributing/#docusaurus_skipToContent_fallback) On this page Rush is developed in the monorepo for the [Rush Stack](https://rushstack.io/) family of projects:      [https://github.com/microsoft/rushstack](https://github.com/microsoft/rushstack) Contribute to the documentation website in the [rushstack-websites](https://github.com/microsoft/rushstack-websites/tree/main/websites/rushjs.io) GitHub repo. For general instructions for building Rush and guidelines for submitting PRs, please read the [Contributing](https://rushstack.io/pages/contributing/get_started/) documentation for the Rush Stack monorepo. The relevant monorepo project folders are: * [apps/rush](https://github.com/microsoft/rushstack/tree/main/apps/rush) - the command line interface front end * [libraries/rush-lib](https://github.com/microsoft/rushstack/tree/main/libraries/rush-lib) - the automation API and "engine" where all the logic is implemented Testing Rush builds[​](https://rushjs.io/pages/contributing/#testing-rush-builds "Direct link to Testing Rush builds") ----------------------------------------------------------------------------------------------------------------------- Once you have coded your fix and built your branch (as described in the general [Contributing](https://rushstack.io/pages/contributing/get_started/) notes), you will want to test your development build of Rush. Rush features a mechanism called the **version selector**, which reads `rushVersion` from **rush.json** and then automatically installs and invokes that specific version of the engine. Thus if we launch your build of `@microsoft/rush`, it will not actually run your modified code. To bypass the version selector, we need to invoke the `@microsoft/rush-lib` engine directly: cd rushstack/libraries/rush-libnode ./lib/start.js --help If you want to make it easy invoke your test build from other locations, we recommend to create a `testrush` command. For Bash on Mac OS or Linux: # Substitute the full path to your own build of rush-lib:alias testrush="node ~/git/rushstack/libraries/rush-lib/lib/start.js" For Windows, we might create `testrush.cmd` and add it to our system `PATH`: @ECHO OFFREM Substitute the full path to your own build of rush-lib:node "C:\Git\rushstack\apps\rush-lib\lib\start.js" %* Debugging Rush[​](https://rushjs.io/pages/contributing/#debugging-rush "Direct link to Debugging Rush") -------------------------------------------------------------------------------------------------------- The same approach is used to debug Rush using the VS Code debugger. Create a debugger configuration file like this: **rushstack/libraries/rush-lib/.vscode/launch.json** { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug Rush", "program": "${workspaceFolder}/lib/start.js", "args": [ "list", "--json" ], // <====== specify your Rush command line arguments here "cwd": "(repo folder that you want to debug)", // <===== specify your target working folder here // The Node.js debugger injects its own messages into the subprocess STDERR, which Rush // may misinterpret as a build failure. You can uncomment this line as a workaround: // "env": { "RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD": "1" } } ]} After saving this file, in VS Code click _"View" --> "Run"_ and choose your "Debug Rush" configuration from the list. Then click _"Run" --> "Start Debugging"_ to start debugging. Breakpoints and TypeScript source maps should work correctly. > **TIP:** If Rush builds seem to fail in the debugger due to "warnings" such as > > Debugger attached.Waiting for the debugger to disconnect... > > ...see the code commented above regarding [RUSH\_ALLOW\_WARNINGS\_IN\_SUCCESSFUL\_BUILD](https://rushjs.io/pages/configs/environment_vars/#rush_allow_warnings_in_successful_build) > . Building without unit tests[​](https://rushjs.io/pages/contributing/#building-without-unit-tests "Direct link to Building without unit tests") ----------------------------------------------------------------------------------------------------------------------------------------------- Rush builds using the [Heft](https://heft.rushstack.io/) toolchain. You can invoke the `heft` command-line directly for better additional options. # Full incremental build of Rush and its dependencies, including unit testsrush build --to rush-lib --verbose# Do a quick build of "rush-lib" only without unit testscd rushstack/libraries/rush-librushx build * [Testing Rush builds](https://rushjs.io/pages/contributing/#testing-rush-builds) * [Debugging Rush](https://rushjs.io/pages/contributing/#debugging-rush) * [Building without unit tests](https://rushjs.io/pages/contributing/#building-without-unit-tests) --- # pnpm-issue-5132 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/link/pnpm-issue-5132/#docusaurus_skipToContent_fallback) Redirecting... --- # Rush files and folders | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/rush_files_and_folders/#docusaurus_skipToContent_fallback) On this page Every Rush monorepo has a standard folder structure that is created by `rush init` and validated by `rush update`. Configuration files[​](https://rushjs.io/pages/advanced/rush_files_and_folders/#configuration-files "Direct link to Configuration files") ------------------------------------------------------------------------------------------------------------------------------------------ | Folder path | What it does | | --- | --- | | [rush.json](https://rushjs.io/pages/configs/rush_json/) | The main configuration file for Rush | | [common/config/rush/.npmrc](https://rushjs.io/pages/configs/npmrc/) | If you need custom settings for "npm install" (e.g. NPM registry mappings), put them in this file. Rush will copy this file into the **common/temp/** folder. | | [common/config/rush/.npmrc-publish](https://rushjs.io/pages/configs/npmrc-publish/) | Used instead of `.npmrc` for publishing operations. | | [common/config/artifactory.json](https://rushjs.io/pages/configs/artifactory_json/) | Configuration for Rush integration with JFrog Artifactory services. | | [common/config/build-cache.json](https://rushjs.io/pages/configs/build-cache_json/) | Configuration for Rush's [Build cache](https://rushjs.io/pages/maintainer/build_cache/) | | [common/config/rush/command-line.json](https://rushjs.io/pages/configs/command-line_json/) | Used to define [custom commands](https://rushjs.io/pages/maintainer/custom_commands/)
. | | [common/config/rush/common-versions.json](https://rushjs.io/pages/configs/common-versions_json/) | Used to specify versions that affect all projects in a repo. | | [common/config/rush/deploy.json](https://rushjs.io/pages/configs/deploy_json/) | Used to define profiles for the [rush deploy](https://rushjs.io/pages/commands/rush_deploy/)
command | | [common/config/rush/experiments.json](https://rushjs.io/pages/configs/experiments_json/) | Enables experimental features of Rush | | common/config/rush/npm-shrinkwrap.json | The shrinkwrap file when your package manager is NPM. This is the common shrinkwrap file that applies to all projects in the Rush repo. For more information, see **"What is this "shrinkwrap file"** in the [Everyday commands](https://rushjs.io/pages/developer/everyday_commands/)
section. | | common/config/rush/rush-plugins.json | Specifies [Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/)
to be loaded for the monorepo. | | common/config/rush/pnpm-lock.yaml | The shrinkwrap file when your package manager is PNPM. | | common/config/rush/yarn.lock | The shrinkwrap file when your package manager is Yarn. | | common/config/rush/browser-approved-packages.json | Used by the **approvedPackagesPolicy** setting from [rush.json](https://rushjs.io/pages/configs/rush_json/) | | common/config/rush/nonbrowser-approved-packages.json | Used by the **approvedPackagesPolicy** setting from rush.json | | [common/config/rush/pnpm-config.json](https://rushjs.io/pages/configs/pnpm-config_json/) | Configuration specific to the PNPM package manager | | [common/config/rush/version-policies.json](https://rushjs.io/pages/configs/version-policies_json/) | Defines the [rush version](https://rushjs.io/pages/commands/rush_version/)
and [rush publish](https://rushjs.io/pages/commands/rush_publish/)
workflows. | Standard Rush folders[​](https://rushjs.io/pages/advanced/rush_files_and_folders/#standard-rush-folders "Direct link to Standard Rush folders") ------------------------------------------------------------------------------------------------------------------------------------------------ | Folder path | What it does | | --- | --- | | common/autoinstallers/... | [Autoinstaller projects](https://rushjs.io/pages/maintainer/autoinstallers/)
are created under this folder | | common/changes/... | Stores change files created by the [rush change](https://rushjs.io/pages/commands/rush_change/)
command and consumed by the [rush version](https://rushjs.io/pages/commands/rush_version/)
command. | | common/deploy/... | The [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/)
creates deployment configurations under this folder. | | common/git-hooks/... | Rush's [git hook scripts](https://rushjs.io/pages/maintainer/git_hooks/)
are defined here | | common/pnpm-patches/... | The [rush-pnpm commit-patch](https://rushjs.io/pages/commands/rush-pnpm/)
command stores package patch files under this folder | | common/scripts/install-run-rush.js | CI bootstrap script for invoking `rush`. The `rush update` generates this file, which should be committed to Git. See [Enabling CI builds](https://rushjs.io/pages/maintainer/enabling_ci_builds/)
for details. | | common/scripts/install-run-rush-pnpm.js | CI bootstrap script for invoking [rush-pnpm](https://rushjs.io/pages/commands/rush-pnpm/)
. | | common/scripts/install-run-rushx.js | CI bootstrap script for invoking [rushx](https://rushjs.io/pages/commands/rushx/)
. | | common/scripts/install-run.js | CI bootstrap script for invoking arbitrary NPM packages. | Temporary files created by Rush[​](https://rushjs.io/pages/advanced/rush_files_and_folders/#temporary-files-created-by-rush "Direct link to Temporary files created by Rush") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | Folder path | What it does | | --- | --- | | common/temp/build-cache/... | Default storage location for Rush's [Build cache](https://rushjs.io/pages/maintainer/build_cache/) | | common/temp/install-run/... | Storage for the **install-run.js** and **install-run-rush.js** scripts. See [Enabling CI builds](https://rushjs.io/pages/maintainer/enabling_ci_builds/)
. | | common/temp/node\_modules/... | The installed packages. This is a plain old `npm install` output, with no symlinks in this tree. | | common/temp/npm-cache/... | A local NPM cache will be created here. Rush does not use the global NPM cache due to its concurrency problems. | | common/temp/npm-local/... | If the NPM package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/npm-tmp/... | Temporary files created by NPM during installation. | | common/temp/patches/... | The [rush-pnpm patch](https://rushjs.io/pages/commands/rush-pnpm/)
command creates patch files under this temporary folder (which `rush-pnpm commit-patch` will copy to `common/pnpm-patches`) | | common/temp/pnpm-local/... | If the PNPM package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/pnpm-store/... | If the PNPM package manager is selected, this is the default location of the PNPM store. (It can be redirected using the `RUSH_PNPM_STORE_PATH` environment variable.) | | common/temp/projects/... | Synthetic projects referenced by **common/temp/package.json**. | | common/temp/rush-recycler/... | Used to speed up recursive deletes. | | common/temp/telemetry/... | Stores telemetry output saved by Rush when `telemetryEnabled=true` in **rush.json** | | common/temp/yarn-local/... | If the Yarn package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/last-install.flag | Don't worry about this file. It tracks the timestamp of the last successful `rush install`. | | common/temp/package.json | The common package definition. | | common/temp/repo-state.json | Generated by the `preventManualShrinkwrapChanges` setting from [pnpm-config.json](https://rushjs.io/pages/configs/pnpm-config_json/) | | common/temp/rush-link.json | Don't worry about this file. It is created whenever you run `rush link`, and read by later commands such as "rush build". | * [Configuration files](https://rushjs.io/pages/advanced/rush_files_and_folders/#configuration-files) * [Standard Rush folders](https://rushjs.io/pages/advanced/rush_files_and_folders/#standard-rush-folders) * [Temporary files created by Rush](https://rushjs.io/pages/advanced/rush_files_and_folders/#temporary-files-created-by-rush) --- # Rush subspaces | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/subspaces/#docusaurus_skipToContent_fallback) On this page What are subspaces?[​](https://rushjs.io/pages/advanced/subspaces/#what-are-subspaces "Direct link to What are subspaces?") ---------------------------------------------------------------------------------------------------------------------------- Subspaces are a Rush feature that enables a single monorepo to install using multiple PNPM lockfiles. For example, if the subspace name is `my-team`, there will be a folder `common/config/subspaces/my-team/` containing the `pnpm-lock.yaml` file and related configuration. Each Rush project belongs to exactly one subspace, and the monorepo still has one unified "workspace." Thus, a project's `package.json` file can use the `workspace:` specifier to depend on projects from other subspaces. What is the benefit?[​](https://rushjs.io/pages/advanced/subspaces/#what-is-the-benefit "Direct link to What is the benefit?") ------------------------------------------------------------------------------------------------------------------------------- Generally it's best to have a single lockfile for the entire monorepo, as this optimizes installation time and minimizes maintenance work for managing version conflicts. However, multiple lockfiles have advantages in certain situations: * **A very large codebase**: A lockfile can be thought of as giant multivariable equation, which we solve by coordinating NPM package version choices across many projects to eliminate conflicts and minimize duplication. (The [Lockfile Explorer](https://lfx.rushstack.io/) docs explain this in depth.) Dividing up monorepo dependencies into smaller lockfiles does make these equations smaller and easier to solve, but with the tradeoff of increasing the total overhead for managing versions. With a very large engineering team, dividing up the work can be more important than minimizing the total amount of work. * **Decoupled project sets**: A large code base may have certain clusters of projects whose dependencies are not aligned with the rest of the repo. For example, suppose 50 projects comprise a legacy application that uses a deprecated or outdated framework, with no business motivation to modernize it. Moving these projects into a subspace enables their versioning to be managed independently. * **Installation testing**: When publishing NPM packages, certain bugs cannot be reproduced using `workspace:*` symlinking. For example, phantom dependencies or incorrect `.npmignore` globs will cause failures for external consumers of a package, but may work fine when the same library is tested within the monorepo. Moving test projects into a subspace (combined with [injected dependencies](https://rushjs.io/pages/advanced/injected_deps/) ) produces a more accurate installation that can catch such problems, while still avoiding the overhead of actually publishing to a testing NPM registry. How many subspaces do I need?[​](https://rushjs.io/pages/advanced/subspaces/#how-many-subspaces-do-i-need "Direct link to How many subspaces do I need?") ---------------------------------------------------------------------------------------------------------------------------------------------------------- We generally recommend "as few as possible" to minimize additional version management overhead. _One subspace per team_ is a sensible maximum limit. That said, this feature has been used successfully in a production monorepo with more than 1,000 subspaces. > **Real world demo** > > Rush Stack's own repository on GitHub is currently configured with two subspaces: > > * [common/config/subspaces/build-tests-subspace](https://github.com/microsoft/rushstack/tree/main/common/config/subspaces/build-tests-subspace) > : used to test installation of published NPM packages > * [common/config/subspaces/default](https://github.com/microsoft/rushstack/tree/main/common/config/subspaces/default) > : contains all other projects Feature design[​](https://rushjs.io/pages/advanced/subspaces/#feature-design "Direct link to Feature design") -------------------------------------------------------------------------------------------------------------- Each subspace must have its name registered centrally in the [common/config/subspaces.json](https://rushjs.io/pages/configs/subspaces_json/) config file. Projects are added to a subspace using their `subspaceName` field in [rush.json](https://rushjs.io/pages/configs/rush_json/) . The configuration for each subspace goes in a folder `common/config/subspaces//`, which may contain the following files: | Subspace file | Purpose | | --- | --- | | [`common-versions.json`](https://rushjs.io/pages/configs/common-versions_json/) | Rush version overrides | | [`pnpm-config.json`](https://rushjs.io/pages/configs/pnpm-config_json/) | PNPM version overrides | | `pnpm-lock.yaml` | The PNPM lockfile | | `repo-state.json` | A config file generated by Rush to prevent manual lockfile changes | | [`.npmrc`](https://rushjs.io/pages/configs/npmrc/) | package manager configuration | | [`.pnpmfile.cjs`](https://rushjs.io/pages/configs/pnpmfile_cjs/) | programmatic version overrides | > Note that `common/config/.npmrc-publish` is not specified for subspaces. Package publishing is generally unrelated to package installation. Some of these files can be defined at both levels, as summarized in the table below: * Subspace config folder: `common/config/subspaces//` * Monorepo config folder: `common/config/rush/` | Subspace file | Monorepo file | Inheritance | | --- | --- | --- | | `common-versions.json` | none | _When using subspaces, the monorepo file is forbidden._ | | `pnpm-config.json` | `pnpm-config.json` | **Fallback**: The monorepo file is used only if the subspace's file is absent. | | `pnpm-lock.yaml` | none | _When using subspaces, the monorepo file is forbidden._ | | `repo-state.json` | none | _When using subspaces, the monorepo file is forbidden._ | | `.npmrc` | `.npmrc` | **Merged**: The two files are merged, with subspace settings taking precedence. (This merging occurs when Rush generates the temporary `.npmrc` file in the working directory of the operation.) | | `.pnpmfile.cjs` | none | _When using subspaces, the monorepo file is forbidden._ | Without subspaces, Rush generates and installs the PNPM workspace in the `common/temp/` folder. With subspaces enabled, this will be performed separately in folders such as `common/temp//`. There are two basic modes of operation: 1. **Just a few subspaces:** You can set `"preventSelectingAllSubspaces": false` in `subspaces.json`, and `rush install` by default will install all subspaces. 2. **Lots of subspaces:** If installing all subspaces would consume too much time and disk space, then you can set `"preventSelectingAllSubspaces": true`. In this mode, when invoking commands like `rush install` or `rush update`, users MUST filter the subspaces in some way, such as: * `rush install --to my-project` to install only dependencies of a given project * `rush install --subspace my-subspace` to install only a specific subspace * `rush install --to subspace:my-subspace` using a [project selector](https://rushjs.io/pages/developer/selecting_subsets/#subspace-members-subspace) to install for projects belonging to a given subspace How to enable subspaces[​](https://rushjs.io/pages/advanced/subspaces/#how-to-enable-subspaces "Direct link to How to enable subspaces") ----------------------------------------------------------------------------------------------------------------------------------------- 1. Make sure your **rush.json** specifies `"rushVersion": "5.122.0"` or newer, and `"pnpmVersion": "8.7.6"` or newer. 2. Use **subspaces.json** to enable the feature and define the subspaces. You can copy the template for this file from the [subspaces.json](https://rushjs.io/pages/configs/subspaces_json/) docs, or use `rush init` to generate it. In this tutorial, we'll create one subspace called `install-test` for testing NPM packages: **common/config/rush/subspaces.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", /** * Set this flag to "true" to enable usage of subspaces. */ "subspacesEnabled": false, /** * When a command such as "rush update" is invoked without the "--subspace" or "--to" * parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces, * this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this * mistake by always requiring selection parameters for commands such as "rush update". */ "preventSelectingAllSubspaces": false, /** * The list of subspace names, which should be lowercase alphanumeric words separated by * hyphens, for example "my-subspace". The corresponding config files will have paths * such as "common/config/subspaces/my-subspace/package-lock.yaml". */ "subspaceNames": [ // The "default" subspace always exists even if you don't define it, // but let's include it for clarity "default", "install-test" // 👈👈👈 Our secondary subspace name ]} 3. Create the `default` subspace folder and move the existing config files there: cd my-repomkdir --parents common/config/subspaces/default# Move these files:mv common/config/rush/common-versions.json common/config/subspaces/default/mv common/config/rush/pnpm-lock.yaml common/config/subspaces/default/mv common/config/rush/.npmrc common/config/subspaces/default/# Rename this file:mv common/config/rush/.pnpmfile.cjs common/config/subspaces/default/.pnpmfile.cjs 4. Create the `install-test` subspace folder: cd my-repomkdir --parents common/config/subspaces/install-test 5. Assign projects to subspaces by editing `rush.json`. For example: **rush.json** . . . "projects": [ { "packageName": "my-library-test", "projectFolder": "test-projects/my-library-test", "subspaceName": "install-test" }. . .\ \ If `"subspaceName"` is omitted for any projects, they will belong to the `default` subspace.\ \ 6. Now update the lockfiles for the new subspaces:\ \ # Clean out the common/temp folder from beforerush purge# Regenerate the "default" subspace:rush update --full --subspace default# Regenerate the "install-test" subspace:rush update --full --subspace install-test\ \ > **Note:** You can migrate to subspaces without using `--full` to regenerate any lockfiles, but it is a more involved process that may involve using a script to rewrite some paths in the `pnpm-lock.yaml` files.\ \ \ See also[​](https://rushjs.io/pages/advanced/subspaces/#see-also "Direct link to See also")\ \ --------------------------------------------------------------------------------------------\ \ * [subspaces.json](https://rushjs.io/pages/configs/subspaces_json/)\ config file\ * [rfc-4230-rush-subspaces.md](https://github.com/microsoft/rushstack/blob/main/common/docs/rfcs/rfc-4230-rush-subspaces.md)\ : The original spec for this feature, which explains the motivation and design in more detail\ \ * [What are subspaces?](https://rushjs.io/pages/advanced/subspaces/#what-are-subspaces)\ \ * [What is the benefit?](https://rushjs.io/pages/advanced/subspaces/#what-is-the-benefit)\ \ * [How many subspaces do I need?](https://rushjs.io/pages/advanced/subspaces/#how-many-subspaces-do-i-need)\ \ * [Feature design](https://rushjs.io/pages/advanced/subspaces/#feature-design)\ \ * [How to enable subspaces](https://rushjs.io/pages/advanced/subspaces/#how-to-enable-subspaces)\ \ * [See also](https://rushjs.io/pages/advanced/subspaces/#see-also) --- # Agent context files | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/ai/context_files/#docusaurus_skipToContent_fallback) Artificial intelligence (AI) **coding assistants** are software agents that help engineers to write code and investigate problems more efficiently. They typically rely on **large language models** (LLMs) trained with general knowledge about software engineering, but often will not have specific familiarity with Rush's workspace structure, the latest features of Rush, or details about your own team's projects. You can improve the accuracy of these tools by adding **context files** to your monorepo. Context files contain additional instructions and information to help the agent. The table below provides links to reusable context files designed for popular coding assistants. | Coding assistant | Context file template for Rush | | --- | --- | | [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot) | [.github/copilot-instructions.md](https://github.com/microsoft/rushstack/blob/main/.github/copilot-instructions.md) | | [Cursor](https://docs.cursor.com/context/rules) | [.cursor/rules/rush.mdc](https://github.com/microsoft/rushstack/blob/main/.cursor/rules/rush.mdc) | | [Trae](https://docs.trae.ai/ide/rules-for-ai?_lang=en) | [.trae/project\_rules.md](https://github.com/microsoft/rushstack/blob/main/.trae/project_rules.md) | **If your coding assistant does not appear in this table:** please add it! First, make a pull request to add your file to the [microsoft/rushstack](https://github.com/microsoft/rushstack/pulls) repository. Then make a pull request in the [microsoft/rushstack-websites](https://github.com/microsoft/rushstack-websites/blob/main/websites/rushjs.io/docs/pages/ai/context_files.md) repository, updating the table above to add a link for your file. --- # rush add | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_add/#docusaurus_skipToContent_fallback) On this page usage: rush add [-h] -p PACKAGE [--exact] [--caret] [--dev] [-m] [-s] [--all]Adds specified package(s) to the dependencies of the current project (asdetermined by the current working directory) and then runs "rush update". Ifno version is specified, a version will be automatically detected (typicallyeither the latest version or a version that won't break the"ensureConsistentVersions" policy). If a version range (or a workspace range)is specified, the latest version in the range will be used. The version willbe automatically prepended with a tilde, unless the "--exact" or "--caret"flags are used. The "--make-consistent" flag can be used to update allpackages with the dependency.Optional arguments: -h, --help Show this help message and exit. -p PACKAGE, --package PACKAGE (Required) The name of the package which should be added as a dependency. A SemVer version specifier can be appended after an "@" sign. WARNING: Symbol characters are usually interpreted by your shell, so it's recommended to use quotes. For example, write "rush add --package "example@^1.2.3"" instead of "rush add --package example@^1.2.3". To add multiple packages, write "rush add --package foo --package bar". --exact If specified, the SemVer specifier added to the package.json will be an exact version (e.g. without tilde or caret). --caret If specified, the SemVer specifier added to the package.json will be a prepended with a "caret" specifier ("^"). --dev If specified, the package will be added to the "devDependencies" section of the package.json -m, --make-consistent If specified, other packages with this dependency will have their package.json files updated to use the same version of the dependency. -s, --skip-update If specified, the "rush update" command will not be run after updating the package.json files. --all If specified, the dependency will be added to all projects. See also[​](https://rushjs.io/pages/commands/rush_add/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------- * [Modifying package.json](https://rushjs.io/pages/developer/modifying_package_json/) * [rush remove](https://rushjs.io/pages/commands/rush_remove/) * [See also](https://rushjs.io/pages/commands/rush_add/#see-also) --- # PNPM Compatibility DB | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/compatibility_db/#docusaurus_skipToContent_fallback) Both Yarn and PNPM support a feature called the **Compatibility DB**, which is a public database of **package.json** fixups. These fixups solve known issues that the official maintainer of an NPM package may be unwilling to solve. (The best practice would be to avoid such packages, but often that is impractical.) Compatibility DB fixups are similar to user-authored rules found in **.pnpmfile.cjs**. They are maintained with the [@yarnpkg/extensions](https://www.npmjs.com/package/@yarnpkg/extensions) package. PNPM's feature protects small projects from common pitfalls, but the approach has some downsides for a large monorepo: * Hidden magic: The fixups are bundled into the PNPM binary. When trying to coordinate complex cross-project version dependencies, it is awkward for key inputs to be in a file with no Git diff, not even viewable in the GitHub website. * Unnecessary coupling: Different versions of the `@yarnpkg/extensions` rules are bundled into different PNPM releases. This may cause churn the lockfile when upgrading or downgrading the package manager. * Applied last: The fixups are applied after **.pnpmfile.cjs**. This means the fixed up versions aren't visible to the user's own transformations or logging, and **.pnpmfile.cjs** is no longer the final authority about version choices. To avoid these issues, `rush install` and `rush update` always disable the Compatibility DB feature when invoking PNPM. Details: * Compatibility DB is implemented by PNPM versions `>= 6.32.12`, `>= 7.0.1` (but not `7.0.0`) * The `ignore-compatibility-db` switch is implemented in newer PNPM releases: `>= 6.34.0 <7.0.01` and `>= 7.9.0` * Compatibility DB is disabled by Rush versions `>= 5.76.0` if possible... * ..otherwise, if the switch is missing, Rush prints a warning recommending to upgrade PNPM The Compatibility DB fixes are useful. To apply them in your Rush repo, it's recommended to copy these settings into a proper Git-tracked file such as **.pnpmfile.cjs**. > 💡 Feature idea: Propose an automated mechanism for syncing `@yarnpkg/extensions` into a Git-tracked file under `common/config/rush`. --- # Authoring change logs | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/best_practices/change_logs/#docusaurus_skipToContent_fallback) On this page When publishing an NPM package, it is common practice to include a [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) file to inform your consumers about bug fixes, new features, and changed or removed functionality. Rush automates this using the [rush change](https://rushjs.io/pages/commands/rush_change/) command. This command should be run once you are ready to merge your PR, after all your changes have been committed to the branch. It analyzes the changes in your branch and (when necessary) prompts you to write human-readable descriptions of your changes. The way in which you phrase your description is important. You don't want to be overly concise or specific, you don't want to reveal private information, and you want the description to be as helpful as possible. We recommend to err on the side of readability. Ask yourself: * "How is my change relevant to a third-party developer?" * "Could it break them?" * "Does it fix a bug that's been annoying them?" * "Is it a new feature for them to try?" In some workflows, a human editor will review the change logs before they are published, however everyone should do their best to ensure that the content is clear and professional. Recommended Practices[​](https://rushjs.io/pages/best_practices/change_logs/#recommended-practices "Direct link to Recommended Practices") ------------------------------------------------------------------------------------------------------------------------------------------- * Use the [present simple tense](http://www.englishtenses.com/tenses/present_simple) using the [imperative ("command") mood](http://grammarist.com/grammar/english-moods/) . * Write from the perspective of an external audience who may be unfamiliar with implementation details of your package * Focus on scenario outcomes ("Searching now supports wildcards") instead of code changes ("Added regular expression support to SearchHelper class") * Start with a verb. These verbs are recommended: * **Add** - when you introduce or expose a new feature, property, class, UI, etc. * **Remove** - when you fully removed something and it can no longer be used. * **Deprecate** - when you plan on removing something, but it is still accessible. * **Fix an issue with/where...** - when you fixed a bug. * **Improve** - when you made an existing thing better. * **Update** - when you refresh something, but don't necessarily make it better. * **Upgrade** - when upgrading the version of a dependency. * **Initial/Beta release of ...** - when releasing a brand-new feature. * Don't use the word **bug**. Use **issue** instead. * Don't use shorthand words or acronyms, unless they are widely recognized (e.g. "HTTP") * Use correct spelling and grammar. The CHANGELOG.md is part of your package's published documentation. * When referring to public API changes, use the `()` suffix to indicate a function name, e.g. `setSomethingOnWebpart()` * When referring to public API changes, use backticks (`` ` ` ``) around class and property names. * When documenting an upgrade, indicate the old and new version. For example: "Upgraded `widget-library` from `1.0.2` to `2.0.1`" * If fixing a GitHub issue, consider adding the issue URL in parentheses. * Don't add a trailing period unless you have two or more sentences. Example Change Log Messages[​](https://rushjs.io/pages/best_practices/change_logs/#example-change-log-messages "Direct link to Example Change Log Messages") ------------------------------------------------------------------------------------------------------------------------------------------------------------- Here are some hypothetical change log messages that might be provided to `rush change`: * _Add "buttonColor" to the button manifest schema_ * _Remove support for older mobile web browsers as described in the README.md_ * _Deprecate the `doSomething()` API function. Use `doSomethingBetter()` instead._ * _Fix an issue where "ExampleWidget" API did not handle dates correctly_ * _Improve the diagnostic logging when running in advanced mode_ * _Upgrade from React 15 to React 16_ * _Initial release of the flexible panels feature_ * [Recommended Practices](https://rushjs.io/pages/best_practices/change_logs/#recommended-practices) * [Example Change Log Messages](https://rushjs.io/pages/best_practices/change_logs/#example-change-log-messages) --- # Enabling a merge queue | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/best_practices/merge_queue/#docusaurus_skipToContent_fallback) On this page A **merge queue** (also called **commit queue** or **merge train**) improves continuous integration (CI) systems by providing two key features: * **increased safety** by avoiding build breaks that may occur if Git branches are validated _before_ they are merged rather than _after_ they are merged * **higher throughput** by intelligently combining work or parallelizing jobs The merge queue can be a built-in feature for popular CI systems such as GitHub or GitLab, or it may be an add-on service. Motivating example[​](https://rushjs.io/pages/best_practices/merge_queue/#motivating-example "Direct link to Motivating example") ---------------------------------------------------------------------------------------------------------------------------------- Suppose pull requests 1 and 2 are waiting to get merged into your `main` branch, and their branches are named `pr1` and `pr2`. Traditionally there were a few basic approaches to validation: 1. **Slow but safe:** Let's use `start` to refer to the latest commit of the `main` branch. The CI system creates a temporary branch `start+pr1` (merging `start` with `pr1`). We build this "hot merge" and, if successful, now we can merge PR 1 into `main`. If PR 2 had an ongoing build, it should be aborted, because `main` has changed. Its hot merge needs to be redone using `start+pr1+pr2`, because that is what will be in `main` after PR 2 merges. This approach ensures correctness of every commit in `main`. However in an active monorepo, a backlog will quickly pile up, because the builds that ultimately get merged are not being parallelized at all. 2. **Optimistic:** Being less strict, we could choose to allow PR 2 to get merged with only a successful build of `start+pr2`, even though the final commit will be `start+pr1+pr2`. In effect, we are hoping that if `start+pr1` and `start+pr2` built successfully, then so would `start+pr1+pr2`. This is usually true, but for example if PR 1 renames an API, whereas PR 2 introduces a new call to that API, then their combination would fail even though they succeeded individually. The optimistic approach is significantly faster, since PR 1 and PR 2 can build in parallel and merge in any order. However, whenever the `main` branch gets broken, it's an unfortunate incident that requires reverting PR's or merging fixes to get back to a good state. Depending on support staff, this could take hours or even days, during which everyone's work is interrupted. In a high traffic monorepo, these incidents become prohibitively costly. 3. **Naively optimistic:** It's worth mentioning that early systems didn't even perform the hot merge. They used the optimistic strategy but with a potentially very outdated base from `main`. A policy might be used to restrict how old the base could be, measured in hours or Git commits. How a merge queue helps[​](https://rushjs.io/pages/best_practices/merge_queue/#how-a-merge-queue-helps "Direct link to How a merge queue helps") ------------------------------------------------------------------------------------------------------------------------------------------------- Let's start with a decision that safety is non-negotiable: after PR 1 has merged into `main`, we will NOT accept PR 2 based on a successful build of `start+pr2`. To be safe, we insist on having a successful build of `start+pr1+pr2`. The big insight of a merge queue is that `start+pr1+pr2` could be started earlier. Here's a hypothetical timeline: | time | PR 1 | PR 2 | `start+pr1` build | `start+pr2` build | `start+pr1+pr2` build | | --- | --- | --- | --- | --- | --- | | 1:00 | created | | | | | | 1:01 | . | | start | | | | 2:00 | . | created | . | | | | 2:01 | . | . | . | start | start | | 4:00 | . | . | . | . | . | | 5:00 | . | . | success | . | . | | 5:01 | merged | . | | . | . | | 5:02 | | . | | cancelled | . | | 6:00 | | . | | | . | | 7:00 | | . | | | success | | 7:01 | | merged | | | | Why did we build `start+pr2`, only to cancel it later? That job is needed if PR 2 happens to finish first, which might look like this: | time | PR 1 | PR 2 | `start+pr1` build | `start+pr2` build | `start+pr1+pr2` build | | --- | --- | --- | --- | --- | --- | | 1:00 | created | | | | | | 1:01 | . | | start | | | | 2:00 | . | created | . | | | | 2:01 | . | . | . | start | start | | 4:00 | . | . | . | . | . | | 5:00 | . | . | . | success | . | | 5:01 | . | merged | . | | . | | 5:02 | . | | cancelled | | . | | 6:00 | . | | | | . | | 7:00 | . | | | | success | | 7:01 | merged | | | | | Shouldn't there be an extra column for `start+pr2+pr1`, since that is what will end up in `main`? No, the checked out files are the same as `start+pr1+pr2`. The build validation only cares about the source file content, not its Git history. Note that as the number of active PR's increases, the number of branch combinations explodes. For example if we have three concurrent PRs, we might need six jobs for `start+pr1`, `start+pr2`, `start+pr3`, `start+pr1+pr2`, `start+pr2+pr3`, and `start+pr1+pr2+pr3`. Building all combinations could quickly exhaust our pool of machines. To avoid exploding resource costs, we can skip combinations that seem relatively unlikely, and still benefit from parallelism on average. As an extreme example, if we have high confidence that PR 1, PR 2, and PR 3 will succeed, maybe we only need one job `start+pr1+pr2+pr3`; other combinations can be tried only if it fails. Clearly there are many opportunities for a sophisticated implementation to significantly outperform a more rudimentary merge queue. Leveraging Rush workspace dependencies[​](https://rushjs.io/pages/best_practices/merge_queue/#leveraging-rush-workspace-dependencies "Direct link to Leveraging Rush workspace dependencies") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > 🚧 Coming soon: This feature is not yet ready. Continuing the above example, suppose that PR 1 is a fix under `project-a`, and PR 2 is a fix under `project-b`; that is, the Git diff for each PR only affects file paths under one project folder. Also let's assume that within the Rush workspace, no other projects depend on `project-a` or `project-b`. This implies that: * The source code built by `rush build --from project-a` is identical for branches `start+pr1` and `start+pr1+pr2`. * The source code built by `rush build --from project-b` is identical for branches `start+pr2` and `start+pr1+pr2`. These assumptions guarantee that PR 1 and PR 2 are completely independent. We can build them independently and safely merge their branches in any order. The merge queue does not need to build `start+pr1+pr2` at all. Next, suppose instead that the **package.json** file for `project-b` specified a dependency on `project-a`. In that case, the PR's are no longer independent: After PR 1 has merged, PR 2 cannot be safely merged without first verifying `start+pr1+pr2`. This analysis relies on knowledge about dependencies between folders, which varies greatly between programming languages and build systems. Even within the ecosystem of JavaScript, the interpretation of **package.json** files requires special considerations for PNPM, Rush+PNPM, Yarn, etc. Merge queues often provide a basic facility for describing folder dependencies, maybe a glob that can describe static relationships such as: * _"This folder has JavaScript code, and that folder has Golang code, so there cannot be any dependencies between them."_ OR * _"This folder only contains non-buildable files such as documentation, so ignore any diffs there."_ However, in a busy monorepo with hundreds or thousands of projects, optimizing the merge queue requires accurately modeling fine-grained dependencies between project folders. To this end, we're collaborating on a language-agnostic [project-impact-graph.yaml](https://github.com/tiktok/project-impact-graph) specification that services such as a merge queue can use to query project dependencies in any monorepo for any programming language. Using a Rush plugin, this YAML file will get generated by `rush update` and committed to Git, which enables the merge queue service to efficiently query folder dependencies for any branch without requiring a Git checkout. Popular merge queues[​](https://rushjs.io/pages/best_practices/merge_queue/#popular-merge-queues "Direct link to Popular merge queues") ---------------------------------------------------------------------------------------------------------------------------------------- It's recommended to use a merge queue in your monorepo. Here's some possible options: * GitHub includes a built-in [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) that can be used with or without GitHub Actions * [Mergify](https://mergify.com/) provides an add-on service for GitHub with advanced optimizations. See [Integrations: Using Mergify with Rush](https://rushjs.io/pages/integrations/mergify/) for setup details. * GitLab includes a built-in [merge trains](https://docs.gitlab.com/ee/ci/pipelines/merge_trains.html) feature _If your organization is using a merge queue with Rush that isn't listed above, please add it._ * [Motivating example](https://rushjs.io/pages/best_practices/merge_queue/#motivating-example) * [How a merge queue helps](https://rushjs.io/pages/best_practices/merge_queue/#how-a-merge-queue-helps) * [Leveraging Rush workspace dependencies](https://rushjs.io/pages/best_practices/merge_queue/#leveraging-rush-workspace-dependencies) * [Popular merge queues](https://rushjs.io/pages/best_practices/merge_queue/#popular-merge-queues) --- # Using watch mode | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/advanced/watch_mode/#docusaurus_skipToContent_fallback) On this page Popular tools like [Webpack](https://webpack.js.org/configuration/watch/) and [Jest](https://jestjs.io/docs/cli) provide a "watch mode" feature: After the task is completed, the tool enters a loop where it watches the file system for changes to your source files. Whenever a change is detected, the task runs again to update its output. This speeds up development because (1) rebuilding happens automatically whenever you save a file, and (2) the task can benefit from in-memory caching because its process never terminates. But these features typically only work for a single project. When working in a monorepo, we need a watch mode that can monitor **_multiple projects at once._** A thought experiment[​](https://rushjs.io/pages/advanced/watch_mode/#a-thought-experiment "Direct link to A thought experiment") --------------------------------------------------------------------------------------------------------------------------------- Suppose hypothetically that our monorepo has the following projects: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) In the above illustration, the circles represent local projects, not external NPM dependencies. The arrow from `D` to `C` indicates that `D` depends on `C`; this means that `C` must be built before `D` can be built. Suppose that you save a change to project `B`: ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) For a multi-project "watch mode", we'd expect the following things to happen in order: * `B` should get rebuilt because its file was changed; * next, `C` should get rebuilt because it depends on `B` * next, `D` should get rebuilt because it depends on `C` * finally, the Webpack dev server (hosted by `D` presumably) refreshes your web browser with the rebuilt app How to accomplish that with Rush? Suppose our projects `B` and `C` have a simplistic build script like this: **package.json** . . . "scripts": { "build": "rm -Rf lib/ && tsc && jest" } . . . We might try an experiment like invoking `rush build --to-except D` in an endless loop... # Build everything that D depends on (but not D itself),# and keep doing that in an endless loop:while true; do rush build --to-except D; done ...and then, while that is running, we invoke `heft start` (or `webpack serve`) in the folder for project `D`. You'll find that this approach has some problems: * The `rm -Rf lib/` deletes files that are symlink targets. Symlinks seem to confuse Webpack's file watcher, so you may see lots of errors reporting that an imported file cannot be found. Webpack won't recover from that, because the symlink timestamp isn't updated when the file is later rewritten. * The `jest` and `rm -Rf` steps are generally unimportant while watching. The developer's inner loop for **_edit -> rebuild -> reload_** is much slower than it needs to be. These problems can be solved by creating a special streamlined script for watch mode, something like this: **package.json** . . . "scripts": { "build": "rm -Rf lib/ && tsc && jest", "build:watch": "tsc" } . . . The "watchForChanges" setting (experimental)[​](https://rushjs.io/pages/advanced/watch_mode/#the-watchforchanges-setting-experimental "Direct link to The "watchForChanges" setting (experimental)") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush's multi-project "watch mode" formalizes this basic idea, replacing the simple loop with an optimized [chokidar](https://www.npmjs.com/package/chokidar) filesystem monitor. How you enable Rush multi-project watch mode depends on whether you are using a _bulk command_ or a _phased command_ for your build scripts. We suggest switching to [phased builds](https://rushjs.io/pages/maintainer/phased_builds/) before enabling watch mode, as it is a better and easier-to-understand experience for developers. ### Watch mode for phased commands[​](https://rushjs.io/pages/advanced/watch_mode/#watch-mode-for-phased-commands "Direct link to Watch mode for phased commands") 1. In your [command-line.json](https://rushjs.io/pages/configs/command-line_json/) config file, add the new `watchOptions` section to each phased command you want to enable. For example: . . . "commands": [ { "commandKind": "phased", "name": "build", "phases": ["_phase:build"], "enableParallelism": true, "incremental": true, "watchOptions": { "alwaysWatch": false, "watchPhases": ["_phase:build"] } }, { "commandKind": "phased", "name": "test", "phases": ["_phase:build", "_phase:test"], "enableParallelism": true, "incremental": true, "watchOptions": { "alwaysWatch": false, "watchPhases": ["_phase:build", "_phase:test"] } } ] Rush will automatically add a new boolean flag, `--watch`, to any command with the `watchOptions` property. 2. Invoke the command using [project selection parameters](https://rushjs.io/pages/developer/selecting_subsets/) that select all of `D`'s dependencies but not `D` itself: # Build everything that D depends on (but not D itself),# and keep doing that in an endless loop:$ rush build --watch --to-except D 3. Then, start your dev server in the app folder: # Start Webpack's dev server in the folder for project D# (which is the web application in this example):$ cd apps/D$ heft start # <-- or your own "npm run start" equivalent here ### Watch mode for bulk commands[​](https://rushjs.io/pages/advanced/watch_mode/#watch-mode-for-bulk-commands "Direct link to Watch mode for bulk commands") 1. Add a [custom command](https://rushjs.io/pages/maintainer/custom_commands/) in your [command-line.json](https://rushjs.io/pages/configs/command-line_json/) config file. Continuing the example above, our custom command will be called `"build:watch"`. The important settings are `"incremental"` and `"watchForChanges"`: **common/config/rush/command-line.json** . . . "commands": [ { "name": "build:watch", "commandKind": "bulk", "summary": "Build projects and watch for changes", "description": "For details, see the article \"Using watch mode\" on the Rush website: https://rushjs.io/", // use incremental build logic (important) "incremental": true, "enableParallelism": true, // Enable "watch mode" "watchForChanges": true }, . . .\ \ 2. Add a `"build:watch"` script to the **package.json** file for each Rush project. ([PR #2298](https://github.com/microsoft/rushstack/pull/2298)\ aims to simplify this step for projects whose `"build:watch"` would be the same as `"build"`. Eventually it will also be possible to consolidate these definitions in a shared [rig package](https://rushstack.io/pages/heft/rig_packages/)\ .)\ \ If you're using [Heft](https://rushstack.io/pages/heft/overview/)\ , your scripts would look like this:\ \ **package.json**\ \ . . . "scripts": { "build": "heft build --clean", "build:watch": "heft build" } . . .\ \ 3. Invoke the command using [project selection parameters](https://rushjs.io/pages/developer/selecting_subsets/)\ that select all of `D`'s dependencies but not `D` itself:\ \ # Build everything that D depends on (but not D itself),# and keep doing that in an endless loop:rush build:watch --to-except D\ \ 4. Lastly, start your dev server in the app folder:\ \ # Start Webpack's dev server in the folder for project D# (which is the web application in this example):cd apps/Dheft start # <-- or your own "npm run start" equivalent here\ \ 5. In some situations, the `--changed-projects-only` command can be combined with `"watchForChanges"` for even faster watching. The section [Building changed projects only](https://rushjs.io/pages/advanced/incremental_builds/#building-changed-projects-only-unsafe)\ explains how it works and when it is appropriate.\ \ \ > **"Experimental"** The `"watchForChanges"` feature is still in its early stages. Feedback is welcome! GitHub issue [#1202](https://github.com/microsoft/rushstack/issues/1202)\ > tracks additional work items and [William Bernting](https://github.com/wbern)\ > 's original dev plan.\ \ Community solutions[​](https://rushjs.io/pages/advanced/watch_mode/#community-solutions "Direct link to Community solutions")\ \ ------------------------------------------------------------------------------------------------------------------------------\ \ The Rush community has shared some interesting alternative approaches to this problem that are also helpful:\ \ * [@telia/rush-select](https://www.npmjs.com/package/@telia/rush-select)\ is an interactive dashboard for monitoring Rush projects and selecting what to rebuild.\ \ * [rush-dev-watcher](https://github.com/dimfeld/rush-dev-watcher)\ is a simple but useful script from [Daniel Imfeld](https://github.com/dimfeld)\ that performs an initial build and then launches multiple watchers.\ \ \ See also[​](https://rushjs.io/pages/advanced/watch_mode/#see-also "Direct link to See also")\ \ ---------------------------------------------------------------------------------------------\ \ * [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/)\ \ * [Incremental builds](https://rushjs.io/pages/advanced/incremental_builds/)\ \ \ * [A thought experiment](https://rushjs.io/pages/advanced/watch_mode/#a-thought-experiment)\ \ * [The "watchForChanges" setting (experimental)](https://rushjs.io/pages/advanced/watch_mode/#the-watchforchanges-setting-experimental)\ * [Watch mode for phased commands](https://rushjs.io/pages/advanced/watch_mode/#watch-mode-for-phased-commands)\ \ * [Watch mode for bulk commands](https://rushjs.io/pages/advanced/watch_mode/#watch-mode-for-bulk-commands)\ \ * [Community solutions](https://rushjs.io/pages/advanced/watch_mode/#community-solutions)\ \ * [See also](https://rushjs.io/pages/advanced/watch_mode/#see-also) --- # 增量构建 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#docusaurus_skipToContent_fallback) On this page Rush 的**增量构建**功能可以通过跳过某些已经是最新的库来加速构建,在本文中,“已经是最新的”含义是: 1. 项目已经在本地构建过,并且 2. 其源码和 NPM 依赖没有发生变化,并且 3. 如果该项目依赖另一个 Rush 项目,这些项目都是最新的,并且 4. 命令行参数没有变化(例如,在 `rush build` 后调用 `rush build --production` 需要重新构建)。 该功能可以和[选择项目参数](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) 结合使用,其作用是开发者显式的告诉 Rush 那些项目需要被处理。增量构建可以重新使用本地磁盘上已经存在的输出(与[构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) 形成鲜明的对比,构建缓存可以从云端获取到之前的构建缓存,它依然是实验性的功能,但是它可能最终会替换增量构建。) 如何使用[​](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- 只需要执行 `rush build` 两次就能使用增量构建: $ rush install# 可能需要一点时间$ rush build# 第二次耗时只需要几秒钟$ rush build `rush build` 是增量构建(`rush rebuild` 不是增量构建)。如果是你自定义的[全局指令](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) , 你可以在配置文件 [command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) 中启用 `"incremental"` 选项来使其成为增量构建。 它是如何工作的?[​](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------- 你的项目构建脚本(被 `rushx build` 或 `npm run build` 调用)可能自身就有增量优化。例如,[Heft](https://rushstack.io/pages/heft/overview/) 对于不同的任务维护了多缓存。然而,甚至当 `rushx build` 对一个项目无效时,仍然会由于开启了 Node 进程、调用 JavaScript 文件,比较单个文件的时间戳而导致的昂贵的开销,假设上述操作需要 500ms, 如果你的 monorepo 存在 100 个项目,那么即使在项目都是最新的情况下,上述工作要花费 100 \* 0.5 == **50 seconds**. Rush 通过一次搜索来对仓库进行全局分析,进而消除了这次操作耗时 —— 这种方式在所有项目都是最新的情况下,可以不唤醒所有项目。作为一个额外的优化,Rush 的增量分析依赖文件哈希而不是时间戳。如果你切换到不同的分支,或者切来切去,许多文件的时间戳会改变,但是 Rush 的增量分析不会受到影响,因为源文件没有发生改变。文件哈希受到 [@rushstack/package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) 管理,哈希值被存储在 `/.rush/temp/package-deps_.json` 的文件中,监视这个文件可以提供一些技术指标。 只构建发生变化的项目(不安全)[​](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%8F%AA%E6%9E%84%E5%BB%BA%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%E7%9A%84%E9%A1%B9%E7%9B%AE%E4%B8%8D%E5%AE%89%E5%85%A8 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 假设我们的 monorepo 有以下项目: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) 上述图例中,圆圈表示本地项目,没有外部的 NPM 依赖。箭头 `D` 到 `C` 表明 `D` 依赖 `C`, 这意味着 `C` 必须在 `D` 构建前构建。 假设构建完所有项目后,在 `B` 项目下改变了源文件。项目 `C` 和 `D` 依赖于 `B`, 因此也需要构建: ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) 我们可能会调用: # 该命令会重新构建 B, C, D$ rush build 但是,你如何知道你对 `C` 的改变是否会影响其 API? 例如,也许你想更新某个控制按钮的颜色,或者某个错误信息中的文本。 `--changed-projects-only` 参数告知 Rush 之构建那些文件被更改的项目: ![rush build --only B](https://rushjs.io/images/docs/selection-only.svg) 我们的调用方式如下: # 下面指令会重新构建 B(但是忽略 C 和 D)$ rush build --changed-projects-only `--changed-projects-only` 参数是不安全的,因为当下游项目重新构建时可能遇到错误。假设你比 Rush 更了解哪些需要重新构建,那么这个参数可以节省时间。如果你不知道,那么可以调用 `rush build` 来保证正确性。 参考 * [选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) * [使用监听模式](https://rushjs.io/zh-cn/pages/advanced/watch_mode/) * [如何使用](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8) * [它是如何工作的?](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84) * [只构建发生变化的项目(不安全)](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#%E5%8F%AA%E6%9E%84%E5%BB%BA%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%E7%9A%84%E9%A1%B9%E7%9B%AE%E4%B8%8D%E5%AE%89%E5%85%A8) --- # Welcome to Rush! | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/intro/welcome/#docusaurus_skipToContent_fallback) ![Rush](https://rushjs.io/images/rush.svg "Rush") **Rush** makes life easier for JavaScript developers who build and publish many NPM packages at once. If you're looking to consolidate all your projects into a single repo, you came to the right place! Rush is a fast, professional solution for managing this scenario. It gives you: * **A single NPM install:** In one step, Rush installs all the dependencies for all your projects into a common folder. This is not just a "package.json" file at the root of your repo (which might set you up to accidentally `require()` a sibling's dependencies). Instead, Rush uses symlinks to reconstruct an accurate "node\_modules" folder for each project, without any of the limitations or glitches that seem to plague other approaches. 👉 **This algorithm supports the [PNPM, NPM, and Yarn](https://rushjs.io/pages/maintainer/package_managers/) package managers.** * **Automatic local linking:** Inside a Rush repo, all your projects are automatically symlinked to each other. When you make a change, you can see the downstream effects without publishing anything, and without any `npm link` headaches. If you don't want certain projects to get linked, that's supported, too. * **Fast builds:** Rush detects your dependency graph and builds your projects in the right order. If two packages don't directly depend on each other, Rush parallelizes their build as separate NodeJS processes (and shows live console output in a [readable order](https://www.npmjs.com/package/@rushstack/stream-collator) ). In practice this multi-process approach can yield more significant speedups than all those async functions in your single-process toolchain. * **Subset and incremental builds:** If you only plan to work with a few projects from your repo, `rush rebuild --to ` does a clean build of just your upstream dependencies. After you make changes, `rush rebuild --from ` does a clean build of only the affected downstream projects. And if your toolchain is [package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) enabled, `rush build` delivers a powerful cross-project incremental build (that also supports subset builds). * **Cyclic dependencies:** If you have hammers that build hammer-factory-factories, Rush has you covered! When a package indirectly depends on an older version of itself, projects in the cycle use the last published version, whereas other projects still get the latest bits. * **Bulk publishing:** When it's time to do a release, Rush can detect which packages have changes, automatically bump all the appropriate version numbers, and run `npm publish` in each folder. If you like, configure your server to automatically run `rush publish` every hour. * **Changelog tracking:** Whenever a PR is created, you can require developers to provide a major/minor/patch log entry for the affected projects. During publishing, these changes will be automatically aggregated into a nicely formatted [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) file. * **Enterprise policies:** Want to review new libraries before developers add them to package.json, but avoid hassling people about already approved cases? Want to enforce that all your projects depend on the same library version numbers? Are unprofessional personal e-mail addresses accidentally showing up in your company's Git history? Rush can help maintain a consistent ecosystem when you've got many developers and many projects in the mix. * **Lots more!** Rush was created by the platform team for [Microsoft SharePoint](http://aka.ms/spfx) . We build hundreds of production NPM packages every day, from internal and public Git repositories, for third party SDKs and live services with millions of users. If there's an important package management problem that needs solvin', it's likely to end up as a feature for Rush. --- # 优先版本 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#docusaurus_skipToContent_fallback) On this page 背景[​](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E8%83%8C%E6%99%AF "Direct link to heading") -------------------------------------------------------------------------------------------------------------- Rush 通过在公共文件夹下创建了一个虚假的 **rush-common** 项目来实现一次性安装,该项目引用了每个项目的。例如,假设 **rush.json** 内有两个项目 "**project1**" 和 "**project2**"。生成的文件可能如下: **common/temp/package.json** { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz" }} 包管理器认为每个以 "**@rush-temp**" 命名的项目都是 **rush-common** 项目的直接依赖。通常而言,NPM 会首先安装项目的直接依赖(在 **node\_modules** 树的根目录),然后再下载间接依赖。但是,由于你的项目的直接依赖现在已经间接依赖 **rush-common** 项目了,所以 `npm install` 的行为可能有些不同。 假如 **project-1/package.json** 如下: { "name": "project-1", "version": "1.0.0", "dependencies": { "library-a": "1.0.1", "library-b": "1.1.3" }} 接着假设 **library-a** (来自于互联网)如下: { "name": "library-a", "version": "1.0.1", "dependencies": { "library-b": "^1.0.0" }} 如果你在 **project-1** 下执行 `npm install`, 你会得到一个如下所示的 **node\_modules** 文件夹,甚至如果 **[library-b@1.4.4](mailto:library-b@1.4.4) ** 在 NPM 上有版本的话: node_modules/ library-a/ (1.0.1) library-b/ (1.1.3) 尽管 **[library-b@1.4.4](mailto:library-b@1.4.4) ** 满足 `"1.0.0"` 的语义化版本,但是 NPM 不会下载它,因此 1.1.3(被 `project-1` 安装)已经满足它。 但是 **common/temp/package.json** 并不能保证上述行为。相反,由于 **project-2** 的依赖,你可能会得到这样的结果: node_modules/ project-1/ library-b/ (1.1.3) library-a/ (1.0.1) library-b/ (1.4.4) 这也是语义化版本的一个有效解决方案。当使用 Rush 和 NPM 的 [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies/) 时,可能会出现相似的问题。 优先的版本[​](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E4%BC%98%E5%85%88%E7%9A%84%E7%89%88%E6%9C%AC "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------- 为了控制上述影响,Rush 引入了“优先版本”的概念,这些依赖会被显式的添加到 **common/temp/package.json** 顶层。 你可以通过配置文件 **common-versions.json** 来“固定”版本,例如: **common/config/rush/common-versions.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", "preferredVersions": { "css-loader": "1.2.3" }} 这将会导致 **css-loader** 添加到 **common/temp/package.json** 中,如下所示: { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "css-loader": "1.2.3", "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz" }} _注意:如果你发布一个包,当你添加优先版本时候应当非常小心,因为这可能会产生一个与普通用户通过 NPM 安装你的库的不同结果。_ 隐性的优先版本[​](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E9%9A%90%E6%80%A7%E7%9A%84%E4%BC%98%E5%85%88%E7%89%88%E6%9C%AC "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------------- 默认情况下,Rush 会自动将你的所有项目的直接依赖添加到 **common/temp/package.json** 中。在上面的例子中,这些“隐性的优先版本”可能会像这样: **common/temp/package.json** { "name": "rush-common", "description": "Temporary file generated by the Rush tool", "private": true, "version": "0.0.0", "dependencies": { "css-loader": "1.2.3", // <---- 明确制定的优先版本 "library-a": "~1.0.0", // <---- 隐形的优先版本 "library-b": "1.1.3", // <---- 隐形的优先版本 "@rush-temp/project1": "file:./projects/project-1.tgz", "@rush-temp/project2": "file:./projects/project-2.tgz", }} 对于某个依赖而言,除了在不同的项目中指定不同的版本范围外,Rush 会自动将所有的直接依赖添加到 **common/temp/package.json** 中。在上述示例中,Rush 不知道哪个版本应当被认为是隐性的优先。例如,如果 **project1** 和 **project2** 指定了不同的 **library-b** 版本,之后你可能需要使用 **common-version.json** 来解决问题。 对于较老的包管理器,自动添加这个这些条目会减少间接依赖的重复。然而,隐性的优先版本可能会导致某些不兼容 `peerDependencies` 范围的依赖出现问题。如果你遇到了同级依赖而导致的安装错误,建议通过设定 \[common/config/rush/common-version.json\] 中的 `implicitlyPreferredVersions` 为 `false` 来禁用这个行为。 * [背景](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E8%83%8C%E6%99%AF) * [优先的版本](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E4%BC%98%E5%85%88%E7%9A%84%E7%89%88%E6%9C%AC) * [隐性的优先版本](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/#%E9%9A%90%E6%80%A7%E7%9A%84%E4%BC%98%E5%85%88%E7%89%88%E6%9C%AC) --- # 幻影依赖 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#docusaurus_skipToContent_fallback) On this page Rush 的文章中时不时提及“幻影”和“复制体”,你是否想更多了解 JavaScript 的包管理器是如何工作的? 一些历史和理论[​](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E4%B8%80%E4%BA%9B%E5%8E%86%E5%8F%B2%E5%92%8C%E7%90%86%E8%AE%BA "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------- 大家都知道软件**包**可以依赖其他的**包**,其生成的[依赖图](https://en.wikipedia.org/wiki/Dependency_graph) 是一种[有向无环图](https://en.wikipedia.org/wiki/Directed_acyclic_graph) 。不同于树状结构,有向无环图可以用菱形分支链接。例如,库 **A** 可能导入 **B** 和 **C**, 之后 **B** 和 **C** 被 **D** 引入, 这四个库中创建了一个**菱形依赖**。通常,编程语言的**模块解析**会沿着图的边向上查找,并且(在其他系统中)包本身被放在一个中央的存储库中,可以被多个项目共享。 由于历史原因,NodeJS 和 NPM 使用了一个不同的方法来在磁盘上组织图的物理形式,NPM 使用库的副本来表示图的顶点,以及图的边被子目录所替代。但是树状的文件夹不能组成菱形,为了解决该问题,NodeJS 增加了一个[特殊的解析规则](https://nodejs.org/api/modules.html#all-together) ,起作用是引入额外的边(指向所有父亲目录的直接子文件夹)。从计算机科学的视角来看,这套规则以两种方式轻松地改变了文件系统的[树状结构](https://en.wikipedia.org/wiki/Tree_(data_structure)) :(1) 它可以表示一些(但不是所有)有向无环图;(2) 我们捕获了一些额外的边,它们不属于任何声明的包依赖。这些额外的边便是“幻影依赖”。 NPM 中用到的方法与传统的包管理方式有很多不同点: * 每一个(根级)目录的 **node\_module** 树来存储大量的库文件夹副本,甚至一个很小的 NodeJS 项目的文件夹下可能有超过 10,000 个文件。 * 在 NPM 2.x 版本中,**node\_modules** 文件树非常深,而且存在很多重复,这可以消除幻影依赖。NPM 3.x 的安装算法改成了将树扁平化,这消除了大量重复项,但代价是引入了幻影依赖(图上额外的边),在某些情况下这个新算法会选择一个更久版本的包(虽然依旧符合语义化规范)来消除包文件夹的重复。 * 安装后的 **node\_modules** 树并不唯一,有很多种可能来重新组织文件夹来使得其接近菱形,并没有独一无二的“标准化”排列。安装后的树依赖于你的包管理器使用了哪种算法,NPM 自身的算法甚至对[你添加的包的次序](http://npm.github.io/how-npm-works-docs/npm3/non-determinism.html) 有关。 **node\_modules** 树是一个奇特的数据结构,让我们关注三个可能造成麻烦的问题,这些问题可能会在大型项目和 monorepo 中导致问题,我们也会展示 Rush 如何改善这些 —— 解决这些问题是 Rush 创立的动机之一。 幻影依赖[​](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E5%B9%BB%E5%BD%B1%E4%BE%9D%E8%B5%96 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------- ![NPM phantom dependency](https://rushjs.io/images/home/card-phantom.svg) 当项目中使用了一个没有在 **package.json** 文件中定义的包时,幻影依赖便出现了。示例如下: **my-library/package.json** { "name": "my-library", "version": "1.0.0", "main": "lib/index.js", "dependencies": { "minimatch": "^3.0.4" }, "devDependencies": { "rimraf": "^2.6.2" }} 代码可能会长成下面的样子: **my-library/lib/index.js** var minimatch = require('minimatch');var expand = require('brace-expansion'); // ???var glob = require('glob'); // ???// (使用这些库的代码) 等一下 —— 这有两个库 `brace-expansion` 和 `glob` 两个库并没在 **package.json** 文件中声明为依赖。那它们是如何运行的呢?结论是 **brace-expansion** 是 **minimatch** 的依赖,**glob** 是 **rimraf** 的依赖。安装时,NPM 会将 **my-library/node\_modules** 下的文件夹铺平,由于 NodeJS 的 `require()` 函数不需要考虑 **package.json** 文件,所以它找到这些库。这也许有一些违反直觉,但是这看起来没有问题,也许这不是个 bug? 不幸的是,项目中缺少声明的依赖最好被视作一个 bug, 它可能导致一些不符合预期错误: * **不兼容的版本:**尽管我们库的 **package.json** 明确需要 **minimatch** 的版本为 3, 我们并没有声明 **brace-expansion** 的版本,[语义化系统](https://semver.org/) 会使得当 **minimatch** 的 API 没发生变动时,**minimatch** 的 PATCH 版本完美的兼容了 **brace-expansion** 的 MAJOR 版本。在实际开发 **my-library** 时,可能永远不会遇到这种情况,相反,当随后有人以相较于我们平日测试时更新(更旧)的版本约束方式来约束 **node\_modules** 排列方式来安装了我们发布的库,这个人就会变成一个受害者。 * **缺少依赖:**库 **glob** 来自于 `devDependencies` 中,这意味着只有开发 **my-library** 的开发者才会安装这些库。对于其他人,`require("glob")` 将会因 **glob** 未安装而立即抛错。只要我们发布了 **my-library**, 就会立即听到这个反馈,对吧?并不是,实际情况中,由于某些原因(例如自身使用了 **rimraf**),绝大部分用户都有 **glob** 这个库,所以看起来可以运行。只有一小部分用户会遇到导入失败的问题,这使得它看起来像是一个难以重现的问题。 **Rush 如何解决问题的:** Rush 的符号链接策略能确保每个项目下的 **node\_modules** 可仅仅包含它直接的依赖。这会在构建阶段捕获到幻影依赖的问题。如果你使用 PNPM, 相同保护措施也会应用到所有间接依赖上(可以通过 **pnpmfile.js** 来解决任何“不良”的包)。 幻影 node\_modules 文件夹[​](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E5%B9%BB%E5%BD%B1-node_modules-%E6%96%87%E4%BB%B6%E5%A4%B9 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 假定我们有一个 monorepo, 有人在根目录下的 **package.json** 文件增加了以下内容: **my-monorepo/package.json**: { "name": "my-monorepo", "version": "0.0.0", "scripts": { "deploy-app": "node ./deploy-app.js" }, "devDependencies": { "semver": "~5.6.0" }} 这会允许人们执行 `npm run deploy-app`, 该脚本会被自动部署 monorepo 中的所有项目(不要再 Rush 中使用这种方式,请使用[自定义指令](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) )。注意,这个幻想的脚本需要使用 **semver** 这个库,所以它被添加到 `devDependencies` 列表中,在项目根目录中,开发者可以在执行 `npm run deploy-app` 之前执行 `npm install`. 安装目录的结构如下: - my-monorepo/ - package.json - node_modules/ - semver/ - ... - my-library/ - package.json - lib/ - index.js - node_modules/ - brace-expansion - minimatch - ... NodeJS 的模块解析器会在父目录下寻找依赖,这意味着 **my-library/lib/index.js** 可以执行 `require("semver")` 并寻找到 **semver** 包,甚至它不会出现在 **my-library/node\_modules** 下。这是一种更隐蔽的方式来捕获幻影依赖 —— 它甚至可以找到不在你的 Git 工作目录下的 **node\_modules** 文件夹。 **Rush 如何解决问题的:** `rush install` 指令可以扫描所有潜在的父目录并在发现 **node\_modules** 中存在幻影依赖时发出警告。 * [一些历史和理论](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E4%B8%80%E4%BA%9B%E5%8E%86%E5%8F%B2%E5%92%8C%E7%90%86%E8%AE%BA) * [幻影依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E5%B9%BB%E5%BD%B1%E4%BE%9D%E8%B5%96) * [幻影 node\_modules 文件夹](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/#%E5%B9%BB%E5%BD%B1-node_modules-%E6%96%87%E4%BB%B6%E5%A4%B9) --- # NPM 分身 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/#docusaurus_skipToContent_fallback) On this page _首先建议先阅读 “[幻影依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) ” 一文,因为这篇文章是其后续。_ NPM 分身如何出现的[​](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/#npm-%E5%88%86%E8%BA%AB%E5%A6%82%E4%BD%95%E5%87%BA%E7%8E%B0%E7%9A%84 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ![NPM doppelganger](https://rushjs.io/images/home/card-doppel.svg) 有时 **node\_modules** 的数据结构会强制安装同一个包的两个**_相同版本的_**。真的吗?它是如何发生的? 假设我们有项目 **A**, 如下: { "name": "library-a", "version": "1.0.0", "dependencies": { "library-b": "^1.0.0", "library-c": "^1.0.0", "library-d": "^1.0.0", "library-e": "^1.0.0" }} 然后 **B** 和 **C** 都依赖于 **F1**: { "name": "library-b", "version": "1.0.0", "dependencies": { "library-f": "^1.0.0" }} { "name": "library-c", "version": "1.0.0", "dependencies": { "library-f": "^1.0.0" }} 之后 **D** 和 **E** 都依赖 **F2**: { "name": "library-d", "version": "1.0.0", "dependencies": { "library-f": "^2.0.0" }} { "name": "library-e", "version": "1.0.0", "dependencies": { "library-f": "^2.0.0" }} **node\_modules** 树可以把 **F1** 放在树的顶部来实现共享,但是需要把 **F2** 拷贝到子目录中: - library-a/ - package.json - node_modules/ - library-b/ - package.json - library-c/ - package.json - library-d/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@2.0.0 - library-e/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@2.0.0 - library-f/ - package.json <-- library-f@1.0.0 另外一种方式是包管理器将 **F2** 放在顶部,之后拷贝 **F1**: - library-a/ - package.json - node_modules/ - library-b/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@1.0.0 - library-c/ - package.json - node_modules/ - library-f/ - package.json <-- library-f@1.0.0 - library-d/ - package.json - library-e/ - package.json - library-f/ - package.json <-- library-f@2.0.0 无论哪种方式,我们都只能在树中拷贝两个相同版本的 **library-f**, 我们将其称之为“分身”。其他语言上的包管理器不会遇到这个问题,它是 NPM 的 **node\_modules** 树的特性,是必然的,是由其设计导致,无法避免。 分身的结果[​](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/#%E5%88%86%E8%BA%AB%E7%9A%84%E7%BB%93%E6%9E%9C "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------- 小项目内很少遇到分身,但是在大型的 monorepo 中很常见,这会导致一些问题。 * **更慢的安装时间:**如今磁盘空间非常宝贵,但是假设你有 20 个依赖于 **F1** 的库,这会导致 20 份拷贝。假设这里有一个安装脚本,它会下载和解压大型的压缩包(例如 PhantomJS),这会在每个分身中重复执行,最终显著影响你的安装时间。 * **增大包体积:**Web 项目经常使用诸如 [webpack](https://webpack.js.org/) 等打包工具,它们会静态分析 `require()` 语句,并将其收集到一个单一的打包产物中。这些产物应该尽可能保持小,因为它会直接影响页面应用的加载时间,假设出现了不符合预期的分身(例如由于 `npm install` 操作导致的 **node\_modules** 树重排),这会导致一个库拷贝了两份之后被嵌入到产物中,进而极大增加了包体积。 * **非单一的:**假设 **library-f** 暴露了一个缓存对象的 API, 其目的是想让库那所有的消费者共享一个单例,当两个不同的组件调用 `require("library-f")` 时,它们可能获取到两个不同的库,这意味着这里会有两个实例(也就是说,“全局”变量会从两个不同的闭包中获取)。这可能会导致一些难以调试的奇怪问题。 * **多重类型:**假设 **library-f** 是一个 TypeScript 库,那么编译器会遇到多个 \*.d.ts 文件。例如,每个类的声明都会有两份拷贝,由于它们是两个分开的真实文件,导致不能被符号链接复用。通常而言,在 TypeScript 中,相同的类声明被视为是不可互换的,混合后会导致编译问题。TypeScript 2.x 引入了一种检测和比较重复的类声明的方法,但是它会引入额外的复杂度。其他的构建任务可能没有如此精明。 * **语义上的分身:**假设 **F** 有一个依赖 **G**, **G** 同样被其他库使用。在这棵树上,**F1** 的第一份拷贝将从 **B** 开始寻找 **G** , 第二个拷贝将从 **C** 开始寻找 **G**. 对于两个不同的起点而言,`require()` 算法可能寻找到不同的 **G** 版本。这意味着运行时两个 **F1** 的实例可能有一些不同。或者在编译阶段,如果 **F** 导出了 TypeScript 的类,该类继承自 **G** 中定义的基类,由于相同的类从相同包的相同版本到处,可能会导致非常有迷惑性的编译错误。 * **Rush 如何改善的:** Rush 的符号链接策略会删除仓库内依赖为本地项目的分身。不幸的是,如果你使用 NPM 或 Yarn 作为包管理器,那么任何间接依赖都还存在分身。如果你选择 Rush 和 PNPM, 那么分身问题会得到了完全性的解决(因为 PNPM 的安装模型模拟了一个真正的有向无环图)。 * [NPM 分身如何出现的](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/#npm-%E5%88%86%E8%BA%AB%E5%A6%82%E4%BD%95%E5%87%BA%E7%8E%B0%E7%9A%84) * [分身的结果](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/#%E5%88%86%E8%BA%AB%E7%9A%84%E7%BB%93%E6%9E%9C) --- # 注入依赖 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#docusaurus_skipToContent_fallback) On this page 注入依赖是 PNPM 的一个特性。与本地项目依赖的符号链接相比,注入依赖允许将本地项目文件夹安装,就好像它们是从远程 NPM 仓库下载的一样。 背景:传统的工作区符号链接[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E8%83%8C%E6%99%AF%E4%BC%A0%E7%BB%9F%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8C%BA%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush monorepo 中的项目通常使用 `workspace:` 协议来依赖工作区内的其他本地项目。假设 `my-project` 和 `my-library` 是 Rush monorepo 中的项目: **my-repo/apps/my-project/package.json** { "name": "my-project", "version": "1.2.3", "dependencies": { "react": "^18.3.1", "my-library": "workspace:*" }} 在上述示例中,`react` 包将通过从 NPM 下载并解压到 `node_modules` 子文件夹中来安装。相比之下,`workspace:*` 协议会让 PNPM 在 `my-project` 的 `node_modules` 中创建一个指向 `my-library` 源码文件夹的符号链接: **符号链接:** `my-repo/apps/my-project/node_modules/my-library` --> `my-repo/libraries/my-library/` 通过这种方式,`my-project` 将始终使用 `my-library` 最新的本地构建产物。在这种情况下 `my-project` 和 `my-library` 甚至都不需要发布到 NPM 托管库。 工作区符号链接的局限性[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E5%B7%A5%E4%BD%9C%E5%8C%BA%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 然而,假设 `my-library` 声明了一个 peer 依赖如下: **my-repo/libraries/my-library/package.json** { "name": "my-library", "version": "0.0.0", "peerDependencies": { "react": "^18.0.0 || ^17.0.0" }, "devDependencies": { "react": "17.0.0" }} `my-library` 项目声明它可以使用 React 版本 17 或者 18。在本地开发中,`devDependencies` 安装了符合要求的最老版本 17.0.0。安装最老版本一种为了验证向后兼容性的常见做法。 为什么我们需要 `peerDependencies` 而不是 `dependencies`?如果使用 `dependencies`,那么包管理器可以自由选择任何匹配 `"^18.0.0 || ^17.0.0"` 的 `react` 版本。例如,如果我们的应用使用 React 17,那么 `my-library` 可能会错误的自身安装 React 18。peer 依赖通过规定 `my-library` 必须与其使用者保持相同的 `react` 版本(并且还确保从相同的磁盘文件夹引用)来避免这种情况。 如果两个不同的应用依赖 `my-library`,且这些应用有不同版本的 `react`,该怎么办?对于外部 NPM 包,PNPM 通常通过将(相同版本的)`my-library` 安装到 `node_modules` 的不同子文件夹来解决此问题。这些副本称为 **“peer 依赖分身”**。这是 Node.js 模块解析器的设计约束所决定的: > _**无上下文解析:** 当某个文件导入 NPM 包时,模块解析器对文件的每个导入者的解析方式都是一致的。_ 换句话说,唯一能让 `my-library/lib/index.js` 在为 `app1` 导入 React 17 而为 `app2` 导入 React 18 的方式,是两个应用从磁盘上的两个不同 `my-library` 文件夹(即分身)导入。 当将 NPM 包提取到 `node_modules` 文件夹时,包管理器会根据需要自动创建分身。然而,在我们的示例中,`my-project` 使用 `workspace:*` 来创建 `my-library` 项目文件夹的符号链接,而不是将 NPM 包提取到 `node_modules` 文件夹。那么 peer 依赖将如何满足?在这种情况下,PNPM 会安装错误的包版本: * 当 `my-project` 导入 React 时,它将获取版本 18 * 当 `my-project` 导入 `my-library` 而 `my-library` 导入 React 时,它将获取版本 17(从 `devDependencies` 安装) `peerDependencies` 的申明被忽略了。 注入依赖的解决方案[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 为了解决这个问题,PNPM 支持一个名为 `injected` 的 [package.json 配置](https://pnpm.io/package_json#dependenciesmetainjected) ,它将使 `my-library` 像发布到 NPM 一样被安装。以下是启用它的方法: **my-repo/apps/my-project/package.json** { "name": "my-project", "version": "1.2.3", "dependencies": { "react": "^18.3.1", "my-library": "workspace:*" }, "dependenciesMeta": { "my-library": { "injected": true } }} 进行此更改后,`pnpm install`(在我们的例子中是 `rush install` 或 `rush update`)将通过将项目内容复制到 `my-project` 的 `node_modules` 文件夹中来安装 `my-library`。由于它们是常规安装的,注入依赖可以成为分身并正确满足 peer 依赖。 注入安装过程也同时会遵循发布过滤规则,例如 `.npmignore`,所以即使在此例子中 `my-library` 是从本地工作区安装的,但安装行为好像就是从远程 `NPM` 仓库被下载安装一样。因此,当你想在本地测试你即将发布的库时,也可以在测试项目中,为即将发布的库的依赖设置 `injected: true`,以提前发现 `.npmignore` 的错误配置——这些通常是在使用 `workspace:` 被符号链接时经常被忽略的配置错误。 听起来很棒——那么为什么 PNPM 不对所有 `workspace:` 引用使用注入安装? 注入依赖的更新[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9B%B4%E6%96%B0 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------- 我们说过,注入依赖会在 `rush install` 期间被复制到 `node_modules` 文件夹中。但是如果我们对 `my-library` 进行了更改,然后运行 `rush build`,会发生什么?当 `my-project` 导入 `my-library` 时,它仍会找到来自 `node_modules` 的旧副本。为了得到正确的结果,我们需要在每次重建 `my-library` 后重新执行 `rush install`。更准确地说,我们需要在构建任何被注入的项目 _**之后**_ 但在依赖方开始构建 _**之前**_ 重新执行 `rush install`。在最坏的情况下,这可能意味着在 `rush build` 期间重复执行 `rush install` 数百次。这是不现实的。 PNPM 目前还没有包含该问题的原生解决方案,因此注入依赖尚未被广泛采用。然而,一个名为 [pnpm-sync](https://github.com/tiktok/pnpm-sync) 的新工具提供了解决方案:每当 `my-library` 被重新构建时,`pnpm-sync` 可被用来将其最新的构建产物复制到适当的 `node_modules` 子文件夹来保持同步。 通常每个项目都需要自行决定是否以及如何调用 `pnpm-sync` 命令,但 Rush 集成了此功能并自动进行管理。要在 Rush 中使用 `pnpm-sync`,可以启用 `usePnpmSyncForInjectedDependencies` 实验: **common/config/rush/experiments.json** /** * (开发中)对于涉及peer 依赖的某些安装问题,PNPM 无法在不在 node_modules 文件夹中安装包的副本的情况下正确满足版本要求。 * 这对“workspace:*”依赖项构成了问题,因为它们通常是通过将符号链接指向本地项目源码文件夹进行安装。 * PNPM 的“注入依赖”功能提供了一种将本地项目文件夹复制到 node_modules 的模型,但复制必须在依赖项目构建 **之后** 并且在消费者项目开始构建 **之前** 发生。 * “pnpm-sync”工具负责管理此操作;有关详细信息,请参阅其文档。 * 如果希望在构建期间通过调用“pnpm-sync”来重新同步注入依赖,请启用此实验。 */ "usePnpmSyncForInjectedDependencies": true 此设置将启用以下行为: * `rush install` 和 `rush update` 将自动调用 `pnpm-sync prepare` 来配置注入依赖(如 `my-library`)的复制 * `rush build`(以及其他 Rush 自定义命令和阶段)将在 `my-library` 等项目重建时自动调用 `pnpm-sync copy` 以重新同步已安装的文件夹 * `rushx` 将在 `my-library` 文件夹下执行的任何操作后自动调用 `pnpm-sync copy` 用于子空间的注入依赖[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E7%94%A8%E4%BA%8E%E5%AD%90%E7%A9%BA%E9%97%B4%E7%9A%84%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 如果您使用 Rush 子空间,请考虑同时启用 `alwaysInjectDependenciesFromOtherSubspaces`: **common/config/subspaces//pnpm-config.json** /** * 当项目使用 `workspace:` 依赖其他 Rush 项目时,PNPM 通常通过在 `node_modules` 下创建一个符号链接来安装。 * 这通常效果很好,但在某些情况下,例如不同的 `peerDependencies` 版本,符号链接可能会引发问题, * 比如错误的版本满足。对于这种情况,可以将依赖项声明为“injected”, * 使得 PNPM 能够将其构建输出复制到 `node_modules` 中,就像从注册表实际安装一样。 * 详细信息:https://rushjs.io/pages/advanced/injected_deps/ * * 使用 Rush 子空间时,如果 `workspace:` 引用来自不同子空间的项目,那么这类版本问题的可能性更高。 * 这是因为符号链接将指向由不同的 PNPM 锁定文件安装的独立 `node_modules` 树。 * 彻底的解决方案是启用 `alwaysInjectDependenciesFromOtherSubspaces`, * 它会自动将其他子空间中的所有项目视为注入依赖,无需手动配置它们。 * * 注意:请谨慎使用——如果注入的依赖过多,过度的文件复制会减慢 `rush install` 和 `pnpm-sync` 操作。 * * 默认值为 false。 */ "alwaysInjectDependenciesFromOtherSubspaces": true 另见[​](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E5%8F%A6%E8%A7%81 "Direct link to heading") --------------------------------------------------------------------------------------------------------- * [pnpm-sync](https://github.com/tiktok/pnpm-sync) GitHub 项目 * PNPM 文档中的 [dependenciesMeta.\*.injected](https://pnpm.io/package_json#dependenciesmetainjected) * [Rush 子空间](https://rushjs.io/zh-cn/pages/advanced/subspaces/) * [背景:传统的工作区符号链接](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E8%83%8C%E6%99%AF%E4%BC%A0%E7%BB%9F%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8C%BA%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5) * [工作区符号链接的局限性](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E5%B7%A5%E4%BD%9C%E5%8C%BA%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7) * [注入依赖的解决方案](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88) * [注入依赖的更新](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9B%B4%E6%96%B0) * [用于子空间的注入依赖](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E7%94%A8%E4%BA%8E%E5%AD%90%E7%A9%BA%E9%97%B4%E7%9A%84%E6%B3%A8%E5%85%A5%E4%BE%9D%E8%B5%96) * [另见](https://rushjs.io/zh-cn/pages/advanced/injected_deps/#%E5%8F%A6%E8%A7%81) --- # 安装变种 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/installation_variants/#docusaurus_skipToContent_fallback) On this page 有时你也许想要使用修改后的依赖来构建整个项目。例如,假设你刚刚完成一个框架的主版本升级工作,但是你想在迁移过程中保持与之前版本的兼容性。开发人员应该使用新版本的依赖,但是提交 PR 时,你想要让 CI 任务构建整个项目两次,一次是使用旧版本的依赖,一次是使用新版本的依赖。 你可以通过编写简单的脚本来搜索和替换 **package.json** 下的版本号来解决这个问题,但是你很快发现其他的文件被影响了: * **shrinkwrap 文件**: 除非你保持两个变量的独立的 shrinkwrap 文件,否则构建不可预知。 * **common-versions.json**: `preferredVersions` 或 `allowedAlternativeVersions` 可能需要不同的版本号。 * **pnpmfile.js**: 如果你对某些有问题的包有解决方案,那么可能需要两个版本号。 这个问题看起来需要使用单独的、并行的配置文件来解决。从 Rush 5.4.0 版本,现在有开箱即用的解决方式。 开始一个变种[​](https://rushjs.io/zh-cn/pages/advanced/installation_variants/#%E5%BC%80%E5%A7%8B%E4%B8%80%E4%B8%AA%E5%8F%98%E7%A7%8D "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------- 假定 "**widget-sdk**" 是刚刚发布了主版本 3 的库,我们将其升级到版本 3, 但是我们想要维持与版本 2 的兼容性,我们可以在 **package.json** 中使用语义化版本来指定一个范围: **libraries/my-controls/package.json** { "name": "my-controls", "version": "1.0.0", "description": "An example library project", "license": "MIT", "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { "build": "node_modules/.bin/my-build" }, "dependencies": { "widget-sdk": "^2.3.4 || ^3.0.2" }, "devDependencies": { "my-toolchain": "^1.0.0", "typescript": "^3.0.3" }} 范围 `"^2.3.4 || ^3.0.2"` 表示我们的库可以接受 **widget-sdk** 2.x 版本(但不能旧于 2.3.4 版本)或者 3.x 版本(但是不能旧于 3.0.2 版本),当你执行 `rush update` 时,你可以得到最新的兼容版本。那么如何构建和测试与旧版本 2 的库?请设置一个安装变种! **1\. 定义你的安装变种** 在 rush.json 配置文件中,我们添加了如下定义: **\*rush.json** 摘录\* "variants": [ // { // /** // * 变种名. // */ // "variantName": "example-variant", // // /** // * 描述信息 // */ // "description": "Build this repo using the previous release of the SDK" // } { "variantName": "old-widget-sdk", "description": "Build this repo using version 2 of the widget-sdk" } ], **2, 拷贝配置文件。**为了开始这个变量,首先要将 **common/config/rush**下的配置文件拷贝到变量目录 **common/config/rush/variants/old-widget-sdk** 下。目前支持三个配置文件(将来可能会添加更多): * **shrinkwrap.yaml**, **npm-shrinkwrap.json**, 或者 **yarn.lock**, 由你的包管理器决定。 * **common-versions.json** * **pnpmfile.js**, 如果你使用 PNPM. 确保已经将拷贝的文件添加到 Git 中: $ git add .$ git commit -m "Creating a new variant" **3\. 重写变种的依赖版本。**例如,我们将会将 **widget-sdk** 降级到使用 2.x 版本。这可以通过使用 Rush 的[偏好版本](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/) 功能实现。我们使用通配符,这样 `rush update --full` 仍然会抓取 minor/patch 版本: **\*common-versions.json** 摘录\* /** * 一个明确“偏好版本”的依赖包列表,“编号版本”通常用于保持间接依赖到特定版本,但是它通常可以是一个语义化版本范围(例如 "~1.2.3")。 * 同时他也会窄化任何(兼容的)语义化繁为。可以参考 Rush 文档来了解该功能的更多细节。 */ "preferredVersions": { /** * 当某些人请求 "^1.0.0" 是需要确保 "1.2.3" 在这个项目里可以正常工作,而不是最新版本。 */ // "some-library": "1.2.3" "widget-sdk": "^2.3.9" }, 注意,`^2.3.9` 满足 **package.json** 中指定的 SemVer 范围 `^2.3.4 || ^3.0.2`.(如果不是这样,那么偏好版本将不会有任何效果。) 4. **安装你的变种并测试。**假设我们想要在变种中运行 `rush update`,来安装新的依赖版本: $ rush update --full --variant old-widget-sdk 这会更新 **common/config/rush/old-widget-sdk/shrinkwrap.yaml** 文件,安装这些依赖到 **common/temp/node\_modules** 下,同时在每个项目下链接这些依赖。`rush install` 命令同样支持 `--variant` 选项。当 CI 任务使用老版本的 **widget-sdk** 构建时,可以使用此命令。 现在你可以构建和测试你的安装变种: $ rush rebuild ⏵ 如果你经常使用 `--variant`,你也可以使用 [RUSH\_PREVIEW\_VERSION](https://rushjs.io/zh-cn/pages/configs/environment_vars/) . **5\. 恢复原始状态。**当你测试完变种后,你通过不带有 `--variant` 参数的 `rush install` 返回到原始状态。我们称其为“**默认变种**”,因为它与一个没有定义安装变种的仓库的默认行为相同: # 通过不带有 `--variant` 参数的 `rush install` 恢复原始状态:$ rush install > **提示:**如果你忘记了安装变种是否被激活,你可以使用 `common/temp/current-variant.json` 文件来查看。如果你在文本编辑器中打开此文件,你应该看到一行如下: > > { "variant": "old-widget-sdk"} * [开始一个变种](https://rushjs.io/zh-cn/pages/advanced/installation_variants/#%E5%BC%80%E5%A7%8B%E4%B8%80%E4%B8%AA%E5%8F%98%E7%A7%8D) --- # Rush MCP plugins | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/ai/rush_mcp_plugins/#docusaurus_skipToContent_fallback) On this page The [Rush MCP server](https://rushjs.io/pages/ai/rush_mcp/) provides a ready-made solution for improving the effectiveness of Artificial intelligence (AI) **coding assistants** when working in a Rush monorepo. However, most businesses will have internal systems that could also be included in this service, but which cannot be contributed to the open source implementation. To handle these requirements, you can implement **Rush MCP plugins** for [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) . Plugins can also be released as open source to provide optional additional functionality or integrations. Example plugin scenarios: * **Team wiki**: Query an internal team wiki that runs on a private content management system * **Issue management**: Create tasks and issues in an internal work management system * **Semantic search**: Search a semantic vector database such as [Supabase](https://supabase.com/docs/guides/ai/semantic-search) using a proprietary sentence transformer Creating a plugin[​](https://rushjs.io/pages/ai/rush_mcp_plugins/#creating-a-plugin "Direct link to Creating a plugin") ------------------------------------------------------------------------------------------------------------------------ > **Copy our example** > > The [build-tests/rush-mcp-example-plugin](https://github.com/microsoft/rushstack/tree/main/build-tests/rush-mcp-example-plugin) > project on GitHub demonstrates an example plugin project for usage with `@rushstack/mcp-server`. The main steps for writing a plugin: 1. Create an NPM package whose name follows the `rush-mcp-_____-plugin` naming pattern. 2. In your **package.json** file, the `@rushstack/mcp-server` package should go under `devDependencies`, NOT under `dependencies`. **IMPORTANT:** Always use `import type` when importing from this package. For example, `import type { RushMcpPluginSession } from '@rushstack/mcp-server';`. 3. Add the plugin manifest file in the root of your project, and make sure [.npmignore](https://github.com/microsoft/rushstack/blob/main/build-tests/rush-mcp-example-plugin/.npmignore) or **package.json** are configured so that `npm publish` will include it: **/rush-mcp-plugin.json** /** * Every plugin package must contain a "rush-mcp-plugin.json" manifest in the top-level folder * (next to package.json). */{ /** * A name that uniquely identifies your plugin. Generally this should be the same name as * the NPM package. If two NPM packages have the same pluginName, they cannot be loaded together. */ "pluginName": "rush-mcp-example-plugin", /** * (OPTIONAL) Indicates that your plugin accepts a config file. The MCP server will load this * file and provide it to the plugin. * * The config file path will be `/common/config/rush-mcp/.json`. */ "configFileSchema": "./lib/rush-mcp-example-plugin.schema.json", /** * The entry point, whose default export should be a class that implements */ "entryPoint": "./lib/index.js"} 4. Create a plugin that implements the `IRushMcpPlugin` contract: **/src/ExamplePlugin.ts** import type { IRushMcpPlugin, RushMcpPluginSession } from '@rushstack/mcp-server';import { StateCapitalTool } from './StateCapitalTool';export interface IExamplePluginConfigFile { capitalsByState: Record;}export class ExamplePlugin implements IRushMcpPlugin { public session: RushMcpPluginSession; public configFile: IExamplePluginConfigFile | undefined = undefined; public constructor(session: RushMcpPluginSession, configFile: IExamplePluginConfigFile | undefined) { this.session = session; this.configFile = configFile; } public async onInitializeAsync(): Promise { this.session.registerTool({ toolName: 'state_capital' }, new StateCapitalTool(this)); }} 5. Above, our manifest specified `"entryPoint": "./lib/index.js"`, so the entry point should return the plugin factory: **/src/index.ts** import type { RushMcpPluginSession, RushMcpPluginFactory } from '@rushstack/mcp-server';import { ExamplePlugin, type IExamplePluginConfigFile } from './ExamplePlugin';function createPlugin( session: RushMcpPluginSession, configFile: IExamplePluginConfigFile | undefined): ExamplePlugin { return new ExamplePlugin(session, configFile);}export default createPlugin satisfies RushMcpPluginFactory; 6. The [MCP SDK for TypeScript](https://github.com/modelcontextprotocol/typescript-sdk) requires the [zod](https://www.npmjs.com/package/zod) framework for generating JSON schema definitions from TypeScript expressions. _You do not need to add `zod` as a **package.json** dependency for each plugin._ Instead, you can import it from the `@rushstack/mcp-server` runtime context. This also ensures that a consistent version of `zod` is used throughout the runtime. Take a look at the [StateCapitalTool.ts](https://github.com/microsoft/rushstack/blob/main/build-tests/rush-mcp-example-plugin/src/StateCapitalTool.ts) for a code sample. 7. Once your plugin is completed, you should publish it to an NPM registry. Enabling your plugin[​](https://rushjs.io/pages/ai/rush_mcp_plugins/#enabling-your-plugin "Direct link to Enabling your plugin") --------------------------------------------------------------------------------------------------------------------------------- The `@rushstack/mcp-server` server expects to load plugins from a Rush [autoinstaller](https://rushjs.io/pages/maintainer/autoinstallers/) . This ensures deterministic NPM versions, and ensures plugins will work correctly even in a branch where `rush install` is broken. 1. Create a `rush-mcp` autoinstaller: rush init-autoinstaller --name rush-mcp 2. Add your plugin as a dependency: **common/autoinstallers/rush-mcp/package.json** { "name": "rush-mcp", "version": "1.0.0", "private": true, "dependencies": { "rush-mcp-example-plugin": "1.0.0" }} Replace `"rush-mcp-example-plugin": "1.0.0"` with your published package version. If you did not publish your NPM package yet, you can use `file:` to simulate an installation by creating a symlink to your local development folder: **common/autoinstallers/rush-mcp/package.json** { "name": "rush-mcp", "version": "1.0.0", "private": true, "dependencies": { "rush-mcp-example-plugin": "file:../../../../rushstack/build-tests/rush-mcp-example-plugin/" }} 3. After updating `rush-mcp/package.json`, you need to regenerate the lockfile: rush update-autoinstaller --name rush-mcp 4. Next, we configure `@rushstack/mcp-server` to load your plugin: **common/config/rush-mcp/rush-mcp.json** /** * This file configures the behavior of `@rushstack/mcp-server` for a given monorepo. * Its file path: /common/config/rush-mcp/rush-mcp.json */{ /** * The list of plugins that `@rushstack/mcp-server` should load when processing this monorepo. */ "mcpPlugins": [ { /** * The name of an NPM package that appears in the package.json "dependencies" for the autoinstaller. */ "packageName": "rush-mcp-example-plugin", /** * The name of a Rush autoinstaller with this package as its dependency. * The `@rushstack/mcp-server` will automatically ensure this folder is installed * before attempting to load the plugin. */ "autoinstaller": "rush-mcp" } ]} 5. Finally, to confirm that it loads correctly, try invoking the MCP server manually from your shell prompt: # Note that MCP hosts will typically invoke this command# with the current working directory set to "/", NOT your monorepo folder.# It's a good idea to test that.node ./my-rush-repo/common/scripts/install-run.js @rushstack/mcp-server@0.2.1 "mcp-server" ./my-rush-repo If it launches without any problems, then your plugin is ready for use! Confirm that the MCP host displays the new tool. See also[​](https://rushjs.io/pages/ai/rush_mcp_plugins/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------- * [Autoinstallers](https://rushjs.io/pages/maintainer/autoinstallers/) * [Rush MCP server](https://rushjs.io/pages/ai/rush_mcp/) * [Creating a plugin](https://rushjs.io/pages/ai/rush_mcp_plugins/#creating-a-plugin) * [Enabling your plugin](https://rushjs.io/pages/ai/rush_mcp_plugins/#enabling-your-plugin) * [See also](https://rushjs.io/pages/ai/rush_mcp_plugins/#see-also) --- # rush init-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_init-autoinstaller/#docusaurus_skipToContent_fallback) On this page usage: rush init-autoinstaller [-h] --name AUTOINSTALLER_NAMEUse this command to initialize a new autoinstaller folder. Autoinstallersprovide a way to manage a set of related dependencies that are used forscripting scenarios outside of the usual "rush install" context. See thecommand-line.json documentation for an example.Optional arguments: -h, --help Show this help message and exit. --name AUTOINSTALLER_NAME Specifies the name of the autoinstaller folder, which must conform to the naming rules for NPM packages. See also[​](https://rushjs.io/pages/commands/rush_init-autoinstaller/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------------------- * [rush init](https://rushjs.io/pages/commands/rush_init/) * [rush update-autoinstaller](https://rushjs.io/pages/commands/rush_update-autoinstaller/) * [See also](https://rushjs.io/pages/commands/rush_init-autoinstaller/#see-also) --- # rush init-deploy | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_init-deploy/#docusaurus_skipToContent_fallback) On this page usage: rush init-deploy [-h] -p PROJECT_NAME [-s SCENARIO]Use this command to initialize a new scenario config file for use with "rushdeploy". The default filename is common/config/rush/deploy.json. However, ifyou need to manage multiple deployments with different settings, you can useuse "--scenario" to create additional config files.Optional arguments: -h, --help Show this help message and exit. -p PROJECT_NAME, --project PROJECT_NAME Specifies the name of the main Rush project to be deployed in this scenario. It will be added to the "deploymentProjectNames" setting. -s SCENARIO, --scenario SCENARIO By default, the deployment configuration will be written to "common/config/rush/deploy.json". You can use "--scenario" to specify an alternate name. The name must be lowercase and separated by dashes. For example, if the name is "web", then the config file would be "common/config/rush/deploy-web.json". See also[​](https://rushjs.io/pages/commands/rush_init-deploy/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------------- * [Deploying projects](https://rushjs.io/pages/maintainer/deploying/) * [deploy.json](https://rushjs.io/pages/configs/deploy_json/) config file * [rush deploy](https://rushjs.io/pages/commands/rush_deploy/) * [rush init](https://rushjs.io/pages/commands/rush_init/) * [See also](https://rushjs.io/pages/commands/rush_init-deploy/#see-also) --- # rush change | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_change/#docusaurus_skipToContent_fallback) On this page usage: rush change [-h] [-v] [--no-fetch] [-b BRANCH] [--overwrite] [--email EMAIL] [--bulk] [--message MESSAGE] [--bump-type {major,minor,patch,none}]Asks a series of questions and then generates a -.jsonfile in the common folder. The `publish` command will consume these files andperform the proper version bumps. Note these changes will eventually bepublished in a changelog.md file in each package. The possible types ofchanges are: MAJOR - these are breaking changes that are not backwardscompatible. Examples are: renaming a public class, adding/removing anon-optional parameter from a public API, or renaming an variable or functionthat is exported. MINOR - these are changes that are backwards compatible(but not forwards compatible). Examples are: adding a new public API oradding an optional parameter to a public API PATCH - these are changes thatare backwards and forwards compatible. Examples are: Modifying a private APIor fixing a bug in the logic of how an existing API works. NONE - these arechanges that are backwards and forwards compatible and don't require animmediate release. Examples are: Modifying dev tooling configuration likeeslint. HOTFIX (EXPERIMENTAL) - these are changes that are hotfixes targetinga specific older version of the package. When a hotfix change is added, otherchanges will not be able to increment the version number. Enable this featureby setting 'hotfixChangeEnabled' in your rush.json.Optional arguments: -h, --help Show this help message and exit. -v, --verify Verify the change file has been generated and that it is a valid JSON file --no-fetch Skips fetching the baseline branch before running "git diff" to detect changes. -b BRANCH, --target-branch BRANCH If this parameter is specified, compare the checked out branch with the specified branch to determine which projects were changed. If this parameter is not specified, the checked out branch is compared against the "main" branch. --overwrite If a changefile already exists, overwrite without prompting (or erroring in --bulk mode). --email EMAIL The email address to use in changefiles. If this parameter is not provided, the email address will be detected or prompted for in interactive mode. --bulk If this flag is specified, apply the same change message and bump type to all changed projects. The --message and the --bump-type parameters must be specified if the --bulk parameter is specified --message MESSAGE The message to apply to all changed projects if the --bulk flag is provided. --bump-type {major,minor,patch,none} The bump type to apply to all changed projects if the --bulk flag is provided. See also[​](https://rushjs.io/pages/commands/rush_change/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [Authoring change logs](https://rushjs.io/pages/best_practices/change_logs/) * [rush version](https://rushjs.io/pages/commands/rush_version/) * [See also](https://rushjs.io/pages/commands/rush_change/#see-also) --- # rush build | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_build/#docusaurus_skipToContent_fallback) On this page usage: rush build [-h] [-p COUNT] [--timeline] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] [-c] [--ignore-hooks]This command is similar to "rush rebuild", except that "rush build" performsan incremental build. In other words, it only builds projects whose sourcefiles have changed since the last successful build. The analysis requires aGit working tree, and only considers source files that are tracked by Git andwhose path is under the project folder. (For more details about thisalgorithm, see the documentation for the "package-deps-hash" NPM package.)The incremental build state is tracked in a per-project folder called ".rush/temp" which should NOT be added to Git. The build command is tracked bythe "arguments" field in the "package-deps_build.json" file containedtherein; a full rebuild is forced whenever the command has changed (e.g."--production" or not).Optional arguments: -h, --help Show this help message and exit. -p COUNT, --parallelism COUNT Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. "50%") or the word "max" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores. This parameter may alternatively be specified via the RUSH_PARALLELISM environment variable. --timeline After the build is complete, print additional statistics and CPU usage information, including an ASCII chart of the start and stop times for each operation. -t PROJECT, --to PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to" parameter expands this selection to include PROJECT and all its dependencies. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -T PROJECT, --to-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to-except" parameter expands this selection to include all dependencies of PROJECT, but not PROJECT itself. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -f PROJECT, --from PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--from" parameter expands this selection to include PROJECT and all projects that depend on it, plus all dependencies of this set. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -o PROJECT, --only PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--only" parameter expands this selection to include PROJECT; its dependencies are not added. "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -i PROJECT, --impacted-by PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -I PROJECT, --impacted-by-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by-except" parameter works the same as "--impacted-by" except that PROJECT itself is not added to the selection. ". " can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". --to-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--to-version-policy" parameter is equivalent to specifying "--to" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --from-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--from-version-policy" parameter is equivalent to specifying "--from" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". -v, --verbose Display the logs during the build, rather than just displaying the build status summary -c, --changed-projects-only Normally the incremental build logic will rebuild changed projects as well as any projects that directly or indirectly depend on a changed project. Specify "--changed-projects-only" to ignore dependent projects, only rebuilding those projects whose files were changed. Note that this parameter is "unsafe"; it is up to the developer to ensure that the ignored projects are okay to ignore. --ignore-hooks Skips execution of the "eventHooks" scripts defined in rush.json. Make sure you know what you are skipping. See also[​](https://rushjs.io/pages/commands/rush_build/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------- * [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/) * [rush rebuild](https://rushjs.io/pages/commands/rush_rebuild/) * [See also](https://rushjs.io/pages/commands/rush_build/#see-also) --- # rush init | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_init/#docusaurus_skipToContent_fallback) On this page usage: rush init [-h] [--overwrite-existing] [--rush-example-repo]When invoked in an empty folder, this command provisions a standard set ofconfig file templates to start managing projects using Rush.Optional arguments: -h, --help Show this help message and exit. --overwrite-existing By default "rush init" will not overwrite existing config files. Specify this switch to override that. This can be useful when upgrading your repo to a newer release of Rush. WARNING: USE WITH CARE! --rush-example-repo When copying the template config files, this uncomments fragments that are used by the "rush-example" GitHub repo, which is a sample monorepo that illustrates many Rush features. This option is primarily intended for maintaining that example. See also[​](https://rushjs.io/pages/commands/rush_init/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------- * [Setting up a new repo](https://rushjs.io/pages/maintainer/setup_new_repo/) * The [rush-example](https://github.com/microsoft/rush-example) repo on GitHub * [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/) * [See also](https://rushjs.io/pages/commands/rush_init/#see-also) --- # rush install-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_install-autoinstaller/#docusaurus_skipToContent_fallback) On this page usage: rush install-autoinstaller [-h] --name AUTOINSTALLER_NAMEUse this command to install dependencies for an autoinstaller folder.Optional arguments: -h, --help Show this help message and exit. --name AUTOINSTALLER_NAME The name of the autoinstaller, which must be one of the folders under common/autoinstallers. See also[​](https://rushjs.io/pages/commands/rush_install-autoinstaller/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------------------- * [rush update-autoinstaller](https://rushjs.io/pages/commands/rush_update-autoinstaller/) * [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) * [See also](https://rushjs.io/pages/commands/rush_install-autoinstaller/#see-also) --- # rush link | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_link/#docusaurus_skipToContent_fallback) On this page usage: rush link [-h] [-f]Create node_modules symlinks for all projects. This operation is normallyperformed automatically as part of "rush install" or "rush update". Youshould only need to use "rush link" if you performed "rush unlink" for somereason, or if you specified the "--no-link" option for "rush install" or"rush update".Optional arguments: -h, --help Show this help message and exit. -f, --force Deletes and recreates all links, even if the filesystem state seems to indicate that this is unnecessary. See also[​](https://rushjs.io/pages/commands/rush_link/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------- * [rush unlink](https://rushjs.io/pages/commands/rush_unlink/) * [See also](https://rushjs.io/pages/commands/rush_link/#see-also) --- # rush purge | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_purge/#docusaurus_skipToContent_fallback) usage: rush purge [-h] [--unsafe]The "rush purge" command is used to delete temporary files created by Rush.This is useful if you are having problems and suspect that cache files may becorrupt.Optional arguments: -h, --help Show this help message and exit. --unsafe (UNSAFE!) Also delete shared files such as the package manager instances stored in the ".rush" folder in the user's home directory. This is a more aggressive fix that is NOT SAFE to run in a live environment because it will cause other concurrent Rush processes to fail. --- # rush setup | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_setup/#docusaurus_skipToContent_fallback) usage: rush setup [-h](EXPERIMENTAL) Invoke this command before working in a new repo to ensurethat any required prerequisites are installed and permissions are configured.The initial implementation configures the NPM registry credentials. Morefeatures will be added later.Optional arguments: -h, --help Show this help message and exit. --- # rush remove | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_remove/#docusaurus_skipToContent_fallback) On this page usage: rush remove [-h] [-s] -p PACKAGE [--all]Removes specified package(s) from the dependencies of the current project (asdetermined by the current working directory) and then runs "rush update".Optional arguments: -h, --help Show this help message and exit. -s, --skip-update If specified, the "rush update" command will not be run after updating the package.json files. -p PACKAGE, --package PACKAGE The name of the package which should be removed. To remove multiple packages, run "rush remove --package foo --package bar". --all If specified, the dependency will be removed from all projects that declare it. See also[​](https://rushjs.io/pages/commands/rush_remove/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [Modifying package.json](https://rushjs.io/pages/developer/modifying_package_json/) * [rush add](https://rushjs.io/pages/commands/rush_add/) * [See also](https://rushjs.io/pages/commands/rush_remove/#see-also) --- # rush scan | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_scan/#docusaurus_skipToContent_fallback) On this page usage: rush scan [-h] [--json] [--all]The Node.js module system allows a project to import NPM packages withoutexplicitly declaring them as dependencies in the package.json file. Such"phantom dependencies" can cause problems. Rush and PNPM use symlinksspecifically to protect against phantom dependencies. These protections maycause runtime errors for existing projects when they are first migrated intoa Rush monorepo. The "rush scan" command is a handy tool for fixing theseerrors. It scans the "./src" and "./lib" folders for import syntaxes such as"import __ from '__'", "require('__')", and "System.import('__'). It prints areport of the referenced packages. This heuristic is not perfect, but it cansave a lot of time when migrating projects.Optional arguments: -h, --help Show this help message and exit. --json If this flag is specified, output will be in JSON format. --all If this flag is specified, output will list all detected dependencies. See also[​](https://rushjs.io/pages/commands/rush_scan/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------- * [Phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/) * [See also](https://rushjs.io/pages/commands/rush_scan/#see-also) --- # rush tab-complete | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_tab-complete/#docusaurus_skipToContent_fallback) On this page usage: rush tab-complete [-h] [--word WORD] [--position INDEX]Provides tab completion.Optional arguments: -h, --help Show this help message and exit. --word WORD The word to complete. The default value is "". --position INDEX The position in the word to be completed. The default value is 0. See also[​](https://rushjs.io/pages/commands/rush_tab-complete/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------------- * [Configuring tab completion](https://rushjs.io/pages/developer/tab_completion/) * [See also](https://rushjs.io/pages/commands/rush_tab-complete/#see-also) --- # rush unlink | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_unlink/#docusaurus_skipToContent_fallback) On this page usage: rush unlink [-h]This removes the symlinks created by the "rush link" command. This is usefulfor cleaning a repo using "git clean" without accidentally deleting sourcefiles, or for using standard NPM commands on a project.Optional arguments: -h, --help Show this help message and exit. See also[​](https://rushjs.io/pages/commands/rush_unlink/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [rush link](https://rushjs.io/pages/commands/rush_link/) * [See also](https://rushjs.io/pages/commands/rush_unlink/#see-also) --- # rush update-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_update-autoinstaller/#docusaurus_skipToContent_fallback) On this page usage: rush update-autoinstaller [-h] --name AUTOINSTALLER_NAMEUse this command to regenerate the shrinkwrap file for an autoinstallerfolder.Optional arguments: -h, --help Show this help message and exit. --name AUTOINSTALLER_NAME The name of the autoinstaller, which must be one of the folders under common/autoinstallers. See also[​](https://rushjs.io/pages/commands/rush_update-autoinstaller/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------------------ * [rush install-autoinstaller](https://rushjs.io/pages/commands/rush_install-autoinstaller/) * [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) * [See also](https://rushjs.io/pages/commands/rush_update-autoinstaller/#see-also) --- # rush update-cloud-credentials | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_update-cloud-credentials/#docusaurus_skipToContent_fallback) On this page usage: rush update-cloud-credentials [-h] [-i] [--credential CREDENTIAL_STRING] [-d](EXPERIMENTAL) If the build caching feature is configured, this commandfacilitates updating the credentials used by a cloud-based provider.Optional arguments: -h, --help Show this help message and exit. -i, --interactive Run the credential update operation in interactive mode, if supported by the provider. --credential CREDENTIAL_STRING A static credential, to be cached. -d, --delete If specified, delete stored credentials. See also[​](https://rushjs.io/pages/commands/rush_update-cloud-credentials/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------------------------- * [Enabling the build cache](https://rushjs.io/pages/maintainer/build_cache/) * [See also](https://rushjs.io/pages/commands/rush_update-cloud-credentials/#see-also) --- # rush upgrade-interactive | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_upgrade-interactive/#docusaurus_skipToContent_fallback) On this page usage: rush upgrade-interactive [-h] [--make-consistent] [-s]Provide an interactive way to upgrade your dependencies. Running the commandwill open an interactive prompt that will ask you which projects and whichdependencies you would like to upgrade. It will then update your package.jsonfiles, and run "rush update" for you. If you are usingensureConsistentVersions policy, upgrade-interactive will update all packageswhich use the dependencies that you are upgrading and match their SemVerrange if provided. If ensureConsistentVersions is not enabled,upgrade-interactive will only update the dependency in the package youspecify. This can be overridden by using the --make-consistent flag.Optional arguments: -h, --help Show this help message and exit. --make-consistent When upgrading dependencies from a single project, also upgrade dependencies from other projects. -s, --skip-update If specified, the "rush update" command will not be run after updating the package.json files. See also[​](https://rushjs.io/pages/commands/rush_upgrade-interactive/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------------------- * [Modifying package.json](https://rushjs.io/pages/developer/modifying_package_json/) * [rush install](https://rushjs.io/pages/commands/rush_install/) * [See also](https://rushjs.io/pages/commands/rush_upgrade-interactive/#see-also) --- # rush-pnpm | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush-pnpm/#docusaurus_skipToContent_fallback) When using the PNPM package manager, Rush relocates the PNPM workspace under the `common/temp/` path. It also injects some configuration hooks to support Rush-specific enhancements such as [preferred versions](https://rushjs.io/pages/advanced/preferred_versions/) and faster incremental installation. As a result, if you try to invoke the `pnpm` command directly in a Rush repo, it may fail because it cannot find the `pnpm-workspace.yaml` file. Some operations may malfunction if they are incompatible with Rush's enhancements. To avoid these problems, use `rush-pnpm` in your Rush repo wherever you would normally use `pnpm`. The `@microsoft/rush` NPM package includes the `rush-pnpm` binary, which is a drop-in replacement for the `pnpm` command. It provides the following features: * sets up the correct context/environment so that PNPM commands work correctly * reports an error for operations that are known to be incompatible with Rush * reports a warning for operations that may be unsafe with Rush --- # rush version | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_version/#docusaurus_skipToContent_fallback) On this page usage: rush version [-h] [-b BRANCH] [--ensure-version-policy] [--override-version NEW_VERSION] [--bump] [--bypass-policy] [--version-policy POLICY] [--override-bump BUMPTYPE] [--override-prerelease-id ID] [--ignore-git-hooks]use this "rush version" command to ensure version policies and bump versions.Optional arguments: -h, --help Show this help message and exit. -b BRANCH, --target-branch BRANCH If this flag is specified, changes will be committed and merged into the target branch. --ensure-version-policy Updates package versions if needed to satisfy version policies. --override-version NEW_VERSION Override the version in the specified --version-policy. This setting only works for lock-step version policy and when --ensure-version-policy is specified. --bump Bumps package version based on version policies. --bypass-policy Overrides "gitPolicy" enforcement (use honorably!) --version-policy POLICY The name of the version policy --override-bump BUMPTYPE Overrides the bump type in the version-policy.json for the specified version policy. Valid BUMPTYPE values include: prerelease, patch, preminor, minor, major. This setting only works for lock-step version policy in bump action. --override-prerelease-id ID Overrides the prerelease identifier in the version value of version-policy.json for the specified version policy. This setting only works for lock-step version policy. This setting increases to new prerelease id when "--bump" is provided but only replaces the prerelease name when "--ensure-version-policy" is provided. --ignore-git-hooks Skips execution of all git hooks. Make sure you know what you are skipping. See also[​](https://rushjs.io/pages/commands/rush_version/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------- * [Publishing packages](https://rushjs.io/pages/maintainer/publishing/) * [rush change](https://rushjs.io/pages/commands/rush_change/) * [rush publish](https://rushjs.io/pages/commands/rush_publish/) * [See also](https://rushjs.io/pages/commands/rush_version/#see-also) --- # cobuild.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/cobuild_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for the [cobuild feature](https://rushjs.io/pages/maintainer/cobuilds/) . **common/config/rush/cobuild.json** /** * This configuration file manages Rush's cobuild feature. * More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", /** * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, * otherwise the cobuild feature will be disabled. */ "cobuildFeatureEnabled": false, /** * (Required) Choose where cobuild lock will be acquired. * * The lock provider is registered by the rush plugins. * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. */ "cobuildLockProvider": "redis"} See also[​](https://rushjs.io/pages/configs/cobuild_json/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [Cobuilds](https://rushjs.io/pages/maintainer/cobuilds/) * [Enabling the build cache](https://rushjs.io/pages/maintainer/build_cache/) * [See also](https://rushjs.io/pages/configs/cobuild_json/#see-also) --- # custom-tips.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/custom-tips_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for the [Custom tips](https://rushjs.io/pages/maintainer/custom_tips/) feature. **common/config/rush/custom-tips.json** /** * This configuration file allows repo maintainers to configure extra details to be * printed alongside certain Rush messages. More documentation is available on the * Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", /** * Custom tips allow you to annotate Rush's console messages with advice tailored for * your specific monorepo. */ "customTips": [ // { // /** // * (REQUIRED) An identifier indicating a message that may be printed by Rush. // * If that message is printed, then this custom tip will be shown. // * The list of available tip identifiers can be found on this page: // * https://rushjs.io/pages/maintainer/custom_tips/ // */ // "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", // // /** // * (REQUIRED) The message text to be displayed for this tip. // */ // "message": "For additional troubleshooting information, refer this wiki article:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" // } ]} See also[​](https://rushjs.io/pages/configs/custom-tips_json/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------------- * [Custom tips](https://rushjs.io/pages/maintainer/custom_tips/) * [See also](https://rushjs.io/pages/configs/custom-tips_json/#see-also) --- # .npmrc-publish | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/npmrc-publish/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **.npmrc-publish**: **common/config/rush/.npmrc-publish** # This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish# is used by the "rush publish" command, as publishing often involves different credentials# and registries than other operations.## Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc"# and then temporarily map that folder as the "home directory" for the current user account.# This enables the same settings to apply for each project folder that gets published. The copied file# will omit any config lines that reference environment variables that are undefined in that session;# this avoids problems that would otherwise result due to a missing variable being replaced by# an empty string.## * * * SECURITY WARNING * * *## It is NOT recommended to store authentication tokens in a text file on a lab machine, because# other unrelated processes may be able to read the file. Also, the file may persist indefinitely,# for example if the machine loses power. A safer practice is to pass the token via an# environment variable, which can be referenced from .npmrc using ${} expansion. For example:## //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}# See also[​](https://rushjs.io/pages/configs/npmrc-publish/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------- * [.npmrc](https://rushjs.io/pages/configs/npmrc/) config file * [See also](https://rushjs.io/pages/configs/npmrc-publish/#see-also) --- # .pnpmfile.cjs | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/pnpmfile_cjs/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for the monorepo **pnpmfile.js** file: **common/config/rush/.pnpmfile.cjs** 'use strict';/** * When using the PNPM package manager, you can use pnpmfile.js to workaround * dependencies that have mistakes in their package.json file. (This feature is * functionally similar to Yarn's "resolutions".) * * For details, see the PNPM documentation: * https://pnpm.js.org/docs/en/hooks.html * * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run * "rush update --full" so that PNPM will recalculate all version selections. */module.exports = { hooks: { readPackage }};/** * This hook is invoked during installation before a package's dependencies * are selected. * The `packageJson` parameter is the deserialized package.json * contents for the package that is about to be installed. * The `context` parameter provides a log() function. * The return value is the updated object. */function readPackage(packageJson, context) { // // The karma types have a missing dependency on typings from the log4js package. // if (packageJson.name === '@types/karma') { // context.log('Fixed up dependencies for @types/karma'); // packageJson.dependencies['log4js'] = '0.6.38'; // } return packageJson;} --- # rush-plugins.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/rush-plugins_json/#docusaurus_skipToContent_fallback) On this page This is the template for the **rush-plugins.json** file that is used to enable [Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) . **common/config/rush/command-line.json** /** * This configuration file manages Rush's plugin feature. */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item configures a plugin to be loaded by Rush. */ // { // /** // * The name of the NPM package that provides the plugin. // */ // "packageName": "@scope/my-rush-plugin", // /** // * The name of the plugin. This can be found in the "pluginName" // * field of the "rush-plugin-manifest.json" file in the NPM package folder. // */ // "pluginName": "my-plugin-name", // /** // * The name of a Rush autoinstaller that will be used for installation, which // * can be created using "rush init-autoinstaller". Add the plugin's NPM package // * to the package.json "dependencies" of your autoinstaller, then run // * "rush update-autoinstaller". // */ // "autoinstallerName": "rush-plugins" // } ]} See also[​](https://rushjs.io/pages/configs/rush-plugins_json/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------------- * [Using Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) * [Creating a Rush plugin](https://rushjs.io/pages/extensibility/creating_plugins/) * [See also](https://rushjs.io/pages/configs/rush-plugins_json/#see-also) --- # rush check | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_check/#docusaurus_skipToContent_fallback) usage: rush check [-h] [--variant VARIANT] [--json] [--verbose]Checks each project's package.json files and ensures that all dependenciesare of the same version throughout the repository.Optional arguments: -h, --help Show this help message and exit. --variant VARIANT Run command using a variant installation configuration. This parameter may alternatively be specified via the RUSH_VARIANT environment variable. --json If this flag is specified, output will be in JSON format. --verbose If this flag is specified, long lists of package names will not be truncated. This has no effect if the --json flag is also specified. --- # rush deploy | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_deploy/#docusaurus_skipToContent_fallback) On this page usage: rush deploy [-h] [-p PROJECT_NAME] [-s SCENARIO_NAME] [--overwrite] [-t PATH] [--create-archive ARCHIVE_PATH]After building the repo, "rush deploy" can be used to prepare a deployment bycopying a subset of Rush projects and their dependencies to a target folder,which can then be uploaded to a production server. The "rush deploy" behavioris specified by a scenario config file that must be created first, using the"rush init-deploy" command.Optional arguments: -h, --help Show this help message and exit. -p PROJECT_NAME, --project PROJECT_NAME Specifies the name of the main Rush project to be deployed. It must appear in the "deploymentProjectNames" setting in the deployment config file. -s SCENARIO_NAME, --scenario SCENARIO_NAME By default, the deployment configuration is specified in "common/config/rush/deploy.json". You can use "--scenario" to specify an alternate name. The name must be lowercase and separated by dashes. For example, if SCENARIO_NAME is "web", then the config file would be "common/config/rush/deploy-web.json". --overwrite By default, deployment will fail if the target folder is not empty. SPECIFYING THIS FLAG WILL RECURSIVELY DELETE EXISTING CONTENTS OF THE TARGET FOLDER. -t PATH, --target-folder PATH By default, files are deployed to the "common/deploy" folder inside the Rush repo. Use this parameter to specify a different location. WARNING: USE CAUTION WHEN COMBINING WITH "--overwrite". This parameter may alternatively be specified via the RUSH_DEPLOY_TARGET_FOLDER environment variable. --create-archive ARCHIVE_PATH If specified, after the deployment has been prepared, "rush deploy" will create an archive containing the contents of the target folder. The newly created archive file will be placed according to the designated path, relative to the target folder. Supported file extensions: .zip See also[​](https://rushjs.io/pages/commands/rush_deploy/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [Deploying projects](https://rushjs.io/pages/maintainer/deploying/) * [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/) * [See also](https://rushjs.io/pages/commands/rush_deploy/#see-also) --- # rush list | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_list/#docusaurus_skipToContent_fallback) usage: rush list [-h] [-v] [-p] [--full-path] [--detailed] [--json] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME]List package names, and optionally version (--version) and path (--path) orfull path (--full-path), for projects in the current rush config.Optional arguments: -h, --help Show this help message and exit. -v, --version If this flag is specified, the project version will be displayed in a column along with the package name. -p, --path If this flag is specified, the project path will be displayed in a column along with the package name. --full-path If this flag is specified, the project full path will be displayed in a column along with the package name. --detailed For the non --json view, if this flag is specified, include path (-p), version (-v) columns along with the project's applicable: versionPolicy, versionPolicyName, shouldPublish, reviewPolicy, and tags fields. --json If this flag is specified, output will be in JSON format. -t PROJECT, --to PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to" parameter expands this selection to include PROJECT and all its dependencies. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -T PROJECT, --to-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to-except" parameter expands this selection to include all dependencies of PROJECT, but not PROJECT itself. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -f PROJECT, --from PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--from" parameter expands this selection to include PROJECT and all projects that depend on it, plus all dependencies of this set. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -o PROJECT, --only PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--only" parameter expands this selection to include PROJECT; its dependencies are not added. "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -i PROJECT, --impacted-by PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -I PROJECT, --impacted-by-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by-except" parameter works the same as "--impacted-by" except that PROJECT itself is not added to the selection. ". " can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". --to-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--to-version-policy" parameter is equivalent to specifying "--to" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --from-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--from-version-policy" parameter is equivalent to specifying "--from" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --- # Rush MCP server | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/ai/rush_mcp/#docusaurus_skipToContent_fallback) On this page [Agent context files](https://rushjs.io/pages/ai/context_files/) provide a simple way to improve artificial intelligence (AI) **coding assistants** by publishing additional information about your Rush repository. The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) takes this to the next level, providing a live service that can answer queries and perform actions in your monorepo. How does it work?[​](https://rushjs.io/pages/ai/rush_mcp/#how-does-it-work "Direct link to How does it work?") --------------------------------------------------------------------------------------------------------------- * An [MCP host](https://modelcontextprotocol.io/clients) is typically a **coding assistant** such as [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-chat-with-mcp) (usable directly in [VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) ), [Trae](https://docs.trae.ai/ide/model-context-protocol) , or [Cursor](https://docs.cursor.com/context/model-context-protocol) . But any kind of software tool could act as a client by implementing the **MCP client** protocol. * An [MCP server](https://modelcontextprotocol.io/docs/concepts/architecture) advertises a menu of capabilities to the client, which the client invokes using the protocol while performing its tasks. According to the specification, the server can run locally or as a remote cloud service. Its capabilities include: * **resources**: for example reading file contents, querying databases, reading log files, capturing screenshots * **tools**: for example running shell commands, modifying files, performing calculations * **prompts**: exposing specific input forms to be shown to the end user * Rush provides a ready-made MCP server [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) that you can install in your monorepo. Its design goals were specifically tailored for large teams: * **Easy for everyone to install,** minimizing the learning curve for casual contributors. * **Centrally managed,** so the monorepo maintainers can control its configuration and installed version, ensuring everyone gets a consistent experience. Deterministic behavior is important when providing on-call support for engineers. * **Extensible** via [Rush MCP plugins](https://rushjs.io/pages/ai/rush_mcp_plugins/) , so you can integrate company-specific capabilities without having to build your own MCP server. Setting up the MCP server[​](https://rushjs.io/pages/ai/rush_mcp/#setting-up-the-mcp-server "Direct link to Setting up the MCP server") ---------------------------------------------------------------------------------------------------------------------------------------- The `@rushstack/mcp-server` server is designed to run as a local process on the developer's computer, not as a cloud service. The Rush MCP server gets launched automatically by an MCP host such as VS Code, Cursor, or Trae. The MCP host is responsible for starting and terminating this process. The inter-process communication uses the`stdio` [transport](https://modelcontextprotocol.io/docs/concepts/transports) , which means you can easily test Rush's MCP server by invoking its CLI manually from your shell. Generally there are two ways to configure launching of an MCP server: **user-level** for your entire machine (e.g. `~/.cursor/mcp.json`) or **workspace-level** for a specific Git repository (e.g. `/.cursor/mcp.json`). For the `@rushstack/mcp-server` service, we recommend a workspace-level configuration file that gets committed to Git. This simplifies setup for users, and it ensures that everyone gets the same version of `@rushstack/mcp-server` for a given branch, which avoids compatibility problems when loading custom plugins. After you get it working, consider implementing a [Rush MCP plugin](https://rushjs.io/pages/ai/rush_mcp_plugins/) to expose specific capabilities for your company's systems. > **If your coding assistant isn't mentioned below:** please [create a pull request](https://github.com/microsoft/rushstack-websites/tree/main/websites/rushjs.io/docs/pages/ai/rush_mcp.md) > to add a setup recipe! ### Cursor[​](https://rushjs.io/pages/ai/rush_mcp/#cursor "Direct link to Cursor") For [Cursor](https://docs.cursor.com/context/model-context-protocol) , add this file to your monorepo: **/.cursor/mcp.json** { "mcpServers": { "rush-mcp-server": { "command": "node", "args": [ "./common/scripts/install-run.js", "@rushstack/mcp-server@0.2.1", "mcp-server", "." ] } }} Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) . > **Cursor Caveats** > > * In the above file, Cursor will magically replace `"."` with the absolute path of the workspace folder. > * Cursor lacks support for `//` comments in JSON files. ### Trae[​](https://rushjs.io/pages/ai/rush_mcp/#trae "Direct link to Trae") For [Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en#c5b33bab) , configure manually as follows: 1. At the top right of the side chat box, click the **Settings icon \> MCP**. 2. Click the **\+ Add MCP Servers** button. 3. Click **"Configure Manually."** Enter the following configuration: { "mcpServers": { "rush-mcp-server": { "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) . Replace `` with the absolute path to your Rush monorepo root directory (the folder containing `rush.json`). ### GitHub Copilot[​](https://rushjs.io/pages/ai/rush_mcp/#github-copilot "Direct link to GitHub Copilot") For [GitHub Copilot](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) , add this file to your monorepo: **/.vscode/mcp.json** { "servers": { "rush-mcp-server": { "type": "stdio", "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) . Replace `` with the absolute path to your Rush monorepo root directory (the folder containing `rush.json`). ### Cline[​](https://rushjs.io/pages/ai/rush_mcp/#cline "Direct link to Cline") For [Cline](https://docs.cline.bot/mcp/mcp-overview#getting-started) , configure manually as follows: 1. Click the **MCP Servers** button. 2. Click the **Installed** button. 3. Click the **Configure MCP Servers** button, and enter the following configuration in the newly opened `cline_mcp_settings.json` file: **cline\_mcp\_settings.json** { "mcpServers": { "rush-mcp-server": { "disabled": false, "timeout": 60, "type": "stdio", "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) . Replace `` with the absolute path to your Rush monorepo root directory (the folder containing `rush.json`). ### Windsurf[​](https://rushjs.io/pages/ai/rush_mcp/#windsurf "Direct link to Windsurf") For [Windsurf](https://docs.windsurf.com/windsurf/cascade/mcp) , configure manually as follows: 1. Click **Settings \> Windsurf Settings** in the top left corner. 2. In the opened page, click **Cascade \> Manage plugins \> View raw config**. 3. Enter the following in the opened `mcp_config.json` file: **mcp\_config.json** { "mcpServers": { "rush-mcp-server": { "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) . Replace `` with the absolute path to your Rush monorepo root directory (the folder containing `rush.json`). ### Claude Code[​](https://rushjs.io/pages/ai/rush_mcp/#claude-code "Direct link to Claude Code") For [Claude Code](https://www.anthropic.com/claude-code) , configure manually as follows: 1. `cd` to your Rush monorepo root directory (the folder containing `rush.json`). 2. Run `claude mcp add rush-mcp-server -- npx -y @rushstack/mcp-server@0.2.1 .` (Replace `@rushstack/mcp-server@0.2.1` with the latest version from [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) .) 3. Start `claude` as usual, you can verify the connection using the `/mcp` command * [How does it work?](https://rushjs.io/pages/ai/rush_mcp/#how-does-it-work) * [Setting up the MCP server](https://rushjs.io/pages/ai/rush_mcp/#setting-up-the-mcp-server) * [Cursor](https://rushjs.io/pages/ai/rush_mcp/#cursor) * [Trae](https://rushjs.io/pages/ai/rush_mcp/#trae) * [GitHub Copilot](https://rushjs.io/pages/ai/rush_mcp/#github-copilot) * [Cline](https://rushjs.io/pages/ai/rush_mcp/#cline) * [Windsurf](https://rushjs.io/pages/ai/rush_mcp/#windsurf) * [Claude Code](https://rushjs.io/pages/ai/rush_mcp/#claude-code) --- # rush update | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_update/#docusaurus_skipToContent_fallback) On this page usage: rush update [-h] [-p] [--bypass-policy] [--no-link] [--network-concurrency COUNT] [--debug-package-manager] [--max-install-attempts NUMBER] [--ignore-hooks] [--variant VARIANT] [--full] [--recheck]The "rush update" command installs the dependencies described in your package.json files, and updates the shrinkwrap file as needed. (This "shrinkwrap"file stores a central inventory of all dependencies and versions for projectsin your repo. It is found in the "common/config/rush" folder.) Note that Rushalways performs a single install for all projects in your repo. You shouldrun "rush update" whenever you start working in a Rush repo, after you pullfrom Git, and after you modify a package.json file. If there is nothing to do, "rush update" is instantaneous. NOTE: In certain cases "rush install" shouldbe used instead of "rush update" -- for details, see the command help for"rush install".Optional arguments: -h, --help Show this help message and exit. -p, --purge Perform "rush purge" before starting the installation --bypass-policy Overrides enforcement of the "gitPolicy" rules from rush.json (use honorably!) --no-link If "--no-link" is specified, then project symlinks will NOT be created after the installation completes. You will need to run "rush link" manually. This flag is useful for automated builds that want to report stages individually or perform extra operations in between the two stages. This flag is not supported when using workspaces. --network-concurrency COUNT If specified, limits the maximum number of concurrent network requests. This is useful when troubleshooting network failures. --debug-package-manager Activates verbose logging for the package manager. You will probably want to pipe the output of Rush to a file when using this command. --max-install-attempts NUMBER Overrides the default maximum number of install attempts. The default value is 1. --ignore-hooks Skips execution of the "eventHooks" scripts defined in rush.json. Make sure you know what you are skipping. --variant VARIANT Run command using a variant installation configuration. This parameter may alternatively be specified via the RUSH_VARIANT environment variable. --full Normally "rush update" tries to preserve your existing installed versions and only makes the minimum updates needed to satisfy the package.json files. This conservative approach prevents your PR from getting involved with package updates that are unrelated to your work. Use "--full" when you really want to update all dependencies to the latest SemVer-compatible version. This should be done periodically by a person or robot whose role is to deal with potential upgrade regressions. --recheck If the shrinkwrap file appears to already satisfy the package.json files, then "rush update" will skip invoking the package manager at all. In certain situations this heuristic may be inaccurate. Use the "--recheck" flag to force the package manager to process the shrinkwrap file. This will also update your shrinkwrap file with Rush's fixups. (To minimize shrinkwrap churn, these fixups are normally performed only in the temporary folder.) See also[​](https://rushjs.io/pages/commands/rush_update/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [rush install](https://rushjs.io/pages/commands/rush_install/) * [See also](https://rushjs.io/pages/commands/rush_update/#see-also) --- # rush publish | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_publish/#docusaurus_skipToContent_fallback) On this page usage: rush publish [-h] [-a] [-b BRANCH] [-p] [--add-commit-details] [--regenerate-changelogs] [-r REGISTRY] [-n TOKEN] [-t TAG] [--set-access-level {public,restricted}] [--pack] [--release-folder FOLDER] [--include-all] [--version-policy POLICY] [--prerelease-name NAME] [--partial-prerelease] [--suffix SUFFIX] [--force] [--apply-git-tags-on-pack] [-c COMMIT_ID] [--ignore-git-hooks]Reads and processes package publishing change requests generated by "rushchange". This will perform a read-only operation by default, printingoperations executed to the console. To commit changes and publish packages,you must use the --commit flag and/or the --publish flag.Optional arguments: -h, --help Show this help message and exit. -a, --apply If this flag is specified, the change requests will be applied to package.json files. -b BRANCH, --target-branch BRANCH If this flag is specified, applied changes and deleted change requests will be committed and merged into the target branch. -p, --publish If this flag is specified, applied changes will be published to the NPM registry. --add-commit-details Adds commit author and hash to the changelog.json files for each change. --regenerate-changelogs Regenerates all changelog files based on the current JSON content. -r REGISTRY, --registry REGISTRY Publishes to a specified NPM registry. If this is specified, it will prevent the current commit will not be tagged. -n TOKEN, --npm-auth-token TOKEN (DEPRECATED) Specifies the authentication token to use during publishing. This parameter is deprecated because command line parameters may be readable by unrelated processes on a lab machine. Instead, a safer practice is to pass the token via an environment variable and reference it from your common/config/rush/.npmrc-publish file. -t TAG, --tag TAG The tag option to pass to npm publish. By default NPM will publish using the 'latest' tag, even if the package is older than the current latest, so in publishing workflows for older releases, providing a tag is important. When hotfix changes are made, this parameter defaults to 'hotfix'. --set-access-level {public,restricted} By default, when Rush invokes "npm publish" it will publish scoped packages with an access level of "restricted". Scoped packages can be published with an access level of "public" by specifying that value for this flag with the initial publication. NPM always publishes unscoped packages with an access level of "public". For more information, see the NPM documentation for the "--access" option of "npm publish". --pack Packs projects into tarballs instead of publishing to npm repository. It can only be used when --include-all is specified. If this flag is specified, NPM registry related parameters will be ignored. --release-folder FOLDER This parameter is used with --pack parameter to provide customized location for the tarballs instead of the default value. --include-all If this flag is specified, all packages with shouldPublish=true in rush.json or with a specified version policy will be published if their version is newer than published version. --version-policy POLICY Version policy name. Only projects with this version policy will be published if used with --include-all. --prerelease-name NAME Bump up to a prerelease version with the provided prerelease name. Cannot be used with --suffix --partial-prerelease Used with --prerelease-name. Only bump packages to a prerelease version if they have changes. --suffix SUFFIX Append a suffix to all changed versions. Cannot be used with --prerelease-name. --force If this flag is specified with --publish, packages will be published with --force on npm --apply-git-tags-on-pack If specified with --publish and --pack, git tags will be applied for packages as if a publish was being run without --pack. -c COMMIT_ID, --commit COMMIT_ID Used in conjunction with git tagging -- apply git tags at the commit hash specified. If not provided, the current HEAD will be tagged. --ignore-git-hooks Skips execution of all git hooks. Make sure you know what you are skipping. See also[​](https://rushjs.io/pages/commands/rush_publish/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------- * [Publishing packages](https://rushjs.io/pages/maintainer/publishing/) * [rush version](https://rushjs.io/pages/commands/rush_version/) * [See also](https://rushjs.io/pages/commands/rush_publish/#see-also) --- # rushx | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rushx/#docusaurus_skipToContent_fallback) On this page The `rushx` command is similar to `npm run` or `pnpm run`: It invokes a shell script that is defined in the `"scripts"` section of the **package.json** file for an individual project. Any additional CLI parameters are passed only to that shell script without any validation. Consider this very simple example project: **/package.json** { "name": "my-project", "version": "0.0.0", "scripts": { "build": "rm -Rf lib && tsc", "test": "jest" }} If you invoke `rushx` alone, it will simply display the available commands: usage: rushx [-h] rushx [-q/--quiet] ...Optional arguments: -h, --help Show this help message and exit. -q, --quiet Hide rushx startup information.Project commands for my-project: build: "rm -Rf lib && tsc" test: "jest" If you invoke `rushx build`, then it would run `rm -Rf lib && tsc`. If you add a parameter such as `rushx build --verbose`, it is blindly appended to the end of the string: `rm -Rf lib && tsc --verbose`. rush vs rushx[​](https://rushjs.io/pages/commands/rushx/#rush-vs-rushx "Direct link to rush vs rushx") ------------------------------------------------------------------------------------------------------- It's easy to confuse these two commands: * **rush** invokes a generic operation that affects the entire repo ("global commands") or else affects multiple projects ("bulk commands"). Such commands [should be carefully designed](https://rushjs.io/pages/maintainer/custom_commands/) . Rush enforces that their parameters must be validated and documented. * **rushx** performs custom operations for one single project. Although some of these are used to implement bulk commands, many of them will be helper scripts that are understood only by the developers of that particular project. Rush does not rigorously validate these commands. Why use "rushx" instead of "pnpm run" or "npx"?[​](https://rushjs.io/pages/commands/rushx/#why-use-rushx-instead-of-pnpm-run-or-npx "Direct link to Why use "rushx" instead of "pnpm run" or "npx"?") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ The `rushx` command has similar functionality as `pnpm run` or `npx`, but with some additional benefits: * Ensures deterministic tooling by using the [Rush version selector](https://rushjs.io/pages/contributing/) * Prepares the shell environment based on Rush's configuration * Implements additional validations * [rush vs rushx](https://rushjs.io/pages/commands/rushx/#rush-vs-rushx) * [Why use "rushx" instead of "pnpm run" or "npx"?](https://rushjs.io/pages/commands/rushx/#why-use-rushx-instead-of-pnpm-run-or-npx) --- # .npmrc | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/npmrc/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for the monorepo **.npmrc** file: **common/config/rush/.npmrc** # Rush uses this file to configure the NPM package registry during installation. It is applicable# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install",# "rush update", and the "install-run.js" scripts.## NOTE: The "rush publish" command uses .npmrc-publish instead.## Before invoking the package manager, Rush will copy this file to the folder where installation# is performed. The copied file will omit any config lines that reference environment variables# that are undefined in that session; this avoids problems that would otherwise result due to# a missing variable being replaced by an empty string.## * * * SECURITY WARNING * * *## It is NOT recommended to store authentication tokens in a text file on a lab machine, because# other unrelated processes may be able to read the file. Also, the file may persist indefinitely,# for example if the machine loses power. A safer practice is to pass the token via an# environment variable, which can be referenced from .npmrc using ${} expansion. For example:## //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}#registry=https://registry.npmjs.org/always-auth=false .npmrc file precedence[​](https://rushjs.io/pages/configs/npmrc/#npmrc-file-precedence "Direct link to .npmrc file precedence") -------------------------------------------------------------------------------------------------------------------------------- Regular Rush operations perform the following lookup: 1. To support unusual situations, NPM config environment variables take precedence over any **.npmrc** settings. The environment variable name is prefixed by `npm_config_`. For example, setting the `npm_config_registry` variable will override the `registry` setting in **.npmrc**. Nonstandard name patterns like `npm_config_@example:registry` are also accepted by NPM's design. 2. Typically settings come from a temporary **.npmrc** file that Rush copies into the working directory for the operation. The file is copied from **common/config/rush/.npmrc**, but omitting any lines that reference undefined environment variables (as explained above). For most operations, the working directory will be **common/temp**. 3. If the package manager cannot find a setting via 1 or 2, then the user's **~/.npmrc** is consulted. Individual users typically store their authentication tokens in this file. The above rules also apply for helpers scripts such as **install-run.js**. The `rush publish` command uses a different file **.npmrc-publish** with its own rules. See [this documentation](https://rushjs.io/pages/configs/npmrc-publish/) for details. The above rules do not apply if the package manager is invoked directly (instead of via Rush). For example, `npm publish` is invoked from the shell, then the [package manager's usual precedence](https://docs.npmjs.com/cli/v7/using-npm/config#npmrc-files) will apply instead. Generally this practice is discouraged in a Rush repo, but if used, you may need to create additional **.npmrc** files. See also[​](https://rushjs.io/pages/configs/npmrc/#see-also "Direct link to See also") --------------------------------------------------------------------------------------- * [NPM registry authentication](https://rushjs.io/pages/maintainer/npm_registry_auth/) * [.npmrc-publish](https://rushjs.io/pages/configs/npmrc-publish/) config file * [.npmrc file precedence](https://rushjs.io/pages/configs/npmrc/#npmrc-file-precedence) * [See also](https://rushjs.io/pages/configs/npmrc/#see-also) --- # common-versions.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/common-versions_json/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **common-versions.json**: **common/config/rush/common-versions.json** /** * This configuration file specifies NPM dependency version selections that affect all projects * in a Rush repo. More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", /** * A table that specifies a "preferred version" for a given NPM package. This feature is typically used * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. * * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager * will calculate versions. The specific effect depends on your package manager. Generally it will have no * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be * achieved using the pnpmfile.js hook. See the Rush documentation for more details. * * After modifying this field, it's recommended to run "rush update --full" so that the package manager * will recalculate all version selections. */ "preferredVersions": { /** * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, * instead of the latest version. */ // "some-library": "1.2.3" }, /** * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, * except in cases where different projects specify different version ranges for a given dependency. For older * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause * trouble for indirect dependencies with incompatible peerDependencies ranges. * * The default value is true. If you're encountering installation errors related to peer dependencies, * it's recommended to set this to false. * * After modifying this field, it's recommended to run "rush update --full" so that the package manager * will recalculate all version selections. */ // "implicitlyPreferredVersions": false, /** * If you would like the version specifiers for your dependencies to be consistent, then * uncomment this line. This is effectively similar to running "rush check" before any * of the following commands: * * rush install, rush update, rush link, rush version, rush publish * * In some cases you may want this turned on, but need to allow certain packages to use a different * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" * section of the common-versions.json. * * In the case that subspaces is enabled, this setting will take effect at a subspace level. */ // "ensureConsistentVersions": true, /** * The "rush check" command can be used to enforce that every project in the repo must specify * the same SemVer range for a given dependency. However, sometimes exceptions are needed. * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be * accepted by "rush check" for a given dependency. * * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). * This design avoids unnecessary churn in this file. */ "allowedAlternativeVersions": { /** * For example, allow some projects to use an older TypeScript compiler * (in addition to whatever "usual" version is being used by other projects in the repo): */ // "typescript": [ // "~2.4.0" // ] }} --- # rush-plugin-manifest.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/rush-plugin-manifest_json/#docusaurus_skipToContent_fallback) On this page This is the template for the **rush-plugin-manifest.json** file that is used when [creating a Rush plugin](https://rushjs.io/pages/extensibility/creating_plugins/) . **/rush-plugin-manifest.json** /** * This file defines the Rush plugins that are provided by this package. */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", /** * An array of one or more plugin definitions provided by this NPM package. * * For more granular installations, it is recommended for plugins to be implemented by an * NPM package that does try to serve other roles such as providing APIs or command-line binaries. * The package name should start with "rush-". The name should end with "-plugin" or "-plugins". * For example: "@scope/rush-business-policy-plugin" */ "plugins": [ { /** * (Required) The name of the plugin. The plugin name must be comprised of letters and numbers * forming one or more words that are separated by hyphens. Note that if the plugin has a * JSON config file, that filename will be the same as the plugin name. See "optionsSchema" below * for details. * * If the manifest defines exactly one plugin, then it is suggested to reuse the name from the * NPM package. For example, if the NPM package is "@scope/rush-business-policy-plugin" * then the plugin name might be "business-policy" and with config file "business-policy.json". */ "pluginName": "example", /** * (Required) Provide some documentation that summarizes the problem solved by this plugin, * how to invoke it, and what operations it performs. */ "description": "An example plugin", /** * (Optional) A path to a JavaScript code module that implements the "IRushPlugin" interface. * This module can use the "@rushstack/rush-sdk" API to register handlers for Rush events * and services. The module path is relative to the folder containing the "package.json" file. */ // "entryPoint": "lib/example/RushExamplePlugin.js", /** * (Optional) A path to a "command-line.json" file that defines Rush command line actions * and parameters contributed by this plugin. This config file has the same JSON schema * as Rush's "common/config/rush/command-line.json" file. */ // "commandLineJsonFilePath": "lib/example/command-line.json", /** * (Optional) A path to a JSON schema for validating the config file that end users can * create to customize this plugin's behavior. Plugin config files are stored in the folder * "common/config/rush-plugins/" with a filename corresponding to the "pluginName" field * from the manifest. For example: "common/config/rush-plugins/business-policy.json" * whose schema is "business-policy.schema.json". */ // "optionsSchema": "lib/example/example.schema.json", /** * (Optional) A list of associated Rush command names such as "build" from "rush build". * If specified, then the plugin's "entryPoint" code module be loaded only if * one of the specified commands is invoked. This improves performance by avoiding * loading the code module when it is not needed. If "associatedCommands" is * not specified, then the code module will always be loaded. */ // "associatedCommands": [ "build" ] } ]} See also[​](https://rushjs.io/pages/configs/rush-plugin-manifest_json/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------------------- * [Creating a Rush plugin](https://rushjs.io/pages/extensibility/creating_plugins/) * [Using Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) * [See also](https://rushjs.io/pages/configs/rush-plugin-manifest_json/#see-also) --- # Modifying package.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/modifying_package_json/#docusaurus_skipToContent_fallback) On this page rush add[​](https://rushjs.io/pages/developer/modifying_package_json/#rush-add "Direct link to rush add") ---------------------------------------------------------------------------------------------------------- Let's say you need to add a new dependency on a library "**example-lib**". Without Rush, you would do something like this: # DON'T DO THIS IN A RUSH REPO:~/my-repo$ cd apps/my-app~/my-repo/apps/my-app$ npm install --save example-lib In a Rush repo, you should instead use the [rush add](https://rushjs.io/pages/commands/rush_add/) command: ~/my-repo$ cd apps/my-app# Add "example-lib" as a dependency of "my-app", and then automatically run "rush update":~/my-repo/apps/my-app$ rush add --package example-lib The `rush add` command can also be used to update the version of an existing dependency: # Update "my-app" to use "example-lib" version "~1.2.3":~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3# Or if you want the version specifier "^1.2.3":~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3 --caret# A more advanced example, where we query the NPM registry to find latest version that is# compatible with the SemVer specifier "^1.2.0" and then add it as a tilde dependency# such as "~1.5.3".## IMPORTANT: When specifying symbol characters on the command line, use quotes so they# don't get misinterpreted by your shell.~/my-repo/apps/my-app$ rush add --package "example-lib@^1.2.0"# If any other projects in the repo are using "example-lib", you can update them all# to "1.2.3" in bulk:~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3 --make-consistent rush remove[​](https://rushjs.io/pages/developer/modifying_package_json/#rush-remove "Direct link to rush remove") ------------------------------------------------------------------------------------------------------------------- There is also a corresponding [rush remove](https://rushjs.io/pages/commands/rush_remove/) command for deleting entries from **package.json**: ~/my-repo$ cd apps/my-app# Remove the "example-lib" dependency from package.json and then automatically run "rush update":~/my-repo/apps/my-app$ rush remove --package example-lib Manually modifying package.json[​](https://rushjs.io/pages/developer/modifying_package_json/#manually-modifying-packagejson "Direct link to Manually modifying package.json") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Of course, you can also simply edit the **package.json** file directly. Remember to run `rush update` afterwards to update the shrinkwrap file. > **Tip: A cool VS Code feature** > > By the way, if you use Visual Studio Code as your editor, the [Version Lens extension](https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens) > can display a tool tip showing the latest version of each dependency in your **package.json**. This is helpful for finding and fixing outdated versions. rush upgrade-interactive[​](https://rushjs.io/pages/developer/modifying_package_json/#rush-upgrade-interactive "Direct link to rush upgrade-interactive") ---------------------------------------------------------------------------------------------------------------------------------------------------------- The `rush add` and `rush remove` commands operate on a single dependency at a time. To upgrade many packages and projects across your repo, you can use the [rush upgrade-interactive](https://rushjs.io/pages/commands/rush_upgrade-interactive/) command. It will walk you through selecting projects and choosing which versions to upgrade: ![rush upgrade-interactive screenshot](https://rushjs.io/images/docs/upgrade-interactive-0.png) _Choosing the project_ ![rush upgrade-interactive screenshot](https://rushjs.io/images/docs/upgrade-interactive-1.png) _Choosing the dependencies to upgrade_ pnpm outdated[​](https://rushjs.io/pages/developer/modifying_package_json/#pnpm-outdated "Direct link to pnpm outdated") ------------------------------------------------------------------------------------------------------------------------- To create a report about outdated dependencies, you can also use the [pnpm outdated](https://pnpm.io/cli/outdated) command. Note that when invoking PNPM commands in a Rush monorepo, you must use the `rush-pnpm` CLI helper. ![rush-pnpm outdated screenshot](https://rushjs.io/images/docs/pnpm-outdated.png) _Invoking rush-pnpm outdated_ * [rush add](https://rushjs.io/pages/developer/modifying_package_json/#rush-add) * [rush remove](https://rushjs.io/pages/developer/modifying_package_json/#rush-remove) * [Manually modifying package.json](https://rushjs.io/pages/developer/modifying_package_json/#manually-modifying-packagejson) * [rush upgrade-interactive](https://rushjs.io/pages/developer/modifying_package_json/#rush-upgrade-interactive) * [pnpm outdated](https://rushjs.io/pages/developer/modifying_package_json/#pnpm-outdated) --- # Getting started as a developer | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/new_developer/#docusaurus_skipToContent_fallback) On this page Prerequisites[​](https://rushjs.io/pages/developer/new_developer/#prerequisites "Direct link to Prerequisites") ---------------------------------------------------------------------------------------------------------------- In order to use Rush, you will need the NodeJS engine. We recommend the latest [LTS version](https://nodejs.org/en/download/releases/) , because non-stable NodeJS releases frequently have bugs. You might consider installing via [nvm-windows](https://github.com/coreybutler/nvm-windows) or [nvm](https://github.com/creationix/nvm) (Mac/Linux), which allows you to easily switch between different NodeJS versions that might be required for different projects that you work on. You also need to install the Rush tool itself. It's pretty easy. From your shell or command prompt, type this: npm install -g @microsoft/rush _NOTE: If this command fails because your user account does not have permissions to access NPM's global folder, you may need to [fix your NPM configuration](https://docs.npmjs.com/getting-started/fixing-npm-permissions) ._ To see Rush's command line help, you can type: rush -h The command-line help is also published online in the [Command Reference](https://rushjs.io/pages/commands/rush_add/) . A couple caveats[​](https://rushjs.io/pages/developer/new_developer/#a-couple-caveats "Direct link to A couple caveats") ------------------------------------------------------------------------------------------------------------------------- Before we get started, a couple important points to keep in mind: #### 1\. Avoid certain commands in a Rush repo[​](https://rushjs.io/pages/developer/new_developer/#1-avoid-certain-commands-in-a-rush-repo "Direct link to 1. Avoid certain commands in a Rush repo") Rush optimizes by installing all of your dependency packages in a central folder, and then uses [symlinks](https://en.wikipedia.org/wiki/Symbolic_link) to create the "node\_modules" folder for each of your projects. **Avoid using package manager commands that install/link dependencies.** For example, `npm run` will work fine, but these commands will get confused by Rush's symlinks: `npm install`, `npm update`, `npm link`, `npm dedupe`, etc. (The same goes for other package managers: Avoid commands such as `pnpm install` or `yarn install`.) If you want to use those commands, first run `rush unlink` to delete the symlinks created by Rush. If you use `git clean -dfx` to clean up your folder, be aware that it handles symlinks poorly. To avoid trouble, always run `rush unlink` before using `git clean -dfx`. Afterwards you can run `rush update` to recreate the symlinks. (There is a standalone `rush link` command, but it's rarely needed.) #### 2\. If you suspect your install is corrupted...[​](https://rushjs.io/pages/developer/new_developer/#2-if-you-suspect-your-install-is-corrupted "Direct link to 2. If you suspect your install is corrupted...") Rush's package management commands are "incremental", which means they save time by skipping steps that appear to be unnecessary. Since Rush runs in automated build environments, we have many safeguards to ensure these checks are accurate. However when debugging or tinkering with packages on your local machine, sometimes your NPM "node\_modules" folder can get into a bad state, causing strange errors. If you suspect your install is corrupted, try running `rush update --purge`. This will force a full reinstall of your packages, and usually get you back into a good state. * [Prerequisites](https://rushjs.io/pages/developer/new_developer/#prerequisites) * [A couple caveats](https://rushjs.io/pages/developer/new_developer/#a-couple-caveats) --- # Other helpful commands | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/other_commands/#docusaurus_skipToContent_fallback) On this page Installing the latest SemVer-compatible version of everything[​](https://rushjs.io/pages/developer/other_commands/#installing-the-latest-semver-compatible-version-of-everything "Direct link to Installing the latest SemVer-compatible version of everything") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Normally `rush update` only makes the minimal incremental changes necessary to satisfy the project **package.json** files. If you want to update everything to the latest version, you would do this: # This effectively deletes the old shrinkwrap file and re-solves everything# using the latest compatible versions as specified in package.json files.# Note that the package.json files themselves are not modified.rush update --full For everyday work, `--full` can introduce unrelated breaks in your PR branch, for example if one of the dependencies didn't perfectly follow the SemVer rules. This isn't too much of a concern for small repos. For a large monorepo, we recommended to use `rush update` for everyday work, and then run `rush update --full` periodically as a separate workflow by a CI job or designated person. Faster ways to build[​](https://rushjs.io/pages/developer/other_commands/#faster-ways-to-build "Direct link to Faster ways to build") -------------------------------------------------------------------------------------------------------------------------------------- * **If you're only working on a few projects**: Let's say your Git repo contains 50 projects, but you really only work on the **widget** and **widget-demo** projects. You can ask Rush to build only those two projects, plus the libraries that they depend on: `rush rebuild --to widget --to widget-demo` * **If you changed a library**: Let's say your Git repo contains 50 projects, and you just fixed some bugs in the **widget** library. You need to run unit tests for all the projects that use this library, and anything that depends on them, but it would be wasteful to rebuild everything else. To rebuild just the downstream projects: `rush rebuild --from widget` The full set of project selection parameters are described in the article [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/) . A faster way to install[​](https://rushjs.io/pages/developer/other_commands/#a-faster-way-to-install "Direct link to A faster way to install") ----------------------------------------------------------------------------------------------------------------------------------------------- If your repo is using PNPM with the new `useWorkspaces=true` mode enabled in your [rush.json](https://rushjs.io/pages/configs/rush_json/) file, you can use a feature called "filtered installs". This feature reduces installation times by only installing the subset of NPM packages required to build a specific project. For example: # Only install the NPM packages needed to build "my-project" and the other# Rush projects that it depends on:rush install --to my-project# Like with "rush build", you can use "." to refer to the project from your# shell's current working directory:cd my-projectrush install --to .# Here's how to install dependencies required to do "rush build --from my-project"rush install --from my-project Getting back to a clean state[​](https://rushjs.io/pages/developer/other_commands/#getting-back-to-a-clean-state "Direct link to Getting back to a clean state") ----------------------------------------------------------------------------------------------------------------------------------------------------------------- After working with Rush, maybe you want to get back to a clean state, e.g. so you can zip up a folder. Here's a couple commands to do that: # Remove all the symlinks created by Rush:rush unlink# Remove all the temporary files created by Rush, including deleting all# the NPM packages that were installed in your common folder:rush purge * [Installing the latest SemVer-compatible version of everything](https://rushjs.io/pages/developer/other_commands/#installing-the-latest-semver-compatible-version-of-everything) * [Faster ways to build](https://rushjs.io/pages/developer/other_commands/#faster-ways-to-build) * [A faster way to install](https://rushjs.io/pages/developer/other_commands/#a-faster-way-to-install) * [Getting back to a clean state](https://rushjs.io/pages/developer/other_commands/#getting-back-to-a-clean-state) --- # Why one big repo⁈ | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/intro/why_mono/#docusaurus_skipToContent_fallback) _Open source NPM packages seem to be developed in lots of small GitHub repos. Shouldn't I do that?_ Sure, if you're building isolated components, and it's not too important how they fit together. But business software doesn't seem to work that way. It's more like this: Most people start out by building a single web application, not a bunch of libraries. After your application ships, it keeps growing in size. Then one day you need to share some code with a different project, and you realize you've got a big rat's nest. Time to refactor! Clearly you must split this thing up into manageable components. NPM packages are the way to do that in JavaScript. Looking around, the convention seems to be "**one GitHub repo for each NPM package.**" During a heroic week or two, you create 10 Git repos, split up your code, and give it a try... ...but working with 10 Git repos turns out to be a big pain! There are just so many headaches: * **Tunnel vision**: If a colleague mostly does their work in repos #5 and #6, they seem to completely ignore pull requests from the other 8 repos. New repos spring into existence every day without you even knowing about it. * **Cascading publishing**: Propagating a fix from **lib3** down to your application project requires updating/building/publishing many Git repos in the right order: **lib3** --> **lib2** --> **lib1** --> **application**. When **lib3** has frequent churn, this becomes really tedious. How will people even remember the right order to publish? The internet has lots of bodies to throw at this problem, but you have limited people, and they're very busy. * **Downstream victims**: When Bob publishes a change to **lib3**, it can take a while before all downstream projects get upgraded to use it. If there's a regression, it might be a week before Alice tries to run "npm update" in **lib1** and discovers the problem. By then, maybe Bob has left for his backpacking trip across Europe. Why should Alice shoulder the burden of fixing someone else's regression? Seems like every time she upgrades, something is broken! * **Linking madness**: The workaround is to use [npm link](https://docs.npmjs.com/cli/link) to symlink your **application** directly to **lib3** for testing. But NPM creates symlinks via a global folder, which causes trouble if you need to work with multiple branches of **lib3** on the same laptop. And with 10+ libraries, it's hard to remember what is symlinked to what. The **"one repo per package"** model makes sense for isolated projects that are maintained by uncoordinated strangers. (Also, most of those libraries get updated fairly infrequently, which makes the problem easier.) Whereas in our example, everyone works at the same company, and the "libraries" act more like components of an integrated architecture. Code gets churned a lot, and a change in one place can easily break another part of the system. Building multiple projects together lets you run all the unit tests for every change, which moves responsibility for fixes where it belongs: To the person who originally introduced the change. The emergent principle becomes **"one Git repo per team"**, or even better **"as few Git repos as possible to get the job done"**. ![monorepo block diagram](https://rushjs.io/images/home/mono-concept-h.svg) [Lots](https://danluu.com/monorepo/) [of](https://medium.com/@bebraw/the-case-for-monorepos-907c1361708a) [people](http://web.archive.org/web/20201108131640/http://blog.shippable.com/our-journey-to-microservices-and-a-mono-repository) who build large scale business software seem to end up with all their code in one big "monorepo". JavaScript is just the last guy to join the party. The big concern with this strategy is obviously _**build times**_. JavaScript tools are slower than compiled languages. If one project takes 1 minute to build, and you have 75 projects, in theory you could be looking at a ridiculous 75 minute build time. It seems intimidating, but with an industrial strength toolchain you can scale very far before build times become an issue. Most of our roadmap for Rush and Heft is focused on build times, and we're optimistic that there's still plenty of room for optimizations. With subset/incremental builds, you can in theory avoid rebuilding everything unless a change really does affect everything -- and for that kind of change, it's hard to argue that finding breaks early isn't worth the price of waiting for a longer build. --- # Getting support | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/help/support/#docusaurus_skipToContent_fallback) Rush is actively developed by a team within MS Office. Although Microsoft does not provide official support for Rush, there are various community options for help: * [Frequently Asked Questions](https://rushjs.io/pages/help/faq/) * **Found a bug?** You can [open a GitHub issue](https://github.com/microsoft/rushstack/issues) in the **rushstack** monorepo where Rush is developed * **Zulip**: Chat with Rush developers in the Rush Stack [Zulip chat room](https://rushstack.zulipchat.com/) * **If a PR needs attention,** try asking in the [#contributor-helpline](https://rushstack.zulipchat.com/#narrow/stream/279883-contributor-helpline) chat room. We carefully review each submission before merging, which is time consuming work. The maintainers are all people who manage large corporate monorepos with regular daily distractions, so PRs frequently get overlooked. Your contributions are greatly appreciated -- we do want to get that PR reviewed! --- # Getting started | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/intro/get_started/#docusaurus_skipToContent_fallback) On this page 3 minute demo[​](https://rushjs.io/pages/intro/get_started/#3-minute-demo "Direct link to 3 minute demo") ---------------------------------------------------------------------------------------------------------- Want to see Rush in action? The only prerequisite you need is [NodeJS](https://nodejs.org/en/download/) . **From your shell, install Rush like this:** npm install -g @microsoft/rush **For command-line help, do this:** rush -h **To see Rush build some real projects, try running these commands:** git clone https://github.com/microsoft/rushstackcd rushstack# Install the NPM packages:# (If you don't have a GitHub email configured, add the "--bypass-policy" option.)rush update# Incremental install:rush update # <-- instantaneous!# Force all projects to be rebuilt:rush rebuild# Incremental build:rush build # <-- instantaneous!# Use "--verbose" to view the console logs for each project as it is built.# Projects build in parallel processes, but their logs are collated.rush rebuild --verbose Let's get started![​](https://rushjs.io/pages/intro/get_started/#lets-get-started "Direct link to Let's get started!") ----------------------------------------------------------------------------------------------------------------------- Choose your tutorial scenario... * [I'm a developer.](https://rushjs.io/pages/developer/new_developer/) Learn how to work in a repo that already uses Rush. * [I'm a repo maintainer.](https://rushjs.io/pages/maintainer/setup_new_repo/) Learn how to convert your repo to use the Rush system. * [3 minute demo](https://rushjs.io/pages/intro/get_started/#3-minute-demo) * [Let's get started!](https://rushjs.io/pages/intro/get_started/#lets-get-started) --- # rush install | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_install/#docusaurus_skipToContent_fallback) On this page usage: rush install [-h] [-p] [--bypass-policy] [--no-link] [--network-concurrency COUNT] [--debug-package-manager] [--max-install-attempts NUMBER] [--ignore-hooks] [--variant VARIANT] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [--check-only]The "rush install" command installs package dependencies for all yourprojects, based on the shrinkwrap file that is created/updated using "rushupdate". (This "shrinkwrap" file stores a central inventory of alldependencies and versions for projects in your repo. It is found in the"common/config/rush" folder.) If the shrinkwrap file is missing or outdated(e.g. because project package.json files have changed), "rush install" willfail and tell you to run "rush update" instead. This read-only nature is themain feature: Continuous integration builds should use "rush install" insteadof "rush update" to catch developers who forgot to commit their shrinkwrapchanges. Cautious people can also use "rush install" if they want to avoidaccidentally updating their shrinkwrap file.Optional arguments: -h, --help Show this help message and exit. -p, --purge Perform "rush purge" before starting the installation --bypass-policy Overrides enforcement of the "gitPolicy" rules from rush.json (use honorably!) --no-link If "--no-link" is specified, then project symlinks will NOT be created after the installation completes. You will need to run "rush link" manually. This flag is useful for automated builds that want to report stages individually or perform extra operations in between the two stages. This flag is not supported when using workspaces. --network-concurrency COUNT If specified, limits the maximum number of concurrent network requests. This is useful when troubleshooting network failures. --debug-package-manager Activates verbose logging for the package manager. You will probably want to pipe the output of Rush to a file when using this command. --max-install-attempts NUMBER Overrides the default maximum number of install attempts. The default value is 1. --ignore-hooks Skips execution of the "eventHooks" scripts defined in rush.json. Make sure you know what you are skipping. --variant VARIANT Run command using a variant installation configuration. This parameter may alternatively be specified via the RUSH_VARIANT environment variable. -t PROJECT, --to PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to" parameter expands this selection to include PROJECT and all its dependencies. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -T PROJECT, --to-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to-except" parameter expands this selection to include all dependencies of PROJECT, but not PROJECT itself. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -f PROJECT, --from PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--from" parameter expands this selection to include PROJECT and all projects that depend on it, plus all dependencies of this set. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -o PROJECT, --only PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--only" parameter expands this selection to include PROJECT; its dependencies are not added. "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -i PROJECT, --impacted-by PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -I PROJECT, --impacted-by-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by-except" parameter works the same as "--impacted-by" except that PROJECT itself is not added to the selection. ". " can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". --to-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--to-version-policy" parameter is equivalent to specifying "--to" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --from-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--from-version-policy" parameter is equivalent to specifying "--from" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --check-only Only check the validity of the shrinkwrap file without performing an install. See also[​](https://rushjs.io/pages/commands/rush_install/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------- * [rush update](https://rushjs.io/pages/commands/rush_update/) * [See also](https://rushjs.io/pages/commands/rush_install/#see-also) --- # rush rebuild | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/commands/rush_rebuild/#docusaurus_skipToContent_fallback) On this page usage: rush rebuild [-h] [-p COUNT] [--timeline] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] [--ignore-hooks]This command assumes that the package.json file for each project contains a"scripts" entry for "npm run build" that performs a full clean build. Rushinvokes this script to build each project that is registered in rush.json.Projects are built in parallel where possible, but always respecting thedependency graph for locally linked projects. The number of simultaneousprocesses will be based on the number of machine cores unless overridden bythe --parallelism flag. (For an incremental build, see "rush build" insteadof "rush rebuild".)Optional arguments: -h, --help Show this help message and exit. -p COUNT, --parallelism COUNT Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. "50%") or the word "max" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores. This parameter may alternatively be specified via the RUSH_PARALLELISM environment variable. --timeline After the build is complete, print additional statistics and CPU usage information, including an ASCII chart of the start and stop times for each operation. -t PROJECT, --to PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to" parameter expands this selection to include PROJECT and all its dependencies. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -T PROJECT, --to-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--to-except" parameter expands this selection to include all dependencies of PROJECT, but not PROJECT itself. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -f PROJECT, --from PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--from" parameter expands this selection to include PROJECT and all projects that depend on it, plus all dependencies of this set. "." can be used as shorthand for the project in the current working directory. For details, refer to the website article "Selecting subsets of projects". -o PROJECT, --only PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--only" parameter expands this selection to include PROJECT; its dependencies are not added. "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -i PROJECT, --impacted-by PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). "." can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". -I PROJECT, --impacted-by-except PROJECT Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each "--impacted-by-except" parameter works the same as "--impacted-by" except that PROJECT itself is not added to the selection. ". " can be used as shorthand for the project in the current working directory. Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies. For details, refer to the website article "Selecting subsets of projects". --to-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--to-version-policy" parameter is equivalent to specifying "--to" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". --from-version-policy VERSION_POLICY_NAME Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The "--from-version-policy" parameter is equivalent to specifying "--from" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article "Selecting subsets of projects". -v, --verbose Display the logs during the build, rather than just displaying the build status summary --ignore-hooks Skips execution of the "eventHooks" scripts defined in rush.json. Make sure you know what you are skipping. See also[​](https://rushjs.io/pages/commands/rush_rebuild/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------- * [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/) * [rush build](https://rushjs.io/pages/commands/rush_build/) * [See also](https://rushjs.io/pages/commands/rush_rebuild/#see-also) --- # artifactory.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/artifactory_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **artifactory.json**: **common/config/rush/artifactory.json** /** * This configuration file manages Rush integration with JFrog Artifactory services. * More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json", "packageRegistry": { /** * (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry. * When enabled, "rush install" will automatically detect when the user's ~/.npmrc * authentication token is missing or expired. And "rush setup" will prompt the user to * renew their token. * * The default value is false. */ "enabled": false, /** * (Required) Specify the URL of your NPM registry. This is the same URL that appears in * your .npmrc file. It should look something like this example: * * https://your-company.jfrog.io/your-project/api/npm/npm-private/ */ "registryUrl": "", /** * A list of custom strings that "rush setup" should add to the user's ~/.npmrc file at the time * when the token is updated. This could be used for example to configure the company registry * to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush * operations like "rush add" and "rush install", which get their mappings from the monorepo's * common/config/rush/.npmrc file). * * NOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful * about adding settings that may interfere with other work outside the monorepo. */ "userNpmrcLinesToAdd": [ // "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/" ], /** * (Required) Specifies the URL of the Artifactory control panel where the user can generate * an API key. This URL is printed after the "visitWebsite" message. * It should look something like this example: https://your-company.jfrog.io/ * Specify an empty string to suppress this line entirely. */ "artifactoryWebsiteUrl": "", /** * Uncomment this line to specify the type of credential to save in the user's ~/.npmrc file. * The default is "password", which means the user's API token will be traded in for an * npm password specific to that registry. Optionally you can specify "authToken", which * will save the user's API token as credentials instead. */ // "credentialType": "password", /** * These settings allow the "rush setup" interactive prompts to be customized, for * example with messages specific to your team or configuration. Specify an empty string * to suppress that message entirely. */ "messageOverrides": { /** * Overrides the message that normally says: * "This monorepo consumes packages from an Artifactory private NPM registry." */ // "introduction": "", /** * Overrides the message that normally says: * "Please contact the repository maintainers for help with setting up an Artifactory user account." */ // "obtainAnAccount": "", /** * Overrides the message that normally says: * "Please open this URL in your web browser:" * * The "artifactoryWebsiteUrl" string is printed after this message. */ // "visitWebsite": "", /** * Overrides the message that normally says: * "Your user name appears in the upper-right corner of the JFrog website." */ // "locateUserName": "", /** * Overrides the message that normally says: * "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key' * button if you haven't already done so previously." */ // "locateApiKey": "" /** * Overrides the message that normally prompts: * "What is your Artifactory user name?" */ // "userNamePrompt": "" /** * Overrides the message that normally prompts: * "What is your Artifactory API key?" */ // "apiKeyPrompt": "" } }} See also[​](https://rushjs.io/pages/configs/artifactory_json/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------------- * [NPM registry authentication](https://rushjs.io/pages/maintainer/npm_registry_auth/) * [See also](https://rushjs.io/pages/configs/artifactory_json/#see-also) --- # experiments.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/experiments_json/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **experiments.json**: **common/config/rush/experiments.json** /** * This configuration file allows repo maintainers to enable and disable experimental * Rush features. More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", /** * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. * Set this option to true to pass '--frozen-lockfile' instead for faster installs. */ // "usePnpmFrozenLockfileForRushInstall": true, /** * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. */ // "usePnpmPreferFrozenLockfileForRushUpdate": true, /** * By default, 'rush update' runs as a single operation. * Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. * Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs. */ // "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate": true, /** * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not * cause hash changes. */ // "omitImportersFromPreventManualShrinkwrapChanges": true, /** * If true, the chmod field in temporary project tar headers will not be normalized. * This normalization can help ensure consistent tarball integrity across platforms. */ // "noChmodFieldInTarHeaderNormalization": true, /** * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. * This will not replay warnings from the cached build. */ // "buildCacheWithAllowWarningsInSuccessfulBuild": true, /** * If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. * This will not replay warnings from the skipped build. */ // "buildSkipWithAllowWarningsInSuccessfulBuild": true, /** * If true, perform a clean install after when running `rush install` or `rush update` if the * `.npmrc` file has changed since the last install. */ // "cleanInstallAfterNpmrcChanges": true, /** * If true, print the outputs of shell commands defined in event hooks to the console. */ // "printEventHooksOutputToConsole": true, /** * If true, Rush will not allow node_modules in the repo folder or in parent folders. */ // "forbidPhantomResolvableNodeModulesFolders": true, /** * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot * correctly satisfy versioning requirements without installing duplicate copies of a package inside the * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" * feature provides a model for copying the local project folder into node_modules, however copying * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. * The "pnpm-sync" tool manages this operation; see its documentation for details. * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies * by invoking "pnpm-sync" during the build. */ // "usePnpmSyncForInjectedDependencies": true, /** * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. */ // "generateProjectImpactGraphDuringRushUpdate": true, /** * If true, when running in watch mode, Rush will check for phase scripts named `_phase::ipc` and run them instead * of `_phase:` if they exist. The created child process will be provided with an IPC channel and expected to persist * across invocations. */ // "useIPCScriptsInWatchMode": true, /** * (UNDER DEVELOPMENT) The Rush alerts feature provides a way to send announcements to engineers * working in the monorepo, by printing directly in the user's shell window when they invoke Rush commands. * This ensures that important notices will be seen by anyone doing active development, since people often * ignore normal discussion group messages or don't know to subscribe. */ // "rushAlerts": true, /** * When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache. */ // "allowCobuildWithoutCache": true} --- # rush-project.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/rush-project_json/#docusaurus_skipToContent_fallback) On this page This is the template for the optional **rush-project.json** config file. This file may be provided by a [rig package](https://rushstack.io/pages/heft/rig_packages/) . **/config/rush-project.json** /** * The "config/rush-project.json" file configures Rush-specific settings for an individual project * in a Rush monorepo. More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. * * To delete an inherited setting, set it to `null` in this file. */ // "extends": "my-rig/profiles/default/config/rush-project.json", /** * The incremental analyzer can skip Rush commands for projects whose input files have not changed since * the last build. Normally, every Git-tracked file under the project folder is assumed to be an input. * Use "incrementalBuildIgnoredGlobs" to ignore specific files, specified as globs relative to * the project folder. The glob syntax is based on the .gitignore file format. */ "incrementalBuildIgnoredGlobs": [ // "etc/api-report/*.md" ], /** * Disable caching for this project. The project will never be restored from cache. This may be useful * if this project affects state outside of its folder. * * Default value: false */ // "disableBuildCacheForProject": true, /** * Options for individual commands and phases. */ "operationSettings": [ // { // /** // * (Required) The name of the operation. // * This should be a key in the "package.json" file's "scripts" section. // */ // "operationName": "build", // // /** // * Specify the folders where this operation writes its output files. If enabled, the Rush build cache // * will restore these folders from the cache. The strings are folder names under the project root folder. // * These folders should not be tracked by Git. They must not contain symlinks. // */ // "outputFolderNames": [ // "lib", "dist" // ], // // /** // * Specify a list of glob (minimatch) paths (absolute or relative) pointing to files // * (within or outside the .git repository) that affect the output of this operation. // * If provided, the hash values of these files will become part of the final hash when // * reading and writing from cache. // */ // "dependsOnAdditionalFiles": [], // // /** // * Specify a list of environment variables that affect the output of this operation. // * If provided, the values of these variables will become part of the hash when reading // * and writing from cache. // */ // "dependsOnEnvVars": [ "MY_ENVIRONMENT_VARIABLE" ], // // /** // * Disable caching for this operation. The operation will never be restored from cache. // * This may be useful if this operation affects state outside of its folder. // */ // // "disableBuildCacheForOperation": true // } ]} See also[​](https://rushjs.io/pages/configs/rush-project_json/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------------- * [Enabling the build cache](https://rushjs.io/pages/maintainer/build_cache/) * [See also](https://rushjs.io/pages/configs/rush-project_json/#see-also) --- # Everyday commands | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/everyday_commands/#docusaurus_skipToContent_fallback) On this page Your daily workflow only needs a few Rush commands: rush update[​](https://rushjs.io/pages/developer/everyday_commands/#rush-update "Direct link to rush update") -------------------------------------------------------------------------------------------------------------- Remember to run `rush update` whenever a **package.json** file has changed. In other words: * After pulling new changes from git (e.g. `git pull`) * After manually editing any project's **package.json** file in any way * After editing any **common/config** files that affect versions (e.g. **pnpmfile.js**, **common-versions.json**, etc.) The `rush update` operation may change some files under **common/config**. If so, you should commit those changes to Git and include them in your PR. When in doubt, run `rush update` -- if everything is already up to date, it won't take any time! What `rush update` does: 1. Rush checks/applies various policies that sometimes update files under **common/config**. 2. Rush compares all of your project **package.json** files against the repository's common shrinkwrap file to see if it's valid. 3. If it's outdated, the package manager updates the shrinkwrap file. 4. Either way, the package manager installs all dependencies into the **common/temp/node\_modules** folder. 5. Finally, Rush constructs a local **node\_modules** folder for each project, by making symlinks into **common/temp/node\_modules**. (This is the same operation as `rush link`.) > **What is this "shrinkwrap file"?** > > Most projects don't specify an exact version such as `1.2.3` for a dependency, but instead specify SemVer range such as `1.x` or `^1.2.3`. By itself, this would mean that what gets installed depends on the latest version at the time. Such **nondeterminism** is bad: It would be maddening for a Git branch that built on Monday to mysteriously be failing on Tuesday because of a new release of a library. The shrinkwrap file solves this problem by storing a complete installation plan in a large file that is tracked by Git. > > The shrinkwrap file has different names depending on the [package manager](https://rushjs.io/pages/maintainer/package_managers/) > that your repo is using: **shrinkwrap.yaml**, **npm-shrinkwrap.json**, or **yarn.lock** You will notice that automated CI jobs use `rush install` instead of `rush update`. The difference is that `rush install` won't update any files. Instead, it will fail your PR build if something is out of date, to let you know that you forgot to run `rush update` or forgot to commit the result. (Some people choose to use `rush install` as their everyday command, in order to catch unintended changes to the shrinkwrap file.) rush rebuild[​](https://rushjs.io/pages/developer/everyday_commands/#rush-rebuild "Direct link to rush rebuild") ----------------------------------------------------------------------------------------------------------------- Once you've pulled the latest changes, it's time to compile everything. `rush rebuild` does a full, clean build of every project in the repository. If your toolchain supports incremental builds, you can also use `rush build` to build only the projects that have changed. rushx[​](https://rushjs.io/pages/developer/everyday_commands/#rushx "Direct link to rushx") -------------------------------------------------------------------------------------------- If you want to build just one project, you can use the `rushx` command. You run it under the project folder that you want to operate on. The `rushx` command is analogous to `npm run`, but with slightly less typing, slightly better error reporting, and command-line help. rush check[​](https://rushjs.io/pages/developer/everyday_commands/#rush-check "Direct link to rush check") ----------------------------------------------------------------------------------------------------------- After editing a **package.json** file, you can run `rush check` to see if multiple projects are depending on different versions of the same library. In a monorepo environment, that is undesirable. Many repos will use `rush check` as a CI build step, so they can fail your PR build if you introduce side-by-side versions. rush change[​](https://rushjs.io/pages/developer/everyday_commands/#rush-change "Direct link to rush change") -------------------------------------------------------------------------------------------------------------- If you work on libraries that get published as NPM packages, your repo probably requires you to include change log entries as part of your PR. You will know because your PR build will fail on the `rush change --verify` step. To write change logs, first commit any pending work to Git. Then type `rush change` from anywhere under your repo working folder. This command will examine your Git history to determine which project folders have diffs. Based on that, it will prompt you to write a change log entry for each one. Each change log entry gets stored in a separate file under **common/changes**. You should add and commit these files to Git. Later, Rush's automated publishing workflow will inspect these files to determine which packages need to be published. It will delete the files and copy your messages into the package's CHANGELOG.md file. 👉 See [Authoring change logs](https://rushjs.io/pages/best_practices/change_logs/) for tips about writing change logs. Common scenarios ================ That's it! Those are all the commonly used Rush commands. Combining everything, a typical daily incantation might look like this: # Pull the latest changes from Gitgit pull# Install NPM packages as neededrush update# Do a clean rebuild of everythingrush rebuild# Work on one projectcd ./my-project# Let's assume there is a "start" script in the package.json.# (To see the available commands, type "rushx" by itself.)rushx start * [rush update](https://rushjs.io/pages/developer/everyday_commands/#rush-update) * [rush rebuild](https://rushjs.io/pages/developer/everyday_commands/#rush-rebuild) * [rushx](https://rushjs.io/pages/developer/everyday_commands/#rushx) * [rush check](https://rushjs.io/pages/developer/everyday_commands/#rush-check) * [rush change](https://rushjs.io/pages/developer/everyday_commands/#rush-change) --- # Using project tags | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/project_tags/#docusaurus_skipToContent_fallback) On this page Rush's **project tags** provide a convenient way to reference arbitrary groups of Rush projects. Tags are applied to projects using the `"tags"` property in the **rush.json** config file. For example: **rush.json** . . . "projects": [ { "packageName": "my-controls", "projectFolder": "libraries/my-controls", "reviewCategory": "production", /** * An optional set of custom tags that can be used to select this project. * For example, adding "my-custom-tag" will allow this project to * be selected by the command "rush list --only tag:my-custom-tag" */ "tags": [ "1.0.0-release", "frontend-team" ] }, { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain", "reviewCategory": "tools", "tags": [ "tools" ] } ] . . . For details about the `tag:my-custom-tag` selector syntax, see [Selecting subsets of projects](https://rushjs.io/pages/developer/selecting_subsets/#selectors) . Tag syntax[​](https://rushjs.io/pages/developer/project_tags/#tag-syntax "Direct link to Tag syntax") ------------------------------------------------------------------------------------------------------ The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, `.`, and `@` characters. Some examples: rush list --to tag:my-custom-tag rush list --to tag:api-extractor.com rush list --to tag:1.0.0 Validating tags[​](https://rushjs.io/pages/developer/project_tags/#validating-tags "Direct link to Validating tags") --------------------------------------------------------------------------------------------------------------------- Allowing arbitrary `"tags"` strings in the **rush.json** `"projects"` array is error-prone. If somebody accidentally misspells a tag, or if they use an old tag that is now obsolete, it may take a while to discover this mistake. You can use the `"allowedProjectTags"` setting to define a fixed list tags to be used in your monorepo. This also provides a centralized place to document their meanings. **rush.json** . . . /** * This is an optional, but recommended, list of allowed tags that can be applied to Rush projects * using the "tags" setting in this file. This list is useful for preventing mistakes such as misspelling, * and it also provides a centralized place to document your tags. If "allowedProjectTags" list is * not specified, then any valid tag is allowed. A tag name must be one or more words * separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, * ".", and "@" characters. */ "allowedProjectTags": [ // Apply this tag to all Rush projects that are CLI tools "tools", // Apply this tag to all projects owned by our company's frontend team "frontend-team", // Use this to tag projects to be included in the QA test pass // for the upcoming product launch. "1.0.0-release" ], . . . * [Tag syntax](https://rushjs.io/pages/developer/project_tags/#tag-syntax) * [Validating tags](https://rushjs.io/pages/developer/project_tags/#validating-tags) --- # version-policies.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/version-policies_json/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **version-policies.json**: **common/config/rush/version-policies.json** /** * This is configuration file is used for advanced publishing configurations with Rush. * More documentation is available on the Rush website: https://rushjs.io *//** * A list of version policy definitions. A "version policy" is a custom package versioning * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies * to a set of projects that are specified using the "versionPolicyName" field in rush.json. */[ // { // /** // * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). // * // * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This // * strategy is appropriate for a set of packages that act as selectable components of a // * unified product. The entire set of packages are always published together, and always share // * the same NPM version number. When the packages depend on other packages in the set, the // * SemVer range is usually restricted to a single version. // */ // "definitionName": "lockStepVersion", // // /** // * (Required) The name that will be used for the "versionPolicyName" field in rush.json. // * This name is also used command-line parameters such as "--version-policy" // * and "--to-version-policy". // */ // "policyName": "MyBigFramework", // // /** // * (Required) The current version. All packages belonging to the set should have this version // * in the current branch. When bumping versions, Rush uses this to determine the next version. // * (The "version" field in package.json is NOT considered.) // */ // "version": "1.0.0", // // /** // * (Required) The type of bump that will be performed when publishing the next release. // * When creating a release branch in Git, this field should be updated according to the // * type of release. // * // * Valid values are: "prerelease", "preminor", "minor", "patch", "major" // */ // "nextBump": "prerelease", // // /** // * (Optional) If specified, all packages in the set share a common CHANGELOG.md file. // * This file is stored with the specified "main" project, which must be a member of the set. // * // * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each // * package in the set. // */ // "mainProject": "my-app", // // /** // * (Optional) If enabled, the "rush change" command will prompt the user for their email address // * and include it in the JSON change files. If an organization maintains multiple repos, tracking // * this contact information may be useful for a service that automatically upgrades packages and // * needs to notify engineers whose change may be responsible for a downstream build break. It might // * also be useful for crediting contributors. Rush itself does not do anything with the collected // * email addresses. The default value is "false". // */ // // "includeEmailInChangeFile": true // }, // // { // /** // * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). // * // * The "individualVersion" mode specifies that the projects will use "individual versioning". // * This is the typical NPM model where each package has an independent version number // * and CHANGELOG.md file. Although a single CI definition is responsible for publishing the // * packages, they otherwise don't have any special relationship. The version bumping will // * depend on how developers answer the "rush change" questions for each package that // * is changed. // */ // "definitionName": "individualVersion", // // "policyName": "MyRandomLibraries", // // /** // * (Optional) This can be used to enforce that all packages in the set must share a common // * major version number, e.g. because they are from the same major release branch. // * It can also be used to discourage people from accidentally making "MAJOR" SemVer changes // * inappropriately. The minor/patch version parts will be bumped independently according // * to the types of changes made to each project, according to the "rush change" command. // */ // "lockedMajor": 3, // // /** // * (Optional) When publishing is managed by Rush, by default the "rush change" command will // * request changes for any projects that are modified by a pull request. These change entries // * will produce a CHANGELOG.md file. If you author your CHANGELOG.md manually or announce updates // * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects // * belonging to this version policy. // */ // "exemptFromRushChange": false, // // // "includeEmailInChangeFile": true // }]; --- # Configuring tab completion | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/tab_completion/#docusaurus_skipToContent_fallback) On this page As of version 5.34.0, Rush supports tab completion so that shell commands can be input more quickly by pressing the TAB key. The setup instructions below are based on the article [Tab completion for the .NET Core CLI](https://docs.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete) which provides some additional tips. PowerShell[​](https://rushjs.io/pages/developer/tab_completion/#powershell "Direct link to PowerShell") -------------------------------------------------------------------------------------------------------- To enable tab completion for PowerShell, create or edit the profile stored in the `$PROFILE` variable. For more information, see [How to create your profile](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles#how-to-create-a-profile) and [Profiles and execution policy](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles#profiles-and-execution-policy) . Add the following code to your profile: # PowerShell parameter completion shim for the Rush CLIRegister-ArgumentCompleter -Native -CommandName rush -ScriptBlock { param($commandName, $commandAst, $cursorPosition) [string]$value = $commandAst.ToString() # Handle input like `rush install; rush bui` + Tab [int]$position = [Math]::Min($cursorPosition, $value.Length) rush tab-complete --position $position --word "$value" | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } Bash[​](https://rushjs.io/pages/developer/tab_completion/#bash "Direct link to Bash") -------------------------------------------------------------------------------------- To enable tab completion for Bash, add the following code to your **.bashrc** file: # bash parameter completion for the Rush CLI_rush_bash_complete(){ local word=${COMP_WORDS[COMP_CWORD]} local completions completions="$(rush tab-complete --position "${COMP_POINT}" --word "${COMP_LINE}" 2>/dev/null)" if [ $? -ne 0 ]; then completions="" fi COMPREPLY=( $(compgen -W "$completions" -- "$word") )}complete -f -F _rush_bash_complete rush Fish[​](https://rushjs.io/pages/developer/tab_completion/#fish "Direct link to Fish") -------------------------------------------------------------------------------------- To enable tab completion for [Fish shell](https://fishshell.com/) , add the following code to the file **~/.config/fish/completions/rush.fish**: # Fish parameter completions for the Rush CLIcomplete rush --no-filesfunction __fish_rush set -l position (string length (commandline -cp)) set -l word (commandline -opc) rush tab-complete --word "$word" --position "$position"endcomplete rush -x -a "(__fish_rush)" Zsh[​](https://rushjs.io/pages/developer/tab_completion/#zsh "Direct link to Zsh") ----------------------------------------------------------------------------------- [Zsh](https://www.zsh.org/) has slightly different env variables, add the following into **~/.zshrc**: (( ${+commands[rush]} )) && { _rush_completion() { compadd -- $(rush tab-complete --position ${CURSOR} --word "${BUFFER}" 2>>/dev/null) } compdef _rush_completion rush} It checks for the existence of rush. This needs to be added after the PATH is properly set (or after [nvm](https://github.com/nvm-sh/nvm) is initialized). Otherwise, you will need to remove the first line. * [PowerShell](https://rushjs.io/pages/developer/tab_completion/#powershell) * [Bash](https://rushjs.io/pages/developer/tab_completion/#bash) * [Fish](https://rushjs.io/pages/developer/tab_completion/#fish) * [Zsh](https://rushjs.io/pages/developer/tab_completion/#zsh) --- # subspaces.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/subspaces_json/#docusaurus_skipToContent_fallback) On this page **common/config/rush/subspaces.json** /** * This configuration file manages the experimental "subspaces" feature for Rush, * which allows multiple PNPM lockfiles to be used in a single Rush workspace. * For full documentation, please see https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", /** * Set this flag to "true" to enable usage of subspaces. */ "subspacesEnabled": false, /** * (DEPRECATED) This is a temporary workaround for migrating from an earlier prototype * of this feature: https://github.com/microsoft/rushstack/pull/3481 * It allows subspaces with only one project to store their config files in the project folder. */ "splitWorkspaceCompatibility": false, /** * When a command such as "rush update" is invoked without the "--subspace" or "--to" * parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces, * this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this * mistake by always requiring selection parameters for commands such as "rush update". */ "preventSelectingAllSubspaces": false, /** * The list of subspace names, which should be lowercase alphanumeric words separated by * hyphens, for example "my-subspace". The corresponding config files will have paths * such as "common/config/subspaces/my-subspace/package-lock.yaml". */ "subspaceNames": []} See also[​](https://rushjs.io/pages/configs/subspaces_json/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------ * [Rush subspaces](https://rushjs.io/pages/advanced/subspaces/) * [See also](https://rushjs.io/pages/configs/subspaces_json/#see-also) --- # Installing Git hooks | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/git_hooks/#docusaurus_skipToContent_fallback) On this page The Git version control system allows you to configure hook scripts that will be invoked whenever certain actions are performed. (See Git's [Customizing Git](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) chapter for complete documentation.) The basic idea is that you create shell scripts with well-known names such as **pre-commit**, **post-update**, **prepare-commit-msg**, and so forth. If the Git client finds these scripts in the local **.git/hooks** folder, it will run the scripts whenever the corresponding operations are performed. For security reasons, Git will not automatically install these scripts when you clone a repo. Instead, each developer must invoke a command that creates the files and chmods them to be executable. Rush can automate this for you! Configuring Rush to install a Git hook script[​](https://rushjs.io/pages/maintainer/git_hooks/#configuring-rush-to-install-a-git-hook-script "Direct link to Configuring Rush to install a Git hook script") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- As an example, suppose we find that developers are making commits without a meaningful description of their work. As a result, the Git history is difficult to understand. To solve this problem, might want to add a `commit-msg` hook that requires the commit message to meet certain requirements. For example, here's a simple Bash script that requires at least 3 words of text: **common/git-hooks/commit-msg** #!/bin/sh## This is an example Git hook for use with Rush. To enable this hook, rename this file# to "commit-msg" and then run "rush install", which will copy it from common/git-hooks# to the .git/hooks folder.## TO LEARN MORE ABOUT GIT HOOKS## The Git documentation is here: https://git-scm.com/githooks# Some helpful resources: https://githooks.com## ABOUT THIS EXAMPLE## The commit-msg hook is called by "git commit" with one argument, the name of the file# that has the commit message. The hook should exit with non-zero status after issuing# an appropriate message if it wants to stop the commit. The hook is allowed to edit# the commit message file.# This example enforces that commit message should contain a minimum amount of# description text.if [ `cat $1 | wc -w` -lt 3 ]; then echo "" echo "Invalid commit message: The message must contain at least 3 words." exit 1fi The sample file shown above is a template that `rush init` generates when setting up a new repo. You can probably find a copy as [common/git-hooks/commit-msg.sample](https://github.com/microsoft/rush-example/blob/main/common/git-hooks/commit-msg.sample) in your own repo. You would use it as follows: 1. Add this file in your **common/git-hooks** folder, and commit to Git. 2. When a developer runs `rush install`, Rush will copy this file to be **.git/hooks/commit-msg** 3. When you run `git commit`, Git will find the script and invoke it 4. If the commit message is too short, the script returns a nonzero exit code; Git shows the `Invalid commit message` notice and rejects the operation. Using Rush to install the hook script avoids the need for a separate solution such as the popular [Husky](https://www.npmjs.com/package/husky) package. Note that Husky expects your repo to have a root-level **package.json** and **node\_modules** folder, and Husky runs shell commands for every Git operation (even unused hooks); using Rush to install hooks avoids those limitations. > **Note:** If you need to uninstall the hooks for some reason, it is safe to delete the files in your **.git/hooks/** folder. Invoking Prettier during "git commit"[​](https://rushjs.io/pages/maintainer/git_hooks/#invoking-prettier-during-git-commit "Direct link to Invoking Prettier during "git commit"") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The Prettier tool ensures that source files follow consistent conventions for syntax issues like spacing and commas. By configuring a `git commit` hook to invoke Prettier automatically, you can apply these fixes without any effort on the developer's part. The [Enabling Prettier](https://rushjs.io/pages/maintainer/enabling_prettier/) article provides step-by-step instructions. * [Configuring Rush to install a Git hook script](https://rushjs.io/pages/maintainer/git_hooks/#configuring-rush-to-install-a-git-hook-script) * [Invoking Prettier during "git commit"](https://rushjs.io/pages/maintainer/git_hooks/#invoking-prettier-during-git-commit) --- # Recommended settings | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/recommended_settings/#docusaurus_skipToContent_fallback) On this page Once your repo is up and running, there are a number of settings in **rush.json** that we recommend enabling. These stricter settings help to improve repo health and reduce maintenance headaches. They are disabled by default because they sometimes require some fixes to your code base, and may not be appropriate for all situations. repository.url[​](https://rushjs.io/pages/maintainer/recommended_settings/#repositoryurl "Direct link to repository.url") -------------------------------------------------------------------------------------------------------------------------- If your repo uses the `rush change` command to track change logs, we strongly recommend to set the `repository.url` in your **rush.json**. This ensures that `rush change` will be able to accurately find the base branch for comparison, especially in situations where the developer's repo has been "forked" from the main repo. Example excerpt from **rush.json**: "repository": { // Replace this with the URL that you use when running "git clone" for your repo "url": "https://github.com/microsoft/rush-example" } ensureConsistentVersions[​](https://rushjs.io/pages/maintainer/recommended_settings/#ensureconsistentversions "Direct link to ensureConsistentVersions") --------------------------------------------------------------------------------------------------------------------------------------------------------- We recommend to set `ensureConsistentVersions` to `true` in **rush.json**. This causes Rush to automatically perform the `rush check` validation whenever any of the following commands are invoked: * `rush install` * `rush update` * `rush link` * `rush version` * `rush publish` This validation checks each project's **package.json** file and ensures that all dependencies are of the same version throughout the repository. This is desirable in general and avoids a lot of problems related to inconsistent versions. Sometimes there are special cases where multiple versions are desirable. For example, maybe you want upgrade your projects to the new TypeScript compiler in stages, rather than all at once. During this transition, you may need two different `typescript` releases installed for your repo. For those exceptions, you can add an entry to the `allowedAlternativeVersions` section of the **common-versions.json**. > NOTE: In earlier releases of Rush, the CI script examples included `rush check` as a build step. The `ensureConsistentVersions` setting removes the need for that. If you enable `ensureConsistentVersions`, then you can delete `rush check` from your CI build steps. strictPeerDependencies[​](https://rushjs.io/pages/maintainer/recommended_settings/#strictpeerdependencies "Direct link to strictPeerDependencies") --------------------------------------------------------------------------------------------------------------------------------------------------- If you're using the PNPM package manager, we strongly recommend setting `strictPeerDependencies` to `true` in **pnpm-config.json**. This causes Rush to use PNPM's `--strict-peer-dependencies` option during installation. With this protection, `rush install` will fail if there are unsatisfied peer dependencies, which is an invalid state that can cause build failures or incompatible dependency versions. (For historical reasons, JavaScript package managers generally do not treat this invalid state as an error.) * [repository.url](https://rushjs.io/pages/maintainer/recommended_settings/#repositoryurl) * [ensureConsistentVersions](https://rushjs.io/pages/maintainer/recommended_settings/#ensureconsistentversions) * [strictPeerDependencies](https://rushjs.io/pages/maintainer/recommended_settings/#strictpeerdependencies) --- # Autoinstallers | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/autoinstallers/#docusaurus_skipToContent_fallback) On this page A monorepo will often need to install NPM packages that provide tools such as shell commands. In most cases, these tooling dependencies can be declared as the `devDependencies` of some Rush project, and then they will be installed by `rush install` using its centralized shrinkwrap file (package manager lock file). However, sometimes such dependencies are needed in situations where `rush install` has not been invoked, or where `rush install` might fail if a person's unfinished work includes some **package.json** modifications. For these situations, Rush's **autoinstallers** feature provides an isolated mechanism for installing tooling dependencies. An autoinstaller is defined as folder under **common/autoinstallers/** with a **package.json** file and its own private shrinkwrap file. This folder is added to Git, but it is not a normal Rush project: It is not installed by `rush install`, nor does it contain any buildable source code for `rush build`. An autoinstaller is purely a container for installing NPM dependencies. Autoinstallers can be associated with Rush features such as [custom commands](https://rushjs.io/pages/maintainer/custom_commands/) or [Rush plugins](https://rushjs.io/pages/extensibility/creating_plugins/) ; when the associated feature is invoked, Rush will automatically install the dependencies. When to use autoinstallers[​](https://rushjs.io/pages/maintainer/autoinstallers/#when-to-use-autoinstallers "Direct link to When to use autoinstallers") --------------------------------------------------------------------------------------------------------------------------------------------------------- If you're enabling a Rush plugin, you must configure an autoinstaller. If you are creating a [Rush custom command](https://rushjs.io/pages/maintainer/custom_commands/) whose script needs NPM dependences, there are several possible approaches to consider: * **rush install**: Typically most dependencies in a Rush monorepo will get installed all together by `rush install` using the centralized shrinkwrap file. For most needs, this is the simplest approach and easiest to maintain. If some dependencies are irrelevant to a particular task, you can skip installing them by using [project selection parameters](https://rushjs.io/pages/developer/selecting_subsets/) such as `rush install --to example-project`. * **install-run.js**: The [install-run.js](https://rushjs.io/pages/maintainer/enabling_ci_builds/#install-runjs-for-other-commands) script enables you to install NPM packages outside of `rush install`. This is useful for commands that run in contexts where `rush install` is not invoked at all, or where `rush install` may be broken. For example, a Git commit hook script gets run on branches where `rush install` might fail: developers often commit work in progress, or a Git rebase may introduce broken commits that get fixed up by a later commit. * **autoinstallers**: A limitation of **install-run.js** is that it only installs one NPM package. For example, if your custom command needs multiple packages (for example the `pretty-quick` driver, the `prettier` engine, and some Prettier plugins), you could add them to the **package.json** file of an autoinstaller. Autoinstallers typically have a small dependency tree and thus install much faster than `rush install`. Some potential downsides of autoinstallers: In situations that require multiple autoinstallers and/or `rush install`, the package manager will be invoked multiple times and may need to install the same dependency from different shrinkwrap files. This can be significantly slower than if `rush install` could install everything together using the centralized shrinkwrap file. Also, autoinstallers are not validated or updated by `rush update`, so they require extra maintenance for upgrades. Creating an autoinstaller[​](https://rushjs.io/pages/maintainer/autoinstallers/#creating-an-autoinstaller "Direct link to Creating an autoinstaller") ------------------------------------------------------------------------------------------------------------------------------------------------------ 1. Use the [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) command to create the folder: # This creates the common/autoinstallers/my-autoinstaller/package.json filerush init-autoinstaller --name my-autoinstaller 2. Edit the **my-autoinstaller/package.json** file to add your dependencies. 3. Run [rush update-autoinstaller](https://rushjs.io/pages/commands/rush_update-autoinstaller/) to update the shrinkwrap file. You should redo this step whenever you modify the **package.json** file. # Create or update common/autoinstallers/my-autoinstaller/pnpm-lock.yaml# This file should be committed and tracked by Git.rush update-autoinstaller --name my-autoinstaller 4. Commit the updated files to git git add common/autoinstallers/my-autoinstaller/git commit -m "Updated autoinstaller" To associate an autoinstaller with a custom command, specify its name in the `autoinstallerName` field in [command-line.json](https://rushjs.io/pages/configs/command-line_json/) . To associate an autoinstaller with a Rush plugin, see the [Creating Rush plugins](https://rushjs.io/pages/extensibility/creating_plugins/) documentation. Maintaining an autoinstaller[​](https://rushjs.io/pages/maintainer/autoinstallers/#maintaining-an-autoinstaller "Direct link to Maintaining an autoinstaller") --------------------------------------------------------------------------------------------------------------------------------------------------------------- * To modify an autoinstaller, edit its **package.json** file. # This will also upgrade any indirect dependencies.rush update-autoinstaller --name my-autoinstaller# Commit the updated pnpm-lock.yamlgit commit -m "Updated autoinstaller" * To delete the autoinstaller, simply delete its folder: # BE CAREFUL WHEN RECURSIVELY DELETING FOLDERSrm -Rf common/autoinstallers/my-autoinstaller# Commit the changes to Gitgit add common/autoinstallersgit commit -m "Deleted autoinstaller" See also[​](https://rushjs.io/pages/maintainer/autoinstallers/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------------- * [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) * [rush update-autoinstaller](https://rushjs.io/pages/commands/rush_update-autoinstaller/) * [Enabling Prettier](https://rushjs.io/pages/maintainer/enabling_prettier/) * [Custom commands](https://rushjs.io/pages/maintainer/custom_commands/) * [Creating Rush plugins](https://rushjs.io/pages/extensibility/creating_plugins/) * [When to use autoinstallers](https://rushjs.io/pages/maintainer/autoinstallers/#when-to-use-autoinstallers) * [Creating an autoinstaller](https://rushjs.io/pages/maintainer/autoinstallers/#creating-an-autoinstaller) * [Maintaining an autoinstaller](https://rushjs.io/pages/maintainer/autoinstallers/#maintaining-an-autoinstaller) * [See also](https://rushjs.io/pages/maintainer/autoinstallers/#see-also) --- # Environment variables | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/environment_vars/#docusaurus_skipToContent_fallback) On this page The Rush tool's behavior can be customized using the shell environment variables described below: RUSH\_ABSOLUTE\_SYMLINKS[​](https://rushjs.io/pages/configs/environment_vars/#rush_absolute_symlinks "Direct link to RUSH_ABSOLUTE_SYMLINKS") ---------------------------------------------------------------------------------------------------------------------------------------------- If this variable is set to `1`, Rush will create symlinks with absolute paths instead of relative paths. This can be necessary when a repository is moved during a build or if parts of a repository are moved into a sandbox. RUSH\_ALLOW\_UNSUPPORTED\_NODEJS[​](https://rushjs.io/pages/configs/environment_vars/#rush_allow_unsupported_nodejs "Direct link to RUSH_ALLOW_UNSUPPORTED_NODEJS") -------------------------------------------------------------------------------------------------------------------------------------------------------------------- If this variable is set to `1`, Rush will not fail the build when running a version of Node that does not match the criteria specified in the `nodeSupportedVersionRange` field from **rush.json**. RUSH\_ALLOW\_WARNINGS\_IN\_SUCCESSFUL\_BUILD[​](https://rushjs.io/pages/configs/environment_vars/#rush_allow_warnings_in_successful_build "Direct link to RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Setting this environment variable overrides the value of `allowWarningsInSuccessfulBuild` in the **command-line.json** configuration file. Specify `1` to allow warnings in a successful build, or `0` to disallow them. (See the comments in the [command-line.json](https://rushjs.io/pages/configs/command-line_json/) file for more information). RUSH\_BUILD\_CACHE\_CREDENTIAL (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_credential-experimental "Direct link to RUSH_BUILD_CACHE_CREDENTIAL (EXPERIMENTAL)") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This environment variable is used by the experimental [build cache](https://rushjs.io/pages/maintainer/build_cache/) feature. Provides a credential for accessing the remote build cache, if configured. This credential overrides any cached credentials. Setting this environment variable overrides whatever credential has been saved in the local cloud cache credentials using `rush update-cloud-credentials`. If Azure Blob Storage is used to store cache entries, this must be a SAS token serialized as query parameters. See [this article](https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview) for details about SAS tokens. RUSH\_BUILD\_CACHE\_ENABLED (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_enabled-experimental "Direct link to RUSH_BUILD_CACHE_ENABLED (EXPERIMENTAL)") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ This environment variable is used by the experimental [build cache](https://rushjs.io/pages/maintainer/build_cache/) feature. Setting this environment variable overrides the value of `buildCacheEnabled` in the [build-cache.json](https://rushjs.io/pages/configs/build-cache_json/) configuration file. Specify `1` to enable the build cache or `0` to disable it. If set to `0`, this is equivalent to passing the `--disable-build-cache` flag. If there is no build cache configured, then this environment variable is ignored. RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_write_allowed-experimental "Direct link to RUSH_BUILD_CACHE_WRITE_ALLOWED (EXPERIMENTAL)") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This environment variable is used by the experimental [build cache](https://rushjs.io/pages/maintainer/build_cache/) feature. Overrides the value of `isCacheWriteAllowed` in the `build-cache.json` configuration file. The value of this environment variable must be `1` (for true) or `0` (for false). If there is no build cache configured, then this environment variable is ignored. RUSH\_COBUILD\_CONTEXT\_ID (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_context_id-experimental "Direct link to RUSH_COBUILD_CONTEXT_ID (EXPERIMENTAL)") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Cobuild pipelines must define this environment variable; without it, Rush will perform a regular build without any cobuild logic. See the [Cobuilds](https://rushjs.io/pages/maintainer/cobuilds/) documentation for details. RUSH\_COBUILD\_LEAF\_PROJECT\_LOG\_ONLY\_ALLOWED (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_leaf_project_log_only_allowed-experimental "Direct link to RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED (EXPERIMENTAL)") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This is useful when you are using the cobuild feature but the Rush build cache is not able for "leaf" projects in the dependency graph. (For example, common libraries have build cache enabled, but the apps that consume these libraries do not.) Normally, because we can't obtain such projects from the cache, all cobuild machines are forced to build that project. This is inefficient if our goal is to validate whether the project builds successfully, not to deploy it. Setting `RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED` to `1` will cause Rush to use a special "log files only" caching for leaf projects with build cache disabled. The log files are cached and will be displayed on other cobuild machines, but the project contents are cached or restored. See the [Cobuilds](https://rushjs.io/pages/maintainer/cobuilds/) documentation for details. RUSH\_COBUILD\_RUNNER\_ID (EXPERIMENTAL)[​](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_runner_id-experimental "Direct link to RUSH_COBUILD_RUNNER_ID (EXPERIMENTAL)") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ This environment variable to uniquely identifies each cobuild machine. If this variable is not defined, Rush will generate a random identifier on each run. See the [Cobuilds](https://rushjs.io/pages/maintainer/cobuilds/) documentation for details. RUSH\_DEPLOY\_TARGET\_FOLDER[​](https://rushjs.io/pages/configs/environment_vars/#rush_deploy_target_folder "Direct link to RUSH_DEPLOY_TARGET_FOLDER") -------------------------------------------------------------------------------------------------------------------------------------------------------- This environment variable can be used to specify the `--target-folder` parameter for the [rush deploy](https://rushjs.io/pages/commands/rush_deploy/) command. RUSH\_GIT\_BINARY\_PATH[​](https://rushjs.io/pages/configs/environment_vars/#rush_git_binary_path "Direct link to RUSH_GIT_BINARY_PATH") ----------------------------------------------------------------------------------------------------------------------------------------- Explicitly specifies the path for the Git binary that is invoked by certain Rush operations. RUSH\_TAR\_BINARY\_PATH[​](https://rushjs.io/pages/configs/environment_vars/#rush_tar_binary_path "Direct link to RUSH_TAR_BINARY_PATH") ----------------------------------------------------------------------------------------------------------------------------------------- Explicitly specifies the path for the `tar` binary that is invoked by certain Rush operations. RUSH\_GLOBAL\_FOLDER[​](https://rushjs.io/pages/configs/environment_vars/#rush_global_folder "Direct link to RUSH_GLOBAL_FOLDER") ---------------------------------------------------------------------------------------------------------------------------------- Overrides the location of the `~/.rush` global folder where Rush stores temporary files. Most of the temporary files created by Rush are stored separately for each monorepo working folder, to avoid issues of concurrency and compatibility between tool versions. However, a small set of files (e.g. installations of the `@microsoft/rush-lib` engine and the package manager) are stored in a global folder to speed up installations. The default location is `~/.rush` on POSIX-like operating systems or `C:\Users\YourName` on Windows. Use `RUSH_GLOBAL_FOLDER` to specify a different folder path. This is useful for example if a Windows group policy forbids executing scripts installed in a user's home directory. (POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc.) RUSH\_INVOKED\_FOLDER[​](https://rushjs.io/pages/configs/environment_vars/#rush_invoked_folder "Direct link to RUSH_INVOKED_FOLDER") ------------------------------------------------------------------------------------------------------------------------------------- When Rush executes shell scripts, it sometimes changes the working directory to be a project folder or the repository root folder. The original working directory (where the Rush command was invoked) is assigned to the the child process's `RUSH_INVOKED_FOLDER` environment variable, in case it is needed by the script. The `RUSH_INVOKED_FOLDER` variable is the same idea as the `INIT_CWD` variable that package managers assign when they execute lifecycle scripts. RUSH\_PARALLELISM[​](https://rushjs.io/pages/configs/environment_vars/#rush_parallelism "Direct link to RUSH_PARALLELISM") --------------------------------------------------------------------------------------------------------------------------- Specifies the maximum number of concurrent processes to launch during a build. For more information, see the command-line help for the `--parallelism` parameter for [rush build](https://rushjs.io/pages/commands/rush_build/) . RUSH\_PNPM\_STORE\_PATH[​](https://rushjs.io/pages/configs/environment_vars/#rush_pnpm_store_path "Direct link to RUSH_PNPM_STORE_PATH") ----------------------------------------------------------------------------------------------------------------------------------------- When using PNPM as the package manager, this variable can be used to configure the path that PNPM will use as the store directory. If a relative path is used, then the store path will be resolved relative to the process's current working directory. An absolute path is recommended. RUSH\_PREVIEW\_VERSION[​](https://rushjs.io/pages/configs/environment_vars/#rush_preview_version "Direct link to RUSH_PREVIEW_VERSION") ---------------------------------------------------------------------------------------------------------------------------------------- This variable overrides the version of Rush that will be installed by the version selector. The default value is determined by the `rushVersion` field from **rush.json**. For example, if you want to try out a different release of Rush before upgrading your repo, you can assign the variable like this: # This is Bash's syntax; for Windows shell, change "export" to be "set"export RUSH_PREVIEW_VERSION=5.0.0-dev.25rush install RUSH\_TEMP\_FOLDER[​](https://rushjs.io/pages/configs/environment_vars/#rush_temp_folder "Direct link to RUSH_TEMP_FOLDER") ---------------------------------------------------------------------------------------------------------------------------- This variable overrides the temporary folder used by Rush. The default value is **common/temp** under the repository root. This environment variable is not compatible with workspace installs (`useWorkspaces` = true). If attempting to move the PNPM store path, see the `RUSH_PNPM_STORE_PATH` environment variable. RUSH\_VARIANT[​](https://rushjs.io/pages/configs/environment_vars/#rush_variant "Direct link to RUSH_VARIANT") --------------------------------------------------------------------------------------------------------------- This variable selects a specific installation variant for Rush to use when installing and linking package dependencies. For more information about this feature, see [Installation Variants](https://rushjs.io/pages/advanced/installation_variants/) . * [RUSH\_ABSOLUTE\_SYMLINKS](https://rushjs.io/pages/configs/environment_vars/#rush_absolute_symlinks) * [RUSH\_ALLOW\_UNSUPPORTED\_NODEJS](https://rushjs.io/pages/configs/environment_vars/#rush_allow_unsupported_nodejs) * [RUSH\_ALLOW\_WARNINGS\_IN\_SUCCESSFUL\_BUILD](https://rushjs.io/pages/configs/environment_vars/#rush_allow_warnings_in_successful_build) * [RUSH\_BUILD\_CACHE\_CREDENTIAL (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_credential-experimental) * [RUSH\_BUILD\_CACHE\_ENABLED (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_enabled-experimental) * [RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_build_cache_write_allowed-experimental) * [RUSH\_COBUILD\_CONTEXT\_ID (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_context_id-experimental) * [RUSH\_COBUILD\_LEAF\_PROJECT\_LOG\_ONLY\_ALLOWED (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_leaf_project_log_only_allowed-experimental) * [RUSH\_COBUILD\_RUNNER\_ID (EXPERIMENTAL)](https://rushjs.io/pages/configs/environment_vars/#rush_cobuild_runner_id-experimental) * [RUSH\_DEPLOY\_TARGET\_FOLDER](https://rushjs.io/pages/configs/environment_vars/#rush_deploy_target_folder) * [RUSH\_GIT\_BINARY\_PATH](https://rushjs.io/pages/configs/environment_vars/#rush_git_binary_path) * [RUSH\_TAR\_BINARY\_PATH](https://rushjs.io/pages/configs/environment_vars/#rush_tar_binary_path) * [RUSH\_GLOBAL\_FOLDER](https://rushjs.io/pages/configs/environment_vars/#rush_global_folder) * [RUSH\_INVOKED\_FOLDER](https://rushjs.io/pages/configs/environment_vars/#rush_invoked_folder) * [RUSH\_PARALLELISM](https://rushjs.io/pages/configs/environment_vars/#rush_parallelism) * [RUSH\_PNPM\_STORE\_PATH](https://rushjs.io/pages/configs/environment_vars/#rush_pnpm_store_path) * [RUSH\_PREVIEW\_VERSION](https://rushjs.io/pages/configs/environment_vars/#rush_preview_version) * [RUSH\_TEMP\_FOLDER](https://rushjs.io/pages/configs/environment_vars/#rush_temp_folder) * [RUSH\_VARIANT](https://rushjs.io/pages/configs/environment_vars/#rush_variant) --- # build-cache.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/build-cache_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **build-cache.json**: **common/config/rush/build-cache.json** /** * This configuration file manages Rush's build cache feature. * More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", /** * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. * * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. */ "buildCacheEnabled": false, /** * (Required) Choose where project build outputs will be cached. * * Possible values: "local-only", "azure-blob-storage", "amazon-s3" */ "cacheProvider": "local-only", /** * Setting this property overrides the cache entry ID. If this property is set, it must contain * a [hash] token. * * Other available tokens: * - [projectName] Example: "@my-scope/my-project" * - [projectName:normalize] Example: "my-scope+my-project" * - [phaseName] Example: "_phase:test/api" * - [phaseName:normalize] Example: "_phase:test+api" * - [phaseName:trimPrefix] Example: "test/api" * - [os] Example: "win32" * - [arch] Example: "x64" */ // "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]" /** * (Optional) Salt to inject during calculation of the cache key. This can be used to invalidate the cache for all projects when the salt changes. */ // "cacheHashSalt": "1", /** * Use this configuration with "cacheProvider"="azure-blob-storage" */ "azureBlobStorageConfiguration": { /** * (Required) The name of the the Azure storage account to use for build cache. */ // "storageAccountName": "example", /** * (Required) The name of the container in the Azure storage account to use for build cache. */ // "storageContainerName": "my-container", /** * The Azure environment the storage account exists in. Defaults to AzurePublicCloud. * * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" */ // "azureEnvironment": "AzurePublicCloud", /** * An optional prefix for cache item blob names. */ // "blobPrefix": "my-prefix", /** * If set to true, allow writing to the cache. Defaults to false. */ // "isCacheWriteAllowed": true, /** * The Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'InteractiveBrowser' otherwise. */ // "loginFlow": "InteractiveBrowser", /** * If set to true, reading the cache requires authentication. Defaults to false. */ // "readRequiresAuthentication": true }, /** * Use this configuration with "cacheProvider"="amazon-s3" */ "amazonS3Configuration": { /** * (Required unless s3Endpoint is specified) The name of the bucket to use for build cache. * Example: "my-bucket" */ // "s3Bucket": "my-bucket", /** * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. * This should not include any path; use the s3Prefix to set the path. * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" */ // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", /** * (Required) The Amazon S3 region of the bucket to use for build cache. * Example: "us-east-1" */ // "s3Region": "us-east-1", /** * An optional prefix ("folder") for cache items. It should not start with "/". */ // "s3Prefix": "my-prefix", /** * If set to true, allow writing to the cache. Defaults to false. */ // "isCacheWriteAllowed": true }, /** * Use this configuration with "cacheProvider"="http" */ "httpConfiguration": { /** * (Required) The URL of the server that stores the caches. * Example: "https://build-cacches.example.com/" */ // "url": "https://build-cacches.example.com/", /** * (Optional) The HTTP method to use when writing to the cache (defaults to PUT). * Should be one of PUT, POST, or PATCH. * Example: "PUT" */ // "uploadMethod": "PUT", /** * (Optional) HTTP headers to pass to the cache server. * Example: { "X-HTTP-Company-Id": "109283" } */ // "headers": {}, /** * (Optional) Shell command that prints the authorization token needed to communicate with the * cache server, and exits with exit code 0. This command will be executed from the root of * the monorepo. * Example: { "exec": "node", "args": ["common/scripts/auth.js"] } */ // "tokenHandler": { "exec": "node", "args": ["common/scripts/auth.js"] }, /** * (Optional) Prefix for cache keys. * Example: "my-company-" */ // "cacheKeyPrefix": "", /** * (Optional) If set to true, allow writing to the cache. Defaults to false. */ // "isCacheWriteAllowed": true }} See also[​](https://rushjs.io/pages/configs/build-cache_json/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------------- * [Enabling the build cache](https://rushjs.io/pages/maintainer/build_cache/) * [See also](https://rushjs.io/pages/configs/build-cache_json/#see-also) --- # deploy.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/deploy_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/) generates for **deploy.json** and **deploy-.json**: **common/config/rush/deploy.json** /** * This configuration file defines a deployment scenario for use with the "rush deploy" command. * The default scenario file path is "deploy.json"; additional files use the naming pattern * "deploy-.json". For full documentation, please see https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/deploy-scenario.schema.json", /** * The "rush deploy" command prepares a deployment folder, starting from the main project and collecting * all of its dependencies (both NPM packages and other Rush projects). The main project is specified * using the "--project" parameter. The "deploymentProjectNames" setting lists the allowable choices for * the "--project" parameter; this documents the intended deployments for your monorepo and helps validate * that "rush deploy" is invoked correctly. If there is only one item in the "deploymentProjectNames" array, * then "--project" can be omitted. The names should be complete package names as declared in rush.json. * * If the main project should include other unrelated Rush projects, add it to the "projectSettings" section, * and then specify those projects in the "additionalProjectsToInclude" list. */ "deploymentProjectNames": [ /* YOUR PROJECT HERE */ ], /** * When deploying a local Rush project, the package.json "devDependencies" are normally excluded. * If you want to include them, set "includeDevDependencies" to true. * * The default value is false. */ // "includeDevDependencies": true, /** * When deploying a local Rush project, normally the .npmignore filter is applied so that Rush only copies * files that would be packaged by "npm pack". Setting "includeNpmIgnoreFiles" to true will disable this * filtering so that all files are copied (with a few trivial exceptions such as the "node_modules" folder). * * The default value is false. */ // "includeNpmIgnoreFiles": true, /** * To improve backwards compatibility with legacy packages, the PNPM package manager installs extra links in the * node_modules folder that enable packages to import undeclared dependencies. In some cases this workaround may * double the number of links created. If your deployment does not require this workaround, you can set * "omitPnpmWorkaroundLinks" to true to avoid creating the extra links. * * The default value is false. */ // "omitPnpmWorkaroundLinks": true, /** * Specify how links (symbolic links, hard links, and/or NTFS junctions) will be created in the deployed folder: * * - "default": Create the links while copying the files; this is the default behavior. * - "script": A Node.js script called "create-links.js" will be written. When executed, this script will * create the links described in the "deploy-metadata.json" output file. * - "none": Do nothing; some other tool may create the links later. */ // "linkCreation": "script", /** * If this path is specified, then after "rush deploy", recursively copy the files from this folder to * the deployment target folder (common/deploy). This can be used to provide additional configuration files * or scripts needed by the server when deploying. The path is resolved relative to the repository root. */ // "folderToCopy": "repo-tools/assets/deploy-config", /** * Customize how Rush projects are processed during deployment. */ "projectSettings": [ // { // /** // * The full package name of the project, which must be declared in rush.json. // */ // "projectName": "@my-scope/my-project", // // /** // * A list of additional local Rush projects to be deployed with this project (beyond the package.json // * dependencies). Specify full package names, which must be declared in rush.json. // */ // "additionalProjectsToInclude": [ // // "@my-scope/my-project2" // ], // // /** // * When deploying a project, the included dependencies are normally determined automatically based on // * package.json fields such as "dependencies", "peerDependencies", and "optionalDependencies", // * subject to other deployment settings such as "includeDevDependencies". However, in cases where // * that information is not accurate, you can use "additionalDependenciesToInclude" to add more // * packages to the list. // * // * The list can include any package name that is installed by Rush and resolvable via Node.js module // * resolution; however, if it resolves to a local Rush project, the "additionalProjectsToInclude" // * field will not be recursively applied. // */ // "additionalDependenciesToInclude": [ // // "@rushstack/node-core-library" // ], // // /** // * This setting prevents specific dependencies from being deployed. It only filters dependencies that // * are explicitly declared in package.json for this project. It does not affect dependencies added // * via "additionalProjectsToInclude" or "additionalDependenciesToInclude", nor does it affect indirect // * dependencies. // * // * The "*" wildcard may be used to match zero or more characters. For example, if your project already // * bundles its own dependencies, specify "dependenciesToExclude": [ "*" ] to exclude all package.json // * dependencies. // */ // "dependenciesToExclude": [ // // "@types/*" // ] // } ]} See also[​](https://rushjs.io/pages/configs/deploy_json/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------- * [Deploying projects](https://rushjs.io/pages/maintainer/deploying/) * [rush deploy](https://rushjs.io/pages/commands/rush_deploy/) command-line parameters * [See also](https://rushjs.io/pages/configs/deploy_json/#see-also) --- # The "rush-lib" API | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/extensibility/api/#docusaurus_skipToContent_fallback) On this page Rush provides an API for use by automation scripts. It is documented in the integrated API reference for all Rush Stack projects:      [API Reference: @microsoft/rush-lib package](https://api.rushstack.io/pages/rush-lib/) Below are some usage examples. > Although these code samples are presented as plain JavaScript, we strongly recommend to use TypeScript and model your scripts as regular Rush projects. It is more work to set up initially, but it generally saves time and simplifies maintenance in the long run. rush-lib vs rush-sdk[​](https://rushjs.io/pages/extensibility/api/#rush-lib-vs-rush-sdk "Direct link to rush-lib vs rush-sdk") ------------------------------------------------------------------------------------------------------------------------------- You may notice that the NPM packages `@microsoft/rush-lib` and `rushstack/rush-sdk` export the same APIs. What is the difference? * `@microsoft/rush-lib` is the **engine** of Rush that implements all the core features. It is a relatively large package that also includes some built-in Rush plugins, with many NPM dependencies. * `@microsoft/rush` is the **CLI** (command-line interface) that provides the `rush` and `rushx` commands that you can invoke from your shell. `@microsoft/rush` depends on `@microsoft/rush-lib`, however if your repository's **rush.json** file requests a different `rushVersion`, the [Rush "version selector"](https://rushjs.io/pages/contributing/) will automatically install the requested version of the `@microsoft/rush-lib` engine and use that instead. This ensures that CLI commands always have deterministic behavior, regardless of what version of `@microsoft/rush` is installed globally. * `@microsoft/rush-sdk` is the **API** interface, which has very few NPM dependencies itself, and mainly acts as a proxy for accessing the `@microsoft/rush-lib` engine. It provides two main benefits: * **Version selector:** If your tool imports from `@microsoft/rush-sdk`, then it will load the appropriate version of the engine based on `rushVersion` from **rush.json**. This is important, for example if your script directly imports from `@microsoft/rush-lib` and it is a different version, then the engine may fail to parse a config file whose format has changed. * **Internal APIs**: `@microsoft/rush-sdk` includes stubs that enable you to import internal API's from `@microsoft/rush-lib`. Internal APIs are normally difficult to access because that package is distributed as a Webpack bundle. See the [@rushstack/rush-sdk](https://www.npmjs.com/package/@rushstack/rush-sdk) documentation for more details. Example 1: Reading the rush.json configuration[​](https://rushjs.io/pages/extensibility/api/#example-1-reading-the-rushjson-configuration "Direct link to Example 1: Reading the rush.json configuration") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rather than trying to load **rush.json** as a JSON file, it is recommended to use the [RushConfiguration](https://api.rushstack.io/pages/rush-lib.rushconfiguration/) class which provides a richer set of data views. For example, this script will show all the Rush projects and their folders: const rushSdk = require('@rushstack/rush-sdk');// loadFromDefaultLocation() will search parent folders to find "rush.json" and then// take care of parsing it and loading related config files.const rushConfiguration = rushSdk.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});for (const project of rushConfiguration.projects) { console.log(project.packageName + ':'); console.log(' ' + project.projectRelativeFolder);} Example 2: Modifying package.json files[​](https://rushjs.io/pages/extensibility/api/#example-2-modifying-packagejson-files "Direct link to Example 2: Modifying package.json files") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- If you want to modify a **package.json** file, the [PackageJsonEditor](https://api.rushstack.io/pages/rush-lib.packagejsoneditor/) class provides helpful validation and normalization: const rushSdk = require('@rushstack/rush-sdk');const rushConfiguration = rushSdk.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});// This will find "@rushstack/ts-command-line" in rush.json, without needing to specify the NPM scopeconst project = rushConfiguration.findProjectByShorthandName('ts-command-line');// Add lodash as an optional dependencyproject.packageJsonEditor.addOrUpdateDependency('lodash', '4.17.15', 'optionalDependencies');// Save the modified package.json fileproject.packageJsonEditor.saveIfModified(); Example 3: Generating a README.md summary[​](https://rushjs.io/pages/extensibility/api/#example-3-generating-a-readmemd-summary "Direct link to Example 3: Generating a README.md summary") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- For a more realistic example, the [repo-toolbox/src/ReadmeAction.ts](https://github.com/microsoft/rushstack/blob/main/repo-scripts/repo-toolbox/src/ReadmeAction.ts) tool uses these APIs to generate the [README.md](https://github.com/microsoft/rushstack/blob/main/README.md#published-packages) inventory for the Rush Stack monorepo. * [rush-lib vs rush-sdk](https://rushjs.io/pages/extensibility/api/#rush-lib-vs-rush-sdk) * [Example 1: Reading the rush.json configuration](https://rushjs.io/pages/extensibility/api/#example-1-reading-the-rushjson-configuration) * [Example 2: Modifying package.json files](https://rushjs.io/pages/extensibility/api/#example-2-modifying-packagejson-files) * [Example 3: Generating a README.md summary](https://rushjs.io/pages/extensibility/api/#example-3-generating-a-readmemd-summary) --- # Speed up Git with Sparo | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/integrations/sparo/#docusaurus_skipToContent_fallback) On this page Monorepos often grow quickly as they assimilate more and more projects. Although Rush provides various mechanisms for speeding up [install times](https://rushjs.io/pages/advanced/subspaces/) and [build times](https://rushjs.io/pages/maintainer/cobuilds/) , for very large repositories even basic operations such as `git clone` and `git checkout` may become frustratingly slow. Git optimizations[​](https://rushjs.io/pages/integrations/sparo/#git-optimizations "Direct link to Git optimizations") ----------------------------------------------------------------------------------------------------------------------- Git offers some built-in features that may be sufficient to speed up a medium-sized repository: * [Shallow clone](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-code--depthcodeemltdepthgtem) allows cloning only a few commits, but is generally only suitable for throwaway clones such as a CI job. * [Partial clone](https://git-scm.com/docs/partial-clone) allows cloning without file contents ("blobless" clone) or even commit details (treeless clone), greatly accelerating your `git clone` time and allowing such details to be fetched during `git checkout`. * [Large file storage (LFS)](https://git-lfs.com/) can move large binary files to a separate server, downloading them during checkout only as needed. Usage of LFS is tricky however, because this feature relies on `.gitattributes` filtering external to Git: Your `.gitattributes` rules can select what's "large" according to file extension, but there is no easy way to select based on the real file size or update frequency. If you accidentally select too many files, performance may be worse than without LFS. Additionally, changes to `.gitattributes` cannot be retroactively applied without rewriting the entire Git history -- a very disruptive action for an active repository. Fortunately, Git offers even more advanced features such as **sparse checkout**, **single-branch clone**, **filesystem monitor**, **background maintenance**, and a variety of opt-in settings for tuning behaviors. These features can be accessed directly via the Git command-line, but configuration can be complex. Casual users often struggle with adoption. How Sparo helps[​](https://rushjs.io/pages/integrations/sparo/#how-sparo-helps "Direct link to How Sparo helps") ----------------------------------------------------------------------------------------------------------------- For an easier alternative for applying advanced Git optimizations, try the [Sparo](https://tiktok.github.io/sparo) tool. It directly integrates with Rush and automatically optimizes Git. The basic strategy is to _**fetch only what you need**_ along three dimensions: (1) skip irrelevant branches, (2) skip irrelevant history (partial clone), (3) skip checkout of irrelevant project folders (sparse checkout). Sparo simplifies sparse checkout using [Sparo profiles](https://tiktok.github.io/sparo/pages/guide/sparo_profiles/) , which can specify intelligent selections such as: _"Checkout only the two apps that my team works on, plus all their dependencies in the Rush workspace."_ In this way, engineers do not need to spend time determining the exact folder paths to be checked out. Sparo checkouts always include a base set of ["skeleton folders"](https://tiktok.github.io/sparo/pages/reference/skeleton_folders/) ; this ensures that every project's **package.json** file is always available. Sparo can also optionally collect anonymized Git timing metrics, helping your build team to analyze performance over time. The [Sparo website](https://tiktok.github.io/sparo/) provides more background. Using Sparo[​](https://rushjs.io/pages/integrations/sparo/#using-sparo "Direct link to Using Sparo") ----------------------------------------------------------------------------------------------------- The Git and Sparo command lines can be used interchangeably. The only requirement is that your working directory must be cloned initially using `sparo clone` instead of `git clone`. Here's a quick walkthrough using [azure-sdk-for-js](https://github.com/Azure/azure-sdk-for-js.git) , a large public RushJS monorepo from GitHub: ### Step 1: Clone the repo[​](https://rushjs.io/pages/integrations/sparo/#step-1-clone-the-repo "Direct link to Step 1: Clone the repo") # Install the Sparo command-linenpm install -g sparo# Clone your Rush repository -- only the minimal "skeleton" gets clonedsparo clone https://github.com/Azure/azure-sdk-for-js.git ### Step 2: Create a profile[​](https://rushjs.io/pages/integrations/sparo/#step-2-create-a-profile "Direct link to Step 2: Create a profile") cd azure-sdk-for-js# Create a sparse checkout profile, saved in common/sparo-profiles/my-team.jsonsparo init-profile --profile my-team Edit the created **my-team.json** file to add a [project selector](https://rushjs.io/pages/developer/selecting_subsets/) . For example: **common/sparo-profiles/my-team.json** { "selections": [ { // This demo profile will check out the "@azure/arm-commerce" project // and all of its dependencies: "selector": "--to", "argument": "@azure/arm-commerce" } ]} ### Step 3: Checkout your profile[​](https://rushjs.io/pages/integrations/sparo/#step-3-checkout-your-profile "Direct link to Step 3: Checkout your profile") After saving your changes to **my-team.json**, now it's time to apply it: sparo checkout --profile my-team Try it out! For example: rush install# The build should succeed because Sparo ensured that dependency projects# were included in the sparse checkout:rush build --to @azure/arm-commerce For everyday work, consider choosing mirrored subcommands such as `sparo revert` instead of `git revert`. The Sparo wrapper provides (1) better defaults, (2) suggestions for better performance, and (3) optional anonymized performance metrics. Examples: sparo pullsparo commit -m "Example command" See also[​](https://rushjs.io/pages/integrations/sparo/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------- * [Sparo website](https://tiktok.github.io/sparo/) * [Faster Git for Frontend Monorepos: Introducing Sparo](https://developers.tiktok.com/blog/2024-sparo-faster-git-for-frontend-monorepos) - blog post from the Sparo maintainers * [Git optimizations](https://rushjs.io/pages/integrations/sparo/#git-optimizations) * [How Sparo helps](https://rushjs.io/pages/integrations/sparo/#how-sparo-helps) * [Using Sparo](https://rushjs.io/pages/integrations/sparo/#using-sparo) * [Step 1: Clone the repo](https://rushjs.io/pages/integrations/sparo/#step-1-clone-the-repo) * [Step 2: Create a profile](https://rushjs.io/pages/integrations/sparo/#step-2-create-a-profile) * [Step 3: Checkout your profile](https://rushjs.io/pages/integrations/sparo/#step-3-checkout-your-profile) * [See also](https://rushjs.io/pages/integrations/sparo/#see-also) --- # rush-alerts.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/rush-alerts_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for the Rush alerts feature. > **NOTE:** Since this feature is experimental, you must invoke `rush init --include-experiments`. **common/config/rush/rush-alerts.json** /** * This configuration file manages the Rush alerts feature. * More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-alerts.schema.json", /** * Settings such as `startTime` and `endTime` will use this timezone. * If omitted, the default timezone is UTC (`+00:00`). */ "timezone": "-08:00", /** * An array of alert messages and conditions for triggering them. */ "alerts": [ // { // /** // * The alertId is used to identify the alert. // */ // "alertId": "node-js", // // /** // * When the alert is displayed, this title will appear at the top of the message box. // * It should be a single line of text, as concise as possible. // */ // "title": "Node.js upgrade soon!", // // /** // * When the alert is displayed, this text appears in the message box. To make the // * JSON file more readable, if the text is longer than one line, you can instead provide // * an array of strings that will be concatenated. Your text may contain newline characters, // * but generally this is unnecessary because word-wrapping is automatically applied. // */ // "message": [ // "This Thursday, we will complete the Node.js version upgrade. Any pipelines that", // " still have not upgraded will be temporarily disabled." // ], // // /** // * (OPTIONAL) To avoid spamming users, the `title` and `message` settings should be kept // * as concise as possible. If you need to provide more detail, use this setting to // * print a hyperlink to a web page with further guidance. // */ // // "detailsUrl": "https://contoso.com/team-wiki/2024-01-01-migration", // // /** // * (OPTIONAL) If `startTime` is specified, then this alert will not be shown prior to // * that time. // * // * Keep in mind that the alert is not guaranteed to be shown at this time, or at all: // * Alerts are only displayed after a Rush command has triggered fetching of the // * latest rush-alerts.json configuration. Also, display of alerts is throttled to // * avoid spamming the user with too many messages. If you need to test your alert, // * set the environment variable `RUSH_ALERTS_DEBUG=1` to disable throttling. // * // * The `startTime` should be specified as `YYYY-MM-DD HH:MM` using 24 hour time format, // * or else `YYYY-MM-DD` in which case the time part will be `00:00` (start of that day). // * The time zone is obtained from the `timezone` setting above. // */ // // "startTime": "2024-01-01 15:00", // // /** // * (OPTIONAL) This alert will not be shown if the current time is later than `endTime`. // * The format is the same as `startTime`. // */ // // "endTime": "2024-01-05", // // /** // * (OPTIONAL) Specifies the maximum frequency at which this alert can be displayed within a defined time period. // * Options are: // * "always" (default) - no limit on display frequency, // * "monthly" - display up to once per month // * "weekly" - display up to once per week // * "daily" - display up to once per day // * "hourly" - display up to once per hour // */ // // "maximumDisplayInterval": "always", // // /** // * (OPTIONAL) Determines the order in which this alert is shown relative to other alerts, based on urgency. // * Options are: // * "high" - displayed first // * "normal" (default) - standard urgency // * "low" - least urgency // */ // // "priority": "normal", // // /** // * (OPTIONAL) The filename of a script that determines whether this alert can be shown, // * found in the "common/config/rush/alert-scripts" folder. The script must define // * a CommonJS export named `canShowAlert` that returns a boolean value, for example: // * // * ``` // * module.exports.canShowAlert = function () { // * // (your logic goes here) // * return true; // * } // * ``` // * // * Rush will invoke this script with the working directory set to the monorepo root folder, // * with no guarantee that `rush install` has been run. To ensure up-to-date alerts, Rush // * may fetch and checkout the "common/config/rush-alerts" folder in an unpredictable temporary // * path. Therefore, your script should avoid importing dependencies from outside its folder, // * generally be kept as simple and reliable and quick as possible. For more complex conditions, // * we suggest to design some other process that prepares a data file or environment variable // * that can be cheaply checked by your condition script. // */ // // "conditionScript": "rush-alert-node-upgrade.js" // } ]} See also[​](https://rushjs.io/pages/configs/rush-alerts_json/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------------- * [rush init](https://rushjs.io/pages/commands/rush_init/) * [See also](https://rushjs.io/pages/configs/rush-alerts_json/#see-also) --- # Setting up a new repo | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/setup_new_repo/#docusaurus_skipToContent_fallback) On this page This tutorial walks through the process of consolidating several projects into a new Rush monorepo. (If you'd like to see a fully worked out sample based on these steps, take a look at the [rush-example](https://github.com/microsoft/rush-example) repo on GitHub.) For this example, suppose we have 3 project folders, like this: * **my-app**: a web application * **my-controls**: a control library used by the application * **my-toolchain**: a NodeJS build tool used to compile the other projects Initially each of these projects is in its own folder. They are built using a cumbersome procedure like this: ~$ cd my-toolchain~/my-toolchain$ npm run build~/my-toolchain$ npm link~/my-toolchain$ cd ../my-controls~/my-controls$ npm link my-toolchain~/my-controls$ npm run build~/my-controls$ npm link~/my-controls$ cd ../my-app~/my-app$ npm link my-toolchain~/my-app$ npm link my-controls~/my-app$ npm run build Let's Rushify these projects! Step 1: Check your Rush version[​](https://rushjs.io/pages/maintainer/setup_new_repo/#step-1-check-your-rush-version "Direct link to Step 1: Check your Rush version") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Before we get started, make sure you have the latest Rush release installed globally: ~$ npm install -g @microsoft/rush _NOTE: If this command fails because your user account does not have permissions to access NPM's global folder, you may need to [fix your NPM configuration](https://docs.npmjs.com/getting-started/fixing-npm-permissions) ._ Step 2: Use "rush init" to initialize your repo[​](https://rushjs.io/pages/maintainer/setup_new_repo/#step-2-use-rush-init-to-initialize-your-repo "Direct link to Step 2: Use "rush init" to initialize your repo") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Let's assume you already created an empty GitHub repo that we will copy these projects into. Clone your repo somewhere and then run `rush init` to generate Rush's config files: ~$ git clone https://github.com/my-team/my-repo~$ cd my-repo~/my-repo$ rush init It will generate these files (see [Config file reference](https://rushjs.io/pages/advanced/config_files/) for more info): | File | What it does | | --- | --- | | **rush.json** | The main configuration file for Rush | | **.gitattributes** | _(Delete this file if you're not using Git.)_
Tells Git not to perform merging operations for shrinkwrap files, because it is unsafe. | | **.gitignore** | _(Delete this file if you're not using Git.)_
Tells Git not to track temporary files created by Rush. | | **.github/workflows/ci.yml** | _(Delete this file if you're not using GitHub Actions.)_
Configures the [GitHub Actions](https://github.com/features/actions)
service to perform PR builds using Rush. | | **common/config/rush/.npmrc** | Rush uses this file to configure the package registry, regardless of whether the package manager is PNPM, NPM, or Yarn. | | **common/config/rush/.npmrc-publish** | Rush uses this file instead of **.npmrc** when publishing NPM packages. | | **common/config/rush/.pnpmfile.cjs** | _(Delete this file if you've chosen to use NPM or Yarn instead of PNPM.)_
Used to workaround problems with dependencies that have mistakes in their package.json file. | | **common/config/rush/artifactory.json** | _(Delete this file if you're not using Artifactory.)_
Used to define a custom `rush setup` experience for configuring Artifactory credentials. | | **common/config/rush/build-cache.json** | Used to configure Rush's cloud build cache. | | **common/config/rush/command-line.json** | You can use this to define custom commands/parameters that will become part of the Rush command-line. | | **common/config/rush/common-versions.json** | Used to specify NPM dependency version selections that affect all projects in a Rush repo. | | **common/config/rush/experiments.json** | Used to enable experimental features of Rush. | | **common/config/rush/pnpm-config.json** | Used to configure how the PNPM package manager behaves during `rush install` and `rush update`. | | **common/config/rush/rush-plugins.json** | Used to enable plugins for Rush. | | **common/config/rush/version-policies.json** | Used to define advanced publishing configurations. | | **git-hooks/commit-msg.sample** | A template for defining Git hooks that will be activated by `rush install`. | **NOTE: If any of these files already exists in your branch, `rush init` will issue a warning and will NOT overwrite the existing files.** Next, add the generated files to Git and commit them to your branch: ~/my-repo$ git add .~/my-repo$ git commit -m "Initialize Rush repo" Step 3: Customize your configuration[​](https://rushjs.io/pages/maintainer/setup_new_repo/#step-3-customize-your-configuration "Direct link to Step 3: Customize your configuration") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The template files have lots of documentation and commented example snippets. We suggest you look over them to familiarize yourself with the basic options and features. You can change your options at any time, but there are a few settings in **rush.json** that you should think about in advance: * **Choose a package manager**: The template defaults to using PNPM, but you can also use NPM or Yarn. See [NPM vs PNPM vs Yarn](https://rushjs.io/pages/maintainer/package_managers/) for guidance. * **Check your Rush version**: Make sure your `rushVersion` setting is the latest version, which is shown in the [NPM registry](https://www.npmjs.com/package/@microsoft/rush) . * **Check other version fields**: Also check that you're using recent stable releases for any other applicable fields such as `pnpmVersion`, `npmVersion`, `yarnVersion`, `nodeSupportedVersionRange` * **Decide whether to use the "category folders" model**: See the comments in **rush.json** regarding `projectFolderMinDepth` and `projectFolderMaxDepth`, and make a plan for how project folders will be organized in the monorepo * **Configure your registry access**: The initial **.npmrc** file is configured to use the public NPM registry. If you will be using a [private registry](https://rushjs.io/pages/maintainer/npm_registry_auth/) , you should update the **common/config/rush/.npmrc** file. * [Step 1: Check your Rush version](https://rushjs.io/pages/maintainer/setup_new_repo/#step-1-check-your-rush-version) * [Step 2: Use "rush init" to initialize your repo](https://rushjs.io/pages/maintainer/setup_new_repo/#step-2-use-rush-init-to-initialize-your-repo) * [Step 3: Customize your configuration](https://rushjs.io/pages/maintainer/setup_new_repo/#step-3-customize-your-configuration) --- # Using Mergify with Rush | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/integrations/mergify/#docusaurus_skipToContent_fallback) On this page [Mergify](https://mergify.com/) provides an add-on service for GitHub offering expanded **merge queue** capabilities. If you're new to merge queues, start with [Best Practices: Enabling a merge queue](https://rushjs.io/pages/best_practices/merge_queue/) from the Rush docs and [What's a Merge Queue and Why Use it?](https://blog.mergify.com/whats-a-merge-queue-and-why-use-it/) from Mergify. The general problem of optimizing queues involves many tradeoffs and heuristics for choosing which work to parallelize or combine. This creates many opportunities for optimization and differentiation between implementors. Mergify's service targets large scale, high velocity monorepos. Their [Merge Queue Benchmark](https://mergify.com/alternative/merge-queue-benchmark) presents a feature matrix highlighting differences between various systems. A basic example[​](https://rushjs.io/pages/integrations/mergify/#a-basic-example "Direct link to A basic example") ------------------------------------------------------------------------------------------------------------------- The [Mergify configuration file](https://docs.mergify.com/configuration/file-format) is typically called `.mergify.yml` and defines most of the behavior. Let's summarize the basic lifecycle of a pull request: Once a PR is created in your repository, Mergify will detect it and check it against the [`pull-request-rules`](https://docs.mergify.com/configuration/file-format/#pull-request-rules) . This ruleset allows you to automate and adapt a wide variety of workflows. The `pull-request-rules` contain conditions and actions, specifically the [`queue`](https://docs.mergify.com/workflow/actions/queue/) action. Once a PR validates the conditions of a pull request rule, it will trigger its action causing the PR to be queued. Here's an example config file: **.mergify.yml** queue_rules: - name: default merge_conditions: - '#approved-reviews-by>=2' - check-success=Travis CI - Pull Requestpull_request_rules: - name: merge using the merge queue conditions: - base=main - label=queue actions: queue: Above we have defined one unique merge queue named `default` with its own set of conditions. The `merge_conditions` will need to be validated before the PR can be merged. Using partitions to increase parallelism[​](https://rushjs.io/pages/integrations/mergify/#using-partitions-to-increase-parallelism "Direct link to Using partitions to increase parallelism") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The key to optimizing a merge queue is identifying jobs that can be performed in parallel because their Git diffs are independent. Two PR's are "independent" if (1) their diffs do not involve the same files and (2) the files "impacted" by the two diffs do not overlap, according to the dependency graph. Rush's dependency analysis operates at the granularity of Rush projects, not individual files. In terms of [Rush project selectors](https://rushjs.io/pages/developer/selecting_subsets/) it means that `rush list --impacted-by git:origin/main` must not have any overlap between the two PR's. Mergify's [partitions](https://docs.mergify.com/merge-queue/partitions/) are analogous to Rush projects in this analysis; each partition defines a collection of a files, with the ability to declare dependency relationships between partitions, which can then determine whether jobs build in parallel or not. As an example, suppose your Rush workspace contains three projects called `project-a`, `project-b`, and `project-c`. Here's a sample hard-wired configuration: **.mergify.yml** partition_rules: - name: project-a conditions: - files~=^apps/project-a - name: project-a conditions: - files~=^apps/project-a - name: project-a conditions: - files~=^apps/project-cqueue_rules: - name: default merge_conditions: - and: - or: - queue-partition-name!=project-a - check-success=ciA - or: - queue-partition-name!=project-a - check-success=ciB - or: - queue-partition-name!=project-a - check-success=ciCpull_request_rules: - name: merge using the merge queue conditions: - base=main - label=queue actions: queue: In this example, if a PR modifies files under the folder `project-a`, the partition and merge queue that will be used to check and merge the PR automatically will be the one of `project-a`. If a PR modifies files from two or more projects at the same time, the PR will be checked in every corresponding partition. In a large monorepo, hand-coding the `files~=` condition is impractical; it will need to be generated using a script. > 💡**Coming soon** > > We're collaborating on a vendor-agnostic [project-impact-graph.yaml](https://github.com/tiktok/project-impact-graph) > specification and accompanying Rush plugin that will enable services such as Mergify to query the **rush.json** dependency graph directly. Automated actions[​](https://rushjs.io/pages/integrations/mergify/#automated-actions "Direct link to Automated actions") ------------------------------------------------------------------------------------------------------------------------- Mergify also includes a workflow automation feature that can automate tasks such as adding comments, assigning reviewers, or adding labels. For example: **.mergify.yml** pull_request_rules: - name: comment on project-a pull request conditions: - files~=^apps/project-a actions: comment: message: This pull request modifies a file in project-a - name: assign review to a project-b reviewer conditions: - files~=^apps/project-b actions: assign: add_users: - projectb_reviewer - name: add label on project-c pull request conditions: - files~=^apps/projectC actions: label: toggle: - project-c Some other useful actions: * [Backport](https://docs.mergify.com/workflow/actions/backport/) : Copy a pull request to another branch once it is merged. * [Update](https://docs.mergify.com/workflow/actions/update/) : Update the pull request branch with its base branch. See also[​](https://rushjs.io/pages/integrations/mergify/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [Best Practices: Enabling a merge queue](https://rushjs.io/pages/best_practices/merge_queue/) from the Rush docs * [Mergify Documentation](https://docs.mergify.com/) * [A basic example](https://rushjs.io/pages/integrations/mergify/#a-basic-example) * [Using partitions to increase parallelism](https://rushjs.io/pages/integrations/mergify/#using-partitions-to-increase-parallelism) * [Automated actions](https://rushjs.io/pages/integrations/mergify/#automated-actions) * [See also](https://rushjs.io/pages/integrations/mergify/#see-also) --- # NPM vs PNPM vs Yarn | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/package_managers/#docusaurus_skipToContent_fallback) On this page Before you can start installing a JavaScript library, you need to choose which package manager you will use. (Our community loves flexibility and choices, so of course there's not just one!) Rush supports the three most popular package managers. In chronological order: * [NPM](https://docs.npmjs.com/getting-started/what-is-npm) : the tool that pioneered the packaging standard and registry protocol used by most JavaScript package managers today. The tool's developers also maintain the npmjs.com registry, which is currently the most popular place to distribute open source JavaScript libraries. * [Yarn](https://yarnpkg.com/en/) : a complete rewrite of the NPM tool that preserves the same installation model, but promises faster installations, better reliability, and some cool new features (e.g. Yarn workspaces) that facilitate large scale development. * [PNPM](https://pnpm.js.org/) : A fundamentally new installation model that solves the ["phantom dependency" and "NPM doppelganger"](https://rushjs.io/pages/advanced/phantom_deps/) " problems, while cleverly making use of [symlinks](https://en.wikipedia.org/wiki/Symbolic_link) to remain 100% compatible with the NodeJS module resolution standard. Which one should I use with Rush?[​](https://rushjs.io/pages/maintainer/package_managers/#which-one-should-i-use-with-rush "Direct link to Which one should I use with Rush?") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The answer depends on your needs. The Rush developers don't endorse a particular package manager, but here are some observations based on our experience from managing our own monorepos: #### Considerations for NPM[​](https://rushjs.io/pages/maintainer/package_managers/#considerations-for-npm "Direct link to Considerations for NPM") * NPM is the most compatible choice, and the most forgiving for dealing with "bad" packages. * If you choose NPM, you may need to use an older release. NPM 5.x and 6.x are both known to have unresolved regressions that cause trouble in Rush repos. NPM **4.5.0** is the most recent version that's known to work very reliably, but unfortunately it's pretty old. (We'd greatly appreciate community help improving this situation. We're using [GitHub issue #886](https://github.com/microsoft/rushstack/issues/886) to track this effort.) _Before reporting a Rush bug involving the NPM package manager, first try downgrading to `"npmVersion": "4.5.0"`. If that eliminates the repro, then your issue is likely an NPM regression and may not be fixable in the Rush code base. We still accept these issues, but we track them differently._ #### Considerations for PNPM[​](https://rushjs.io/pages/maintainer/package_managers/#considerations-for-pnpm "Direct link to Considerations for PNPM") * PNPM is the only option that solves the [NPM doppelgangers](https://rushjs.io/pages/advanced/npm_doppelgangers/) problem. In a complex monorepo, doppelgangers sometimes cause a lot of trouble, so PNPM has an important advantage in this regard. * Although PNPM's symlinking strategy correctly follows the modern NodeJS module resolution standard, many legacy packages do not, which causes compatibility problems. Teams who migrate existing projects from Yarn/NPM to PNPM often encounter "bad packages" that need workarounds or fixes. The incompatibilities generally reflect real problems with those packages: (1) forgetting to list dependencies in the **package.json** file, or (2) implementing homebrew module resolution without handling symlinks according to the standard. Most "bad" packages have straightforward fixes, but it may seem daunting for a small team. (The [PNPM Discord chat room](https://discord.gg/mThkzAT) is a great resource for help, though.) * PNPM is newer and less widely used than NPM or Yarn, but it's a solid piece of software. Microsoft uses PNPM in Rush repos with hundreds of projects and hundreds of PRs per day, and we've found it to be very fast and reliable. * PNPM is currently the only option that supports the `--strict-peer-dependencies` protection (see `"strictPeerDependencies"` in **rush.json**). #### Considerations for Yarn[​](https://rushjs.io/pages/maintainer/package_managers/#considerations-for-yarn "Direct link to Considerations for Yarn") * Rush's support for Yarn is relatively new and unproven, so we're eager to hear about issues and get them fixed. * Yarn installs faster than NPM (although somewhat slower than PNPM). * Yarn's "workspaces" are not used in a Rush repo, since they rely on an installation model that doesn't protect against phantom dependencies. Rush's linking strategy is mostly equivalent to workspaces, however. Specifying your package manager[​](https://rushjs.io/pages/maintainer/package_managers/#specifying-your-package-manager "Direct link to Specifying your package manager") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To change your package manager, edit the **rush.json** file and uncomment one of the three fields (`npmVersion`, `pnpmVersion`, or `yarnVersion`): **rush.json** /** * The next field selects which package manager should be installed and determines its version. * Rush installs its own local copy of the package manager to ensure that your build process * is fully isolated from whatever tools are present in the local environment. * * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation * for details about these alternatives. */"pnpmVersion": "2.15.1",// "npmVersion": "4.5.0",// "yarnVersion": "1.9.4", After changing the setting, delete your old shrinkwrap file and other package manager specific files from the **common/config/rush** folder. (Otherwise Rush will complain about unsupported config files.) Then run `rush update --full --purge`. That's it! * [Which one should I use with Rush?](https://rushjs.io/pages/maintainer/package_managers/#which-one-should-i-use-with-rush) * [Specifying your package manager](https://rushjs.io/pages/maintainer/package_managers/#specifying-your-package-manager) --- # Frequently Asked Questions (FAQ) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/help/faq/#docusaurus_skipToContent_fallback) On this page ### All my projects in one big repo? Is that a good idea?[​](https://rushjs.io/pages/help/faq/#all-my-projects-in-one-big-repo-is-that-a-good-idea "Direct link to All my projects in one big repo? Is that a good idea?") _Answered in [this article](https://rushjs.io/pages/intro/why_mono/) ._ ### Where do I send bug reports or feature requests?[​](https://rushjs.io/pages/help/faq/#where-do-i-send-bug-reports-or-feature-requests "Direct link to Where do I send bug reports or feature requests?") Open a [GitHub issue](https://github.com/microsoft/rushstack/issues) for the **rushstack** project. Include "Rush" in your issue title. ### With many projects in one repo, will "npm install" take too long?[​](https://rushjs.io/pages/help/faq/#with-many-projects-in-one-repo-will-npm-install-take-too-long "Direct link to With many projects in one repo, will "npm install" take too long?") You might be thinking: "Hmmm.. if my current install takes 3 minutes, and you want me to put 20 projects in one repo, won't that multiply my NPM install time to 60 minutes!?" Nope. Rush centralizes your dependencies in a "common" folder and runs "npm install" exactly once, with essentially the same install time as your original monolithic application. ### Will Rush make my tooling nonstandard?[​](https://rushjs.io/pages/help/faq/#will-rush-make-my-tooling-nonstandard "Direct link to Will Rush make my tooling nonstandard?") Nope! Rush works within the existing systems and standards. It just does things better and faster. * Each project folder remains self-contained (no blurring of package boundaries) * It's still possible to build any project without Rush; just do `pnpm install` and `npm run build` as usual (although `workspace:*` [references](https://pnpm.io/workspaces#workspace-protocol-workspace) in **package.json** might need to be removed) * A project can be moved to a separate repo at any time, without any code changes; no commitment! ### Is "Rush Stack" the same thing as Rush?[​](https://rushjs.io/pages/help/faq/#is-rush-stack-the-same-thing-as-rush "Direct link to Is "Rush Stack" the same thing as Rush?") No. **Rush Stack** is a suite of projects, maintained by a group of developers with a common mission to build professional tooling for large scale TypeScript monorepos. Rush is a part of Rush Stack. The other pieces are strictly optional, though. Rush itself is toolchain agnostic -- it works great as a standalone tool. For more details, check out the [Rush Stack](https://rushstack.io/) website. ### After installing Rush, why am I still seeing the old version?[​](https://rushjs.io/pages/help/faq/#after-installing-rush-why-am-i-still-seeing-the-old-version "Direct link to After installing Rush, why am I still seeing the old version?") This problem isn't specific to Rush, but we hear about it a lot because Rush is one of the first tools people need to invoke when starting work in a repo. The symptoms look like this: C:\> npm install -g @microsoft/rushC:\Program Files\nodejs\rush -> C:\Program Files\nodejs\node_modules\@microsoft\rush\bin\rushC:\Program Files\nodejs`-- @microsoft/rush@3.0.1C:\> rushRush Multi-Package Build Tool 2.5.0 - http://aka.ms/rush NPM seems to say that it is installing version 3.0.1, but when we execute the command, it shows Rush version 2.5.0. What's going on here?! The problem is that when you type commands like "heft" or "rush", they are found in your system PATH, which can be pointing to folders from previous installs of NodeJS or NPM. The fix: 1. Run `npm ls -g --depth 0` to figure out where your NPM packages are being installed. 2. Run the `set` command, and examine your PATH environment variable. 3. Make sure that no other NPM or NodeJS folders appear in your PATH before the folder from #1 4. Delete any obsolete folders from your PATH, e.g. from an old install of NPM, NodeJS, nodist, nvm-windows, etc. 5. If you previously used one of these alternative engines, most likely you have a bunch of deadwood NPM packages left behind on your disk somewhere. It's a good idea to track them down and delete them. Some places to look: C:\Program Files\nodejsC:\Program Files (x86)\nodist%APPDATA%\npm%APPDATA%\nvm ### The "npm install" step is reporting network errors -- what to do?[​](https://rushjs.io/pages/help/faq/#the-npm-install-step-is-reporting-network-errors----what-to-do "Direct link to The "npm install" step is reporting network errors -- what to do?") If you install packages from a custom NPM registry (e.g. a private server for your company or a caching proxy), then your project maintainer will instruct you to add special configuration settings in your .npmrc file. If these settings are incorrect, "npm install" may report confusing errors that seem to indicate a network failure. It's important to understand that the NPM tool looks for ".npmrc" files multiple locations (and ignores other locations). Without Rush, NPM looks for "**.npmrc**" in these two places, _and merges their contents_: * in the same folder as your package.json (useful for storing project-specific settings in Git) * in your user home directory (your authentication token goes here) When Rush invokes "npm install", it looks for "**.npmrc**" in these two places: * "**./common/config/rush/.npmrc**" (which gets copied to "**./common/temp/.npmrc**" during install) * in your user home directory ### Why do Rush's JSON config files contain `//` comments that GitHub shows in red?[​](https://rushjs.io/pages/help/faq/#why-do-rushs-json-config-files-contain--comments-that-github-shows-in-red "Direct link to why-do-rushs-json-config-files-contain--comments-that-github-shows-in-red") JSON was originally intended as a machine interchange format, and thus does not formally support code comments. Recently JSON has gained popularity as a human-edited config file format, which obviously requires comments. As such, most serious JSON libraries can handle comments without any trouble. (A notable exception is `JSON.parse()`; don't use that -- it cannot validate schemas and has poor error reporting.) VS Code highlights JSON comments as errors by default, but it provides an optional "[JSON with comments](https://code.visualstudio.com/docs/languages/json#_json-with-comments) " mode. To enable this, add this line to your **settings.json** in VS Code: "files.associations": { "*.json": "jsonc" } GitHub also highlights comments as errors by default. To fix that, you can add this line to your **.gitattributes** file (and you may also need to commit a change to the affected files to work around a GitHub caching issue): *.json linguist-language=JSON-with-Comments _For a discussion of some other possibilities, see [issue #1088](https://github.com/microsoft/rushstack/issues/1088) ._ ### How to clean up Rush's installation to avoid interfering with other tools?[​](https://rushjs.io/pages/help/faq/#how-to-clean-up-rushs-installation-to-avoid-interfering-with-other-tools "Direct link to How to clean up Rush's installation to avoid interfering with other tools?") Generally it's recommended to perform all monorepo management using Rush. The symlinks that Rush creates under the project `node_modules` folders may confuse other tools such as NPM or Yarn, causing them to malfunction because they expect a different installation model. Sometimes this is unavoidable, however. For example, when migrating an existing repo to use Rush however, the CI system may need to reuse an existing working folder to build different branches that use different installation models. To prevent interference, your CI job will first need to invoke a command that deletes the old files from the previous installation model. For Yarn or NPM, a command like `git clean -dfx` is generally sufficient. (THIS DELETES FILES -- [read the manual](https://git-scm.com/docs/git-clean) before invoking!) For cleaning up a Rush installation, `git clean` is NOT recommended because it does not handle symlinks reliably. Instead, use the [rush purge](https://rushjs.io/pages/commands/rush_purge/) command to delete the `node_modules` folders created by Rush. * [All my projects in one big repo? Is that a good idea?](https://rushjs.io/pages/help/faq/#all-my-projects-in-one-big-repo-is-that-a-good-idea) * [Where do I send bug reports or feature requests?](https://rushjs.io/pages/help/faq/#where-do-i-send-bug-reports-or-feature-requests) * [With many projects in one repo, will "npm install" take too long?](https://rushjs.io/pages/help/faq/#with-many-projects-in-one-repo-will-npm-install-take-too-long) * [Will Rush make my tooling nonstandard?](https://rushjs.io/pages/help/faq/#will-rush-make-my-tooling-nonstandard) * [Is "Rush Stack" the same thing as Rush?](https://rushjs.io/pages/help/faq/#is-rush-stack-the-same-thing-as-rush) * [After installing Rush, why am I still seeing the old version?](https://rushjs.io/pages/help/faq/#after-installing-rush-why-am-i-still-seeing-the-old-version) * [The "npm install" step is reporting network errors -- what to do?](https://rushjs.io/pages/help/faq/#the-npm-install-step-is-reporting-network-errors----what-to-do) * [Why do Rush's JSON config files contain `//` comments that GitHub shows in red?](https://rushjs.io/pages/help/faq/#why-do-rushs-json-config-files-contain--comments-that-github-shows-in-red) * [How to clean up Rush's installation to avoid interfering with other tools?](https://rushjs.io/pages/help/faq/#how-to-clean-up-rushs-installation-to-avoid-interfering-with-other-tools) --- # Enabling CI builds | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/enabling_ci_builds/#docusaurus_skipToContent_fallback) On this page When you set up a PR build definition for continuous integration, the automated script can run essentially the same commands that a developer invokes manually. But there are some additional options that you may find useful. If we were invoking these commands manually, it might look something like this: # Fetch the main branchgit fetch origin main:refs/remotes/origin/main -a# (optional) Fail if the developer didn't create a required change log.# By "fail", we mean that the script will stop because Rush returned# a nonzero exit code.rush change -v# Install NPM packages in the common folder, but don't automatically do "rush link"rush install --no-link# Run "rush link" explicitly, so your CI system can measure it as a separate steprush link# Do a full "ship" build, showing detailed logs in real time# (We assume "--ship" was defined in common/config/rush/command-line.json)rush rebuild --ship --verbose But there's one hitch -- what if your CI environment doesn't come with Rush preinstalled? You might consider sticking a **package.json** at the root of your repo, and then invoking `npm install` to install Rush. Unfortunately this would introduce a phantom **node\_modules** folder, which defeats Rush's protection against [phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/) . install-run-rush.js for bootstrapping Rush[​](https://rushjs.io/pages/maintainer/enabling_ci_builds/#install-run-rushjs-for-bootstrapping-rush "Direct link to install-run-rush.js for bootstrapping Rush") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Fortunately there's a more elegant solution for getting Rush installed on a CI machine: All Rush repos come with a script `common/scripts/install-run-rush.js` that will: * find your **rush.json** file * read the `rushVersion` that's specified there * automatically install that version of Rush under the **common/temp/install-run** folder * using the appropriate settings from your repo's .npmrc file * ...and then invoke the Rush tool, passing along any command-line parameters that you provided The installation is cached, so this is not any slower than invoking Rush normally. In fact, for CI systems that preserve files from previous runs, **install-run-rush.js** is faster than `npm install` because it can cache different versions of Rush depending on the Git branch being built. Try executing the script from your shell: ~$ cd my-repo~/my-repo$ node common/scripts/install-run-rush.js --help~/my-repo$ node common/scripts/install-run-rush.js install Below we'll show how to incorporate this into a Travis build definition. install-run.js for other commands[​](https://rushjs.io/pages/maintainer/enabling_ci_builds/#install-runjs-for-other-commands "Direct link to install-run.js for other commands") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- By the way, Rush provides a second script **install-run.js** that allows you to use this same technology with arbitrary NPM packages. For example, here's a command that prints a QR code for the Rush web site: :-) ~/my-repo$ node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io Note that the **install-run.js** command line is a little different: It must include the package name and version (which can be a SemVer range, although it's best to avoid nondeterminism). It also needs a second parameter that specifies the name of the executable binary (even though the binary name is often the same as the package name). In the above example, we're invoking the `qrcode` binary and its command-line parameter is `https://rushjs.io`. Of course, a more straightforward approach would be to specify **qrcode** as an ordinary dependency of a **package.json** file somewhere, for example a **tools/repo-scripts** project. That way it can part of your normal installation, and tracked by your repo's shrinkwrap file. But in some cases that is undesirable, for example scripts that are only used by a lightweight CI job that doesn't require a `rush install`. or Git hooks that need to work correctly even when the `rush install` state is broken or outdated. GitHub Actions example from "rush init"[​](https://rushjs.io/pages/maintainer/enabling_ci_builds/#github-actions-example-from-rush-init "Direct link to GitHub Actions example from "rush init"") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [GitHub Actions](https://github.com/features/actions) is a continuous integration build service that integrates with GitHub and is free for open source projects. The `rush init` command creates a **ci.yml** pipeline that's a good starting point if you use this service. Note how it uses **install-run-rush.js** to invoke the Rush tool: **.github/workflows/ci.yml** name: CIon: push: branches: ['main'] pull_request: branches: ['main']jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 2 - name: Git config user uses: snow-actions/git-config-user@v1.0.0 with: name: # Service Account's Name email: # Service Account's Email Address - uses: actions/setup-node@v3 with: node-version: 16 - name: Verify Change Logs run: node common/scripts/install-run-rush.js change --verify - name: Rush Install run: node common/scripts/install-run-rush.js install - name: Rush rebuild run: node common/scripts/install-run-rush.js rebuild --verbose --production For an example of an equivalent setup using an Azure DevOps build pipeline, take a look at the [build.yaml file](https://github.com/microsoft/rushstack/blob/main/common/config/azure-pipelines/templates/build.yaml) , in the monorepo where Rush is developed. * [install-run-rush.js for bootstrapping Rush](https://rushjs.io/pages/maintainer/enabling_ci_builds/#install-run-rushjs-for-bootstrapping-rush) * [install-run.js for other commands](https://rushjs.io/pages/maintainer/enabling_ci_builds/#install-runjs-for-other-commands) * [GitHub Actions example from "rush init"](https://rushjs.io/pages/maintainer/enabling_ci_builds/#github-actions-example-from-rush-init) --- # Custom tips (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/custom_tips/#docusaurus_skipToContent_fallback) On this page Custom tips allow you to annotate Rush's console messages with advice tailored for your specific monorepo. Here's an example situation where custom tips can help: Suppose that your company uses a private NPM registry, which periodically syncs the latest package versions from the upstream `npmjs.com` server. Sometimes users may try to install a version that was just published, and has not synced yet, in which case `rush update` might display this error: Progress: resolved 0, reused 1, downloaded 0, added 0/users/example/code/my-repo/apps/my-app: ERR_PNPM_NO_MATCHING_VERSION  No matching version found for example-library@1.2.3This error happened while installing a direct dependency of my-appThe latest release of example-library is "1.1.0". This error is a bit confusing, since the latest release really is `1.2.3`, whereas the error is referring to the latest version synced by the private registry. If you maintain a helpline for your monorepo, you may frequently receive support tickets about this error, which can be avoided by showing a custom tip. Configuring a custom tip[​](https://rushjs.io/pages/maintainer/custom_tips/#configuring-a-custom-tip "Direct link to Configuring a custom tip") ------------------------------------------------------------------------------------------------------------------------------------------------ The `ERR_PNPM_NO_MATCHING_VERSION` code above is from PNPM. Rush's corresponding tip ID is `TIP_PNPM_NO_MATCHING_VERSION`. We can define the tip as follows: **common/config/rush/custom-tips.json** /** * This configuration file allows repo maintainers to configure extra details to be * printed alongside certain Rush messages. More documentation is available on the * Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", /** * Specifies the custom tips to be displayed by Rush. */ "customTips": [ // { // /** // * (REQUIRED) An identifier indicating a message that may be printed by Rush. // * If that message is printed, then this custom tip will be shown. // * Consult the Rush documentation for the current list of possible identifiers. // */ // "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", // // /** // * (REQUIRED) The message text to be displayed for this tip. // */ // "message": "For additional troubleshooting information, refer this wiki article:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" // } { "tipId": "TIP_PNPM_NO_MATCHING_VERSION", "message": "This \"no matching version\" error from PNPM often results from a new version that has not been synced yet to our company's internal NPM registry.\n\nFor troubleshooting guidance, consult our team wiki:\n\nhttps://example.com/wiki/npm-syncing" } ]} > If you don't have this file, you can generate it using `rush init`. With this change, users will now see the custom message alongside the original error: Progress: resolved 0, reused 1, downloaded 0, added 0/users/example/code/my-repo/apps/my-app: ERR_PNPM_NO_MATCHING_VERSION  No matching version found for example-library@1.2.3This error happened while installing a direct dependency of my-appThe latest release of example-library is "1.1.0".| Custom Tip (TIP_PNPM_NO_MATCHING_VERSION)|| This "no matching version" error from PNPM often results from a new version that has not been synced| yet to our company's internal NPM registry.|| For troubleshooting guidance, consult our team wiki:|| https://example.com/wiki/npm-syncing Note that Rush prefixes custom tips with a `|` to distinguish them from the official messaging from the Rush software. Contributing new tips[​](https://rushjs.io/pages/maintainer/custom_tips/#contributing-new-tips "Direct link to Contributing new tips") --------------------------------------------------------------------------------------------------------------------------------------- Is there a Rush message that you would like to customize, but no `tipId` is available? Implementing new tips is relatively easy. The code is in [rush-lib/src/api/CustomTipsConfiguration.ts](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/api/CustomTipsConfiguration.ts) , so feel free to create a pull request proposing new tips. Custom tip identifiers[​](https://rushjs.io/pages/maintainer/custom_tips/#custom-tip-identifiers "Direct link to Custom tip identifiers") ------------------------------------------------------------------------------------------------------------------------------------------ ### TIP\_PNPM\_INVALID\_NODE\_VERSION[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_invalid_node_version "Direct link to TIP_PNPM_INVALID_NODE_VERSION") Corresponds to PNPM's [ERR\_PNPM\_INVALID\_NODE\_VERSION](https://pnpm.io/errors#err_pnpm_invalid_node_version) . ### TIP\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_mismatched_release_channel "Direct link to TIP_PNPM_MISMATCHED_RELEASE_CHANNEL") Corresponds to PNPM's [ERR\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL](https://pnpm.io/errors#err_pnpm_mismatched_release_channel) . ### TIP\_PNPM\_NO\_MATCHING\_VERSION[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version "Direct link to TIP_PNPM_NO_MATCHING_VERSION") Corresponds to PNPM's [ERR\_PNPM\_NO\_MATCHING\_VERSION](https://pnpm.io/next/errors) . ### TIP\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version_inside_workspace "Direct link to TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE") Corresponds to PNPM's [ERR\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE](https://pnpm.io/errors#err_pnpm_no_matching_version_inside_workspace) . ### TIP\_PNPM\_OUTDATED\_LOCKFILE[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_outdated_lockfile "Direct link to TIP_PNPM_OUTDATED_LOCKFILE") Corresponds to PNPM's [ERR\_PNPM\_OUTDATED\_LOCKFILE](https://pnpm.io/errors#err_pnpm_outdated_lockfile) . ### TIP\_PNPM\_PEER\_DEP\_ISSUES[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_peer_dep_issues "Direct link to TIP_PNPM_PEER_DEP_ISSUES") Corresponds to PNPM's [ERR\_PNPM\_PEER\_DEP\_ISSUES](https://pnpm.io/errors#err_pnpm_peer_dep_issues) . ### TIP\_PNPM\_TARBALL\_INTEGRITY[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_tarball_integrity "Direct link to TIP_PNPM_TARBALL_INTEGRITY") Corresponds to PNPM's [ERR\_PNPM\_TARBALL\_INTEGRITY](https://pnpm.io/errors#err_pnpm_tarball_integrity) ### TIP\_PNPM\_UNEXPECTED\_STORE[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_unexpected_store "Direct link to TIP_PNPM_UNEXPECTED_STORE") Corresponds to PNPM's [ERR\_PNPM\_UNEXPECTED\_STORE](https://pnpm.io/errors#err_pnpm_unexpected_store) . ### TIP\_RUSH\_DISALLOW\_INSECURE\_SHA1[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_rush_disallow_insecure_sha1 "Direct link to TIP_RUSH_DISALLOW_INSECURE_SHA1") Reported for violations of the `disallowInsecureSha1` policy from [pnpm-config.json](https://rushjs.io/pages/configs/pnpm-config_json/) ; see that documentation for details. **Example Rush output:** Error: An integrity field with "sha1" was found in pnpm-lock.yaml; this conflicts with the"disallowInsecureSha1" policy from pnpm-config.json. ### TIP\_RUSH\_INCONSISTENT\_VERSIONS[​](https://rushjs.io/pages/maintainer/custom_tips/#tip_rush_inconsistent_versions "Direct link to TIP_RUSH_INCONSISTENT_VERSIONS") This message is printed by `rush install` or `rush update` when projects have inconsistent dependency versions, only if `ensureConsistentVersions` is enabled in **rush.json**. **Example Rush output:** Found 5 mis-matching dependencies! See also[​](https://rushjs.io/pages/maintainer/custom_tips/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------ * [custom-tips.json](https://rushjs.io/pages/configs/custom-tips_json/) documentation * [Configuring a custom tip](https://rushjs.io/pages/maintainer/custom_tips/#configuring-a-custom-tip) * [Contributing new tips](https://rushjs.io/pages/maintainer/custom_tips/#contributing-new-tips) * [Custom tip identifiers](https://rushjs.io/pages/maintainer/custom_tips/#custom-tip-identifiers) * [TIP\_PNPM\_INVALID\_NODE\_VERSION](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_invalid_node_version) * [TIP\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_mismatched_release_channel) * [TIP\_PNPM\_NO\_MATCHING\_VERSION](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version) * [TIP\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version_inside_workspace) * [TIP\_PNPM\_OUTDATED\_LOCKFILE](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_outdated_lockfile) * [TIP\_PNPM\_PEER\_DEP\_ISSUES](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_peer_dep_issues) * [TIP\_PNPM\_TARBALL\_INTEGRITY](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_tarball_integrity) * [TIP\_PNPM\_UNEXPECTED\_STORE](https://rushjs.io/pages/maintainer/custom_tips/#tip_pnpm_unexpected_store) * [TIP\_RUSH\_DISALLOW\_INSECURE\_SHA1](https://rushjs.io/pages/maintainer/custom_tips/#tip_rush_disallow_insecure_sha1) * [TIP\_RUSH\_INCONSISTENT\_VERSIONS](https://rushjs.io/pages/maintainer/custom_tips/#tip_rush_inconsistent_versions) * [See also](https://rushjs.io/pages/maintainer/custom_tips/#see-also) --- # Publishing packages | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/publishing/#docusaurus_skipToContent_fallback) On this page How to use Rush in your build flow to automate publishing of updated packages ============================================================================= There are two stages in a Rush publishing flow. The first stage is during development. Developers are asked to provide change files to track changes that deserve a space in change log. The second stage is at publishing time. Rush can be used to gather all change files to increase version, update change log, and publish new packages to a npm registry. 1\. Track Changes[​](https://rushjs.io/pages/maintainer/publishing/#1-track-changes "Direct link to 1. Track Changes") ----------------------------------------------------------------------------------------------------------------------- Only changes to public packages need to be tracked. People can control which package should get published and which package should not get published in rush.json by specifying field [shouldPublish](https://rushjs.io/pages/maintainer/setup_new_repo/) . Once public packages have been defined, repo admins can enforce developers to provide change files if they have modified any public packages. Developers can use a tool to generate change files after answering a few questions. ### How to enforce developers to provide change files[​](https://rushjs.io/pages/maintainer/publishing/#how-to-enforce-developers-to-provide-change-files "Direct link to How to enforce developers to provide change files") rush change --verify This command fails if a developer modifies a public package without providing related change files. It is recommended to add this command as a step of CI builds so that build fails when change files are missing. ### How a developer generates change files[​](https://rushjs.io/pages/maintainer/publishing/#how-a-developer-generates-change-files "Direct link to How a developer generates change files") rush change Running `rush change` will prompt a developer with a few questions and generate appropriate change files after questions have been answered. A change file contains what type of version increase this change needs and a description of the change. The change file should be committed with related changes into the repo. 2\. Publish packages[​](https://rushjs.io/pages/maintainer/publishing/#2-publish-packages "Direct link to 2. Publish packages") -------------------------------------------------------------------------------------------------------------------------------- rush publish When it is time to publish updated packages, `rush publish` is the command that increases package version and publish updated packages. It does quite a few things internally to make it happen: gather all change files to figure out what kind of version increase is needed, what packages need to have version increase, increase the versions of dependencies, clean up change files, and so on. This command should have its own build definition. So people can just trigger it to run when it is time to publish packages. `rush publish` is configurable to serve difference purposes. For example, it supports a dry run mode so that the changes can be verified and tested before real publishing. More usage cases are listed here: ### Dry run mode[​](https://rushjs.io/pages/maintainer/publishing/#dry-run-mode "Direct link to Dry run mode") `rush publish` has several flavors of dry runs that allow you to execute intermediate steps of the publish process without actually publishing to an npm registry. This can be useful for testing as well as for creating version bumps and changelogs in situations where this is no external package repository in use for publishing. rush publish When run without any parameters, this does the whole process in a read-only mode, which means the changes are not saved to disk, not committed to the source repository, and packages are not really published. It is useful if you want to check if the version increases and change log updates look right for you. rush publish --apply In this mode the changes are added to the changelog files and the package.json files are updated with new version numbers and written to disk, but nothing is actually committed to the source repository or published. This is useful if you want to review or edit any of these files before committing to the source repository or publishing to the package repository. rush publish --apply --target-branch targetBranch In this mode, the changes above are actually committed to a new git branch (prefixed with `publish-`) that is based off of `targetBranch`. Running this command with `targetBranch` set to the branch specified in `repository.defaultBranch` will effectively do everything that a "live" publish would do (including commits to git source), short of actually publishing to an npm repository. ### Publish mode[​](https://rushjs.io/pages/maintainer/publishing/#publish-mode "Direct link to Publish mode") There are extra parameters for configuring the publishing process: which registry to publish to, what token to use, and whether to include commit details. rush publish --apply --target-branch targetBranch --publish This command increases versions, commit changes to targetBranch, and publish packages to a registry based on environmental npm registry value. rush publish --apply --target-branch targetBranch --publish --registry registryUrl --npm-auth-token npmToken In addition to what previous command can do, this command allows packages to be published to the specified registry with a specified npm token. rush publish --apply --target-branch targetBranch --publish --registry registryUrl --npm-auth-token npmToken --add-commit-details In addition to what previous command can do, This command will include commit details in the change logs. ### Pack mode[​](https://rushjs.io/pages/maintainer/publishing/#pack-mode "Direct link to Pack mode") Instead of publishing, you also have the option to pack the outputs locally into `.tgz` files. rush publish --pack --include-all --publish > Note: Any command that uses the `--publish` flag will disable dry mode, which allows writing the file contents to the disk. > > You can also use this command in combination with `--release-folder` to hint where the files should be outputted. 3\. Version Policy[​](https://rushjs.io/pages/maintainer/publishing/#3-version-policy "Direct link to 3. Version Policy") -------------------------------------------------------------------------------------------------------------------------- Version policy is a new concept introduced into Rush to solve the problem of how to notify packages to do different types of version increase when the number of packages is large. For example, `@microsoft/rush` and `@microsoft/rush-lib` are always published together and use the same version. Those two versions should always be increased together. Another example is that developers can create different branches to service different major versions. People should not be able to modify the major version in that branch. Version policy solves this kind of problems by defining different policies, one enforcing that `rush` and `rush-lib` always have the same version and the other locking the major version in a branch. ### What is a version policy?[​](https://rushjs.io/pages/maintainer/publishing/#what-is-a-version-policy "Direct link to What is a version policy?") A version policy is set of rules that define how the version should be increased. It is defined in **common/config/rush/version-policies.json**. An example can be found in [here](https://github.com/microsoft/rushstack/blob/master/common/config/rush/version-policies.json) . A public package specifies what version policy it is associated with by providing `versionPolicyName` in **rush.json**. An example can be found in [Rush and Rush-lib configuration](https://github.com/microsoft/rushstack/blob/master/rush.json#L46) . Multiple packages can use one version policy if they all follow the same rules. When a package is associated with a version policy, it becomes public and can be published when `rush publish` runs. The schema of **version-policies.json** is defined [here](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/version-policies.schema.json) . ### Two types of version policies[​](https://rushjs.io/pages/maintainer/publishing/#two-types-of-version-policies "Direct link to Two types of version policies") There are currently two types of version policies supported: lockstep version policy and individual version policy. Projects using one lockstep version policy all have the same version. Projects using an individual version policy get version increased according to their change files and the restrictions of the policy. For example, if an individual version policy has a locked major version, all packages using this policy will have their major version locked. [ { "policyName": "myPublic", "definitionName": "lockStepVersion", "version": "1.0.0-dev.6", "nextBump": "prerelease" }, { "policyName": "myInternal", "definitionName": "individualVersion", "lockedMajor": 3 }] ### Publishing process when version policies are used[​](https://rushjs.io/pages/maintainer/publishing/#publishing-process-when-version-policies-are-used "Direct link to Publishing process when version policies are used") You need two steps to publish your packages when version policies are used. The first step is to increase the package versions. And the second step is to publish the packages. The reason to break up publishing into two steps is that it is very often that you need to test the packages after version increase and before package publishing. #### Command to increase version[​](https://rushjs.io/pages/maintainer/publishing/#command-to-increase-version "Direct link to Command to increase version") `rush version --bump` Running `rush version --bump` will increase package versions based on their associated version policies. #### Command to publish packages[​](https://rushjs.io/pages/maintainer/publishing/#command-to-publish-packages "Direct link to Command to publish packages") `rush publish --include-all` Running `rush publish --include-all` will publish all the public packages that have version increased. 4\. Summary[​](https://rushjs.io/pages/maintainer/publishing/#4-summary "Direct link to 4. Summary") ----------------------------------------------------------------------------------------------------- In summary, you can use Rush to automate the whole publishing flow for your repo. * [1\. Track Changes](https://rushjs.io/pages/maintainer/publishing/#1-track-changes) * [How to enforce developers to provide change files](https://rushjs.io/pages/maintainer/publishing/#how-to-enforce-developers-to-provide-change-files) * [How a developer generates change files](https://rushjs.io/pages/maintainer/publishing/#how-a-developer-generates-change-files) * [2\. Publish packages](https://rushjs.io/pages/maintainer/publishing/#2-publish-packages) * [Dry run mode](https://rushjs.io/pages/maintainer/publishing/#dry-run-mode) * [Publish mode](https://rushjs.io/pages/maintainer/publishing/#publish-mode) * [Pack mode](https://rushjs.io/pages/maintainer/publishing/#pack-mode) * [3\. Version Policy](https://rushjs.io/pages/maintainer/publishing/#3-version-policy) * [What is a version policy?](https://rushjs.io/pages/maintainer/publishing/#what-is-a-version-policy) * [Two types of version policies](https://rushjs.io/pages/maintainer/publishing/#two-types-of-version-policies) * [Publishing process when version policies are used](https://rushjs.io/pages/maintainer/publishing/#publishing-process-when-version-policies-are-used) * [4\. Summary](https://rushjs.io/pages/maintainer/publishing/#4-summary) --- # Using Rush plugins (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/using_rush_plugins/#docusaurus_skipToContent_fallback) On this page Rush plugins enable you to: * Share common Rush configuration across multiple monorepos * Extend Rush's base functionality with custom features * Prototype new feature ideas before officially contributing them to Rush Plugins are distributed via an NPM package, which we call a **plugin package**. A single package may define one or more Rush plugins. (If you are interested in creating your plugin package, see the article [Creating rush plugins](https://rushjs.io/pages/extensibility/creating_plugins/) .) Enabling a Rush plugin[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#enabling-a-rush-plugin "Direct link to Enabling a Rush plugin") ------------------------------------------------------------------------------------------------------------------------------------------------- There are three steps for enabling a Rush plugin in your monorepo. For this tutorial, let's configure a hypothetical plugin called `"example"` that is provided by the NPM package `@your-company/rush-example-plugin`. ### Step 1: Configure an autoinstaller[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-1-configure-an-autoinstaller "Direct link to Step 1: Configure an autoinstaller") Plugins rely on Rush's [autoinstaller](https://rushjs.io/pages/maintainer/autoinstallers/) feature for on-demand installation of their NPM package. Here's how to create a new autoinstaller called `rush-plugins`: rush init-autoinstaller --name rush-plugins This will create an autoinstaller **package.json** file. Add your plugin's NPM package as a dependency: **common/autoinstallers/rush-plugins/package.json** { "name": "rush-plugins", "version": "1.0.0", "private": true, "dependencies": { "@your-company/rush-example-plugin": "^1.0.0" 👈 👈 👈 }} Next, generate the shrinkwrap file: # Creates the shrinkwrap file common/autoinstallers/rush-plugins/pnpm-lock.yamlrush update-autoinstaller --name rush-plugins Commit these files to Git. ### Step 2: Update rush-plugins.json[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-2-update-rush-pluginsjson "Direct link to Step 2: Update rush-plugins.json") In order for the plugin to be loaded, we need to register it in **rush-plugins.json**. Continuing our example: **common/config/rush/rush-plugins.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item defines a plugin to be loaded by Rush. */ { /** * The name of the NPM package that provides the plugin. */ "packageName": "@your-company/rush-example-plugin", /** * The name of the plugin. This can be found in the "pluginName" * field of the "rush-plugin-manifest.json" file in the NPM package folder. */ "pluginName": "example", /** * The name of a Rush autoinstaller that will be used for installation, which * can be created using "rush init-autoinstaller". Add the plugin's NPM package * to the package.json "dependencies" of your autoinstaller, then run * "rush update-autoinstaller". */ "autoinstallerName": "rush-plugins" } ]} The `pluginName` field can be found in the [rush-plugin-manifest.json](https://rushjs.io/pages/configs/rush-plugin-manifest_json/) of the plugin package. ### Step 3: Optional config file[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-3-optional-config-file "Direct link to Step 3: Optional config file") Some plugins can be customized via their own config file; if so, their **rush-plugin-manifest.json** will specify the `optionsSchema` field. The config filename will have the same as the `pluginName`, for example: **common/config/rush-plugins/example.json** First-party plugins[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#first-party-plugins "Direct link to First-party plugins") ---------------------------------------------------------------------------------------------------------------------------------------- | NPM Package | Description | | --- | --- | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-amazon-s3-build-cache-plugin) | Cloud build cache provider for Amazon S3 | | [@rushstack/rush-azure-storage-build-cache-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-azure-storage-build-cache-plugin) | Cloud build cache provider for Azure Storage | | [@rushstack/rush-serve-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-serve-plugin) | (Experimental) A Rush plugin that hooks into action execution and runs an express server to serve project outputs | > **NOTE:** The `@rushstack/rush-amazon-s3-build-cache-plugin` and `@rushstack/rush-azure-storage-build-cache-plugin` packages are currently built-in to Rush and enabled automatically. For now, you should NOT register them in **rush-plugins.json**. > > This is a temporary accommodation while the plugin framework is still experimental. In the next major release of Rush, the build cache packages will need to be configured in standard way. Third-party plugins[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#third-party-plugins "Direct link to Third-party plugins") ---------------------------------------------------------------------------------------------------------------------------------------- Here's a gallery of some community contributed plugins. | NPM Package | Description | | --- | --- | | [rush-archive-project-plugin](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-archive-project-plugin) | Archive Rush projects that are no longer maintained | | [rush-github-action-build-cache-plugin](https://github.com/gigara/rush-github-action-build-cache-plugin) | Save and restore the build cache in Github actions | | [rush-init-project-plugin](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-init-project-plugin) | Initialize new Rush projects | | [rush-lint-staged-plugin](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-lint-staged-plugin) | Integrate [lint-staged](https://www.npmjs.com/package/lint-staged)
with a Rush monorepo | | [rush-print-log-if-error-plugin](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-print-log-if-error-plugin) | Print a project's entire log file when an error occurs | | [rush-sort-package-json](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-sort-package-json) | Sort the package.json file entries for Rush projects | | [rush-upgrade-self-plugin](https://github.com/tiktok/rush-plugins/tree/main/rush-plugins/rush-upgrade-self-plugin) | A helper for upgrading to the latest release of Rush | If you created an interesting plugin for Rush, let us know in a GitHub issue. Thanks! See also[​](https://rushjs.io/pages/maintainer/using_rush_plugins/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------------- * [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) * [rush update-autoinstaller](https://rushjs.io/pages/commands/rush_update-autoinstaller/) * [Creating a Rush plugin](https://rushjs.io/pages/extensibility/creating_plugins/) * [Enabling a Rush plugin](https://rushjs.io/pages/maintainer/using_rush_plugins/#enabling-a-rush-plugin) * [Step 1: Configure an autoinstaller](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-1-configure-an-autoinstaller) * [Step 2: Update rush-plugins.json](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-2-update-rush-pluginsjson) * [Step 3: Optional config file](https://rushjs.io/pages/maintainer/using_rush_plugins/#step-3-optional-config-file) * [First-party plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/#first-party-plugins) * [Third-party plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/#third-party-plugins) * [See also](https://rushjs.io/pages/maintainer/using_rush_plugins/#see-also) --- # Creating Rush plugins (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/extensibility/creating_plugins/#docusaurus_skipToContent_fallback) On this page Rush plugins enable repository maintainers to: * Share common Rush configuration across multiple monorepos * Extend Rush's base functionality with custom features * Prototype new feature ideas before officially contributing them to Rush Creating a plugin package[​](https://rushjs.io/pages/extensibility/creating_plugins/#creating-a-plugin-package "Direct link to Creating a plugin package") ----------------------------------------------------------------------------------------------------------------------------------------------------------- A **plugin package** is an NPM package that provides one or more **Rush plugins**. The plugins are described by a **plugin manifest** file. This file is always named [rush-plugin-manifest.json](https://rushjs.io/pages/configs/rush-plugin-manifest_json/) and found in same folder as the **package.json** file. Common extensibility scenarios[​](https://rushjs.io/pages/extensibility/creating_plugins/#common-extensibility-scenarios "Direct link to Common extensibility scenarios") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Defining a Rush custom command[​](https://rushjs.io/pages/extensibility/creating_plugins/#defining-a-rush-custom-command "Direct link to Defining a Rush custom command") A plugin can define new commands and parameters that extend Rush's command-line, using the same **command-line.json** file format that is used to implement [Rush custom commands](https://rushjs.io/pages/maintainer/custom_commands/) . Here's an example: **rush-example-plugin/rush-plugin-manifest.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", "plugins": [ { "pluginName": "check-readme", "description": "Adds a custom command \"rush check-readme\" that validates each project's README.md", /** * (Optional) A path to a "command-line.json" file that defines Rush command line actions * and parameters contributed by this plugin. This config file has the same JSON schema * as Rush's "common/config/rush/command-line.json" file. */ "commandLineJsonFilePath": "./command-line.json" } ]} **rush-example-plugin/command-line.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", "commands": [ { "name": "check-readme", "commandKind": "bulk", "summary": "Validates a project's README.md to make sure it conforms to company policy", "shellCommand": "node /lib/start.js", "safeForSimultaneousRushProcesses": true } ]} Example project for this scenario: [rush-sort-package-json](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-sort-package-json) from **bytesfriends** ### Loading a code module[​](https://rushjs.io/pages/extensibility/creating_plugins/#loading-a-code-module "Direct link to Loading a code module") A plugin can use the [@rushstack/rush-sdk](https://www.npmjs.com/package/@rushstack/rush-sdk) APIs to register handlers for Rush events and services. This is specified using the `entryPoint` setting in the plugin manifest: **rush-example-plugin/rush-plugin-manifest.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", "plugins": [ { "pluginName": "check-readme", "description": "Adds a custom command \"rush check-readme\" that validates each project's README.md", /** * (Optional) A path to a JavaScript code module that implements the "IRushPlugin" interface. * This module can use the "@rushstack/rush-sdk" API to register handlers for Rush events * and services. The module path is relative to the folder containing the "package.json" file. */ "entryPoint": "lib/RushExamplePlugin.js" } ]} The plugin module should have a `default` export that is an implementation of the [IRushPlugin](https://api.rushstack.io/pages/rush-lib.irushplugin/) interface. For example: **rush-example-plugin/src/RushExamplePlugin.ts** import type { IRushPlugin, RushSession, RushConfiguration } from '@rushstack/rush-sdk';export interface IRushExamplePluginOptions {}export class RushExamplePlugin implements IRushPlugin { public readonly pluginName: string = 'RushExamplePlugin'; public constructor(options: IRushExamplePluginOptions) { // Add your initialization here } public apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void { rushSession.hooks.initialize.tap(this.pluginName, () => { const logger: ILogger = rushSession.getLogger(this.pluginName); logger.terminal.writeLine('Add your custom logic here'); }); }}export default { RushExamplePlugin }; The [RushSession.hooks](https://api.rushstack.io/pages/rush-lib.rushsession/) API exposes various [lifecycle hooks](https://api.rushstack.io/pages/rush-lib.rushlifecyclehooks/) that your plugin can use to register its handlers. The hook system is based on the popular [tapable](https://www.npmjs.com/package/tapable) framework familiar from Webpack. Example project for this scenario: [@rushstack/rush-amazon-s3-build-cache-plugin](https://github.com/microsoft/rushstack/blob/main/rush-plugins/rush-amazon-s3-build-cache-plugin) > **Note:** If your code module is only used with certain Rush commands, use the `"associatedCommands"` setting to improve performance by avoiding loading the module when it is not needed. ### Defining a config file for your plugin[​](https://rushjs.io/pages/extensibility/creating_plugins/#defining-a-config-file-for-your-plugin "Direct link to Defining a config file for your plugin") Often a plugin will need to be configured using its own custom settings. Rush's convention is that the plugin's config file should be stored in the folder **common/config/rush-plugins** with the same filename as the `"pluginName"` field from the manifest. Here's a complete example of this naming pattern: | Plugin component | Example naming pattern | | --- | --- | | NPM package name: | `@your-company/rush-policy-plugins` | | `"pluginName"` in **rush-plugin-manifest.json**: | `"email-policy"` | | end user config file: | **/common/config/rush-plugins/email-policy.json** | | config file JSON schema: | **src/schemas/email-policy.schema.json** | | code module: | **src/RushEmailPolicyPlugin.ts** | To enable Rush's automatic validation of your plugin's config file, specify the `optionsSchema` setting in your plugin manifest: **rush-policy-plugins/rush-plugin-manifest.json** . . . /** * (Optional) A path to a JSON schema for validating the config file that end users can * create to customize this plugin's behavior. Plugin config files are stored in the folder * "common/config/rush-plugins/" with a filename corresponding to the "pluginName" field * from the manifest. For example: "common/config/rush-plugins/business-policy.json" * whose schema is "business-policy.schema.json". */ "optionsSchema": "lib/schemas/email-policy.schema.json", . . . See also[​](https://rushjs.io/pages/extensibility/creating_plugins/#see-also "Direct link to See also") -------------------------------------------------------------------------------------------------------- * [Using Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) * [rush-plugin-manifest.json](https://rushjs.io/pages/configs/rush-plugin-manifest_json/) config file documentation * [command-line.json](https://rushjs.io/pages/configs/command-line_json/) * [Rush custom commands](https://rushjs.io/pages/maintainer/custom_commands/) * [Creating a plugin package](https://rushjs.io/pages/extensibility/creating_plugins/#creating-a-plugin-package) * [Common extensibility scenarios](https://rushjs.io/pages/extensibility/creating_plugins/#common-extensibility-scenarios) * [Defining a Rush custom command](https://rushjs.io/pages/extensibility/creating_plugins/#defining-a-rush-custom-command) * [Loading a code module](https://rushjs.io/pages/extensibility/creating_plugins/#loading-a-code-module) * [Defining a config file for your plugin](https://rushjs.io/pages/extensibility/creating_plugins/#defining-a-config-file-for-your-plugin) * [See also](https://rushjs.io/pages/extensibility/creating_plugins/#see-also) --- # NPM registry authentication | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/npm_registry_auth/#docusaurus_skipToContent_fallback) On this page A **private NPM registry** enables your monorepo to publish NPM packages for internal usage. It works the same as the public [https://www.npmjs.com/](https://www.npmjs.com/) registry, except that accessing the private registry requires authorization. Each user will need to obtain an access token that typically gets stored in the [~/.npmrc file](https://docs.npmjs.com/cli/v6/configuring-npm/npmrc) on their computer. Most large monorepos eventually require a private NPM registry. It's useful for: * sharing code privately between teams * proxying access to the public registry, to improve reliability, audit package usage, and apply security screening * speeding up CI operations by installing prebuilt tooling packages, instead of performing `rush install && rush build` before a tool can be invoked * testing installation behaviors before publishing a package to public NPM registry * publishing wrappers or temporary forks of third-party packages (Compared to [GitHub URL dependencies](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#github-urls) , NPM packages give you proper SemVer versioning and better caching semantics.) Some popular providers are: * [AWS CodeArtifact](https://aws.amazon.com/blogs/devops/publishing-private-npm-packages-aws-codeartifact/) * [Azure DevOps Artifacts](https://docs.microsoft.com/en-us/azure/devops/artifacts/get-started-npm?view=azure-devops) * [GitHub Packages](https://github.com/features/packages) * [GitLab Package Registry](https://docs.gitlab.com/ee/user/packages/npm_registry/) * [JFrog Artifactory](https://jfrog.com/artifactory/) * [NPM private packages](https://docs.npmjs.com/about-private-packages) And for testing purposes, [Verdaccio](https://verdaccio.org/) is a lightweight Node.js server that can run on `http://localhost` and implements a complete private registry with proxy capabilities. Registry mappings[​](https://rushjs.io/pages/maintainer/npm_registry_auth/#registry-mappings "Direct link to Registry mappings") --------------------------------------------------------------------------------------------------------------------------------- The mappings for your private registry are specified in [the monorepo .npmrc file](https://rushjs.io/pages/configs/npmrc/) . Below is an example configuration that installs company packages from the private registry, but gets all other packages from the public registry. The company packages are identified by their `@example` NPM scope. **common/config/rush/.npmrc** # Map your company's NPM scope ("@example") to the private registry URL:@example:registry=https://my-registry.example.com/npm-private/# Otherwise, all other packages come from the public NPM registry:registry=https://registry.npmjs.org/always-auth=false# Here we specify how the package manager should authenticate to the private registry.# For security reasons, CI jobs should obtain their tokens from environment variables.# The exact syntax depends on your registry provider. If a line references an environment# variable that is undefined, Rush will ignore that line. This avoids producing an invalid# string that might interfere with a developer who obtains their credentials from ~/.npmrc.//my-registry.example.com/npm-private/:_password=${MY_CI_TOKEN}//my-registry.example.com/npm-private/:username=${MY_CI_USER}//my-registry.example.com/npm-private/:always-auth=true More commonly, your private registry will act as a **caching proxy** so that it can provide packages from the public NPM registry as well. In this case, NPM scopes don't need to be mapped. Your setup might look like this: **common/config/rush/.npmrc** # Map everything to the private registry URLregistry=https://my-registry.example.com/npm-private/always-auth=true# Here we specify how the package manager should authenticate to the private registry.# For security reasons, CI jobs should obtain their tokens from environment variables.# The exact syntax depends on your registry provider. If a line references an environment# variable that is undefined, Rush will ignore that line. This avoids producing an invalid# string that might interfere with a developer who obtains their credentials from ~/.npmrc.//my-registry.example.com/npm-private/:_password=${MY_CI_TOKEN}//my-registry.example.com/npm-private/:username=${MY_CI_USER} > For details about the lookup precedence for **.npmrc** settings, see the [.npmrc](https://rushjs.io/pages/configs/npmrc/) > page. Prompting for credentials with "rush setup"[​](https://rushjs.io/pages/maintainer/npm_registry_auth/#prompting-for-credentials-with-rush-setup "Direct link to Prompting for credentials with "rush setup"") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush recently introduced an experimental feature where `rush install` can detect when a user's registry credentials are missing or expired. If so, they are asked to run `rush setup`, which walks the user through the process of obtaining a token, and then updates their **~/.npmrc** file. The new settings will be intelligently merged with any existing contents of that file. A sample `rush setup` interaction looks like this: NPM credentials are missing or expired==> Fix this problem now? (y/N) YesThis monorepo consumes packages from an Artifactory private NPM registry.==> Do you already have an Artifactory user account? (y/n) YesPlease open this URL in your web browser: https://my-company.jfrog.io/Your user name appears in the upper-right corner of the JFrog website.==> What is your Artifactory user name? example-userClick "Edit Profile" on the JFrog website. Click the "Generate API Key" button if you haven't already done sopreviously.==> What is your Artifactory API key? ***************Fetching an NPM token from the Artifactory service...Adding Artifactory token to: /home/example-user/.npmrc The initial implementation supports the [JFrog Artifactory](https://jfrog.com/artifactory/) service only. Other services will be implemented in the future. To use this feature, simply assign the `"registryUrl"` field and set `"enabled": true` in your [artifactory.json](https://rushjs.io/pages/configs/artifactory_json/) config file. The file template contains documentation for other optional settings that can be used to customize the dialogue. See also[​](https://rushjs.io/pages/maintainer/npm_registry_auth/#see-also "Direct link to See also") ------------------------------------------------------------------------------------------------------ * [rush setup](https://rushjs.io/pages/commands/rush_setup/) * [artifactory.json](https://rushjs.io/pages/configs/artifactory_json/) config file * [.npmrc](https://rushjs.io/pages/configs/npmrc/) config file * [.npmrc-publish](https://rushjs.io/pages/configs/npmrc-publish/) config file * [Registry mappings](https://rushjs.io/pages/maintainer/npm_registry_auth/#registry-mappings) * [Prompting for credentials with "rush setup"](https://rushjs.io/pages/maintainer/npm_registry_auth/#prompting-for-credentials-with-rush-setup) * [See also](https://rushjs.io/pages/maintainer/npm_registry_auth/#see-also) --- # Adding projects to a repo | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/add_to_repo/#docusaurus_skipToContent_fallback) On this page _This continues the tutorial that started with "[Setting up a new repo](https://rushjs.io/pages/maintainer/setup_new_repo/) ". (To see a fully worked out sample based on these steps, take a look at the [rush-example](https://github.com/microsoft/rush-example) repo on GitHub.)_ Step 4: Add your first project[​](https://rushjs.io/pages/maintainer/add_to_repo/#step-4-add-your-first-project "Direct link to Step 4: Add your first project") ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Rather than trying to add all your projects to **rush.json** all at once, we recommend adding and validating each project one at a time. Recall that your projects form a [dependency graph](https://en.wikipedia.org/wiki/Dependency_graph) , so start with the "leaf" projects (that don't depend on anything else in the repo), and then work your way backwards. If you encounter any errors, this approach makes it easier to understand and investigate them. If you commit each added project individually, this will also make your Git history more understandable to others. For this example, let's start by adding our hypothetical **my-toolchain** project, which is needed to build everything else. Since we'll be conforming to the "category folders" model (described in the **rush.json** comments), we'll move this project under a "tools" category folder. Eventually we'll plan for other NodeJS tooling packages to go in the "tools" folder: ~/my-repo$ mkdir tools~/my-repo$ cd tools~/my-repo/tools$ cp -R ~/my-toolchain/ .~/my-repo/tools$ cd my-toolchain Next we need to delete project-specific files that are centrally coordinated in a monorepo: * Delete the local shrinkwrap file, since it's superseded by Rush's common shrinkwrap file. * Consider deleting the project's **.npmrc** file, since Rush operations always use **common/config/rush/.npmrc** * Consider deleting the project's Git config files unless they contain rules that are really specific to that project ~/my-repo/tools/my-toolchain$ rm -f shrinkwrap.yaml npm-shrinkwrap.json package-lock.json yarn.lock~/my-repo/tools/my-toolchain$ rm -f .npmrc # (if it makes sense)~/my-repo/tools/my-toolchain$ rm -f .gitattributes # (if it makes sense)~/my-repo/tools/my-toolchain$ rm -f .gitignore # (if it makes sense) > **More about the "shrinkwrap file"** > > Depending on your package manager, the shrinkwrap file may be called **shrinkwrap.yaml**, **npm-shrinkwrap.json**, **package-lock.json**, or **yarn.lock**. (Some package managers use the term "lock file", although it has nothing to do with file locking. In this documentation we will generically refer to it as a "shrinkwrap file" since we don't know which package manager you will choose.) > > Normally the package manager creates a shrinkwrap file in each project folder, but in a Rush repo there is a single "common" shrinkwrap file that describes the entire repo. It will be stored in the **common/config/rush** folder, and should be committed to Git. Consolidating all dependency information in a single shrinkwrap file has many benefits for reducing merge conflicts, reviewing diffs, and improving installation speed. Commit the new project files to Git: ~/my-repo/tools/my-toolchain$ cd ../..~/my-repo$ git add .~/my-repo$ git commit -m "Adding my-toolchain" Step 5: Running your first "rush update"[​](https://rushjs.io/pages/maintainer/add_to_repo/#step-5-running-your-first-rush-update "Direct link to Step 5: Running your first "rush update"") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- After copying over the project files, we need to edit **rush.json** and add an entry like this under the `projects` inventory: "projects": [ { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain" } ] This tells Rush that it should manage this project. > **Why can't Rush automatically detect my projects?** > > Rush does not automatically discover projects using wildcards. We have a few motivations for this design decision: > > 1. Depth-first scans are expensive, particularly when tools need to repeatedly collect the list. > 2. On a caching CI machine, scans can accidentally pick up files left behind from a previous build. > 3. It's useful to have a centralized inventory of all projects and their important metadata. For example, this makes the approval/policy features more intuitive. Next, run `rush update` to install the dependencies of **my-toolchain**. This command can be run in any subfolder of the repo folder that contains rush.json: ~/my-repo$ rush update~/my-repo$ git add .~/my-repo$ git commit -m "rush update" Since this is the first project for the repo, you'll notice that `rush update` creates several new files: * **common/config/rush/shrinkwrap.yaml**: The common shrinkwrap file (here we're assuming PNPM package manager) * **common/scripts/install-run-rush.js**: Used by CI jobs to bootstrap the Rush tool in a reliable way * **common/scripts/install-run.js**: Used by CI jobs to bootstrap arbitrary tools in a reliable way Step 6: Verify that the new project builds[​](https://rushjs.io/pages/maintainer/add_to_repo/#step-6-verify-that-the-new-project-builds "Direct link to Step 6: Verify that the new project builds") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In order to build your projects, Rush will look for a `"build"` script in the `"scripts"` section of your **package.json** file. In our example from [rush-example](https://github.com/microsoft/rush-example) , the project builds using a simple shell script `"rimraf ./lib/ && tsc"`: { "name": "my-toolchain", "version": "1.0.0", "description": "An example toolchain used to build projects in this repo", "license": "MIT", "bin": { "my-build": "bin/my-build.js" }, "scripts": { "build": "rimraf ./lib/ && tsc" }, "dependencies": { "colors": "^1.3.2" }, "devDependencies": { "@types/node": "^10.9.4", "rimraf": "^2.6.2", "typescript": "^3.0.3" }} There are a few things to keep in mind when creating a `"build"` script: * Rush will normally use your system PATH environment variable to find the script commands. However, if you specify a single-word command like "heft" or "make", Rush will first look for the program in the `common\temp\node_modules\.bin` folder. * If the process returns a non-zero exit status, Rush will assume there was a failure and will block downstream builds. * If the command writes anything to the `stderr` stream, Rush will interpret this to mean that at least one error or warning was reported. This will break the build. (This is by design -- if you allow people to merge PRs that "cry wolf", pretty soon you will find that so many warnings have accumulated that nobody even reads them any more.) Some tooling libraries (e.g. Jest) write to `stderr` as part of their normal operation; you will need to [redirect their output](https://github.com/microsoft/spfx-gulp-tools/blob/main/core-build/gulp-core-build/src/tasks/JestReporter.ts#L23) . * If certain projects don't need to be processed by `rush build`, you still need a `build` entry. Set the value to an empty string (`""`) and Rush will ignore it. Now let's try building your project. From anywhere under the folder containing **rush.json**, run this command (which builds all projects in the repo): rush build Rush provides a lot of command-line switches for building projects. See [rush build](https://rushjs.io/pages/commands/rush_build/) and [rush rebuild](https://rushjs.io/pages/commands/rush_rebuild/) for details. > **Phantom dependency errors** > > Rush and PNPM use symlinks to prevent projects from importing [phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/) > . If an NPM dependency is not declared in your **package.json** file, a runtime error may occur if your project tries to import it. These phantom dependency errors are one of the most common issues when migrating an existing project into a Rush monorepo. Generally the fix is simply to add the missing dependency to your **package.json** file. > > The [rush scan](https://rushjs.io/pages/commands/rush_scan/) > command is a quick way to detect these problems. Step 7: Adding more projects[​](https://rushjs.io/pages/maintainer/add_to_repo/#step-7-adding-more-projects "Direct link to Step 7: Adding more projects") ----------------------------------------------------------------------------------------------------------------------------------------------------------- You can add more projects by following the same operations from Step 4. In our example, we would add **my-controls** next (because it depends on **my-toolchain**), and then **my-application** last (because it depends on everything). We proactively added a couple more category folders ("libraries" and "apps") since we expect more of these types of things in our scenario. The filled out `"projects"` section looks like this: "projects": [ { "packageName": "my-app", "projectFolder": "apps/my-app" }, { "packageName": "my-controls", "projectFolder": "libraries/my-controls", "reviewCategory": "production" }, { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain", "reviewCategory": "tools" } ] Once you have all your projects added and building without errors, you may consider enabling other optional features. The config files contain lots of snippets that you can uncomment to get started. The [rush-example](https://github.com/microsoft/rush-example) repo uses some of these snippets. * [Step 4: Add your first project](https://rushjs.io/pages/maintainer/add_to_repo/#step-4-add-your-first-project) * [Step 5: Running your first "rush update"](https://rushjs.io/pages/maintainer/add_to_repo/#step-5-running-your-first-rush-update) * [Step 6: Verify that the new project builds](https://rushjs.io/pages/maintainer/add_to_repo/#step-6-verify-that-the-new-project-builds) * [Step 7: Adding more projects](https://rushjs.io/pages/maintainer/add_to_repo/#step-7-adding-more-projects) --- # Selecting subsets of projects | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/developer/selecting_subsets/#docusaurus_skipToContent_fallback) On this page [Bulk commands](https://rushjs.io/pages/maintainer/custom_commands/) like `rush build` and `rush rebuild` operate on all projects in the monorepo by default. This becomes expensive as you accumulate more and more projects. To speed things up, Rush provides a set of command-line parameters for selecting subsets of projects. Suppose we're working with the following collection of Rush projects: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) In the above illustration, the circles represent local projects, not external NPM dependencies. The arrow from `D` to `C` indicates that `D` depends on `C`; this means that `C` must be built before `D` can be built. We'll use the `rush build` command in the examples given below, but these same parameters work for any bulk command. Selection parameters[​](https://rushjs.io/pages/developer/selecting_subsets/#selection-parameters "Direct link to Selection parameters") ----------------------------------------------------------------------------------------------------------------------------------------- ### \-\-to[​](https://rushjs.io/pages/developer/selecting_subsets/#--to "Direct link to --to") **Possible scenario:** Suppose that you have just cloned your monorepo, and now you want to start working on project `B`. You need to build all the things that `B` depends on, and also `B` itself. Here's how to do that: # Build everything up to (and including) project Brush build --to B The projects selected by this command are `A`, `B`, and `E`: ![rush build --to B](https://rushjs.io/images/docs/selection-to.svg) ### \-\-to-except[​](https://rushjs.io/pages/developer/selecting_subsets/#--to-except "Direct link to --to-except") **Possible scenario:** In many cases we do not need `rush build` to process `B`, because our next step will be to invoke Webpack or Jest in "watch mode" for `B`. You can use `--to-except` instead of `--to` to exclude `B`. # Build everything up to project B, but not B itselfrush build --to-except B# Invoke Jest watch mode to build Bheft test --watch The projects selected by this command are `A` and `E`: ![rush build --to-except B](https://rushjs.io/images/docs/selection-to-except.svg) ### \-\-from[​](https://rushjs.io/pages/developer/selecting_subsets/#--from "Direct link to --from") **Possible scenario:** Now that we've finished making our changes to `B`, we want to build the downstream projects `C` and `D` to make sure their tests were not broken by our change. In order to build `D`, we also need to include its dependency `G`. The `--from` command does this. It will also include `A` and `E` since they're required by `B`. (Since `rush build` is incremental, `A` and `E` will probably get skipped assuming they are still up to date.) # Build everything downstream from B, including any implied dependenciesrush build --from B This command selects everything except for `F`: ![rush build --from B](https://rushjs.io/images/docs/selection-from.svg) > **Compatibility note:** If the `rushVersion` setting in your **rush.json** is older than 5.38.0, then `--from` will instead behave like `--impacted-by`. The meaning was changed in Rush 5.38.0 because most users expected `--from` to include dependencies. ### \-\-impacted-by (unsafe)[​](https://rushjs.io/pages/developer/selecting_subsets/#--impacted-by-unsafe "Direct link to --impacted-by-unsafe") **Possible scenario:** Suppose that while working on `B` we made some changes to `E`. The `rush build` incremental analysis assumes that any change to `E` requires all its downstream dependents to be rebuilt, including `F` for example. That can be a big set. Maybe you know better -- perhaps you later reverted your change in `E`, or maybe you manually invoked the toolchain so `E` is in good shape, or maybe your change to `E` is not relevant right now. In these situations the `--impacted-by` parameter can be handy: It means _"Select only those projects that might be broken by a change to B, and trust me that their dependencies are in a usable state."_ # Build B and everything downstream from B, but don't include dependenciesrush build --impacted-by B The projects selected by this command are `B`, `C`, and `D`: ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) ### \-\-impacted-by-except (unsafe)[​](https://rushjs.io/pages/developer/selecting_subsets/#--impacted-by-except-unsafe "Direct link to --impacted-by-except-unsafe") **Possible scenario:** This is the same as `--impacted-by` except that it does not include `B` itself. For example that might make sense if you already built `B` manually while implementing the thing that we now want to test. # Build everything downstream from B, but don't include dependenciesrush build --impacted-by-except B The projects selected by this command are `C` and `D`: ![rush build --impacted-by-except B](https://rushjs.io/images/docs/selection-impact-except.svg) ### \-\-only (unsafe)[​](https://rushjs.io/pages/developer/selecting_subsets/#--only-unsafe "Direct link to --only-unsafe") **Possible scenario:** As its name implies, the `--only` parameter adds exactly one project to the selection, ignoring dependencies. # Build only B and nothing elserush build --only B ![rush build --only B](https://rushjs.io/images/docs/selection-only.svg) The `--only` parameter is most useful when combined with other parameters. For example, in our narrative above when we did `rush build --impacted-by B`, maybe we had not actually built `G` yet. We can include it by doing `rush build --impacted-by B --only G`. > **"Unsafe" parameters:** The parameters `--only`, `--impacted-by`, and `--impacted-by-except` can all fail if the required dependencies are not built. These three parameters save time by assuming that you know better than Rush about what really needs to be built. If that assumption is incorrect, you can always do `rush build` to get back to a good state. Selectors[​](https://rushjs.io/pages/developer/selecting_subsets/#selectors "Direct link to Selectors") -------------------------------------------------------------------------------------------------------- When you use a **selection parameter** such as `rush build --to X`, the argument `X` is called a **selector**. In the discussion above, we assumed that the selector was always the name of a single Rush project. Rush supports a variety of other selector syntaxes, some of which can refer to more than one Rush project. ### Project name[​](https://rushjs.io/pages/developer/selecting_subsets/#project-name "Direct link to Project name") The simplest selector is the full name of the Rush project, which is the `"name"` field from **package.json**. Examples: rush build --to @my-company/my-project-name rush build --from @my-company/my-project-name rush list --impacted-by @my-company/my-project-name If the package name includes an NPM scope such as `@my-company`, Rush allows you to omit the scope for brevity (as long as the unscoped name is not used by some other project in your workspace). Examples: rush build --to my-project-name rush build --from my-project-name rush list --impacted-by my-project-name Generally the disk folder of `@my-company/my-project-name` would also be called `my-project-name`, a practice which we strongly recommend to avoid confusion. It is important to understand that this selector is NOT matching the disk folder. ### Current folder: `.`[​](https://rushjs.io/pages/developer/selecting_subsets/#current-folder- "Direct link to current-folder-") The folder containing a Rush project's **package.json** file is called the **project folder**. If your shell's current working directory is somewhere under a project folder, then the selector `.` provides a convenient shorthand for referring to that project. Examples: cd my-project-name# Build "@my-company/my-project-name" whose package.json# is in the current working directoryrush build --to .cd src# The "." selector can also be resolved from a subfolder# such as my-project-name/srcrush list --to-except . ### Modified projects: `git:`[​](https://rushjs.io/pages/developer/selecting_subsets/#modified-projects-git "Direct link to modified-projects-git") By providing a [Git reference](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection) expression (branch, tag, or commit hash), you can select all projects with modifications since the corresponding commit. This type of query uses similar logic as the `rush change` command: Rush calculates the `git diff` of the current working directory versus the referenced commit, then computes a list of affected file paths. These file paths are then matched with project folders from your **rush.json** workspace: In this way, the `git:` selector identifies the set of Rush projects with at least one modified file. # Select projects whose source code has been changed according to Git,# using the "main" branch as the basis for comparison.# Build "--to" those projects and their dependencies.rush build --to git:origin/main # Select projects whose source code has been changed since# the Git tag named "release/v3.0.0".# List the downstream projects that would be "impacted by" these changes.rush list --impacted-by git:release/v3.0.0 ### Subspace members: `subspace:`[​](https://rushjs.io/pages/developer/selecting_subsets/#subspace-members-subspace "Direct link to subspace-members-subspace") The [subspaces](https://rushjs.io/pages/advanced/subspaces/) feature enables Rush projects to be grouped into subspaces that install using their own PNPM lockfile. The `subspace:` selector matches all projects belonging to a given subspace. Example: # Build all projects belonging to the "install-test" subspace, as well# as their dependencies:rush build --to subspace:install-test ### Tagged projects: `tag:`[​](https://rushjs.io/pages/developer/selecting_subsets/#tagged-projects-tag "Direct link to tagged-projects-tag") Rush [project tags](https://rushjs.io/pages/developer/project_tags/) enable you to define arbitrary collections of projects, which can then be referenced using the `tag:` selector. Examples: # Build all projects that were tagged with the "shipping" project tag.rush build --to tag:shipping # Print a report showing the set of projects# that have the "frontend-team-libs" project tag.rush list --only tag:frontend-team-libs --detailed Combining parameters[​](https://rushjs.io/pages/developer/selecting_subsets/#combining-parameters "Direct link to Combining parameters") ----------------------------------------------------------------------------------------------------------------------------------------- * You can combine any of the selection parameters on a single command line. The result is always the union of each individual selection. * The same parameter can be specified multiple times. For example: `rush build --only A --only B --only C` will select `A`, `B`, and `C` * Note that Rush does not provide any parameter that would reduce the selection. This is an intentional design choice; in [#1241](https://github.com/microsoft/rushstack/issues/1241) we'll implement personal tags for building up more complex selections.) Here's a more complex combined command-line: rush build --only A --impacted-by-except B --to F The projects selected by this example are `A`, `C`, `D`, `E`, and `F`: ![rush build --only A --impacted-by-except B --to F](https://rushjs.io/images/docs/selection-multi.svg) See also[​](https://rushjs.io/pages/developer/selecting_subsets/#see-also "Direct link to See also") ----------------------------------------------------------------------------------------------------- * [Incremental builds](https://rushjs.io/pages/advanced/incremental_builds/) * [Using watch mode](https://rushjs.io/pages/advanced/watch_mode/) * [Using project tags](https://rushjs.io/pages/developer/project_tags/) * [rush build](https://rushjs.io/pages/commands/rush_build/) * [rush rebuild](https://rushjs.io/pages/commands/rush_rebuild/) * [Selection parameters](https://rushjs.io/pages/developer/selecting_subsets/#selection-parameters) * [\--to](https://rushjs.io/pages/developer/selecting_subsets/#--to) * [\--to-except](https://rushjs.io/pages/developer/selecting_subsets/#--to-except) * [\--from](https://rushjs.io/pages/developer/selecting_subsets/#--from) * [\--impacted-by (unsafe)](https://rushjs.io/pages/developer/selecting_subsets/#--impacted-by-unsafe) * [\--impacted-by-except (unsafe)](https://rushjs.io/pages/developer/selecting_subsets/#--impacted-by-except-unsafe) * [\--only (unsafe)](https://rushjs.io/pages/developer/selecting_subsets/#--only-unsafe) * [Selectors](https://rushjs.io/pages/developer/selecting_subsets/#selectors) * [Project name](https://rushjs.io/pages/developer/selecting_subsets/#project-name) * [Current folder: `.`](https://rushjs.io/pages/developer/selecting_subsets/#current-folder-) * [Modified projects: `git:`](https://rushjs.io/pages/developer/selecting_subsets/#modified-projects-git) * [Subspace members: `subspace:`](https://rushjs.io/pages/developer/selecting_subsets/#subspace-members-subspace) * [Tagged projects: `tag:`](https://rushjs.io/pages/developer/selecting_subsets/#tagged-projects-tag) * [Combining parameters](https://rushjs.io/pages/developer/selecting_subsets/#combining-parameters) * [See also](https://rushjs.io/pages/developer/selecting_subsets/#see-also) --- # Deploying projects | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/deploying/#docusaurus_skipToContent_fallback) On this page Suppose that your monorepo includes a Node.js service that we want to deploy to a web server. For example, let's say the Node.js service is a local Rush project called `app1`, and the repo is organized as follows: * **apps/app1**: * depends on `ext-lib7` (from NPM) and `lib3` (a local project) * dev dependencies on `ext-tool8` (from NPM) and `tool6` (a local project) * **apps/app2**: depends on `lib3` and `lib4` * **libraries/lib3**: depends on `lib5` * **libraries/lib4**: no dependencies * **libraries/lib5**: peer dependency on `ext-lib7` * **tools/tool6**: no dependencies One solution might be to run `rush install` and `rush build`, and then copy the entire monorepo to the server. However, this could potentially include many extraneous files and NPM packages. Instead we would like to copy only `app1` and its regular dependencies (`ext-lib7`, `lib3`, `lib5`). We do not want to include dev dependencies such as `ext-tool8`. The [rush deploy](https://rushjs.io/pages/commands/rush_deploy/) command calculates this set of files and copies them to a target folder, which you can then upload to your server. Configuring "rush deploy"[​](https://rushjs.io/pages/maintainer/deploying/#configuring-rush-deploy "Direct link to Configuring "rush deploy"") ----------------------------------------------------------------------------------------------------------------------------------------------- The `rush deploy` command reads its settings from a config file [common/config/rush/deploy.json](https://rushjs.io/pages/configs/deploy_json/) . This config file is not created by `rush init`. Instead, you create the file using [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/) . Continuing our example, we can create the file using this command: # Create common/config/rush/deploy.json and configure it to deploy "app1"rush init-deploy --project app1 After the file **deploy.json** is created, open it in your editor and adjust the settings as appropriate. Then commit this file to Git. Preparing a deployment[​](https://rushjs.io/pages/maintainer/deploying/#preparing-a-deployment "Direct link to Preparing a deployment") ---------------------------------------------------------------------------------------------------------------------------------------- To copy the files to the deployment target folder, you would use these commands: # Install dependenciesrush install# Build the monoreporush build# Copy app1 and its dependencies to the default target folder: common/deploy/rush deploy This will prepare a deployment by copying `app1` and its dependencies the target folder. The copied files will be organized similarly to the monorepo's folder structure: * **common/deploy/apps/app1/...** * **common/deploy/common/temp/node\_modules/ext-lib7/...** * **common/deploy/libraries/lib3/...** * **common/deploy/libraries/lib4/...** You can test that the deployment worked correctly by executing `app1` from within the deployment target folder: # Change to the app1 location under the target foldercd common/deploy/apps/app1# Invoke the package.json script that starts the web servicerushx start If the project fails to run (but worked correctly from its original location **apps/app1**), then you many need to tune the settings in **deploy.json**. Once you've confirmed that the project works correctly, the next step is to upload the **common/deploy** subtree to your server machine. Handling links[​](https://rushjs.io/pages/maintainer/deploying/#handling-links "Direct link to Handling links") ---------------------------------------------------------------------------------------------------------------- The **common/deploy** subtree will have symbolic links created by `rush install`. For example, if you are using the PNPM package manager, then **common/deploy/apps/app1/node\_modules/ext-lib7** may be a symlink to a folder under the **common/deploy/common/temp/node\_modules/.pnpm/...** path. Correctly replicating these links can be problematic for upload tools such as `tar` or `ftp`. The **deploy.json** config file provides a setting `linkCreation` that offers choices for handling links: * `"default"`: Create the links while copying the files; this is the default behavior. Use this setting if your file copy tool can handle links correctly. * `"script"`: A Node.js script called **create-links.js** will be written to the target folder. Use this setting to create links on the server machine, after the files have been uploaded. * `"none"`: Do nothing; some other tool may create the links later, based on the **deploy-metadata.json** file. The **deploy-metadata.json** file is written to the deployment target folder and contains a full inventory of links that need to be created. It might look something like this: { "scenarioName": "deploy.json", "mainProjectName": "app1", "links": [ { "kind": "folderLink", "linkPath": "common/deploy/apps/app1/node_modules/ext-lib7", "targetPath": "common/deploy/common/temp/node_modules/.pnpm/registry.npmjs.org/ext-lib7/1.0.0/node_modules/ext-lib7" }, . . . ]} If you specify `"linkCreation": "script"` then `rush deploy` will create the **common/deploy** folder without any links. After you have uploaded this folder to your server machine, you can then invoke the script to create the links: # Invoke this command on the server machine, after the files have been uploadednode create-links.js create > NOTE: When using `"linkCreation": "script"`, the current implementation does not yet generate the **node\_modules/.bin** command-line binaries. If you're interested in contributing a fix, see [this PR comment](https://github.com/microsoft/rushstack/pull/2010#issuecomment-656900649) > for a suggested solution. Including additional projects[​](https://rushjs.io/pages/maintainer/deploying/#including-additional-projects "Direct link to Including additional projects") ------------------------------------------------------------------------------------------------------------------------------------------------------------- Continuing our example, suppose that we want to include `app1` and `app2` together as a single deployment. Since `app2` is not a dependency of `app1`, it will not be included automatically. We can consider `app1` to be the "main project" (listed in `deploymentProjectNames`), and then declare `app2` as an "additional project". The config file would look like this: **common/config/rush/deploy.json** { . . . // The main project "deploymentProjectNames": ["app1"], . . . "projectSettings": [ { "projectName": "app1", // When deploying "app1", include "app2". We need to add this explicitly because // "app2" is not a dependency of "app1". "additionalProjectsToInclude": [ "app2" ] } ]} Multiple deployments using the same config file[​](https://rushjs.io/pages/maintainer/deploying/#multiple-deployments-using-the-same-config-file "Direct link to Multiple deployments using the same config file") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Continuing our example, suppose that instead we want `app1` and `app2` to be deployed separately to two different web servers. If the settings are the same, we can simply add both of them to the `deploymentProjectNames` array, like this: **common/config/rush/deploy.json** . . . "deploymentProjectNames": [ "app1", "app2" ], . . . When performing the deployment, the `--project` parameter selects which project to deploy. For example: # Copy app1 and its dependencies to /mnt/deploy/app1rush deploy --project app1 --target-folder /mnt/deploy/app1# Copy app2 and its dependencies to /mnt/deploy/app2rush deploy --project app2 --target-folder /mnt/deploy/app2 The `--target-folder` parameter copies the files to a custom location instead of the **common/deploy/** default folder. Multiple deployments using different config files[​](https://rushjs.io/pages/maintainer/deploying/#multiple-deployments-using-different-config-files "Direct link to Multiple deployments using different config files") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Continuing our example, suppose that `app2` deploys separately and it requires different settings from `app1`. For example, suppose that we want `"linkCreation": "default"` for `app1`, but `"linkCreation": "script"` for `app2`. We will create two config files: * **common/config/rush/deploy.json** - the default scenario file, which we'll use for `app1` * **common/config/rush/deploy-app2-example.json** -- the `app2-example` scenario, which we will use for `app2` Both of these files can be created using `rush init-deploy`: # Create common/config/rush/deploy.jsonrush init-deploy --project app1# Create common/config/rush/deploy-app2-example.jsonrush init-deploy --project app2 --scenario app2-example After editing **deploy-app2-example.json** to specify `"linkCreation": "script"`, we can now use the `--scenario` parameter with `rush deploy`: # Copy app1 and its dependencies to /mnt/deploy/app1# Uses scenario file: common/config/rush/deploy.jsonrush deploy --target-folder /mnt/deploy/app1# Copy app2 and its dependencies to /mnt/deploy/app2# Uses scenario file: common/config/rush/deploy-app2-example.jsonrush deploy --target-folder /mnt/deploy/app2 --scenario app2-example Note that the `--project` parameter is not needed with `rush deploy` because each config file has only one project in its `"deploymentProjectNames"` array. See also[​](https://rushjs.io/pages/maintainer/deploying/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------- * [common/config/rush/deploy.json](https://rushjs.io/pages/configs/deploy_json/) config file * [rush deploy](https://rushjs.io/pages/commands/rush_deploy/) command-line parameters * [rush init-deploy](https://rushjs.io/pages/commands/rush_init-deploy/) command-line parameters * [Configuring "rush deploy"](https://rushjs.io/pages/maintainer/deploying/#configuring-rush-deploy) * [Preparing a deployment](https://rushjs.io/pages/maintainer/deploying/#preparing-a-deployment) * [Handling links](https://rushjs.io/pages/maintainer/deploying/#handling-links) * [Including additional projects](https://rushjs.io/pages/maintainer/deploying/#including-additional-projects) * [Multiple deployments using the same config file](https://rushjs.io/pages/maintainer/deploying/#multiple-deployments-using-the-same-config-file) * [Multiple deployments using different config files](https://rushjs.io/pages/maintainer/deploying/#multiple-deployments-using-different-config-files) * [See also](https://rushjs.io/pages/maintainer/deploying/#see-also) --- # Custom commands | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/custom_commands/#docusaurus_skipToContent_fallback) On this page If your toolchain has special modes or features, you can expose these as custom commands or parameters for the Rush tool. Defining custom commands and parameters[​](https://rushjs.io/pages/maintainer/custom_commands/#defining-custom-commands-and-parameters "Direct link to Defining custom commands and parameters") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- These are defined in the config file **common/config/rush/command-line.json**. Your config file should conform to the [command-line.schema.json](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/command-line.schema.json) schema. Consider this sample: { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", "commands": [ { /** * (Required) Determines the type of custom command. * Rush's "bulk" commands are invoked separately for each project. Rush will look in * each project's package.json file for a "scripts" entry whose name matches the * command name. By default, the command will run for every project in the repo, * according to the dependency graph (similar to how "rush build" works). * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. */ "commandKind": "bulk", "name": "import-strings", "summary": "Imports translated strings into each project.", "description": "Requests translated strings from the translation service and imports them into each project.", "enableParallelism": true }, { /** * (Required) Determines the type of custom command. * Rush's "global" commands are invoked once for the entire repo. */ "commandKind": "global", "name": "deploy-app", "summary": "Deploys the application", "description": "Run this command to deploy the application", "shellCommand": "node common/scripts/deploy-app.js" } ], "parameters": [ { /** * (Required) Determines the type of custom parameter. * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. */ "parameterKind": "flag", "longName": "--ship", "shortName": "-s", "description": "Perform a production build, including minification and localization steps", "associatedCommands": [ "build", "rebuild", "import-strings" ], }, { "parameterKind": "flag", "longName": "--minimal", "shortName": "-m", "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", "associatedCommands": [ "build", "rebuild" ] }, { /** * (Required) Determines the type of custom parameter. * "A "choice" is a custom command-line parameter whose argument must be chosen from a list * of allowable alternatives. */ "parameterKind": "choice", "longName": "--locale", "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", "associatedCommands": [ "build", "rebuild", "import-strings" ], "alternatives": [ { "name": "en-us", "description": "US English" }, { "name": "fr-fr", "description": "French (France)" }, { "name": "es-es", "description": "Spanish (Spain)" }, { "name": "zh-cn", "description": "Chinese (China)" } ] } ]} **Custom commands:** You can define your own commands that are similar to Rush's built-in command verbs (e.g. `rush build`, `rush check`, etc). There are two kinds: * **bulk command:** These commands run individually for each project in the repo, similar to how `rush build` works. If you set `"enableParallelism": true`, projects can be processed in parallel. Bulk commands can execute a script defined in each project's **package.json** file, or a single script file specified by the (optional) `shellCommand` field. * **global command:** These commands run once for the entire repo, by executing a single script file specified by the (required) `shellCommand` field. You can also define your own command-line "parameters". A parameter can be associated with one or more commands via its `associatedCommands` list. You can even associate your custom parameters with Rush's own built-in `build` and `rebuild` commands. In the above example, we associate the `--ship` parameter with `rush build`, `rush rebuild`, and our custom `rush import-strings`. Currently three kinds of `parameterKind` are supported: * **flag parameter**: A "flag" is a simple switch, for example `--production`. * **string parameter**: A parameter that includes a text string argument, for example `--title "Hello, world!"`. * **string list parameter**: A string parameter that can be specified multiple times, for example `--category docs --category dashboard` * **choice parameter**: Similar to a string but the argument must come from a list of supported alternatives, for example `--locale fr-fr`. * **integer parameter**: A parameter that includes an integer argument, for example `--pull-request 1234`. * **integer list parameter**: An integer parameter that can be specified multiple times, for example `--pr 1234 --pr 1235 --pr 1236` More parameter kinds may be supported in the future. (They are parsed using the [ts-command-line](https://www.npmjs.com/package/@microsoft/ts-command-line) library which supports other parameter kinds that could be exposed.) Using custom commands and options[​](https://rushjs.io/pages/maintainer/custom_commands/#using-custom-commands-and-options "Direct link to Using custom commands and options") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Your custom definitions and their descriptions will be incorporated into Rush's command-line help (when invoked under your repo working folder). Continuing the above example, if we run `rush import-strings --help` we'll now see something like this: Rush Multi-Project Build Tool 5.1.0 - https://rushjs.iousage: rush import-strings [-h] [-p COUNT] [-t PROJECT1] [--to-version-policy VERSION_POLICY_NAME] [-f PROJECT2] [-v] [-s] [--locale {en-us,fr-fr,es-es,zh-cn}]Requests translated strings from the translation service and imports theminto each project.Optional arguments: -h, --help Show this help message and exit. -p COUNT, --parallelism COUNT Specify the number of concurrent build processes The value "max" can be specified to indicate the number of CPU cores. If this parameter omitted, the default value depends on the operating system and number of CPU cores. -t PROJECT1, --to PROJECT1 Run command in the specified project and all of its dependencies --to-version-policy VERSION_POLICY_NAME Run command in all projects with the specified version policy and all of their dependencies -f PROJECT2, --from PROJECT2 Run command in all projects that directly or indirectly depend on the specified project -v, --verbose Display the logs during the build, rather than just displaying the build status summary -s, --ship Perform a production build, including minification and localization steps --locale {en-us,fr-fr,es-es,zh-cn} Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds. How to implement a custom command/parameter? For global commands, Rush simply invokes their `shellCommand` and passes the parameters along. For bulk commands, Rush can alternatively look for a corresponding script name in your **package.json** file. Suppose we have something like this: **example/package.json** { "name": "example", "version": "1.0.0", "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { "import-strings": "./node_modules/.bin/loc-importer", "build": "./node_modules/.bin/heft build" }} If we run `rush import-strings --locale fr-fr`, then Rush will read the "import-strings" script body and execute it like this: ./node_modules/.bin/loc-importer --locale fr-fr (Rush directly executes it using your shell; it does not rely on `npm run`.) Since this choice parameter has a default value, if we run `rush import-strings`, then **loc-importer** is executed like this: ./node_modules/.bin/loc-importer --locale en-us In other words, Rush's custom parameters are simply appended to the **package.json** script body. This means you may run into trouble if your script body uses shell expressions such as "`rimraf ./lib && rimraf ./temp`" which don't support these parameters, or need them to be inserted in the middle of the string. This is by design: We don't recommend writing nontrivial build scripts inside a JSON string. Instead, it's better to move this operation into a proper script file that can be commented and reviewed. As your monorepo grows, you'll probably also want to move that script into a reusable library that can be shared across projects. See also[​](https://rushjs.io/pages/maintainer/custom_commands/#see-also "Direct link to See also") ---------------------------------------------------------------------------------------------------- * [command-line.json](https://rushjs.io/pages/configs/command-line_json/) documentation * [Defining custom commands and parameters](https://rushjs.io/pages/maintainer/custom_commands/#defining-custom-commands-and-parameters) * [Using custom commands and options](https://rushjs.io/pages/maintainer/custom_commands/#using-custom-commands-and-options) * [See also](https://rushjs.io/pages/maintainer/custom_commands/#see-also) --- # Enabling phased builds | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/phased_builds/#docusaurus_skipToContent_fallback) On this page By default, Rush builds each project by running a build script (similar to `npm run build`) separately in each project folder, processing projects in parallel when the dependency graph allows. From Rush's perspective, everything that happens inside that build script is a single operation. _Phased builds_ are a way to increase parallelism, by defining individual operations as _phases_ that can be executed on a project. As an example, if project B depends on project A, we could first build project A, and then begin building project B while running the unit tests for project A in parallel. > NOTE: Phased builds are built on top of, and require, the build cache feature -- if you haven't already enabled the build cache for your monorepo, see [Enabling build cache](https://rushjs.io/pages/maintainer/build_cache/) > . Define phases[​](https://rushjs.io/pages/maintainer/phased_builds/#define-phases "Direct link to Define phases") ----------------------------------------------------------------------------------------------------------------- In `common/config/rush/command-line.json`, add a section `"phases"`, as follows: { "phases": [ { /** * The name of the phase. Note that this value must start with the \"_phase:\" prefix. */ "name": "_phase:build", /** * The dependencies of this phase. */ "dependencies": { "upstream": ["_phase:build"] }, /** * Normally Rush requires that each project's package.json has a \"scripts\" entry matching the phase name. To disable this check, set \"ignoreMissingScript\" to true. */ "ignoreMissingScript": true, /** * By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is set to \"true\", Rush will return a zero exit code if warnings occur during the execution of this phase. */ "allowWarningsOnSuccess": false }, { "name": "_phase:test", "dependencies": { "self": ["_phase:build"] }, "ignoreMissingScript": true, "allowWarningsOnSuccess": false } ]} In this example, we define two phases -- `_phase:build` and `_phase:test`. The `_phase:build` operation depends on the `_phase:build` operation of its upstream projects (using the traditional Rush dependency graph). The `_phase:test` operation does not depend on any upstream projects, but requires the `_phase:build` operation of its _own_ project to be completed first. Note that phase names must start with `_phase:`. Individual projects can choose not to implement a phase (if `ignoreMissingScript` is enabled), but they cannot define their own phases, or change the dependencies of phases. This ensures that phases will behave consistently within your monorepo, regardless of what subset of projects you are building. Redefine the build and test commands[​](https://rushjs.io/pages/maintainer/phased_builds/#redefine-the-build-and-test-commands "Direct link to Redefine the build and test commands") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- In `common/config/rush/command-line.json`, in the `"commands"` section, redefine the `"build"` command to be a `phased` command instead of a `bulk` command, and specify what phases you would like it to run. In the example below we also define a `"test"` command. { "commands": [ { "commandKind": "phased", "name": "build", "phases": ["_phase:build"], "enableParallelism": true, "incremental": true }, // No need to define "rebuild", by default, it is the same as build // but with incremental=false. { "commandKind": "phased", "name": "test", "summary": "Build and test all projects.", "phases": ["_phase:build", "_phase:test"], "enableParallelism": true, "incremental": true }, { "commandKind": "phased", "name": "retest", "summary": "Build and test all projects.", "phases": ["_phase:build", "_phase:test"], "enableParallelism": true, "incremental": false } ]} This command definition shows off another useful feature of phased builds: we can create our "phase" building blocks and then build commands out of them. Instead of `rush build` running builds and tests for all projects, we can define `rush build` to mean "build everything without tests", and `rush test` to mean "build everything and run tests". Assign parameters to phases[​](https://rushjs.io/pages/maintainer/phased_builds/#assign-parameters-to-phases "Direct link to Assign parameters to phases") ----------------------------------------------------------------------------------------------------------------------------------------------------------- If you have defined any custom parameters for your build command in `command-line.json`, you'll now need to associate them to phases, so Rush knows which phases can accept your parameter. Here are some examples: { "parameters": [ { "longName": "--production", "parameterKind": "flag", "description": "Perform a production build, including minification and localization steps", "associatedCommands": ["build", "rebuild", "test", "retest"], "associatedPhases": ["_phase:build"] }, { "longName": "--update-snapshots", "parameterKind": "flag", "description": "Update unit test snapshots for all projects", "associatedCommands": ["test", "retest"], "associatedPhases": ["_phase:test"] } ]} Here, we've defined one flag (`--production`) that can be specified on all 4 variations of our build command, but it will only be passed to the _build_ phase. And, we've defined another flag (`--update-snapshots`) that can be specified only on the `test` and `retest` commands, and is only passed to the `test` phase. So, if we were to execute this command: rush test --production --update-snapshots Rush will pass the `--production` parameter to the `_phase:build` script for each project, and then pass the `--update-snapshots` parameter to the `_phase:test` script for each project. Add the phase scripts to your projects[​](https://rushjs.io/pages/maintainer/phased_builds/#add-the-phase-scripts-to-your-projects "Direct link to Add the phase scripts to your projects") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Within the `package.json` file for every project in your monorepo, add the new `_phase:` scripts: { "scripts": { "_phase:build": "heft build --clean", "_phase:test": "heft test --no-build", "build": "heft build --clean", "test": "heft test --clean" }} The example above attempts to align developer expectations for the `build` and `test` commands: * Moving into the project folder and running `rushx build` cleans and builds the project, without testing. * Moving into the project folder and running `rushx test` cleans, builds, and tests the project. * Running `rush build --only ` cleans and builds the project, without testing. * Running `rush test --only ` cleans, builds, and tests the project. Where possible, for any custom phases you define, keep this pattern in mind -- what's important isn't that phases are implemented identically to rushx commands, but rather that `rush ` and `rushx ` produce similar results, if applicable. Some projects may not have any meaningful work to do for a phase, in which case you can define it as an empty operation (`""`), or leave it off entirely, if `ignoreMissingScript` was specified in the phase definition. Define per-phase output folder names[​](https://rushjs.io/pages/maintainer/phased_builds/#define-per-phase-output-folder-names "Direct link to Define per-phase output folder names") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Within the `rush-project.json` configuration file of each project (or, preferably, each rig profile), redefine your `operationSettings` so that each folder is specified in only one phase. For example: { "operationSettings": [ // Old configuration (before phases) { "operationName": "build", "outputFolderNames": ["lib", "lib-commonjs", "dist", "temp"] }, // New configuration (after phases) { "operationName": "_phase:build", "outputFolderNames": ["lib", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", "outputFolderNames": ["temp/coverage", "temp/jest-reports"] } ]} Note how there's no overlap between the output folders specified by `_phase:build` and `_phase:test` -- this is an important new requirement for phased builds. In general, it's not possible for Rush to reliably cache the output of an operation if that output can be modified by a different operation, so you should structure your operations such that if `_phase:build` produces a `"lib"` folder, no other operation will put output in that folder. > The phased builds feature is still under development. Feedback is welcome! > > Some relevant GitHub issues to follow: > > * [Design proposal: "phased" custom commands](https://github.com/microsoft/rushstack/issues/2300) > * [Define phases](https://rushjs.io/pages/maintainer/phased_builds/#define-phases) * [Redefine the build and test commands](https://rushjs.io/pages/maintainer/phased_builds/#redefine-the-build-and-test-commands) * [Assign parameters to phases](https://rushjs.io/pages/maintainer/phased_builds/#assign-parameters-to-phases) * [Add the phase scripts to your projects](https://rushjs.io/pages/maintainer/phased_builds/#add-the-phase-scripts-to-your-projects) * [Define per-phase output folder names](https://rushjs.io/pages/maintainer/phased_builds/#define-per-phase-output-folder-names) --- # Enabling the build cache | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/build_cache/#docusaurus_skipToContent_fallback) On this page Rush has always supported an [incremental build](https://rushjs.io/pages/advanced/incremental_builds/) analyzer that enables `rush build` to skip projects whose input files have not changed since the last build. It can also be used with custom commands by enabling the `incremental` flag in **custom-commands.json**. We call this the **"output preservation"** strategy for incremental builds. Because the build output is not saved anywhere, a full rebuild is generally still required when checking out a different branch. Rush's **build cache** improves on this by creating a tar archive of each project's build outputs. The archive is cached so that later, if `rush build` can find a match in the cache, it can extract the archive instead of building that project. This can provide dramatic speedups, for example reducing a 30 minute build time to 30 seconds. We call this the **"cache restoration"** strategy for incremental builds. The build cache archives are stored in two places: * **In a cache folder on your local disk.** This way you can switch between different branches without losing your incremental build state. You can even configure a centralized folder to be shared between multiple enlistments on your machine. The default location is **common/temp/build-cache**. * **In a cloud-hosted storage container. (Optional)** In a typical setup, the CI system would be configured to write to cloud storage, and individual users are granted read-only access. For example, each time a PR is merged into the `main` branch, the CI system builds that baseline and uploads it to cloud storage. Even for a user who is doing `git clone` for the first time, their `rush build` will be very fast. Enabling the local disk cache[​](https://rushjs.io/pages/maintainer/build_cache/#enabling-the-local-disk-cache "Direct link to Enabling the local disk cache") --------------------------------------------------------------------------------------------------------------------------------------------------------------- The build cache feature is enabled using the [build-cache.json](https://rushjs.io/pages/configs/build-cache_json/) config file. You can copy the template from the website or use `rush init` to create this file. To enable the basic local disk cache, add these two settings: **common/config/rush/build-cache.json** { . . . /** * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. * * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. */ "buildCacheEnabled": true, /** * (Required) Choose where project build outputs will be cached. * * Possible values: "local-only", "azure-blob-storage", "amazon-s3" */ "cacheProvider": "local-only", . . .} > **Upgrade note:** Early releases of this feature were enabled using the `"buildCache": true` setting in **experiments.json**. This has been superseded by `"buildCacheEnabled"` in **build-cache.json**. Configuring project output folders[​](https://rushjs.io/pages/maintainer/build_cache/#configuring-project-output-folders "Direct link to Configuring project output folders") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ With only this change, if you run `rush rebuild --verbose`, you will see this warning: Project does not have a rush-project.json configuration file, or one provided by a rig,so it does not support caching. The build cache needs to know which folders should be stored in the tar archive. Those details vary between toolchains, and are thus configured separately for each project using the [rush-project.json](https://rushjs.io/pages/configs/rush-project_json/) config file. For example: **/config/rush-project.json** { . . . /** * Specify the folders where your toolchain writes its output files. If enabled, the Rush build cache will * restore these folders from the cache. * * The strings are folder names under the project root folder. These folders should not be tracked by Git. * They must not contain symlinks. */ "projectOutputFolderNames": ["lib", "dist"] . . .} Configuring project inputs[​](https://rushjs.io/pages/maintainer/build_cache/#configuring-project-inputs "Direct link to Configuring project inputs") ------------------------------------------------------------------------------------------------------------------------------------------------------ By default, the following inputs are incorporated into Rush's cache key. In other words, if any of these things changes, then the project must be rebuilt: * the hash of the source files that are under the project's folder, ignoring any files excluded by `.gitignore` * the hashes of source files under other workspace projects that are dependencies of the project (applies to **cache restoration** strategy but not **output preservation** strategy) * the versions of all external NPM packages that your project depends on, including indirect dependencies * the Rush command-line parameters used to perform the operation These details can be customized using the [rush-project.json](https://rushjs.io/pages/configs/rush-project_json/) config file. For example, you can include/exclude certain glob patterns, or specify environment variables that affect the build output. It's recommended to use a [rig package](https://heft.rushstack.io/pages/intro/rig_packages/) to avoid having to copy **rush-project.json** into every project folder. > **Important:** Configure these settings carefully. If a project inputs/outputs are not accurately specified, then the build cache may produce incorrect or inconsistent results. For example, the restored output may be missing some files. Or it may be different from what would be produced by a full rebuild. Such problems can be difficult to reproduce and troubleshoot. > > If you suspect that the Rush build cache may be misconfigured, try the [rush-audit-cache-plugin](https://www.npmjs.com/package/rush-audit-cache-plugin) > . It monitors file writes during the build to identify inputs that are not part of your cache key. Testing the build cache[​](https://rushjs.io/pages/maintainer/build_cache/#testing-the-build-cache "Direct link to Testing the build cache") --------------------------------------------------------------------------------------------------------------------------------------------- Now you should see projects being cached as shown in this sample log output: rush build --verbose . . .==[ example-project ]==============================================[ 1 of 5 ]==This project was not found in the build cache.Invoking: heft test --clean. . .Caching build output folders: libSuccessfully set cache entry."example-project" completed successfully in 11.27 seconds. When we run the same command a second time, Rush extracts the archive instead of invoking the build task: rush build --verbose . . .==[ example-project ]==============================================[ 1 of 5 ]==Build cache hit.Clearing cached folders: lib, distSuccessfully restored output from the build cache.example-project was restored from the build cache. Note that `rush rebuild` will not read from cache, only `rush build` does. To disable writing from cache during `rush rebuild`, set the [`RUSH_BUILD_CACHE_WRITE_ALLOWED`](https://rushjs.io/pages/configs/environment_vars/) environment variable to `0`. By default, the cached tar archives are stored under your **common/temp/build-cache** folder (and thus will be cleaned by `rush purge`). It is safe to delete these files. Enabling cloud storage[​](https://rushjs.io/pages/maintainer/build_cache/#enabling-cloud-storage "Direct link to Enabling cloud storage") ------------------------------------------------------------------------------------------------------------------------------------------ Currently the `cacheProvider` setting provides three choices: * `"local-only"`: no cloud storage; archives are only kept on a local disk folder * `"azure-blob-storage"`: Microsoft Azure [blob storage container](https://docs.microsoft.com/en-us/azure/storage/blobs/) * `"amazon-s3"`: Amazon [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) (The above providers are [modeled as Rush plugins](https://github.com/microsoft/rushstack/tree/main/rush-plugins) . Custom build cache storage providers can be implemented in the same way.) As one example, here's how to configure an Azure blob container: **common/config/rush/build-cache.json** { . . . /** * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. * * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. */ "buildCacheEnabled": true, /** * (Required) Choose where project build outputs will be cached. * * Possible values: "local-only", "azure-blob-storage", "amazon-s3" */ "cacheProvider": "azure-blob-storage", /** * Use this configuration with "cacheProvider"="azure-blob-storage" */ "azureBlobStorageConfiguration": { /** * (Required) The name of the the Azure storage account to use for build cache. */ "storageAccountName": "example", /** * The name of the container in the Azure storage account to use for build cache. */ "storageContainerName": "my-container" /** * If set to true, allow writing to the cache. Defaults to false. */ "isCacheWriteAllowed": false . . . Note that we have set `"isCacheWriteAllowed": false` to prevent regular users from writing to the container. (Later, we will use an environment variable to override this for our CI job.) User authentication[​](https://rushjs.io/pages/maintainer/build_cache/#user-authentication "Direct link to User authentication") --------------------------------------------------------------------------------------------------------------------------------- If security is not a priority for your repo, you can simplify user setup by configuring your storage container to allow unauthenticated anonymous access. The container is accessed via an HTTPS URL containing randomized hashes which are difficult to guess without access to your Git repo. This provides rudimentary [security through obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity) . A more security-conscious organization however will prefer to require authentication even for read-only access. Rush provides a [rush update-cloud-credentials](https://rushjs.io/pages/commands/rush_update-cloud-credentials/) command to make this easy for users to set up: rush update-cloud-credentials --interactive Rush Multi-Project Build Tool 5.45.6 (unmanaged) - https://rushjs.ioNode.js version is 12.20.1 (LTS)Starting "rush update-cloud-credentials" ╔═════════════════════════════════════════════════════════════════════════╗ ║ To sign in, use a web browser to open the page ║ ║ https://microsoft.com/devicelogin and enter the code XAYBQEGRK ║ ║ to authenticate. ║ ╚═════════════════════════════════════════════════════════════════════════╝ The credentials are stored in the user's home directory under `~/.rush-user/credentials.json`. CI setup[​](https://rushjs.io/pages/maintainer/build_cache/#ci-setup "Direct link to CI setup") ------------------------------------------------------------------------------------------------ In a typical configuration, users have read-only access and the cache is populated by an automation account; for example, a CI job that builds your `main` branch after each PR is merged. In our example above, the `"isCacheWriteAllowed": false` setting is what prevents users from writing to the cache. The CI job can override this by setting the [RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED](https://rushjs.io/pages/configs/environment_vars/) environment variable, and by providing credentials for the CI environment in the [RUSH\_BUILD\_CACHE\_CREDENTIAL](https://rushjs.io/pages/configs/environment_vars/) environment variable. ### Credentials[​](https://rushjs.io/pages/maintainer/build_cache/#credentials "Direct link to Credentials") #### Azure Storage[​](https://rushjs.io/pages/maintainer/build_cache/#azure-storage "Direct link to Azure Storage") For Azure Blob Storage, `RUSH_BUILD_CACHE_CREDENTIAL` must be a SAS token serialized as query parameters. See [this article](https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview) for details about SAS tokens. You can obtain a SAS token via the [Settings > Access keys](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) page for your storage account. #### AWS[​](https://rushjs.io/pages/maintainer/build_cache/#aws "Direct link to AWS") For Amazon S3, `RUSH_BUILD_CACHE_CREDENTIAL` will be your AWS Access Key ID and AWS Secret Access Key separated by a colon, such as: `:`. You can also pass temporary session tokens required when assuming an IAM role: `::`. If `RUSH_BUILD_CACHE_CREDENTIAL` is not set, the build cache will attempt to read the environment vars `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` that are commonly set via the AWS CLI or other CI tooling. However, `RUSH_BUILD_CACHE_CREDENTIAL` will always take precedence if it exists. > The build cache feature is still under development. Feedback is welcome! > > Some relevant GitHub issues to follow: > > * [Build cache feature #2393](https://github.com/microsoft/rushstack/issues/2393) > - the original feature spec > * [Build Cache: split apart RUSH\_BUILD\_CACHE\_WRITE\_CREDENTIAL #2642](https://github.com/microsoft/rushstack/issues/2642) > > * [Allow project config to specify non-build-related files #2618](https://github.com/microsoft/rushstack/issues/2618) > > * ["tar" exited with code 1 while attempting to create the cache entry #2622](https://github.com/microsoft/rushstack/issues/2622) > * [Enabling the local disk cache](https://rushjs.io/pages/maintainer/build_cache/#enabling-the-local-disk-cache) * [Configuring project output folders](https://rushjs.io/pages/maintainer/build_cache/#configuring-project-output-folders) * [Configuring project inputs](https://rushjs.io/pages/maintainer/build_cache/#configuring-project-inputs) * [Testing the build cache](https://rushjs.io/pages/maintainer/build_cache/#testing-the-build-cache) * [Enabling cloud storage](https://rushjs.io/pages/maintainer/build_cache/#enabling-cloud-storage) * [User authentication](https://rushjs.io/pages/maintainer/build_cache/#user-authentication) * [CI setup](https://rushjs.io/pages/maintainer/build_cache/#ci-setup) * [Credentials](https://rushjs.io/pages/maintainer/build_cache/#credentials) --- # Enabling Prettier | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/enabling_prettier/#docusaurus_skipToContent_fallback) On this page The Rush Stack [lint strategy](https://rushstack.io/pages/heft_tasks/eslint/) recommends the [Prettier](https://prettier.io/) tool for ensuring consistent syntax across all source files. With this approach, ESLint and Prettier have complementary roles: Recommended ESLint usage: * ESLint enforces a set of rules for coding conventions. _Example: "Function names should be capitalized with camelCase."_ * Fixing these issues can break tests or API contracts. ESLint can cause build errors. * Rules are highly customizable -- different projects may require different rules. * Thus, we recommend to invoke ESLint separately for each project folder, as part of building that project. Recommended Prettier usage: * Prettier normalizes syntax formatting. _Example: indentation and comma placement_ * Fixing these issues should never affect the meaning of the code. Prettier can be run automatically and invisibly. * Prettier discourages customization -- one convention is good enough for the entire repo, if not the entire world. * Thus, we recommend applying Prettier globally for the entire repo. In this article we'll show how to configure Prettier to run automatically during `git commit`. We also suggest for developers to install the [Prettier extension for VS Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) , which formats files automatically whenever you save. Preparing for Prettier[​](https://rushjs.io/pages/maintainer/enabling_prettier/#preparing-for-prettier "Direct link to Preparing for Prettier") ------------------------------------------------------------------------------------------------------------------------------------------------ Before we get to the Git hook, first we need to configure Prettier, and get your existing files prettified. 1. Since Prettier will run for all files, its [config file](https://prettier.io/docs/en/configuration.html) goes at the root of the repo. Prettier allows many different names for this config file, but despite all that flexibility its JSON parser rejects code comments. Therefore it's recommended to use the `.js` file extension. **/.prettierrc.js** // Documentation for this file: https://prettier.io/en/configuration.htmlmodule.exports = { // We use a larger print width because Prettier's word-wrapping seems to be tuned // for plain JavaScript without type annotations printWidth: 110, // Use .gitattributes to manage newlines endOfLine: 'auto', // Use single quotes instead of double quotes singleQuote: true, // For ES5, trailing commas cannot be used in function parameters; it is counterintuitive // to use them for arrays only trailingComma: 'none'}; 2. You also need to make a `.prettierignore` file to tell Prettier which files to skip. Note that the Git hook will implicitly filter any files that are not committed to Git, however this is not the case for other tools such as the [Prettier extension for VS Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) . It is recommended to for `.prettierignore` to extend the same patterns used in `.gitignore`, like this: **/.prettierignore** #-------------------------------------------------------------------------------------------------------------------# Keep this section in sync with .gitignore#-------------------------------------------------------------------------------------------------------------------👋 (copy + paste your .gitignore file contents here) 👋#-------------------------------------------------------------------------------------------------------------------# Prettier-specific overrides#-------------------------------------------------------------------------------------------------------------------# Rush filescommon/changes/common/scripts/common/config/CHANGELOG.*# Package manager filespnpm-lock.yamlyarn.lockpackage-lock.jsonshrinkwrap.json# Build outputsdistlib# Prettier reformats code blocks inside Markdown, which affects rendered output*.md 3. Once the configuration is set up, next we need to invoke Prettier manually to reformat all the existing source files. You can fine-tune your `.prettierignore` configuration by examining the Git diff after performing this command. # Install prettier so you can invoke it manuallynpm install --global prettier# Run these commands from your repo root, since "." below refers to the current foldercd my-repo# See what files Prettier will operate on; use this to tune your .prettierignore rulesprettier . --list-different# When you are ready, this will bulk fix all existing source files in your repoprettier . --write The first time you run Prettier, it may produce a very large diff if you already have many files in your repo. In that case it's a good idea to merge a PR with just those changes. That will make it easier to review the PR for the next steps below. Git hook requirements[​](https://rushjs.io/pages/maintainer/enabling_prettier/#git-hook-requirements "Direct link to Git hook requirements") --------------------------------------------------------------------------------------------------------------------------------------------- Let's set up a [Git hook](https://rushjs.io/pages/maintainer/git_hooks/) that will invoke Prettier automatically whenever changes are committed. Keep in mind that the `git commit` command is a core operation that must always be quick and reliable: Developers may want to make commits to their branch without running `rush install` first. In some situations `rush install` cannot be run, because the branch may be in a partially working state. It seems that our Git hook should NOT rely on the usual monorepo installation mechanism. We could solve this by using Rush's [install-run.js](https://rushjs.io/pages/maintainer/enabling_ci_builds/) script to install the Prettier package on demand. But it turns out that we need to install several dependencies together: * `pretty-quick`: To speed up the operation, we'll use [pretty-quick](https://www.npmjs.com/package/pretty-quick) to calculate the subset of files that are staged for commit. Only those files need to processed. Prettier cannot do this part, because it doesn't interface with Git. * `prettier`: The `pretty-quick` tools has a peer dependency on Prettier's package. * **optional plugins:** If you use any plugins for Prettier, they need to be resolvable by the `prettier` package. For this situation, Rush's "autoinstaller" feature provides a convenient alternative to **install-run.js**. Enabling the Git hook[​](https://rushjs.io/pages/maintainer/enabling_prettier/#enabling-the-git-hook "Direct link to Enabling the Git hook") --------------------------------------------------------------------------------------------------------------------------------------------- 1. First, use the [rush init-autoinstaller](https://rushjs.io/pages/commands/rush_init-autoinstaller/) command to create an autoinstaller: # This creates the common/autoinstallers/rush-prettier/package.json file:rush init-autoinstaller --name rush-prettier 2. Install the dependencies and create the **pnpm-lock.yaml** file: cd common/autoinstallers/rush-prettier# Instead of running these commands, you could instead manually edit the# "dependencies" in the package.json filepnpm install prettierpnpm install pretty-quick# (If you need plugins, install them as well)# When you are finished, run this command to ensure that the# common/autoinstallers/rush-prettier/pnpm-lock.yaml file is up to daterush update-autoinstaller --name rush-prettier 3. You should now have two files **package.json** and **pnpm-lock.yaml** in your **common/autoinstallers/rush-prettier** folder. Add them to Git and commit them. git add package.jsongit add pnpm-lock.yamlgit commit -m "Create rush-prettier autoinstaller" 4. Next, we will create a `rush prettier` custom command that invokes the `pretty-quick` tool. Add this to the `"commands"` section of your **command-line.json** file: **common/config/rush/command-line.json** . . . "commands": [ { "name": "prettier", "commandKind": "global", "summary": "Used by the pre-commit Git hook. This command invokes Prettier to reformat staged changes.", "safeForSimultaneousRushProcesses": true, "autoinstallerName": "rush-prettier", // This will invoke common/autoinstallers/rush-prettier/node_modules/.bin/pretty-quick "shellCommand": "pretty-quick --staged" } . . .\ \ The `"autoinstallerName": "rush-prettier"` line ensures that our autoinstaller will install Prettier before the shell command is invoked. The shell command `pretty-quick --staged` will be invoked in the **common/autoinstallers/rush-prettier** folder.\ \ 5. After saving these changes, let's test our custom command by running `rush prettier`. The first time you should see Rush automatically performing a number of steps: (1) install the correct version of the Rush engine, (2) install the correct version of the PNPM package manager, (3) installing **rush-prettier/package.json** and its dependencies, (4) invoking `pretty-quick --staged`. However the second time you invoke it, the first 3 steps are up to date, so step (4) runs without any delay. Nice!\ \ Because `rush prettier` only processes files that are staged for commit, the report will most likely show:\ \ Found 0 changed files.Everything is awesome!\ \ 6. The last step is to add a Git hook that invokes `rush prettier` automatically whenever `git commit` is performed. To do this, create a file called **pre-commit** in the **common/git-hooks** folder:\ \ **common/git-hooks/pre-commit**\ \ #!/bin/sh# Called by "git commit" with no arguments. The hook should# exit with non-zero status after issuing an appropriate message if# it wants to stop the commit.# Invoke the "rush prettier" custom command to reformat files whenever they# are committed. The command is defined in common/config/rush/command-line.json# and uses the "rush-prettier" autoinstaller.node common/scripts/install-run-rush.js prettier || exit $?\ \ 7. Make the file executable: `chmod +x pre-commit`\ \ 8. To actually install the hook, run `rush install`.\ \ 9. Before finally merging your PR, you may want to run `prettier . --write` one last time to reformat any files that may have been modified before we installed the hook.\ \ \ You're done! Whenever changes are committed to Git, they will now be automatically prettified.\ \ Installing prettier plugins[​](https://rushjs.io/pages/maintainer/enabling_prettier/#installing-prettier-plugins "Direct link to Installing prettier plugins")\ \ ---------------------------------------------------------------------------------------------------------------------------------------------------------------\ \ Prettier supports [plugins](https://prettier.io/docs/en/plugins.html)\ , which can add new languages or formatting rules. If you choose to add prettier plugins to your setup, special care must be taken to ensure that all of the tooling that might call prettier will be able to load your prettier configuration:\ \ * `rush prettier` as configured in the steps above\ * Editors (VSCode, Webstorm, Sublime, etc.) that are configured to format on save\ * Jest and heft test, which use prettier to format snapshots\ \ Here's an example, using the `prettier-plugin-packagejson` plugin:\ \ 1. First, add the plugin package to your autoinstaller `package.json` file -- if configured as above, this will be `common/autoinstallers/rush-prettier/package.json`.\ \ { "dependencies": { "prettier-plugin-packagejson": "^2.2.18" }}\ \ 2. Update your autoinstaller's lockfile:\ \ rush update-autoinstaller --name rush-prettier\ \ 3. Add the _full path_ of your plugin folder to the `plugins` array in `.prettierrc.js`:\ \ module.exports = { // ... your other configuration goes here ... // , plugins: ['./common/autoinstallers/rush-prettier/node_modules/prettier-plugin-packagejson']};\ \ 4. Commit your autoinstaller and prettierrc changes.\ \ \ Note that after pulling this change, local developers will need to run `rush prettier` at least once to install the updated autoinstaller -- otherwise, their format-on-save functions and jest snapshot formatting may stop working. In practice this will fix itself after they perform at least one git commit and run the git hooks, but it may be worth notifying your team any time you do update prettier plugins this way.\ \ * [Preparing for Prettier](https://rushjs.io/pages/maintainer/enabling_prettier/#preparing-for-prettier)\ \ * [Git hook requirements](https://rushjs.io/pages/maintainer/enabling_prettier/#git-hook-requirements)\ \ * [Enabling the Git hook](https://rushjs.io/pages/maintainer/enabling_prettier/#enabling-the-git-hook)\ \ * [Installing prettier plugins](https://rushjs.io/pages/maintainer/enabling_prettier/#installing-prettier-plugins) --- # Enabling policies | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/setup_policies/#docusaurus_skipToContent_fallback) On this page The [rush-schema.json](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/rush.schema.json) JSON schema defines some additional settings you can specify in **rush.json**. projectFolderMinDepth: Controlling folder size[​](https://rushjs.io/pages/maintainer/setup_policies/#projectfoldermindepth-controlling-folder-size "Direct link to projectFolderMinDepth: Controlling folder size") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush repositories can grow very big. When you have lots of projects (and maybe several repositories), it's very useful to impose a standard structure that makes it immediately obvious which folders contain buildable projects. We suggest a convention like this: * In the repo, top-level folders are "category folders" (e.g. "**~/demo/libraries**") * Project folders are always nested under a category folder (e.g. "**~/demo/libraries/lib1**") * A project folder must always be at the second level (e.g. we forbid nesting such as "**~/demo/libraries/lib1/lib2**") * Cross-project files are always stored in the common folder (e.g. "**~/demo/common/docs**", "**~demo/common/scripts**", etc.) * There are no exceptions to these rules If we want to adopt this policy for our demo repo, we can move the projects into category folders like this: **~/demo/apps/application** **~/demo/libraries/lib1** **~/demo/libraries/lib2** ...and then enforce that projects must be a the second level using these settings in **~/demo/rush.json**: // The minimum folder depth for the projectFolder field. // (The default value is 1, i.e. no slashes in the path name.) "projectFolderMinDepth": 2, // The maximum folder depth for the projectFolder field. // (The default value is 2, i.e. a single slash in the path name.) "projectFolderMaxDepth": 2, allowedEmailRegExps: Avoiding private e-mail addresses[​](https://rushjs.io/pages/maintainer/setup_policies/#allowedemailregexps-avoiding-private-e-mail-addresses "Direct link to allowedEmailRegExps: Avoiding private e-mail addresses") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Git requires every commit to be accompanied by a name and e-mail address. However, there is no validation of these fields, and their defaults are pulled from a global setting on your PC that's easy to forget about. When using Git for work, people often accidentally commit using an unintended e-mail address that looks... not so professional. If the repo is hosted on GitHub, these e-mail addresses immediately become queryable via the GitHub REST API, easy pickings for unscrupulous spammers. (The privacy settings for your GitHub account don't affect "git commit".) Rush can help, though. The "gitPolicy" setting in **rush.json** allows you to specify a list of acceptable e-mail patterns for a repository. The patterns are regular expressions. (Since they are inside a JSON string literal, note that backslashes must be double-escaped.) "gitPolicy": { // A list of regular expressions describing allowable e-mail patterns // for Git commits. They are case-insensitive anchored JavaScript RegExps. // Example: ".*@example\\.com" "allowedEmailRegExps": [ // Require GitHub scrubbed e-mails "[^@]+@users\\.noreply\\.github\\.com" ], // An example valid e-mail address for "Mr. Example" that conforms to one // of the allowedEmailRegExps. Example: "mr-example@contoso.com" "sampleEmail": "mrexample@users.noreply.github.com" }, Whenever the developer runs `rush install`, Rush will check that their e-mail address follows one of the patterns. If not, it displays a warning like this: rush install Rush Multi-Package Build ToolChecking Git policy for this repository.Hey there! To keep things tidy, this repo asks you to submit your Git commmitsusing an e-mail like this pattern: [^@]+@users\.noreply\.github\.com...but yours is configured like this: Bob To fix it, you can use commands like this: git config --local user.name "Mr. Example" git config --local user.email "mrexample@users.noreply.github.com"Aborting, so you can go fix your settings. (Or use --bypass-policy to skip.) approvedPackagesPolicy: Reviewing new NPM dependencies[​](https://rushjs.io/pages/maintainer/setup_policies/#approvedpackagespolicy-reviewing-new-npm-dependencies "Direct link to approvedPackagesPolicy: Reviewing new NPM dependencies") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Are there certain people on your team who constantly find exciting new libraries and add them to your package.json? This can quickly get out of hand, especially in environments that require legal or security reviews for external code. The **approvedPackagesPolicy** feature allows you to detect when new NPM dependencies are introduced. Since different levels of scrutiny are often required (e.g. for a shipping product, versus an intern project, versus an internal library), we distinguish "review categories". This allows us to approve a package once for an entire category of projects, while still being alerted when the dependency is used somewhere else. Continuing the example scenario from [Setting up a new repo](https://rushjs.io/pages/maintainer/setup_new_repo/) , here's how we would update **rush.json** to define some review categories for "published" versus "internal" projects: { "rushVersion": "4.0.0", "npmVersion": "5.5.1", "nodeSupportedVersionRange": ">=8.9.0 <9.0.0", "approvedPackagesPolicy": { "reviewCategories": [ "published", "internal" ], // We don't need to review @types packages, because we can assume // the untyped package should already have been approved "ignoredNpmScopes": [ "@types" ] }, "projects": [ { "packageName": "application", "projectFolder": "application", "reviewCategory": "internal" }, { "packageName": "lib1", "projectFolder": "lib1", "reviewCategory": "internal" }, { "packageName": "lib2", "projectFolder": "lib2", "reviewCategory": "published" } ]} When you run `rush install`, it will create two files that report your dependencies. These files should be added to Git and can be configured so that changes require approval: * **~/demo/common/config/rush/browser-approved-packages.json**: Packages approved for usage in a web browser. This is generally the stricter of the two types, so by default all new packages are added to this file. For web browser dependencies, the review discussion typically focuses on: _How big is the minified code?_ _What's the license?_ _Are there security issues?_ * **~/demo/common/config/rush/nonbrowser-approved-packages.json**: Packages approved for usage everywhere _except_ in a web browser. This review discussion typically focuses on: _How much clutter will it pull into our node\_modules folder?_ _Do we already have an equivalent package?_ _Is there any real code in there, or is it a just a flimsy wrapper for another package?_ After running `rush install`, the **browser-approved-packages.json** file might look like this: { "packages": [ { "name": "@rushstack/heft", "allowedCategories": [ "internal" ] }, { "name": "@rushstack/node-library-build", "allowedCategories": [ "internal", "published" ] }, { "name": "semver", "allowedCategories": [ "internal", "published" ] } ]} For example, this file is showing that the external dependency **@rushstack/heft** was found in the package.json file for an "internal" project (let's say **~/demo/lib1**) but not any "public" project (such as **~/demo/application**). Rush has no way to detect whether an NPM package is for the browser or not. Since these are all non-browser files, you must manually move them to the other file **browser-approved-packages.json**. #### How approvals work[​](https://rushjs.io/pages/maintainer/setup_policies/#how-approvals-work "Direct link to How approvals work") Whenever `rush install` is run, the content in these files will be broadened to match the current contents of package.json. This file should be committed to Git. When the developer creates a pull request, the PR diff can be used e.g. to trigger a special approval. * [projectFolderMinDepth: Controlling folder size](https://rushjs.io/pages/maintainer/setup_policies/#projectfoldermindepth-controlling-folder-size) * [allowedEmailRegExps: Avoiding private e-mail addresses](https://rushjs.io/pages/maintainer/setup_policies/#allowedemailregexps-avoiding-private-e-mail-addresses) * [approvedPackagesPolicy: Reviewing new NPM dependencies](https://rushjs.io/pages/maintainer/setup_policies/#approvedpackagespolicy-reviewing-new-npm-dependencies) --- # pnpm-config.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/pnpm-config_json/#docusaurus_skipToContent_fallback) > NOTE: This config file was introduced with Rush 5.79.0. Prior to that release, PNPM settings were instead stored in the `"pnpmOptions"` section of **rush.json**. For backwards compatibility, Rush 5 still accepts the `"pnpmOptions"` section. If you are upgrading an old monorepo, in order to access these new PNPM settings, you must manually delete the `"pnpmOptions"` setting from **rush.json** and create the **pnpm-config.json** file. This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **pnpm-config.json**: **common/config/rush/pnpm-config.json** /** * This configuration file provides settings specific to the PNPM package manager. * More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", /** * If true, then `rush install` and `rush update` will use the PNPM workspaces feature * to perform the install, instead of the old model where Rush generated the symlinks * for each projects's node_modules folder. * * When using workspaces, Rush will generate a `common/temp/pnpm-workspace.yaml` file referencing * all local projects to install. Rush will also generate a `.pnpmfile.cjs` shim which implements * Rush-specific features such as preferred versions. The user's `common/config/rush/.pnpmfile.cjs` * is invoked by the shim. * * This option is strongly recommended. The default value is false. */ "useWorkspaces": true, /** * This setting determines how PNPM chooses version numbers during `rush update`. * For example, suppose `lib-x@3.0.0` depends on `"lib-y": "^1.2.3"` whose latest major * releases are `1.8.9` and `2.3.4`. The resolution mode `lowest-direct` might choose * `lib-y@1.2.3`, wheres `highest` will choose 1.8.9, and `time-based` will pick the * highest compatible version at the time when `lib-x@3.0.0` itself was published (ensuring * that the version could have been tested by the maintainer of "lib-x"). For local workspace * projects, `time-based` instead works like `lowest-direct`, avoiding upgrades unless * they are explicitly requested. Although `time-based` is the most robust option, it may be * slightly slower with registries such as npmjs.com that have not implemented an optimization. * * IMPORTANT: Be aware that PNPM 8.0.0 initially defaulted to `lowest-direct` instead of * `highest`, but PNPM reverted this decision in 8.6.12 because it caused confusion for users. * Rush version 5.106.0 and newer avoids this confusion by consistently defaulting to * `highest` when `resolutionMode` is not explicitly set in pnpm-config.json or .npmrc, * regardless of your PNPM version. * * PNPM documentation: https://pnpm.io/npmrc#resolution-mode * * Possible values are: `highest`, `time-based`, and `lowest-direct`. * The default is `highest`. */ // "resolutionMode": "time-based", /** * This setting determines whether PNPM will automatically install (non-optional) * missing peer dependencies instead of reporting an error. Doing so conveniently * avoids the need to specify peer versions in package.json, but in a large monorepo * this often creates worse problems. The reason is that peer dependency behavior * is inherently complicated, and it is easier to troubleshoot consequences of an explicit * version than an invisible heuristic. The original NPM RFC discussion pointed out * some other problems with this feature: https://github.com/npm/rfcs/pull/43 * IMPORTANT: Without Rush, the setting defaults to true for PNPM 8 and newer; however, * as of Rush version 5.109.0 the default is always false unless `autoInstallPeers` * is specified in pnpm-config.json or .npmrc, regardless of your PNPM version. * PNPM documentation: https://pnpm.io/npmrc#auto-install-peers * The default value is false. */ // "autoInstallPeers": false, /** * If true, then Rush will add the `--strict-peer-dependencies` command-line parameter when * invoking PNPM. This causes `rush update` to fail if there are unsatisfied peer dependencies, * which is an invalid state that can cause build failures or incompatible dependency versions. * (For historical reasons, JavaScript package managers generally do not treat this invalid * state as an error.) * * PNPM documentation: https://pnpm.io/npmrc#strict-peer-dependencies * * The default value is false to avoid legacy compatibility issues. * It is strongly recommended to set `strictPeerDependencies=true`. */ // "strictPeerDependencies": true, /** * Environment variables that will be provided to PNPM. */ // "environmentVariables": { // "NODE_OPTIONS": { // "value": "--max-old-space-size=4096", // "override": false // } // }, /** * Specifies the location of the PNPM store. There are two possible values: * * - `local` - use the `pnpm-store` folder in the current configured temp folder: * `common/temp/pnpm-store` by default. * - `global` - use PNPM's global store, which has the benefit of being shared * across multiple repo folders, but the disadvantage of less isolation for builds * (for example, bugs or incompatibilities when two repos use different releases of PNPM) * * In both cases, the store path can be overridden by the environment variable `RUSH_PNPM_STORE_PATH`. * * The default value is `local`. */ // "pnpmStore": "global", /** * If true, then `rush install` will report an error if manual modifications * were made to the PNPM shrinkwrap file without running `rush update` afterwards. * * This feature protects against accidental inconsistencies that may be introduced * if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this * feature is enabled, `rush update` will append a hash to the file as a YAML comment, * and then `rush update` and `rush install` will validate the hash. Note that this * does not prohibit manual modifications, but merely requires `rush update` be run * afterwards, ensuring that PNPM can report or repair any potential inconsistencies. * * To temporarily disable this validation when invoking `rush install`, use the * `--bypass-policy` command-line parameter. * * The default value is false. */ // "preventManualShrinkwrapChanges": true, /** * When a project uses `workspace:` to depend on another Rush project, PNPM normally installs * it by creating a symlink under `node_modules`. This generally works well, but in certain * cases such as differing `peerDependencies` versions, symlinking may cause trouble * such as incorrectly satisfied versions. For such cases, the dependency can be declared * as "injected", causing PNPM to copy its built output into `node_modules` like a real * install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/ * * When using Rush subspaces, these sorts of versioning problems are much more likely if * `workspace:` refers to a project from a different subspace. This is because the symlink * would point to a separate `node_modules` tree installed by a different PNPM lockfile. * A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`, * which automatically treats all projects from other subspaces as injected dependencies * without having to manually configure them. * * NOTE: Use carefully -- excessive file copying can slow down the `rush install` and * `pnpm-sync` operations if too many dependencies become injected. * * The default value is false. */ // "alwaysInjectDependenciesFromOtherSubspaces": false, /** * Defines the policies to be checked for the `pnpm-lock.yaml` file. */ "pnpmLockfilePolicies": { /** * This policy will cause "rush update" to report an error if `pnpm-lock.yaml` contains * any SHA1 integrity hashes. * * For each NPM dependency, `pnpm-lock.yaml` normally stores an `integrity` hash. Although * its main purpose is to detect corrupted or truncated network requests, this hash can also * serve as a security fingerprint to protect against attacks that would substitute a * malicious tarball, for example if a misconfigured .npmrc caused a machine to accidentally * download a matching package name+version from npmjs.com instead of the private NPM registry. * NPM originally used a SHA1 hash; this was insecure because an attacker can too easily craft * a tarball with a matching fingerprint. For this reason, NPM later deprecated SHA1 and * instead adopted a cryptographically strong SHA512 hash. Nonetheless, SHA1 hashes can * occasionally reappear during "rush update", for example due to missing metadata fallbacks * (https://github.com/orgs/pnpm/discussions/6194) or an incompletely migrated private registry. * The `disallowInsecureSha1` policy prevents this, avoiding potential security/compliance alerts. */ // "disallowInsecureSha1": { // /** // * Enables the "disallowInsecureSha1" policy. The default value is false. // */ // "enabled": true, // // /** // * In rare cases, a private NPM registry may continue to serve SHA1 hashes for very old // * package versions, perhaps due to a caching issue or database migration glitch. To avoid // * having to disable the "disallowInsecureSha1" policy for the entire monorepo, the problematic // * package versions can be individually ignored. The "exemptPackageVersions" key is the // * package name, and the array value lists exact version numbers to be ignored. // */ // "exemptPackageVersions": { // "example1": ["1.0.0"], // "example2": ["2.0.0", "2.0.1"] // } // } }, /** * The "globalOverrides" setting provides a simple mechanism for overriding version selections * for all dependencies of all projects in the monorepo workspace. The settings are copied * into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated * by Rush during installation. * * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, * and `globalOverrides` has lowest precedence. * * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides */ "globalOverrides": { // "example1": "^1.0.0", // "example2": "npm:@company/example2@^1.0.0" }, /** * The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors * that are reported during installation with `strictPeerDependencies=true`. The settings are copied * into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated * by Rush during installation. * * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, * and `globalOverrides` has lowest precedence. * * https://pnpm.io/package_json#pnpmpeerdependencyrules */ "globalPeerDependencyRules": { // "ignoreMissing": ["@eslint/*"], // "allowedVersions": { "react": "17" }, // "allowAny": ["@babel/*"] }, /** * The `globalPackageExtension` setting provides a way to patch arbitrary package.json fields * for any PNPM dependency of the monorepo. The settings are copied into the `pnpm.packageExtensions` * field of the `common/temp/package.json` file that is generated by Rush during installation. * The `globalPackageExtension` setting has similar capabilities as `.pnpmfile.cjs` but without * the downsides of an executable script (nondeterminism, unreliable caching, performance concerns). * * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, * and `globalOverrides` has lowest precedence. * * PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions */ "globalPackageExtensions": { // "fork-ts-checker-webpack-plugin": { // "dependencies": { // "@babel/core": "1" // }, // "peerDependencies": { // "eslint": ">= 6" // }, // "peerDependenciesMeta": { // "eslint": { // "optional": true // } // } // } }, /** * The `globalNeverBuiltDependencies` setting suppresses the `preinstall`, `install`, and `postinstall` * lifecycle events for the specified NPM dependencies. This is useful for scripts with poor practices * such as downloading large binaries without retries or attempting to invoke OS tools such as * a C++ compiler. (PNPM's terminology refers to these lifecycle events as "building" a package; * it has nothing to do with build system operations such as `rush build` or `rushx build`.) * The settings are copied into the `pnpm.neverBuiltDependencies` field of the `common/temp/package.json` * file that is generated by Rush during installation. * * PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies */ "globalNeverBuiltDependencies": [ // "fsevents" ], /** * The `globalIgnoredOptionalDependencies` setting suppresses the installation of optional NPM * dependencies specified in the list. This is useful when certain optional dependencies are * not needed in your environment, such as platform-specific packages or dependencies that * fail during installation but are not critical to your project. * These settings are copied into the `pnpm.overrides` field of the `common/temp/package.json` * file that is generated by Rush during installation, instructing PNPM to ignore the specified * optional dependencies. * * PNPM documentation: https://pnpm.io/package_json#pnpmignoredoptionaldependencies */ "globalIgnoredOptionalDependencies": [ // "fsevents" ], /** * The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package * versions that the NPM registry reports as being deprecated. This is useful if the * deprecated package is an indirect dependency of an external package that has not released a fix. * The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json` * file that is generated by Rush during installation. * * PNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions * * If you are working to eliminate a deprecated version, it's better to specify `allowedDeprecatedVersions` * in the package.json file for individual Rush projects. */ "globalAllowedDeprecatedVersions": { // "request": "*" }, /** * (THIS FIELD IS MACHINE GENERATED) The "globalPatchedDependencies" field is updated automatically * by the `rush-pnpm patch-commit` command. It is a dictionary, where the key is an NPM package name * and exact version, and the value is a relative path to the associated patch file. * * PNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies */ "globalPatchedDependencies": { }, /** * (USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into * the `common/temp/package.json` file that is generated by Rush during installation. * This provides a way to experiment with new PNPM features. These settings will override * any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`. * * USAGE OF THIS SETTING IS NOT SUPPORTED BY THE RUSH MAINTAINERS AND MAY CAUSE RUSH * TO MALFUNCTION. If you encounter a missing PNPM setting that you believe should * be supported, please create a GitHub issue or PR. Note that Rush does not aim to * support every possible PNPM setting, but rather to promote a battle-tested installation * strategy that is known to provide a good experience for large teams with lots of projects. */ "unsupportedPackageJsonSettings": { // "dependencies": { // "not-a-good-practice": "*" // }, // "scripts": { // "do-something": "echo Also not a good practice" // }, // "pnpm": { "futurePnpmFeature": true } }} --- # command-line.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/command-line_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **command-line.json**: **common/config/rush/command-line.json** /** * This configuration file defines custom commands for the "rush" command-line. * More documentation is available on the Rush website: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", /** * Custom "commands" introduce new verbs for the command-line. To see the help for these * example commands, try "rush --help", "rush my-bulk-command --help", or * "rush my-global-command --help". */ "commands": [ // { // /** // * (Required) Determines the type of custom command. // * Rush's "bulk" commands are invoked separately for each project. By default, the command will run for // * every project in the repo, according to the dependency graph (similar to how "rush build" works). // * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. // */ // "commandKind": "bulk", // // /** // * (Required) The name that will be typed as part of the command line. This is also the name // * of the "scripts" hook in the project's package.json file (if "shellCommand" is not specified). // * // * The name should be comprised of lower case words separated by hyphens or colons. The name should include an // * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands // * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). // * // * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command // * and will call the "rebuild" script instead of the "build" script. // */ // "name": "my-bulk-command", // // /** // * (Required) A short summary of the custom command to be shown when printing command line // * help, e.g. "rush --help". // */ // "summary": "Example bulk custom command", // // /** // * A detailed description of the command to be shown when printing command line // * help (e.g. "rush --help my-command"). // * If omitted, the "summary" text will be shown instead. // * // * Whenever you introduce commands/parameters, taking a little time to write meaningful // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "This is an example custom command that runs separately for each project", // // /** // * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously // * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the // * same time.) If your command makes sense to run concurrently with other operations, // * set "safeForSimultaneousRushProcesses" to true to disable this protection. // * // * In particular, this is needed for custom scripts that invoke other Rush commands. // */ // "safeForSimultaneousRushProcesses": false, // // /** // * (Optional) If the `shellCommand` field is set for a bulk command, Rush will invoke it for each // * selected project; otherwise, Rush will invoke the package.json `"scripts"` entry matching Rush command name. // * // * The string is the path to a script that will be invoked using the OS shell. The working directory will be // * the folder that contains rush.json. If custom parameters are associated with this command, their // * values will be appended to the end of this string. // */ // // "shellCommand": "node common/scripts/my-bulk-command.js", // // /** // * (Required) If true, then this command is safe to be run in parallel, i.e. executed // * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism // * projects will not start processing until their dependencies have completed processing. // */ // "enableParallelism": false, // // /** // * Normally projects will be processed according to their dependency order: a given project will not start // * processing the command until all of its dependencies have completed. This restriction doesn't apply for // * certain operations, for example a "clean" task that deletes output files. In this case // * you can set "ignoreDependencyOrder" to true to increase parallelism. // */ // "ignoreDependencyOrder": false, // // /** // * Normally Rush requires that each project's package.json has a "scripts" entry matching // * the custom command name. To disable this check, set "ignoreMissingScript" to true; // * projects with a missing definition will be skipped. // */ // "ignoreMissingScript": false, // // /** // * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: // * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". // * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. // * - If the shell script returns a zero process exit code but writes something to its stderr stream, // * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent // * Rush from processing downstream projects. // * // * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because // * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. // * In an active monorepo, we've found that if you allow any warnings in your main branch, it inadvertently // * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings // * have accumulated that warnings no longer serve any useful purpose. // * // * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. // * In that case, it's strongly recommended to fix the task. However, as a workaround you can set // * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. // * // * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. // */ // "allowWarningsInSuccessfulBuild": false, // // /** // * If true then this command will be incremental like the built-in "build" command // */ // "incremental": false, // // /** // * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush // * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a // * change is detected, the command will be invoked again for the changed project and any selected projects that // * directly or indirectly depend on it. // * // * For details, refer to the website article "Using watch mode". // */ // "watchForChanges": false, // // /** // * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of // * projects' own folders. // */ // "disableBuildCache": false // }, // // { // /** // * (Required) Determines the type of custom command. // * Rush's "global" commands are invoked once for the entire repo. // */ // "commandKind": "global", // // "name": "my-global-command", // "summary": "Example global custom command", // "description": "This is an example custom command that runs once for the entire repo", // // "safeForSimultaneousRushProcesses": false, // // /** // * (Required) A script that will be invoked using the OS shell. The working directory will be // * the folder that contains rush.json. If custom parameters are associated with this command, their // * values will be appended to the end of this string. // */ // "shellCommand": "node common/scripts/my-global-command.js", // // /** // * If your "shellCommand" script depends on NPM packages, the recommended best practice is // * to make it into a regular Rush project that builds using your normal toolchain. In cases where // * the command needs to work without first having to run "rush build", the recommended practice // * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. // * // * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with // * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to // * install these dependencies before an associated command is invoked. Autoinstallers have the // * advantage that they work even in a branch where "rush install" is broken, which makes them a // * good solution for Git hook scripts. But they have the disadvantages of not being buildable // * projects, and of increasing the overall installation footprint for your monorepo. // * // * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. // * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and // * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when // * invoking the "shellCommand". // */ // // "autoinstallerName": "my-task" // } ], /** * Custom "parameters" introduce new parameters for specified Rush command-line commands. * For example, you might define a "--production" parameter for the "rush build" command. */ "parameters": [ // { // /** // * (Required) Determines the type of custom parameter. // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. // */ // "parameterKind": "flag", // // /** // * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. // */ // "longName": "--my-flag", // // /** // * An optional alternative short name for the parameter. It must be a dash followed by a single // * lower-case or upper-case letter, which is case-sensitive. // * // * NOTE: The Rush developers recommend that automation scripts should always use the long name // * to improve readability. The short name is only intended as a convenience for humans. // * The alphabet letters run out quickly, and are difficult to memorize, so *only* use // * a short name if you expect the parameter to be needed very often in everyday operations. // */ // "shortName": "-m", // // /** // * (Required) A long description to be shown in the command-line help. // * // * Whenever you introduce commands/parameters, taking a little time to write meaningful // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", // // /** // * (Required) A list of custom commands and/or built-in Rush commands that this parameter may // * be used with. The parameter will be appended to the shell command that Rush invokes. // */ // "associatedCommands": ["build", "rebuild"] // }, // // { // /** // * (Required) Determines the type of custom parameter. // * A "string" is a custom command-line parameter whose argument is a single text string. // */ // "parameterKind": "string", // "longName": "--my-string", // "description": "A custom string parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // // "argumentName": "SOME_TEXT", // // /** // * If true, this parameter must be included with the command. The default is false. // */ // "required": false // }, // // { // /** // * (Required) Determines the type of custom parameter. // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of // * allowable alternatives (similar to an enum). // */ // "parameterKind": "choice", // "longName": "--my-choice", // "description": "A custom choice parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // "required": false, // // /** // * If a "defaultValue" is specified, then if the Rush command line is invoked without // * this parameter, it will be automatically added with the "defaultValue" as the argument. // * The value must be one of the defined alternatives. // */ // "defaultValue": "vanilla", // // /** // * (Required) A list of alternative argument values that can be chosen for this parameter. // */ // "alternatives": [ // { // /** // * A token that is one of the alternatives that can be used with the choice parameter, // * e.g. "vanilla" in "--flavor vanilla". // */ // "name": "vanilla", // // /** // * A detailed description for the alternative that can be shown in the command-line help. // * // * Whenever you introduce commands/parameters, taking a little time to write meaningful // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "Use the vanilla flavor" // }, // // { // "name": "chocolate", // "description": "Use the chocolate flavor" // }, // // { // "name": "strawberry", // "description": "Use the strawberry flavor" // } // ] // }, // // { // /** // * (Required) Determines the type of custom parameter. // * An "integer" is a custom command-line parameter whose value is an integer number. // */ // "parameterKind": "integer", // "longName": "--my-integer", // "description": "A custom integer parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // "argumentName": "SOME_NUMBER", // "required": false // }, // // { // /** // * (Required) Determines the type of custom parameter. // * An "integerList" is a custom command-line parameter whose argument is an integer. // * The parameter can be specified multiple times to build a list. // * // * For example, if the parameter name is "--my-integer-list", then the custom command // * might be invoked as // * `rush my-global-command --my-integer-list 1 --my-integer-list 2 --my-integer-list 3` // * and the parsed array would be [1,2,3]. // */ // "parameterKind": "integerList", // "longName": "--my-integer-list", // "description": "A custom integer list parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // "argumentName": "SOME_NUMBER", // "required": false // }, // // { // /** // * (Required) Determines the type of custom parameter. // * An "stringList" is a custom command-line parameter whose argument is a text string. // * The parameter can be specified multiple times to build a list. // * // * For example, if the parameter name is "--my-string-list", then the custom command // * might be invoked as // * `rush my-global-command --my-string-list A --my-string-list B --my-string-list C` // * and the parsed array would be [A,B,C]. // */ // "parameterKind": "stringList", // "longName": "--my-string-list", // "description": "A custom string list parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // "argumentName": "SOME_TEXT", // "required": false // }, // // { // /** // * (Required) Determines the type of custom parameter. // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of // * allowable alternatives (similar to an enum). // * The parameter can be specified multiple times to build a list. // * // * For example, if the parameter name is "--my-choice-list", then the custom command // * might be invoked as // * `rush my-global-command --my-string-list vanilla --my-string-list chocolate` // * and the parsed array would be [vanilla,chocolate]. // */ // "parameterKind": "choiceList", // "longName": "--my-choice-list", // "description": "A custom choice list parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // "required": false, // // /** // * (Required) A list of alternative argument values that can be chosen for this parameter. // */ // "alternatives": [ // { // /** // * A token that is one of the alternatives that can be used with the choice parameter, // * e.g. "vanilla" in "--flavor vanilla". // */ // "name": "vanilla", // // /** // * A detailed description for the alternative that can be shown in the command-line help. // * // * Whenever you introduce commands/parameters, taking a little time to write meaningful // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "Use the vanilla flavor" // }, // // { // "name": "chocolate", // "description": "Use the chocolate flavor" // }, // // { // "name": "strawberry", // "description": "Use the strawberry flavor" // } // ] // } ]} See also[​](https://rushjs.io/pages/configs/command-line_json/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------------- * [Custom commands](https://rushjs.io/pages/maintainer/custom_commands/) * [See also](https://rushjs.io/pages/configs/command-line_json/#see-also) --- # rush.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/configs/rush_json/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/pages/commands/rush_init/) generates for **rush.json** (in the repo root folder): **rush.json** /** * This is the main configuration file for Rush. * For full documentation, please see https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", /** * (Required) This specifies the version of the Rush engine to be used in this repo. * Rush's "version selector" feature ensures that the globally installed tool will * behave like this release, regardless of which version is installed globally. * * The common/scripts/install-run-rush.js automation script also uses this version. * * NOTE: If you upgrade to a new major version of Rush, you should replace the "v5" * path segment in the "$schema" field for all your Rush config files. This will ensure * correct error-underlining and tab-completion for editors such as VS Code. */ "rushVersion": "5.82.1", /** * The next field selects which package manager should be installed and determines its version. * Rush installs its own local copy of the package manager to ensure that your build process * is fully isolated from whatever tools are present in the local environment. * * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation * for details about these alternatives. */ "pnpmVersion": "6.7.1", // "npmVersion": "6.14.15", // "yarnVersion": "1.9.4", /** * Older releases of the Node.js engine may be missing features required by your system. * Other releases may have bugs. In particular, the "latest" version will not be a * Long Term Support (LTS) version and is likely to have regressions. * * Specify a SemVer range to ensure developers use a Node.js version that is appropriate * for your repo. * * LTS schedule: https://nodejs.org/en/about/releases/ * LTS versions: https://nodejs.org/en/download/releases/ */ "nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0 || >=16.13.0 <17.0.0", /** * Odd-numbered major versions of Node.js are experimental. Even-numbered releases * spend six months in a stabilization period before the first Long Term Support (LTS) version. * For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended * for production usage because they frequently have bugs. They may cause Rush itself * to malfunction. * * Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing * pre-LTS versions in preparation for supporting the first LTS version, you can use this setting * to disable Rush's warning. */ // "suppressNodeLtsWarning": false, /** * If you would like the version specifiers for your dependencies to be consistent, then * uncomment this line. This is effectively similar to running "rush check" before any * of the following commands: * * rush install, rush update, rush link, rush version, rush publish * * In some cases you may want this turned on, but need to allow certain packages to use a different * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" * section of the common-versions.json. */ // "ensureConsistentVersions": true, /** * Large monorepos can become intimidating for newcomers if project folder paths don't follow * a consistent and recognizable pattern. When the system allows nested folder trees, * we've found that teams will often use subfolders to create islands that isolate * their work from others ("shipping the org"). This hinders collaboration and code sharing. * * The Rush developers recommend a "category folder" model, where buildable project folders * must always be exactly two levels below the repo root. The parent folder acts as the category. * This provides a basic facility for grouping related projects (e.g. "apps", "libraries", * "tools", "prototypes") while still encouraging teams to organize their projects into * a unified taxonomy. Limiting to 2 levels seems very restrictive at first, but if you have * 20 categories and 20 projects in each category, this scheme can easily accommodate hundreds * of projects. In practice, you will find that the folder hierarchy needs to be rebalanced * occasionally, but if that's painful, it's a warning sign that your development style may * discourage refactoring. Reorganizing the categories should be an enlightening discussion * that brings people together, and maybe also identifies poor coding practices (e.g. file * references that reach into other project's folders without using Node.js module resolution). * * The defaults are projectFolderMinDepth=1 and projectFolderMaxDepth=2. * * To remove these restrictions, you could set projectFolderMinDepth=1 * and set projectFolderMaxDepth to a large number. */ // "projectFolderMinDepth": 2, // "projectFolderMaxDepth": 2, /** * Today the npmjs.com registry enforces fairly strict naming rules for packages, but in the early * days there was no standard and hardly any enforcement. A few large legacy projects are still using * nonstandard package names, and private registries sometimes allow it. Set "allowMostlyStandardPackageNames" * to true to relax Rush's enforcement of package names. This allows upper case letters and in the future may * relax other rules, however we want to minimize these exceptions. Many popular tools use certain punctuation * characters as delimiters, based on the assumption that they will never appear in a package name; thus if we relax * the rules too much it is likely to cause very confusing malfunctions. * * The default value is false. */ // "allowMostlyStandardPackageNames": true, /** * This feature helps you to review and approve new packages before they are introduced * to your monorepo. For example, you may be concerned about licensing, code quality, * performance, or simply accumulating too many libraries with overlapping functionality. * The approvals are tracked in two config files "browser-approved-packages.json" * and "nonbrowser-approved-packages.json". See the Rush documentation for details. */ // "approvedPackagesPolicy": { // /** // * The review categories allow you to say for example "This library is approved for usage // * in prototypes, but not in production code." // * // * Each project can be associated with one review category, by assigning the "reviewCategory" field // * in the "projects" section of rush.json. The approval is then recorded in the files // * "common/config/rush/browser-approved-packages.json" and "nonbrowser-approved-packages.json" // * which are automatically generated during "rush update". // * // * Designate categories with whatever granularity is appropriate for your review process, // * or you could just have a single category called "default". // */ // "reviewCategories": [ // // Some example categories: // "production", // projects that ship to production // "tools", // non-shipping projects that are part of the developer toolchain // "prototypes" // experiments that should mostly be ignored by the review process // ], // // /** // * A list of NPM package scopes that will be excluded from review. // * We recommend to exclude TypeScript typings (the "@types" scope), because // * if the underlying package was already approved, this would imply that the typings // * are also approved. // */ // // "ignoredNpmScopes": ["@types"] // }, /** * If you use Git as your version control system, this section has some additional * optional features you can use. */ "gitPolicy": { /** * Work at a big company? Tired of finding Git commits at work with unprofessional Git * emails such as "beer-lover@my-college.edu"? Rush can validate people's Git email address * before they get started. * * Define a list of regular expressions describing allowable e-mail patterns for Git commits. * They are case-insensitive anchored JavaScript RegExps. Example: ".*@example\.com" * * IMPORTANT: Because these are regular expressions encoded as JSON string literals, * RegExp escapes need two backslashes, and ordinary periods should be "\\.". */ // "allowedEmailRegExps": [ // "[^@]+@users\\.noreply\\.github\\.com", // "rush-bot@example\\.org" // ], /** * When Rush reports that the address is malformed, the notice can include an example * of a recommended email. Make sure it conforms to one of the allowedEmailRegExps * expressions. */ // "sampleEmail": "example@users.noreply.github.com", /** * The commit message to use when committing changes during 'rush publish'. * * For example, if you want to prevent these commits from triggering a CI build, * you might configure your system's trigger to look for a special string such as "[skip-ci]" * in the commit message, and then customize Rush's message to contain that string. */ // "versionBumpCommitMessage": "Bump versions [skip ci]", /** * The commit message to use when committing changes during 'rush version'. * * For example, if you want to prevent these commits from triggering a CI build, * you might configure your system's trigger to look for a special string such as "[skip-ci]" * in the commit message, and then customize Rush's message to contain that string. */ // "changeLogUpdateCommitMessage": "Update changelogs [skip ci]", /** * The commit message to use when commiting changefiles during 'rush change --commit' * * If no commit message is set it will default to 'Rush change' */ // "changefilesCommitMessage": "Rush change" }, "repository": { /** * The URL of this Git repository, used by "rush change" to determine the base branch for your PR. * * The "rush change" command needs to determine which files are affected by your PR diff. * If you merged or cherry-picked commits from the main branch into your PR branch, those commits * should be excluded from this diff (since they belong to some other PR). In order to do that, * Rush needs to know where to find the base branch for your PR. This information cannot be * determined from Git alone, since the "pull request" feature is not a Git concept. Ideally * Rush would use a vendor-specific protocol to query the information from GitHub, Azure DevOps, etc. * But to keep things simple, "rush change" simply assumes that your PR is against the "main" branch * of the Git remote indicated by the repository.url setting in rush.json. If you are working in * a GitHub "fork" of the real repo, this setting will be different from the repository URL of your * your PR branch, and in this situation "rush change" will also automatically invoke "git fetch" * to retrieve the latest activity for the remote main branch. */ // "url": "https://github.com/microsoft/rush-example", /** * The default branch name. This tells "rush change" which remote branch to compare against. * The default value is "main" */ // "defaultBranch": "main", /** * The default remote. This tells "rush change" which remote to compare against if the remote URL is * not set or if a remote matching the provided remote URL is not found. */ // "defaultRemote": "origin" }, /** * Event hooks are customized script actions that Rush executes when specific events occur */ "eventHooks": { /** * The list of shell commands to run before the Rush installation starts */ "preRushInstall": [ // "common/scripts/pre-rush-install.js" ], /** * The list of shell commands to run after the Rush installation finishes */ "postRushInstall": [], /** * The list of shell commands to run before the Rush build command starts */ "preRushBuild": [], /** * The list of shell commands to run after the Rush build command finishes */ "postRushBuild": [] }, /** * Installation variants allow you to maintain a parallel set of configuration files that can be * used to build the entire monorepo with an alternate set of dependencies. For example, suppose * you upgrade all your projects to use a new release of an important framework, but during a transition period * you intend to maintain compatibility with the old release. In this situation, you probably want your * CI validation to build the entire repo twice: once with the old release, and once with the new release. * * Rush "installation variants" correspond to sets of config files located under this folder: * * common/config/rush/variants/ * * The variant folder can contain an alternate common-versions.json file. Its "preferredVersions" field can be used * to select older versions of dependencies (within a loose SemVer range specified in your package.json files). * To install a variant, run "rush install --variant ". * * For more details and instructions, see this article: https://rushjs.io/pages/advanced/installation_variants/ */ "variants": [ // { // /** // * The folder name for this variant. // */ // "variantName": "old-sdk", // // /** // * An informative description // */ // "description": "Build this repo using the previous release of the SDK" // } ], /** * Rush can collect anonymous telemetry about everyday developer activity such as * success/failure of installs, builds, and other operations. You can use this to identify * problems with your toolchain or Rush itself. THIS TELEMETRY IS NOT SHARED WITH MICROSOFT. * It is written into JSON files in the common/temp folder. It's up to you to write scripts * that read these JSON files and do something with them. These scripts are typically registered * in the "eventHooks" section. */ // "telemetryEnabled": false, /** * Allows creation of hotfix changes. This feature is experimental so it is disabled by default. * If this is set, 'rush change' only allows a 'hotfix' change type to be specified. This change type * will be used when publishing subsequent changes from the monorepo. */ // "hotfixChangeEnabled": false, /** * This is an optional, but recommended, list of allowed tags that can be applied to Rush projects * using the "tags" setting in this file. This list is useful for preventing mistakes such as misspelling, * and it also provides a centralized place to document your tags. If "allowedProjectTags" list is * not specified, then any valid tag is allowed. A tag name must be one or more words * separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, * ".", and "@" characters. */ // "allowedProjectTags": [ "tools", "frontend-team", "1.0.0-release" ], /** * (Required) This is the inventory of projects to be managed by Rush. * * Rush does not automatically scan for projects using wildcards, for a few reasons: * 1. Depth-first scans are expensive, particularly when tools need to repeatedly collect the list. * 2. On a caching CI machine, scans can accidentally pick up files left behind from a previous build. * 3. It's useful to have a centralized inventory of all projects and their important metadata. */ "projects": [ // { // /** // * The NPM package name of the project (must match package.json) // */ // "packageName": "my-app", // // /** // * The path to the project folder, relative to the rush.json config file. // */ // "projectFolder": "apps/my-app", // // /** // * This field is only used if "subspacesEnabled" is true in subspaces.json. // * It specifies the subspace that this project belongs to. If omitted, then the // * project belongs to the "default" subspace. // */ // "subspaceName": "my-subspace", // // /** // * An optional category for usage in the "browser-approved-packages.json" // * and "nonbrowser-approved-packages.json" files. The value must be one of the // * strings from the "reviewCategories" defined above. // */ // "reviewCategory": "production", // // /** // * A list of Rush project names that are to be installed from NPM // * instead of linking to the local project. // * // * If a project's package.json specifies a dependency that is another Rush project // * in the monorepo workspace, normally Rush will locally link its folder instead of // * installing from NPM. If you are using PNPM workspaces, this is indicated by // * a SemVer range such as "workspace:^1.2.3". To prevent mistakes, Rush reports // * an error if the "workspace:" protocol is missing. // * // * Locally linking ensures that regressions are caught as early as possible and is // * a key benefit of monorepos. However there are occasional situations where // * installing from NPM is needed. A classic example is a cyclic dependency. // * Imagine three Rush projects: "my-toolchain" depends on "my-tester", which depends // * on "my-library". Suppose that we add "my-toolchain" to the "devDependencies" // * of "my-library" so it can be built by our toolchain. This cycle creates // * a problem -- Rush can't build a project using a not-yet-built dependency. // * We can solve it by adding "my-toolchain" to the "decoupledLocalDependencies" // * of "my-library", so it builds using the last published release. Choose carefully // * which package to decouple; some choices are much easier to manage than others. // * // * (In older Rush releases, this setting was called "cyclicDependencyProjects".) // */ // "decoupledLocalDependencies": [ // // "my-toolchain" // ], // // /** // * If true, then this project will be ignored by the "rush check" command. // * The default value is false. // */ // // "skipRushCheck": false, // // /** // * A flag indicating that changes to this project will be published to npm, which affects // * the Rush change and publish workflows. The default value is false. // * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. // */ // // "shouldPublish": false, // // /** // * Facilitates postprocessing of a project's files prior to publishing. // * // * If specified, the "publishFolder" is the relative path to a subfolder of the project folder. // * The "rush publish" command will publish the subfolder instead of the project folder. The subfolder // * must contain its own package.json file, which is typically a build output. // */ // // "publishFolder": "temp/publish", // // /** // * An optional version policy associated with the project. Version policies are defined // * in "version-policies.json" file. See the "rush publish" documentation for more info. // * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. // */ // // "versionPolicyName": "", // // /** // * An optional set of custom tags that can be used to select this project. For example, // * adding "my-custom-tag" will allow this project to be selected by the // * command "rush list --only tag:my-custom-tag". The tag name must be one or more words // * separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, // * ".", and "@" characters. // */ // // "tags": [ "1.0.0-release", "frontend-team" ] // }, // // { // "packageName": "my-controls", // "projectFolder": "libraries/my-controls", // "reviewCategory": "production", // "tags": [ "frontend-team" ] // }, // // { // "packageName": "my-toolchain", // "projectFolder": "tools/my-toolchain", // "reviewCategory": "tools", // "tags": [ "tools" ] // } ]} --- # Cobuilds (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/pages/maintainer/cobuilds/#docusaurus_skipToContent_fallback) On this page Rush's "cobuild" feature (cooperative builds) provides a lightweight solution for distributing work across multiple machines. The idea is a simple extension of what you're already doing: just spawn multiple instances of the same CI pipeline on different machines, allowing them to share work via Rush's [build cache](https://rushjs.io/pages/maintainer/build_cache/) . For example, suppose your job runs `rush install && rush build`, and we launch this command on two machines. If machine #1 has already built a project, then machine #2 will skip that project, instead fetching the result from the build cache. In this way, the building gets divided between the two pipelines, and with perfect parallelism the build might finish in half the time. But there is a flaw in this idea: What if machine #2 reaches a project that machine #1 already started building but has not finished yet? This cache miss will cause machine #2 to start building the same project, when it may have been better to work on something else while waiting for machine #1 to finish that project. We can solve this by using a simple key/value store to communicate progress between machines. (In this tutorial we'll use Rush's [Redis](https://redis.io/) provider, but if your company already hosts some other service such as [Memcached](https://www.memcached.org/) , it's [fairly easy](https://github.com/microsoft/rushstack/blob/main/rush-plugins/rush-redis-cobuild-plugin/src/RedisCobuildLockProvider.ts) to implement your own provider.) When to use cobuilds?[​](https://rushjs.io/pages/maintainer/cobuilds/#when-to-use-cobuilds "Direct link to When to use cobuilds?") ----------------------------------------------------------------------------------------------------------------------------------- Without cobuilds, Rush already parallelizes your jobs on a single machine. (This may not be immediately obvious, since Rush's output is "collated" for readability, making it appear as if projects are getting built one at a time.) You can fine-tune the maximum parallelism using the `--parallelism` command-line parameter, but keep in mind that projects can only build concurrently if they don't depend on each other. Thus, cobuilds will only help if you've already reached the limits for a single machine (considering cpu cores, disk I/O rates, and available memory). And only if further parallelism is actually possible for your monorepo's project dependency graph. The cobuild feature launches multiple instances of a CI pipeline, under the assumption that machines will be readily available. For example, if your cobuild allocates 4 machines, and your machine pool has 40 machines, then pool contention would not become a concern until 10 pull requests are waiting in the queue. By contrast, an extremely large monorepo might need thousands of machines, at which point it would make more sense to use a "build accelerator" such as [BuildXL](https://github.com/microsoft/BuildXL/blob/main/Documentation/Wiki/Frontends/js-rush-options.md) instead of cobuilds. (There are also plans to integrate Rush with [bazel-buildfarm](https://github.com/bazelbuild/bazel-buildfarm) ; Bazel is Google's equivalent of BuildXL.) Build accelerators generally require you to replace your CI system with their centralized job scheduler that manages its own dedicated pool of machines. Such systems require nontrivial maintenance and can have steeper learning curves, so we generally recommend to start with cobuilds. Before adopting cobuilds, we recommend to first consider simpler solutions: 1. **Enable the build cache**: The [build cache](https://rushjs.io/pages/maintainer/build_cache/) is a prerequisite for cobuilds. 2. **Identify bottlenecks:** If your monorepo's dependency graph does not actually allow lots of projects to be built in parallel, that must be fixed first before considering distributed builds. You can use Rush's `--timeline` parameter to identify bottlenecks that are causing too many projects to wait before they can start building. These bottlenecks can be solved by: * eliminating unnecessary dependencies between projects * introducing [Rush phases](https://rushjs.io/pages/maintainer/phased_builds/) to break up build steps into multiple operations * refactoring code to break up big projects into smaller projects 3. **Upgrade your hardware:** If your builds are slow, it can help to add more machines. We generally recommend to choose high end hardware with the maximum amount of RAM and CPU cores for your plan, based on typical behavior of `rush install` and `rush build`. But every monorepo is different, so collect benchmarks on different hardware configurations to inform your decision. Speeding up the build makes everybody more productive; however, because hardware upgrades usually come from a different budget than engineering salaries, management sometimes may need some help to see this connection. 4. **Cache state between runs:** CI machines often start `rush install && rush build` with a completely clean machine image. Caching can improve this, for example `rush install` time can be improved by using the `RUSH_PNPM_STORE_PATH` environment variable to relocate the PNPM store to a location that your CI system can save and restore across runs. Some environments permit the same machine to be reused for multiple jobs, so that other Rush caches are preserved. 5. **Consider using a merge queue**: If two pull requests are waiting to get merged, normally a CI system will build a hot merge of `pr1+main` and `pr2+main`, to ensure that each PR branch is tested with the latest `main`. However after `pr1+main` has merged, we generally won't force `pr2+main` to be redone with the new `main`; this lack of safety can occasionally cause build breaks. (For example, suppose `pr1` deleted an API, but `pr2` added another call to that API.) A "merge queue" (also known as "commit queue") improves safety by instead building `pr1+main` and `pr1+pr2+main`; if the first PR fails, then it will retry with `pr2+main`. Advanced merge queues support "batches", where they directly test a "train" of pull requests `pr1+pr2+main` and only test `pr1+main` if there is a failure. This can speed up builds and/or reduce machine contention, while still guaranteeing safety. GitHub's [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) doesn't support batches at the time of this writing, however, the [Mergify](https://mergify.com/) third-party service [implements batches](https://docs.mergify.com/actions/queue/#batch-size) and has been tested with Rush. > **Prerequisites** > > In order to use the cobuild feature, you will need: > > * The Rush [build cache](https://rushjs.io/pages/maintainer/build_cache/) > enabled with a cloud storage provider. > > * A [Redis server](https://redis.io/) > . If your company uses some other key/value service, you can implement a plugin by following the example of [rush-redis-cobuild-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-redis-cobuild-plugin) > . (And consider contributing it back to Rush Stack!) > > * A CI system that is able to allocate multiple machines when a CI pipeline is triggered. For example, with GitHub Actions, a "workflow" can launch multiple "jobs" whose "runner" is a separate machine. With Azure DevOps, "pipelines" can run jobs on multiple "agents" that can be on different machines. > > * [Rush phases](https://rushjs.io/pages/maintainer/phased_builds/) > are suggested to increase parallelism, but are _not required_ for cobuilds. > Enabling the cobuild feature[​](https://rushjs.io/pages/maintainer/cobuilds/#enabling-the-cobuild-feature "Direct link to Enabling the cobuild feature") --------------------------------------------------------------------------------------------------------------------------------------------------------- 1. Upgrade `rushVersion` in your **rush.json** to `5.104.1` or newer. 2. Create an autoinstaller for the Rush plugin: rush init-autoinstaller --name cobuild-plugin It's also okay to use an existing autoinstaller. For more about Rush plugins and autoinstallers, see [Using Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) and [Autoinstallers](https://rushjs.io/pages/maintainer/autoinstallers/) . 3. Add the `@rushstack/rush-redis-cobuild-plugin` plugin to the autoinstaller. (We'll use Redis for this tutorial.) **common/autoinstallers/cobuild-plugin/package.json** { "name": "cobuild-plugin", "version": "1.0.0", "private": true, "dependencies": { "@rushstack/rush-redis-cobuild-plugin": "5.104.0" }} > 👉 **IMPORTANT:** > > Over time, make sure to keep the version of `@rushstack/rush-redis-cobuild-plugin` in sync with the `rushVersion` from your **rush.json**. 4. Update the autoinstaller's lockfile: rush update-autoinstaller --name cobuild-plugin# Remember to commit the updated pnpm-lock.yaml file to git 5. Next, we need to update **rush-plugins.json** to load the plugin from our `rush-plugins` autoinstaller. **common/config/rush/rush-plugins.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item defines a plugin to be loaded by Rush. */ { /** * The name of the NPM package that provides the plugin. */ "packageName": "@rushstack/rush-redis-cobuild-plugin", /** * The name of the plugin. This can be found in the "pluginName" * field of the "rush-plugin-manifest.json" file in the NPM package folder. */ "pluginName": "rush-redis-cobuild-plugin", /** * The name of a Rush autoinstaller that will be used for installation, which * can be created using "rush init-autoinstaller". Add the plugin's NPM package * to the package.json "dependencies" of your autoinstaller, then run * "rush update-autoinstaller". */ "autoinstallerName": "cobuild-plugin" } ]} 6. Configure `rush-redis-cobuild-plugin` by creating its config file: **common/config/rush-plugins/rush-redis-cobuild-plugin.json** { /** * The URL of your Redis server */ "url": "redis://server.example.com:6379", /** * An environment variable that your CI pipeline will assign, * which the plugin uses to authenticate with Redis. */ "passwordEnvironmentVariable": "REDIS_PASSWORD"} 7. You can use `rush init` to create the **cobuild.json** [config file](https://rushjs.io/pages/configs/cobuild_json/) that is used to enable the cobuild feature. Make sure to set `"cobuildFeatureEnabled": true` as shown below: **common/config/rush/cobuild.json** /** * This configuration file manages Rush's cobuild feature. * More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", /** * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, * otherwise the cobuild feature will be disabled. */ "cobuildFeatureEnabled": true, /** * (Required) Choose where cobuild lock will be acquired. * * The lock provider is registered by the rush plugins. * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. */ "cobuildLockProvider": "redis"} 8. Run `rush update` which should now install the `cobuild-plugin` autoinstaller. This downloads its manifest file: **common/autoinstallers/cobuild-plugin/rush-plugins/@rushstack/rush-redis-cobuild-plugin/rush-plugin-manifest.json** Commit this file to Git as well. (As part of the plugin system, this file caches important information so that Rush can access it without having to install the plugin's NPM package.) Configuring build pipelines[​](https://rushjs.io/pages/maintainer/cobuilds/#configuring-build-pipelines "Direct link to Configuring build pipelines") ------------------------------------------------------------------------------------------------------------------------------------------------------ Each CI system has different ways of defining jobs. For this tutorial, we'll use a [GitHub Actions workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) since it's included with the free plan for public projects. Suppose our non-cobuild CI pipeline looks like this (with build cache writes enabled): **.github/workflows/ci-single.yml** name: ci-single.ymlon: #push: # branches: ['main'] #pull_request: # branches: ['main'] # Allows you to run this workflow manually from the Actions tab workflow_dispatch:jobs: build: name: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - name: Rush Install run: node common/scripts/install-run-rush.js install - name: Rush build (install-run-rush) run: node common/scripts/install-run-rush.js build --verbose --timeline env: RUSH_BUILD_CACHE_WRITE_ALLOWED: 1 RUSH_BUILD_CACHE_CREDENTIAL: ${{ secrets.RUSH_BUILD_CACHE_CREDENTIAL }} Here's how we would convert that into a cobuild with 3 runners: **.github/workflows/ci-cobuild.yml** name: ci-cobuild.ymlon: #push: # branches: ['main'] #pull_request: # branches: ['main'] # Allows you to run this workflow manually from the Actions tab workflow_dispatch:jobs: build: name: cobuild runs-on: ubuntu-latest strategy: matrix: runner_id: [runner1, runner2, runner3] steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - name: Rush Install run: node common/scripts/install-run-rush.js install - name: Rush build (install-run-rush) run: node common/scripts/install-run-rush.js build --verbose --timeline env: RUSH_BUILD_CACHE_WRITE_ALLOWED: 1 RUSH_BUILD_CACHE_CREDENTIAL: ${{ secrets.RUSH_BUILD_CACHE_CREDENTIAL }} RUSH_COBUILD_CONTEXT_ID: ${{ github.run_id }}_${{ github.run_number }}_${{ github.run_attempt }} RUSH_COBUILD_RUNNER_ID: ${{ matrix.runner_id }} REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }} The `runner_id` matrix causes the job to be run on 3 separate machines. The `REDIS_PASSWORD` variable name is what we defined earlier in **rush-redis-cobuild-plugin.json**. The `RUSH_COBUILD_CONTEXT_ID` and `RUSH_COBUILD_RUNNER_ID` variables are explained below. Cobuild environment variables in detail[​](https://rushjs.io/pages/maintainer/cobuilds/#cobuild-environment-variables-in-detail "Direct link to Cobuild environment variables in detail") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ### `RUSH_COBUILD_CONTEXT_ID`[​](https://rushjs.io/pages/maintainer/cobuilds/#rush_cobuild_context_id "Direct link to rush_cobuild_context_id") Cobuild runners must define this environment variable; without it, Rush will perform a regular build without any cobuild logic. The `RUSH_COBUILD_CONTEXT_ID` variable controls caching: Imagine that a pull request validation has failed because a project had errors. Without cobuilds, a project with errors is NOT saved to the build cache. If a person goes to the GitHub website and clicks a button to **"Re-run this job"**, the successful projects will be pulled from the cache, but that failed project will be forced to build again, which is good because maybe it was a transient failure. Whereas with cobuilds, if a project has errors, we don't want the other two machines to try to build that project. The error logs are saved to the build cache, and will be restored and printed by the other runners (to provide a complete log on every machine). But if a person clicks **"Re-run this job"**, how do we force the failing projects to get rebuild in that case? The `RUSH_COBUILD_CONTEXT_ID` identifier solves this. Rush adds it to the build cache key for failing projects to ensure they are rebuilt if the job is reattempted. `RUSH_COBUILD_CONTEXT_ID` is specified differently for each system. It can be any string with these properties: * `RUSH_COBUILD_CONTEXT_ID` must be the same across every machine for a given pipeline * `RUSH_COBUILD_CONTEXT_ID` must be different each time the pipeline is run, including "reattempts" and "retries" * It must be a short string, because it becomes part of a cache key Some examples: | CI system | Suggested value for `RUSH_COBUILD_CONTEXT_ID` | | --- | --- | | [Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/run-number?view=azure-devops&tabs=yaml) | `$(Build.BuildNumber)_$(System.JobAttempt)` | | [CircleCI](https://circleci.com/docs/variables/) | `${CIRCLE_WORKFLOW_ID}_${CIRCLE_WORKFLOW_JOB_ID}` | | [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables) | `${{ github.run_id }}_${{ github.run_number }}_${{ github.run_attempt }}` | ### `RUSH_COBUILD_RUNNER_ID`[​](https://rushjs.io/pages/maintainer/cobuilds/#rush_cobuild_runner_id "Direct link to rush_cobuild_runner_id") This environment variable uniquely identifies each machine. If this variable is not defined, Rush will generate a random identifier on each run. In the example, we specified it as `RUSH_COBUILD_RUNNER_ID: ${{ matrix.runner_id }}` for readability. Technical details[​](https://rushjs.io/pages/maintainer/cobuilds/#technical-details "Direct link to Technical details") ------------------------------------------------------------------------------------------------------------------------ ### Build cache correctness[​](https://rushjs.io/pages/maintainer/cobuilds/#build-cache-correctness "Direct link to Build cache correctness") You will find that the cobuild feature increases the requirement that every project's output is accurately saved and restored by the cache. To see why, suppose that project `A` directly depends on project `B`. There are several ways that an inaccurate cache might still produce a successful build: 1. Project `A` and `B` are both cache misses, so no caching occurs. **\- OR -** 2. Project `A` and `B` are both cache hits. `B` does not get restored accurately. `A` would have failed to compile, except that we didn't need to build `A`. The final result of `A` is still usable. **\- OR -** 3. Only project `A` is a cache miss. `B` does not get restored accurately, but the missing files are still on disk from a previous build on the same machine. Thus `A` compiles without errors. These lucky situations are relatively common in non-cobuild scenarios. If you're unlucky, reattempting the job may cause the problem to "clear up" (due to new cache hits). The underlying problem won't be noticed consistently until this situation: 4. Only project `A` is a cache miss. `B` does not get restored accurately, and our build starts with a clean disk. Cobuilds greatly increase the likelihood of encountering #4, because as much as possible, their aim is to build cache misses that depend on a cache hit. In short, after first enabling the cobuilds feature, you may need to spend some time fixing incorrect build cache configurations. > 👉 **Troubleshooting build cache inaccuracies** > > If you suspect that files are not getting accurately saved/restored by the Rush build cache, try the [rush-audit-cache-plugin](https://www.npmjs.com/package/rush-audit-cache-plugin) > . It detects such problems by monitoring file writes during your build operation. The written file paths are then compared with the project's cache configuration, producing a report of file paths that aren't being cached correctly. Then you can resolve the problem by correcting the cache configuration or fixing the tool to write its outputs in a cacheable location. ### What gets stored in Redis?[​](https://rushjs.io/pages/maintainer/cobuilds/#what-gets-stored-in-redis "Direct link to What gets stored in Redis?") The cobuild feature uses Redis for two main purposes: 1. **A reentrant locking mechanism.** The key corresponding to the lock is in the format of `cobuild:lock::`, and the corresponding value is ``. When setting the lock key, a 30-second expiration time is also set. This ensures that the same runner can reacquire the lock when attempting to obtain it again, while also automatically releasing the lock if the runner does not respond for a certain period of time. 2. **Track completed operations.** The key corresponding to the completed state is in the format of `cobuild:completed::`, and the corresponding value is a string in a serialized form of the operation's execution result and the corresponding `cache_id`. Before attempting to acquire a lock, a machine will first query this completion result information. If there is a completion result available, the result is reused based on the parsed information. See also[​](https://rushjs.io/pages/maintainer/cobuilds/#see-also "Direct link to See also") --------------------------------------------------------------------------------------------- * [Enabling the build cache](https://rushjs.io/pages/maintainer/build_cache/) * [Environment variables](https://rushjs.io/pages/configs/environment_vars/) * [Using Rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/) * [Autoinstallers](https://rushjs.io/pages/maintainer/autoinstallers/) * [When to use cobuilds?](https://rushjs.io/pages/maintainer/cobuilds/#when-to-use-cobuilds) * [Enabling the cobuild feature](https://rushjs.io/pages/maintainer/cobuilds/#enabling-the-cobuild-feature) * [Configuring build pipelines](https://rushjs.io/pages/maintainer/cobuilds/#configuring-build-pipelines) * [Cobuild environment variables in detail](https://rushjs.io/pages/maintainer/cobuilds/#cobuild-environment-variables-in-detail) * [`RUSH_COBUILD_CONTEXT_ID`](https://rushjs.io/pages/maintainer/cobuilds/#rush_cobuild_context_id) * [`RUSH_COBUILD_RUNNER_ID`](https://rushjs.io/pages/maintainer/cobuilds/#rush_cobuild_runner_id) * [Technical details](https://rushjs.io/pages/maintainer/cobuilds/#technical-details) * [Build cache correctness](https://rushjs.io/pages/maintainer/cobuilds/#build-cache-correctness) * [What gets stored in Redis?](https://rushjs.io/pages/maintainer/cobuilds/#what-gets-stored-in-redis) * [See also](https://rushjs.io/pages/maintainer/cobuilds/#see-also) --- # Rush files and folders | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#docusaurus_skipToContent_fallback) On this page Every Rush monorepo has a standard folder structure that is created by `rush init` and validated by `rush update`. Configuration files[​](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#configuration-files "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------ | Folder path | What it does | | --- | --- | | [rush.json](https://rushjs.io/zh-cn/pages/configs/rush_json/) | The main configuration file for Rush | | [common/config/rush/.npmrc](https://rushjs.io/zh-cn/pages/configs/npmrc/) | If you need custom settings for "npm install" (e.g. NPM registry mappings), put them in this file. Rush will copy this file into the **common/temp/** folder. | | [common/config/rush/.npmrc-publish](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/) | Used instead of `.npmrc` for publishing operations. | | [common/config/artifactory.json](https://rushjs.io/zh-cn/pages/configs/artifactory_json/) | Configuration for Rush integration with JFrog Artifactory services. | | [common/config/build-cache.json](https://rushjs.io/zh-cn/pages/configs/build-cache_json/) | Configuration for Rush's [Build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) | | [common/config/rush/command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) | Used to define [custom commands](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/)
. | | [common/config/rush/common-versions.json](https://rushjs.io/zh-cn/pages/configs/common-versions_json/) | Used to specify versions that affect all projects in a repo. | | [common/config/rush/deploy.json](https://rushjs.io/zh-cn/pages/configs/deploy_json/) | Used to define profiles for the [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/)
command | | [common/config/rush/experiments.json](https://rushjs.io/zh-cn/pages/configs/experiments_json/) | Enables experimental features of Rush | | common/config/rush/npm-shrinkwrap.json | The shrinkwrap file when your package manager is NPM. This is the common shrinkwrap file that applies to all projects in the Rush repo. For more information, see **"What is this "shrinkwrap file"** in the [Everyday commands](https://rushjs.io/zh-cn/pages/developer/everyday_commands/)
section. | | common/config/rush/rush-plugins.json | Specifies [Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/)
to be loaded for the monorepo. | | common/config/rush/pnpm-lock.yaml | The shrinkwrap file when your package manager is PNPM. | | common/config/rush/yarn.lock | The shrinkwrap file when your package manager is Yarn. | | common/config/rush/browser-approved-packages.json | Used by the **approvedPackagesPolicy** setting from [rush.json](https://rushjs.io/zh-cn/pages/configs/rush_json/) | | common/config/rush/nonbrowser-approved-packages.json | Used by the **approvedPackagesPolicy** setting from rush.json | | [common/config/rush/pnpm-config.json](https://rushjs.io/zh-cn/pages/configs/pnpm-config_json/) | Configuration specific to the PNPM package manager | | [common/config/rush/version-policies.json](https://rushjs.io/zh-cn/pages/configs/version-policies_json/) | Defines the [rush version](https://rushjs.io/zh-cn/pages/commands/rush_version/)
and [rush publish](https://rushjs.io/zh-cn/pages/commands/rush_publish/)
workflows. | Standard Rush folders[​](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#standard-rush-folders "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- | Folder path | What it does | | --- | --- | | common/autoinstallers/... | [Autoinstaller projects](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/)
are created under this folder | | common/changes/... | Stores change files created by the [rush change](https://rushjs.io/zh-cn/pages/commands/rush_change/)
command and consumed by the [rush version](https://rushjs.io/zh-cn/pages/commands/rush_version/)
command. | | common/deploy/... | The [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/)
creates deployment configurations under this folder. | | common/git-hooks/... | Rush's [git hook scripts](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/)
are defined here | | common/pnpm-patches/... | The [rush-pnpm commit-patch](https://rushjs.io/zh-cn/pages/commands/rush-pnpm/)
command stores package patch files under this folder | | common/scripts/install-run-rush.js | CI bootstrap script for invoking `rush`. The `rush update` generates this file, which should be committed to Git. See [Enabling CI builds](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/)
for details. | | common/scripts/install-run-rush-pnpm.js | CI bootstrap script for invoking [rush-pnpm](https://rushjs.io/zh-cn/pages/commands/rush-pnpm/)
. | | common/scripts/install-run-rushx.js | CI bootstrap script for invoking [rushx](https://rushjs.io/zh-cn/pages/commands/rushx/)
. | | common/scripts/install-run.js | CI bootstrap script for invoking arbitrary NPM packages. | Temporary files created by Rush[​](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#temporary-files-created-by-rush "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------ | Folder path | What it does | | --- | --- | | common/temp/build-cache/... | Default storage location for Rush's [Build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) | | common/temp/install-run/... | Storage for the **install-run.js** and **install-run-rush.js** scripts. See [Enabling CI builds](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/)
. | | common/temp/node\_modules/... | The installed packages. This is a plain old `npm install` output, with no symlinks in this tree. | | common/temp/npm-cache/... | A local NPM cache will be created here. Rush does not use the global NPM cache due to its concurrency problems. | | common/temp/npm-local/... | If the NPM package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/npm-tmp/... | Temporary files created by NPM during installation. | | common/temp/patches/... | The [rush-pnpm patch](https://rushjs.io/zh-cn/pages/commands/rush-pnpm/)
command creates patch files under this temporary folder (which `rush-pnpm commit-patch` will copy to `common/pnpm-patches`) | | common/temp/pnpm-local/... | If the PNPM package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/pnpm-store/... | If the PNPM package manager is selected, this is the default location of the PNPM store. (It can be redirected using the `RUSH_PNPM_STORE_PATH` environment variable.) | | common/temp/projects/... | Synthetic projects referenced by **common/temp/package.json**. | | common/temp/rush-recycler/... | Used to speed up recursive deletes. | | common/temp/telemetry/... | Stores telemetry output saved by Rush when `telemetryEnabled=true` in **rush.json** | | common/temp/yarn-local/... | If the Yarn package manager is selected, this is a symlink to Rush's global install of the version specified in **rush.json**. | | common/temp/last-install.flag | Don't worry about this file. It tracks the timestamp of the last successful `rush install`. | | common/temp/package.json | The common package definition. | | common/temp/repo-state.json | Generated by the `preventManualShrinkwrapChanges` setting from [pnpm-config.json](https://rushjs.io/zh-cn/pages/configs/pnpm-config_json/) | | common/temp/rush-link.json | Don't worry about this file. It is created whenever you run `rush link`, and read by later commands such as "rush build". | * [Configuration files](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#configuration-files) * [Standard Rush folders](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#standard-rush-folders) * [Temporary files created by Rush](https://rushjs.io/zh-cn/pages/advanced/rush_files_and_folders/#temporary-files-created-by-rush) --- # Rush 子空间 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/subspaces/#docusaurus_skipToContent_fallback) On this page 什么是子空间?[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E4%BB%80%E4%B9%88%E6%98%AF%E5%AD%90%E7%A9%BA%E9%97%B4 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------- 子空间是 Rush 的一个功能,使单一的 monorepo 能够使用多个 PNPM 锁定文件进行安装。例如,如果子空间名称是 `my-team`,则会有一个文件夹 `common/config/subspaces/my-team/`,其中包含 `pnpm-lock.yaml` 文件和相关配置。每个 Rush 项目都只属于一个子空间,monorepo 仍然保持一个统一的 "工作区"。因此,一个项目的 `package.json` 文件可以使用 `workspace:` 来指定对其他子空间项目的依赖。 有什么好处?[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%A4%84 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------ 通常情况下,整个 monorepo 使用单个锁定文件是最好的,因为这可以优化安装时间,并最大限度地减少管理版本冲突的维护工作。然而,在某些情况下,允许多个锁定文件有其优势: * **非常庞大的代码库**:锁定文件可以被视为一个庞大的多变量方程,我们通过在许多项目中协调 NPM 包版本选择来消除冲突并尽量减少重复。([锁定文件浏览器](https://lfx.rushstack.io/) 文档对此有详细说明。)将 monorepo 的依赖关系分成较小的锁定文件确实使这些方程更小、更容易解决,但增加了管理版本的整体开销。对于庞大的工程团队来说,分工比减少工作总量更重要。 * **解耦的项目集合**:一个庞大的代码库中可能有一些项目集,它们的依赖关系与代码库的其他部分不一致。例如,假设有 50 个项目构成一个使用已弃用或过时框架的遗留应用程序,没有业务动机去现代化。将这些项目移入一个子空间可以使其版本管理独立。 * **安装测试**:在发布 NPM 包时,使用 `workspace:*` 符号链接无法重现某些错误。例如,幽灵依赖或错误的 `.npmignore` 通配符会导致外部消费者的包失败,但在 monorepo 中测试同一库时可能工作正常。将测试项目移入子空间(结合[注入依赖](https://rushjs.io/zh-cn/pages/advanced/injected_deps/) )会产生更准确的安装,从而发现此类问题,同时避免实际发布到测试 NPM 注册表的开销。 我需要多少个子空间?[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E6%88%91%E9%9C%80%E8%A6%81%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%90%E7%A9%BA%E9%97%B4 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 我们通常建议 "尽可能少" 以尽量减少额外的版本管理开销。_每个团队一个子空间_ 是一个合理的最大上限。尽管如此,在一个包含超过 1000 个子空间的生产环境的 monorepo 中,该功能已被成功使用。 > **真实世界示例** > > Rush Stack 在 GitHub 上的自有仓库目前配置了两个子空间: > > * [common/config/subspaces/build-tests-subspace](https://github.com/microsoft/rushstack/tree/main/common/config/subspaces/build-tests-subspace) > : 用于测试发布的 NPM 包的安装 > * [common/config/subspaces/default](https://github.com/microsoft/rushstack/tree/main/common/config/subspaces/default) > : 包含所有其他项目 功能设计[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- 每个子空间必须在 [common/config/subspaces.json](https://rushjs.io/zh-cn/pages/configs/subspaces_json/) 配置文件中进行集中注册。项目通过 [rush.json](https://rushjs.io/zh-cn/pages/configs/rush_json/) 中的 `subspaceName` 字段添加到子空间。 每个子空间的配置位于文件夹 `common/config/subspaces//` 中,可能包含以下文件: | 子空间文件 | 作用 | | --- | --- | | [`common-versions.json`](https://rushjs.io/zh-cn/pages/configs/common-versions_json/) | Rush 版本覆盖 | | [`pnpm-config.json`](https://rushjs.io/zh-cn/pages/configs/pnpm-config_json/) | PNPM 版本覆盖 | | `pnpm-lock.yaml` | PNPM 锁定文件 | | `repo-state.json` | Rush 生成的配置文件,用于防止手动更改锁定文件 | | [`.npmrc`](https://rushjs.io/zh-cn/pages/configs/npmrc/) | 包管理器配置 | | [`.pnpmfile.cjs`](https://rushjs.io/zh-cn/pages/configs/pnpmfile_cjs/) | 程序化版本覆盖 | > 注意:`common/config/.npmrc-publish` 并不适用于子空间。包发布通常与包安装无关。 以下部分文件既可以在子空间中定义,也可以在 monorepo 配置中定义,继承关系如下表所示: * 子空间配置目录:`common/config/subspaces//` * monorepo 配置目录:`common/config/rush/` | 子空间文件 | monorepo 文件 | 继承关系 | | --- | --- | --- | | `common-versions.json` | 无 | _启用子空间时禁止使用 monorepo 的该文件。_ | | `pnpm-config.json` | `pnpm-config.json` | **回退机制**:仅当子空间中不存在该文件时才使用 monorepo 文件。 | | `pnpm-lock.yaml` | 无 | _启用子空间时禁止使用 monorepo 的该文件。_ | | `repo-state.json` | 无 | _启用子空间时禁止使用 monorepo 的该文件。_ | | `.npmrc` | `.npmrc` | **合并**:两个文件合并使用,子空间设置具有优先权。(Rush 在操作的工作目录中生成临时 `.npmrc` 文件时进行合并。) | | `.pnpmfile.cjs` | 无 | _启用子空间时禁止使用 monorepo 的该文件。_ | 在未启用子空间的情况下,Rush 会在 `common/temp/` 文件夹中生成并安装 PNPM 工作区。启用子空间后,则会分别在如 `common/temp//` 的文件夹中进行安装。 有两种基本的操作模式: 1. **只有几个子空间:** 你可以在 `subspaces.json` 中设置 `"preventSelectingAllSubspaces": false`,并且默认情况下,`rush install` 将安装所有子空间。 2. **大量子空间:** 如果安装所有子空间会消耗过多的时间和磁盘空间,那么你可以设置 `"preventSelectingAllSubspaces": true`。在此模式下,调用 `rush install` 或 `rush update` 等命令时,用户必须以某种方式过滤子空间,例如: * 使用 `rush install --to my-project` 只安装指定项目的依赖 * 使用 `rush install --subspace my-subspace` 只安装特定子空间 * 使用 [项目选择器](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#subspace-members-subspace) 中的 `rush install --to subspace:my-subspace` 为属于某个子空间的项目安装 如何启用子空间[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%A6%82%E4%BD%95%E5%90%AF%E7%94%A8%E5%AD%90%E7%A9%BA%E9%97%B4 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------- 1. 确保你的 **rush.json** 文件中指定了 `"rushVersion": "5.122.0"` 或更新版本,`"pnpmVersion": "8.7.6"` 或更新版本。 2. 使用 **subspaces.json** 启用此功能并定义子空间。你可以从 [subspaces.json](https://rushjs.io/zh-cn/pages/configs/subspaces_json/) 文档中复制此文件的模板,或者使用 `rush init` 生成它。在本教程中,我们将创建一个名为 `install-test` 的子空间,用于测试 NPM 包: **common/config/rush/subspaces.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", /** * 设置此标志为 "true" 以启用子空间。 */ "subspacesEnabled": false, /** * 当执行类似 "rush update" 的命令且没有使用 "--subspace" 或 "--to" 参数时,Rush 会安装所有子空间。 * 在拥有大量子空间的庞大 monorepo 中,这样做会非常缓慢。 * 通过始终要求选择参数来执行类似 "rush update" 之类的命令,可以设置 "preventSelectingAllSubspaces" 为 true 以避免此类错误。 */ "preventSelectingAllSubspaces": false, /** * 子空间名称列表,应为小写的字母数字单词并用连字符分隔,例如 "my-subspace"。 * 对应的配置文件路径可能为 "common/config/subspaces/my-subspace/package-lock.yaml"。 */ "subspaceNames": [ // "default" 子空间即使你没有定义它也总是存在,但为了清晰起见,让我们将其包含在内 "default", "install-test" // 👈👈👈 我们的第二个子空间名称 ]} 3. 创建 `default` 子空间文件夹并将现有配置文件移动到那里: cd my-repomkdir --parents common/config/subspaces/default# 移动这些文件:mv common/config/rush/common-versions.json common/config/subspaces/default/mv common/config/rush/pnpm-lock.yaml common/config/subspaces/default/mv common/config/rush/.npmrc common/config/subspaces/default/# 重命名此文件:mv common/config/rush/.pnpmfile.cjs common/config/subspaces/default/.pnpmfile.cjs 4. 创建 `install-test` 子空间文件夹: cd my-repomkdir --parents common/config/subspaces/install-test 5. 通过编辑 `rush.json` 将项目分配到子空间。例如: **rush.json** . . . "projects": [ { "packageName": "my-library-test", "projectFolder": "test-projects/my-library-test", "subspaceName": "install-test" }. . .\ \ 如果任何项目省略了 `"subspaceName"`,它们将属于 `default` 子空间。\ \ 6. 更新新子空间的锁定文件:\ \ # 清理之前的 common/temp 文件夹rush purge# 重新生成 "default" 子空间:rush update --full --subspace default# 重新生成 "install-test" 子空间:rush update --full --subspace install-test\ \ > **注意:** 你可以在不使用 `--full` 重新生成任何锁定文件的情况下迁移到子空间, 但这是一个更复杂的过程,可能需要使用脚本重写 `pnpm-lock.yaml` 文件中的某些路径。\ \ \ 另见[​](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%8F%A6%E8%A7%81 "Direct link to heading")\ \ -----------------------------------------------------------------------------------------------------\ \ * [subspaces.json](https://rushjs.io/zh-cn/pages/configs/subspaces_json/)\ 配置文件\ * [rfc-4230-rush-subspaces.md](https://github.com/microsoft/rushstack/blob/main/common/docs/rfcs/rfc-4230-rush-subspaces.md)\ :此功能的原始规范,其中更详细地解释了动机和设计\ \ * [什么是子空间?](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E4%BB%80%E4%B9%88%E6%98%AF%E5%AD%90%E7%A9%BA%E9%97%B4)\ \ * [有什么好处?](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%A4%84)\ \ * [我需要多少个子空间?](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E6%88%91%E9%9C%80%E8%A6%81%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%90%E7%A9%BA%E9%97%B4)\ \ * [功能设计](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1)\ \ * [如何启用子空间](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%A6%82%E4%BD%95%E5%90%AF%E7%94%A8%E5%AD%90%E7%A9%BA%E9%97%B4)\ \ * [另见](https://rushjs.io/zh-cn/pages/advanced/subspaces/#%E5%8F%A6%E8%A7%81) --- # 代理上下文文件 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/ai/context_files/#docusaurus_skipToContent_fallback) 人工智能(AI)**编码助手**是一类软件代理,旨在帮助工程师更高效地编写代码和分析问题。它们通常依赖于经过通用软件工程知识训练的**大型语言模型**(LLMs),但往往不熟悉 Rush 的工作区结构、Rush 的最新特性,或者你所在团队项目的具体细节。你可以通过在 monorepo 中添加**上下文文件**来提升这些工具的准确性。上下文文件包含用于辅助 agent 的额外说明和信息。 下表提供了为主流编码助手设计的可复用上下文文件链接。 | 编码助手 | Rush 的上下文文件模板 | | --- | --- | | [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot) | [.github/copilot-instructions.md](https://github.com/microsoft/rushstack/blob/main/.github/copilot-instructions.md) | | [Cursor](https://docs.cursor.com/context/rules) | [.cursor/rules/rush.mdc](https://github.com/microsoft/rushstack/blob/main/.cursor/rules/rush.mdc) | | [Trae](https://docs.trae.ai/ide/rules-for-ai?_lang=en) | [.trae/project\_rules.md](https://github.com/microsoft/rushstack/blob/main/.trae/project_rules.md) | **如果你的编码助手未出现在本表中:**欢迎补充!请先创建一个 pull request,将你的文件添加到 [microsoft/rushstack](https://github.com/microsoft/rushstack/pulls) 仓库。然后再在 [microsoft/rushstack-websites](https://github.com/microsoft/rushstack-websites/blob/main/websites/rushjs.io/docs/pages/ai/context_files.md) 仓库中创建一个 pull request,更新上述表格并添加你的文件链接。 --- # rush add | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_add/#docusaurus_skipToContent_fallback) 用法:rush add [-h] -p PACKAGE [--exact] [--caret] [--dev] [-m] [-s] [--all]在当前项目下(由当前的工作目录决定)添加指定的包作为依赖,然后运行"rush update"。如果版本没有指定,则会自动检测版本(通常是最新的版本或者是不会破坏 "ensureConsistentVersions" 策略的版本)如果指定了版本范围(或者工作区范围),则会使用范围内的最新版本。如果没有使用 "--exact" 或 "--carte" 参数,则会自动在版本号前面加上波浪号。如果使用 "--make-consistent" 参数,则可以更新所有包的 package.json 文件,使其使用相同的依赖。可选参数: -h, --help 展示帮助信息并退出。 -p PACKAGE, --package PACKAGE (必须) 应当被添加到依赖的包名。可以在 "@" 符号后添加语义化版本。 警告: 特征字符串经常被 shell 解释,所以建议使用引号。例如,书 写 "rush add --package "example@^1.2.3"", 而不是 "rush add --package example@^1.2.3". --exact 一旦使用该参数,添加到 package.json 那的版本将是一个精确 版本(例如,没有 ~ 或 ^ 标记)。 --caret 一旦使用该参数,那么添加到 package.json 中的版本将带有 ^ 标记。 --dev 一旦使用该参数,那么添加到库将添加到 package.json 中的 "devDependencies" 字段。 -m, --make-consistent 一旦使用该参数,使用该库的其他项目将会在 package.json 文件中 将该依赖成相同的版本。 -s, --skip-update 一旦使用该参数,当更新完 package.json 文件后将不会执行 "rush update". --all 一旦使用该参数,该依赖将被添加到所有项目中。 --- # 编写变更日志 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/best_practices/change_logs/#docusaurus_skipToContent_fallback) On this page 当发布一个 NPM 包时,最普遍的做法是带上一个 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) 文件,该文件记录了问题修复、新功能、功能变动或移除。Rush 中可以使用 [rush change](https://rushjs.io/zh-cn/pages/commands/rush_change/) 来自动完成这些功能。当你准备提交 PR 时,并将变动 commit 到相应的分支上后,需要执行这个命令,它会分析当前分支中的变动,并在必要时让你对其变动进行描述。 如何组织你的描述是很重要的:不能太具体,也不能太复杂,不能暴露隐私,同时要让描述信息更友好。我们建议在可读性上做文章,问问你自己: * “此次变更是否与第三方开发者有关?” * “是否存在破坏性变更?” * “是否修复了某个让人不悦的 bug? ” * “是否有需要他人适用的新功能?” 在一些工作流中,发布前需要有人来编辑变更日志,然而应该是每个人都尽其最大努力来保证日志内容的清晰和专业。 最佳实践[​](https://rushjs.io/zh-cn/pages/best_practices/change_logs/#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- * 使用 [简单的现代时](http://www.englishtenses.com/tenses/present_simple) 和 [命令式语气](http://grammarist.com/grammar/english-moods/) 。 * 从一个不熟悉项目细节的外部人员的角度来写。 * 尽量描述场景(例如:“搜索现在支持通配符”),而不是代码的变更(例如:“在 SearchHelper 类中增加正则表达式的支持”) * 使用动词开头,推荐使用: * **Add** - 当你引入或暴露一个新功能、属性、类、UI 等。 * **Remove** - 当你完全移除了不会再被使用的东西。 * **Deprecate** - 当你计划移除某些东西,但是目前仍然可用。 * **Fix an issue with/where...** - 当你修复一个 bug. * **Improve** - 改进了一个已有的东西。 * **Update** - 更新了某项东西,但不一定使其更好。 * **Upgrade** - 升级了依赖包的版本。 * **Initial/Beta release of ...** - 发布了一个新功能。 * 别用 **bug** 一词,转而使用 **issue**. * 不要使用缩写,除非是被广泛认可的(例如:"HTTP") * 使用正确的拼写和语法。CHANGELOG.md 是发布文档的一部分。 * 当涉及到公共 API 变化时,使用 `()` 后缀来指出函数名,例如 `setSomethingOnWebpart()`. * 当涉及到公共 API 变化时,使用 (`` ` ` ``) 来包裹类和其属性名。 * 当描述版本升级时,表明旧版本和新版本,例如:"Upgraded widget-library from `1.0.2` to `2.0.1`". * 当修复一个 Github issue 后,考虑在括号中添加 issue URL. * 不要在句尾添加句号,除非你有两个以上句子。 变更日志消息示例[​](https://rushjs.io/zh-cn/pages/best_practices/change_logs/#%E5%8F%98%E6%9B%B4%E6%97%A5%E5%BF%97%E6%B6%88%E6%81%AF%E7%A4%BA%E4%BE%8B "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 这里有一些用于编写 `rush change` 变更日志的示例: * _Add "buttonColor" to the button manifest schema_ * _Remove support for older mobile web browsers as described in the README.md_ * _Deprecate the `doSomething()` API function. Use `doSomethingBetter()` instead._ * _Fix an issue where "ExampleWidget" API did not handle dates correctly_ * _Improve the diagnostic logging when running in advanced mode_ * _Upgrade from React 15 to React 16_ * _Initial release of the flexible panels feature_ * [最佳实践](https://rushjs.io/zh-cn/pages/best_practices/change_logs/#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5) * [变更日志消息示例](https://rushjs.io/zh-cn/pages/best_practices/change_logs/#%E5%8F%98%E6%9B%B4%E6%97%A5%E5%BF%97%E6%B6%88%E6%81%AF%E7%A4%BA%E4%BE%8B) --- # 启用合并队列 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#docusaurus_skipToContent_fallback) On this page **合并队列**(merge queue),也称为**提交队列**(commit queue)或**合并列车**(merge train),通过提供两个关键功能,改善了持续集成(CI)系统: * **增加安全性**,通过在合并 Git 分支之前而非之后对其进行验证,避免构建中断 * **提高吞吐量**,通过智能地结合工作或并行化任务 合并队列可以是流行的 CI 系统(如 GitHub 或 GitLab)的内置功能, 或者可能是一个附加服务。 动机示例[​](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%8A%A8%E6%9C%BA%E7%A4%BA%E4%BE%8B "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- 假设拉取请求 1 和 2 正等待合并到您的`main`分支,它们的分支分别命名为`pr1`和`pr2`。传统上有几种基本的验证方法: 1. **缓慢但安全**:我们用`start`来指代`main`分支的最新提交。 CI 系统创建一个临时分支`start+pr1`(将`start`与`pr1`合并)。 我们构建这个“热合并”,如果成功,现在我们可以将 PR 1 合并到`main`。 如果 PR 2 有正在进行的构建,它应该被中止,因为`main`已经改变。它的热合并需要 用`start+pr1+pr2`重做,因为这是 PR 2 合并后将在`main`中的内容。 这种方法确保了`main`中每个提交的正确性。然而,在一个活跃的 monorepo 中, 很快就会积累很多临时分支,因为最终合并的构建根本没有被并行化。 2. **乐观**:不那么严格,我们可以选择允许 PR 2 仅在`start+pr2`构建成功的情况下合并, 即使最终提交将是`start+pr1+pr2`。实际上,我们希望如果 `start+pr1`和`start+pr2`构建成功,那么`start+pr1+pr2`也会成功。这通常是正确的, 但例如,如果 PR 1 重命名了一个 API,而 PR 2 引入了对该 API 的新调用,那么它们的 组合将失败,尽管它们单独成功。 乐观方法明显更快,因为 PR 1 和 PR 2 可以并行构建 并且以任何顺序合并。然而,每当`main`分支被破坏时,都是一个不幸的事件, 需要撤销 PR 或合并修复以恢复到良好状态。根据支持人员的不同, 这可能需要几小时甚至几天,在此期间每个人的工作都被打断。 在一个繁忙的 monorpeo 中,这些故障的代价会十分高昂 3. **盲目乐观**:值得一提的是,早期系统甚至没有执行热合并。 它们使用了乐观策略,但基于一个可能非常过时的`main`基础。 可能会使用策略来限制基础可以有多老,以小时或 Git 提交为度量。 合并队列如何帮助[​](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%90%88%E5%B9%B6%E9%98%9F%E5%88%97%E5%A6%82%E4%BD%95%E5%B8%AE%E5%8A%A9 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 我们首先做出一个决定,安全是毋庸置疑的:在 PR 1 合并到`main`之后, 我们不会接受基于`start+pr2`成功构建的 PR 2。为了安全起见,我们坚持要求 `start+pr1+pr2`的成功构建。 合并队列的一个重要策略是`start+pr1+pr2`可以更早开始。 这里是一个 假设的时间表: | 时间 | PR 1 | PR 2 | `start+pr1` 构建 | `start+pr2` 构建 | `start+pr1+pr2` 构建 | | --- | --- | --- | --- | --- | --- | | 1:00 | 创建 | | | | | | 1:01 | . | | 开始 | | | | 2:00 | . | 创建 | . | | | | 2:01 | . | . | . | 开始 | 开始 | | 4:00 | . | . | . | . | . | | 5:00 | . | . | 成功 | . | . | | 5:01 | 合并 | . | | . | . | | 5:02 | | . | | 取消 | . | | 6:00 | | . | | | . | | 7:00 | | . | | | 成功 | | 7:01 | | 合并 | | | | 为什么我们要构建`start+pr2`,只是为了稍后取消它吗?如果是 PR 2 的构建提前完成,那么实际的工作流程 可能看起来是这样的: | 时间 | PR 1 | PR 2 | `start+pr1` 构建 | `start+pr2` 构建 | `start+pr1+pr2` 构建 | | --- | --- | --- | --- | --- | --- | | 1:00 | 创建 | | | | | | 1:01 | . | | 开始 | | | | 2:00 | . | 创建 | . | | | | 2:01 | . | . | . | 开始 | 开始 | | 4:00 | . | . | . | . | . | | 5:00 | . | . | . | 成功 | . | | 5:01 | . | 合并 | . | | . | | 5:02 | . | | 取消 | | . | | 6:00 | . | | | | . | | 7:00 | . | | | | 成功 | | 7:01 | 合并 | | | | | 既然最终会合并到 `main` 分支,那么是否应该有一个额外的列用于 `start+pr2+pr1` 呢?不,检出的文件与 `start+pr1+pr2` 是相同的。构建验证只关心源文件内容,而不关心其 Git 历史。 注意,随着活跃 PR 的数量增加,分支组合的数量也会呈指数级增长。 例如,如果我们有三个同时进行的 PR,可能需要六个任务来处理 `start+pr1`、`start+pr2`、`start+pr3`、`start+pr1+pr2`、`start+pr2+pr3` 以及 `start+pr1+pr2+pr3`。 构建所有组合可能会迅速耗尽我们的机器资源。 为了避免资源成本激增,我们可以跳过那些看起来相对不太可能的组合,并且平均而言仍然可以从并行性中受益。极端的例子是,如果我们对 PR 1、PR 2 和 PR 3 成功有高度信心,可能我们只需要一个任务 `start+pr1+pr2+pr3`;其他组合只有在它失败时才尝试。显然,这种精细化实现的队列有更多的机会可以使合并效率显著高于基础的合并队列。 利用 Rush 工作区依赖[​](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%88%A9%E7%94%A8-rush-%E5%B7%A5%E4%BD%9C%E5%8C%BA%E4%BE%9D%E8%B5%96 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > 🚧 即将推出:此功能尚未准备好。 继续上面的例子,假设 PR 1 是对 `project-a` 的修复,而 PR 2 是对 `project-b` 的修复; 也就是说,每个 PR 的 Git 差异只影响一个项目文件夹下的文件路径。假设在 Rush 工作区内,没有其他项目依赖于 `project-a` 或 `project-b`。这意味着: * 通过 `rush build --from project-a` 构建的源代码,对于分支 `start+pr1` 和 `start+pr1+pr2` 是相同的。 * 通过 `rush build --from project-b` 构建的源代码,对于分支 `start+pr2` 和 `start+pr1+pr2` 是相同的。 这些假设保证了 PR 1 和 PR 2 是完全独立的。我们可以独立地构建它们,并安全地以任何顺序合并它们的分支。合并队列根本不需要构建 `start+pr1+pr2`。 接下来,假设 `project-b` 的 **package.json** 文件指定了对 `project-a` 的依赖。 在这种情况下,PR 就不再独立:在 PR 1 合并后,PR 2 只有先验证`start+pr1+pr2`后才能安全合并。 这种分析依赖于对文件夹之间依赖关系的了解,这在不同的编程语言和构建系统之间差异很大。即使在 JavaScript 的生态系统内,对 **package.json** 文件的解释也需要对 PNPM、Rush+PNPM、Yarn 等进行特别考虑。 合并队列通常提供了一种基本设施来描述文件夹依赖关系,可能使用一个 glob 模式来描述如下的静态关系: * _"这个文件夹包含 JavaScript 代码,而那个文件夹包含 Golang 代码, 所以它们之间不可能有任何依赖。"_ 或 * _"这个文件夹只包含非可构建文件,例如文档,因此忽略那里的任何差异。"_ 然而,在一个繁忙的 monorepo 中,有成百上千个项目,优化合并队列需要 准确地模拟项目文件夹之间的细粒度依赖关系。为此,我们正在协作 一种与语言无关的 [project-impact-graph.yaml](https://github.com/tiktok/project-impact-graph) 规范, 对于合并队列这样的服务而言,可以用来查询任何 monorepo 中任何编程语言的项目依赖。 使用 Rush 插件,这个 YAML 文件将通过 `rush update` 生成并提交到 Git,这使得 合并队列服务能够高效地查询任何分支的文件夹依赖关系,而无需进行 Git 检出。 流行的合并队列[​](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E6%B5%81%E8%A1%8C%E7%9A%84%E5%90%88%E5%B9%B6%E9%98%9F%E5%88%97 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------- 建议在您的 monorepo 中使用合并队列。以下是一些可能的选项: * GitHub 包括一个内置的 [合并队列](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) 可以与 GitHub Actions 一起使用或单独使用 * [Mergify](https://mergify.com/) 为 GitHub 提供了一个附加服务,具有高级优化功能。 有关设置详情,请参阅 [集成:将 Mergify 与 Rush 一起使用](https://rushjs.io/zh-cn/pages/integrations/mergify/) 。 * GitLab 包括一个内置的 [合并列车](https://docs.gitlab.com/ee/ci/pipelines/merge_trains.html) 功能 _如果您的组织使用的 Rush 相关合并队列未在上面列出,请添加它。_ * [动机示例](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%8A%A8%E6%9C%BA%E7%A4%BA%E4%BE%8B) * [合并队列如何帮助](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%90%88%E5%B9%B6%E9%98%9F%E5%88%97%E5%A6%82%E4%BD%95%E5%B8%AE%E5%8A%A9) * [利用 Rush 工作区依赖](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E5%88%A9%E7%94%A8-rush-%E5%B7%A5%E4%BD%9C%E5%8C%BA%E4%BE%9D%E8%B5%96) * [流行的合并队列](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/#%E6%B5%81%E8%A1%8C%E7%9A%84%E5%90%88%E5%B9%B6%E9%98%9F%E5%88%97) --- # 使用监听模式 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#docusaurus_skipToContent_fallback) On this page 诸如 [Webpack](https://webpack.js.org/configuration/watch/) 和 [Jest](https://jestjs.io/docs/cli) 等流行工具提供了“监听模式”功能:当任务完成后,工具选择文件系统来等待源代码发生变动,一旦监听到变动,任务队列会更新其输出。这加速开发,因为 (1) 一旦你保存文件就可以重新构建;(2) 由于进程没有停止,因此可以使用缓存。 因为这些功能仅仅对单个项目有效,一旦在 monorepo 中开发,我们需要能够**_一次性监听多项目_**的监听模式。 一个实验性的想法[​](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E4%B8%80%E4%B8%AA%E5%AE%9E%E9%AA%8C%E6%80%A7%E7%9A%84%E6%83%B3%E6%B3%95 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------ 假设我们的 monorepo 有如下项目: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) 上述图例中,圆圈表示本地项目,没有外部的 NPM 依赖。箭头 `D` 到 `C` 表明 `D` 依赖 `C`, 这意味着 `C` 必须在 `D` 构建前构建。 假设你保存了对项目 `B` 的变动: ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) 对于多项目的“监听模式”,我们预期会发生如下事情: * `B` 应该被重新构建,因为它的文件被改变了; * 之后,`C` 应该被重新构建,因为它依赖于 `B` * 之后,`D` 应该被重新构建,因为它依赖于 `C` * 最后,Webpack dev server(预期是由 `D` 唤起的)刷新你的 web 浏览器,重新构建的 app 如果通过 rush 来实现这个方案?假设项目内 `B` 和 `C` 都有如下的简单脚本: **package.json** . . . "scripts": { "build": "rm -Rf lib/ && tsc && jest" } . . . 我们将尝试在一个无限循环中调用 `rush build --to-except D`: # 构建所有依赖于 D 的项目(但不包括 D 本身),并在无限循环中重复这个操作$ while true; do rush build --to-except D; done 之后让它一直运行,我们在项目 `D` 中唤起 `heft start`(或者 `webpack serve`): 之后你会发现上述方案有一些问题: * `rm -Rf lib/` 删除了符号链接文件;符号链接会迷惑 Webpack 的文件监听,所以你会看到很多报错提示说:找不到导入的文件。Webpack 不会从中恢复它们,因为当文件重新写入时,符号链接的文件不会更新。 * 当监听时,`jest` 和 `rm -Rf` 步骤一般不重要。开发者的内部循环 **_编辑 -> 重新构建 -> 重新加载_** 比文件监听所需时间慢多了。 这些问题可以通过创建一个特殊的简化脚本来解决,比如这样: **package.json** . . . "scripts": { "build": "rm -Rf lib/ && tsc && jest", "build:watch": "tsc" } . . . 设置 "watchForChanges"(实验性)[​](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E8%AE%BE%E7%BD%AE-watchforchanges%E5%AE%9E%E9%AA%8C%E6%80%A7 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Rush 的“文件监听” 基本思想是用 [chokidar](https://www.npmjs.com/package/chokidar) 来优化循环。下面是其用法: 1. 在 [command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) 中的添加一个[自定义指令](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) 。继续上面的示例,我们的自定义指令将被命名为 `"build:watch"`。重要的设置是 `"incremental"` 和 `"watchForChanges"`: **common/config/rush/command-line.json** . . . "commands": [ { "name": "build:watch", "commandKind": "bulk", "summary": "Build projects and watch for changes", "description": "For details, see the article \"Using watch mode\" on the Rush website: https://rushjs.io/", // 使用增量构建(重要) "incremental": true, "enableParallelism": true, // 启用“监听模式” "watchForChanges": true }, . . .\ \ 2. 在每个项目的 **package.json** 下增加 `"build:watch"` 脚本([PR #2298](https://github.com/microsoft/rushstack/pull/2298)\ 的目标是简化这一步骤,来使得项目内的 `"build:watch"` 与 `"build"` 相等,最终可以被合并到一个共享的 [rig 包](https://rushstack.io/pages/heft/rig_packages/)\ 中。\ \ \ 如果你使用 [Heft](https://rushstack.io/pages/heft/overview/)\ , 你的脚本将会像这样:\ \ **package.json**\ \ . . . "scripts": { "build": "heft build --clean", "build:watch": "heft build" } . . .\ \ 3. 参考[选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/)\ 一文选中 `D` 的所有依赖,但不包含 `D` 本身:\ \ # 构建所有依赖于 D 的项目(但不包括 D 本身),并在无限循环中重复这个操作$ rush build:watch --to-except D\ \ 4. 随后,开一个项目目录中开启开发服务器:\ \ # 在项目 D 的目录下开启 Webpack 的开发服务器# (这是示例中的 web 应用)$ cd apps/D$ heft start # 或者用自己的 "npm run start"\ \ 5. 在某些情况下,为了实现更快的监听,`--changed-projects-only` 命令可以与 `"watchForChanges"` 结合使用。[增量构建](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/#building-changed-projects-only-unsafe)\ 一文详细说明了他是如何工作的,以及它是否适合使用。\ \ > **“实验性”** `"watchForChanges"` 的功能还在其初期阶段。有意见或建议请联系我们! GitHub issue [#1202](https://github.com/microsoft/rushstack/issues/1202)\ > 跟踪更多工作项,以及 [William Bernting](https://github.com/wbern)\ > 的开发计划。\ \ 社区解决方法[​](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E7%A4%BE%E5%8C%BA%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95 "Direct link to heading")\ \ ----------------------------------------------------------------------------------------------------------------------------------------------\ \ Rush 的社区分享了一些有用的替代方案:\ \ * [@telia/rush-select](https://www.npmjs.com/package/@telia/rush-select)\ 是为监听 RUsh 项目和选中部分构建的交互式工具。\ \ * [rush-dev-watcher](https://github.com/dimfeld/rush-dev-watcher)\ 是一个简单有用的脚本,它是由 [Daniel Imfeld](https://github.com/dimfeld)\ 开发的,它会执行一次初始构建,然后启动多个监听器。\ \ \ 参考[​](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E5%8F%82%E8%80%83 "Direct link to heading")\ \ ------------------------------------------------------------------------------------------------------\ \ * [选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/)\ \ * [增量构建](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/)\ \ \ * [一个实验性的想法](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E4%B8%80%E4%B8%AA%E5%AE%9E%E9%AA%8C%E6%80%A7%E7%9A%84%E6%83%B3%E6%B3%95)\ \ * [设置 "watchForChanges"(实验性)](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E8%AE%BE%E7%BD%AE-watchforchanges%E5%AE%9E%E9%AA%8C%E6%80%A7)\ \ * [社区解决方法](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E7%A4%BE%E5%8C%BA%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95)\ \ * [参考](https://rushjs.io/zh-cn/pages/advanced/watch_mode/#%E5%8F%82%E8%80%83) --- # Rush MCP 插件 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#docusaurus_skipToContent_fallback) On this page [Rush MCP 服务器](https://rushjs.io/zh-cn/pages/ai/rush_mcp/) 提供了一种现成的解决方案,用于提升人工智能(AI)**编码助手**在 Rush monorepo 中的工作效率。然而,大多数企业还拥有无法贡献给开源实现的内部系统,这些系统也可以集成到该服务中。为了满足这些需求,您可以为 [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) 实现 **Rush MCP 插件**。插件也可以以开源形式发布,以提供可选的附加功能或集成能力。 插件示例场景: * **团队 wiki**:查询运行在私有内容管理系统上的内部团队 wiki * **问题管理**:在内部工作管理系统中创建任务和问题 * **语义搜索**:使用专有句子转换模型在如 [Supabase](https://supabase.com/docs/guides/ai/semantic-search) 这样的语义向量数据库中进行搜索 创建插件[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%88%9B%E5%BB%BA%E6%8F%92%E4%BB%B6 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- > **复制我们的示例** > > GitHub 上的 [build-tests/rush-mcp-example-plugin](https://github.com/microsoft/rushstack/tree/main/build-tests/rush-mcp-example-plugin) > 项目展示了一个与 `@rushstack/mcp-server` 搭配使用的插件项目示例。 编写插件的主要步骤如下: 1. 创建一个名称遵循 `rush-mcp-_____-plugin` 命名模式的 NPM 包。 2. 在 **package.json** 文件中,`@rushstack/mcp-server` 包应放入 `devDependencies`,而不是 `dependencies`。 **重要提示:** 从该包中导入时应始终使用 `import type`。例如:`import type { RushMcpPluginSession } from '@rushstack/mcp-server';`。 3. 在项目根目录添加插件清单文件,并确保 [.npmignore](https://github.com/microsoft/rushstack/blob/main/build-tests/rush-mcp-example-plugin/.npmignore) 或 **package.json** 已配置,使得执行 `npm publish` 时能包含该文件: **/rush-mcp-plugin.json** /** * 每个插件包都必须在顶层文件夹(与 package.json 同级)中包含一个 "rush-mcp-plugin.json" 清单文件。 */{ /** * 唯一标识插件的名称。通常应与 NPM 包名称相同。 * 如果两个 NPM 包的 pluginName 相同,则它们不能同时加载。 */ "pluginName": "rush-mcp-example-plugin", /** * (可选)表示插件接受一个配置文件。MCP 服务器将加载该文件并传递给插件。 * * 配置文件路径将为 `/common/config/rush-mcp/.json`。 */ "configFileSchema": "./lib/rush-mcp-example-plugin.schema.json", /** * 入口点,其默认导出应为一个实现类。 */ "entryPoint": "./lib/index.js"} 4. 创建一个实现 `IRushMcpPlugin` 接口的插件: **/src/ExamplePlugin.ts** import type { IRushMcpPlugin, RushMcpPluginSession } from '@rushstack/mcp-server';import { StateCapitalTool } from './StateCapitalTool';export interface IExamplePluginConfigFile { capitalsByState: Record;}export class ExamplePlugin implements IRushMcpPlugin { public session: RushMcpPluginSession; public configFile: IExamplePluginConfigFile | undefined = undefined; public constructor(session: RushMcpPluginSession, configFile: IExamplePluginConfigFile | undefined) { this.session = session; this.configFile = configFile; } public async onInitializeAsync(): Promise { this.session.registerTool({ toolName: 'state_capital' }, new StateCapitalTool(this)); }} 5. 上述清单指定了 `"entryPoint": "./lib/index.js"`,因此入口点应返回插件工厂: **/src/index.ts** import type { RushMcpPluginSession, RushMcpPluginFactory } from '@rushstack/mcp-server';import { ExamplePlugin, type IExamplePluginConfigFile } from './ExamplePlugin';function createPlugin( session: RushMcpPluginSession, configFile: IExamplePluginConfigFile | undefined): ExamplePlugin { return new ExamplePlugin(session, configFile);}export default createPlugin satisfies RushMcpPluginFactory; 6. [TypeScript 的 MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) 依赖 [zod](https://www.npmjs.com/package/zod) 框架,用于从 TypeScript 表达式生成 JSON schema 定义。 _您不需要为每个插件在 **package.json** 中添加 `zod` 依赖项。_ 相反,您可以从 `@rushstack/mcp-server` 的运行时上下文中导入它。这也可确保运行时中使用一致版本的 `zod`。请参阅 [StateCapitalTool.ts](https://github.com/microsoft/rushstack/blob/main/build-tests/rush-mcp-example-plugin/src/StateCapitalTool.ts) 获取代码示例。 7. 插件完成后,应将其发布到 NPM 注册表。 启用插件[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%90%AF%E7%94%A8%E6%8F%92%E4%BB%B6 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------- `@rushstack/mcp-server` 服务器期望从 Rush [autoinstaller](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/) 加载插件。这可确保 NPM 版本确定性,并确保即使在 `rush install` 出现故障的分支中插件也能正常工作。 1. 创建一个 `rush-mcp` autoinstaller: rush init-autoinstaller --name rush-mcp 2. 将插件添加为依赖项: **common/autoinstallers/rush-mcp/package.json** { "name": "rush-mcp", "version": "1.0.0", "private": true, "dependencies": { "rush-mcp-example-plugin": "1.0.0" }} 将 `"rush-mcp-example-plugin": "1.0.0"` 替换为您发布的包版本。 如果您尚未发布 NPM 包,可以使用 `file:` 方式模拟安装,即将其符号链接到本地开发目录: **common/autoinstallers/rush-mcp/package.json** { "name": "rush-mcp", "version": "1.0.0", "private": true, "dependencies": { "rush-mcp-example-plugin": "file:../../../../rushstack/build-tests/rush-mcp-example-plugin/" }} 3. 更新 `rush-mcp/package.json` 后,需要重新生成锁文件: rush update-autoinstaller --name rush-mcp 4. 接下来配置 `@rushstack/mcp-server` 加载您的插件: **common/config/rush-mcp/rush-mcp.json** /** * 本文件用于配置 `@rushstack/mcp-server` 在特定 monorepo 中的行为。 * 文件路径:/common/config/rush-mcp/rush-mcp.json */{ /** * MCP 服务器在处理该 monorepo 时应加载的插件列表。 */ "mcpPlugins": [ { /** * 出现在 autoinstaller 的 package.json "dependencies" 中的 NPM 包名称。 */ "packageName": "rush-mcp-example-plugin", /** * 含有该插件依赖项的 Rush autoinstaller 名称。 * `@rushstack/mcp-server` 会自动确保该文件夹被安装, * 然后再尝试加载插件。 */ "autoinstaller": "rush-mcp" } ]} 5. 最后,为确认其能正确加载,可在 shell 提示符中手动运行 MCP 服务器: # 注意,MCP 宿主通常会将当前工作目录设置为 "/",而非 monorepo 文件夹。# 建议以这种方式进行测试。node ./my-rush-repo/common/scripts/install-run.js @rushstack/mcp-server@0.2.1 "mcp-server" ./my-rush-repo 若无报错启动,即表示您的插件已准备就绪!确认 MCP 宿主是否显示了新工具。 参见[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%8F%82%E8%A7%81 "Direct link to heading") ------------------------------------------------------------------------------------------------------ * [Autoinstallers](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/) * [Rush MCP 服务器](https://rushjs.io/zh-cn/pages/ai/rush_mcp/) * [创建插件](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%88%9B%E5%BB%BA%E6%8F%92%E4%BB%B6) * [启用插件](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%90%AF%E7%94%A8%E6%8F%92%E4%BB%B6) * [参见](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/#%E5%8F%82%E8%A7%81) --- # 最新动态 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/news/#docusaurus_skipToContent_fallback) On this page 通过 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush/CHANGELOG.md) 来查看最新的更新。 Rush 由 Rush Stack 的开发者社区维护。查看 [Rush Stack News](https://rushstack.io/pages/news/) 页面以获取最新的更新和路线图。 Announcements[​](https://rushjs.io/zh-cn/pages/news/#announcements "Direct link to heading") --------------------------------------------------------------------------------------------- Follow us on [Mastodon (@rushstack@fosstodon.org)](https://fosstodon.org/@rushstack) or [Twitter (@rushstack)](https://twitter.com/rushstack) . Mastodon feed for [@rushstack@fosstodon.org](https://fosstodon.org/@rushstack) . . . [•   •   •](https://fosstodon.org/@rushstack) * [Announcements](https://rushjs.io/zh-cn/pages/news/#announcements) --- # 贡献 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/contributing/#docusaurus_skipToContent_fallback) On this page Rush 是在 [Rush Stack](https://rushstack.io/) 项目下进行开发:      [https://github.com/microsoft/rushstack](https://github.com/microsoft/rushstack) 在 [rushjs.io-website](https://github.com/microsoft/rushjs.io-website) 仓库中贡献文档。 请阅读 [Contributing](https://rushstack.io/pages/contributing/get_started/) 文档以获取更多关于构建 Rush 和提交 PR 的指南。 相关的仓库目录是: * [apps/rush](https://github.com/microsoft/rushstack/tree/main/apps/rush) - 前端命令行交互 * [libraries/rush-lib](https://github.com/microsoft/rushstack/tree/main/libraries/rush-lib) - 实现自动化 API 和引擎的逻辑。 测试 Rush 构建[​](https://rushjs.io/zh-cn/pages/contributing/#%E6%B5%8B%E8%AF%95-rush-%E6%9E%84%E5%BB%BA "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------- 一旦你完成了修复和构建了你的分支(就像[贡献](https://rushstack.io/pages/contributing/get_started/) 一文中描述的),你需要测试你的 Rush 构建。 Rush 有一个**版本选择器**功能,它读取从 **rush.json** 中读取了 `rushVersion`, 之后自动下载并调用指定的引擎版本。因此如果我们启用你构建的 `@microsoft/rush`, 它将并不会执行你的代码。为了跳过这个版本选择器,我们需要直接调用 `@microsoft/rush-lib` 引擎: $ cd rushstack/libraries/rush-lib$ node ./lib/start.js --help 如果你想从其他位置上更容易地调用你的测试构建,我们建议创建一个 `testrush` 命令。 对于 Mac OS 或 Linux 系统的 Bash: # 用自己构建的rush-lib的完整路径来代替。alias testrush="node ~/git/rushstack/libraries/rush-lib/lib/start.js" 对于 Windows, 可以创建一个 `testrush.cmd` 并将其加到系统路径 `PATH`: @ECHO OFFREM Substitute the full path to your own build of rush-lib:node "C:\Git\rushstack\apps\rush-lib\lib\start.js" %* 调试 Rush[​](https://rushjs.io/zh-cn/pages/contributing/#%E8%B0%83%E8%AF%95-rush "Direct link to heading") --------------------------------------------------------------------------------------------------------- 使用 VS Code 的调试器来调试 Rush 也是如此。创建一个如下的配置文件: **rushstack/libraries/rush-lib/.vscode/launch.json** { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug Rush", "program": "${workspaceFolder}/lib/start.js", "args": [ "list", "--json" ], // <====== 定义你自己的 Rush 命令 "cwd": "(repo folder that you want to debug)" // <===== 定义你的工作目录 } ]} 保存完上述文件后,在 VSCode 中点击 _"View" --> "Run"_ 并选择 "Debug Rush" 配置。之后点击 _"Run" --> "Start Debugging"_ 开始调试。调试器会正确地工作。 不使用单元测试来构建[​](https://rushjs.io/zh-cn/pages/contributing/#%E4%B8%8D%E4%BD%BF%E7%94%A8%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E6%9D%A5%E6%9E%84%E5%BB%BA "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush 目前使用 **gulp-core-build** 来进行构建,它默认执行了单元测试,这将花费很长时间。你可以通过直接调用 gulp 来跳过它们。 # 完整的构建 Rush 及其依赖,包括单元测试。$ rush build --to rush-lib --verbose# "rush-lib" 快速构建,没有单元测试。$ npm install -g gulp$ cd rushstack/libraries/rush-lib$ gulp build * [测试 Rush 构建](https://rushjs.io/zh-cn/pages/contributing/#%E6%B5%8B%E8%AF%95-rush-%E6%9E%84%E5%BB%BA) * [调试 Rush](https://rushjs.io/zh-cn/pages/contributing/#%E8%B0%83%E8%AF%95-rush) * [不使用单元测试来构建](https://rushjs.io/zh-cn/pages/contributing/#%E4%B8%8D%E4%BD%BF%E7%94%A8%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E6%9D%A5%E6%9E%84%E5%BB%BA) --- # 欢迎使用 Rush | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/intro/welcome/#docusaurus_skipToContent_fallback) ![Rush](https://rushjs.io/images/rush.svg "Rush") **Rush** 可以让 JavaScript 开发者更轻松地同时构建、发布多个 NPM 包。如果你正在将你的所有项目整合到一个仓库内,那么你来对地方了!Rush 是一个快速、专业的解决方案,它可以帮助你: * **仅需一次 NPM 安装:** 仅需一步,Rush 便可以将你项目的所有依赖安装到一个公共文件夹下,该文件夹并不像 "package.json" 一样位于项目的根目录(放到根目录的设计可能存在幻影依赖的问题),相反,Rush 使用符号链接来为每个项目重新构建一个准确的 "node\_modules" 文件。 ⏵ **该算法支持 [PNPM, NPM, and Yarn](https://rushjs.io/zh-cn/pages/maintainer/package_managers/) 等包管理工具.** * **本地自动链接:** 在 Rush 仓库内的所有项目之间被自动链接,当代码发生变动时,你可以在不发布的情况下看到下游所有的变动,同时,也不会困扰于 `npm link` 如何使用;如果你不想让某一个仓库被链接,那也很容易做到。 **快速构建:** Rush 会检测依赖图,并按照正确的顺序构建你的项目。如果两个库没有被互相依赖,Rush 会使用独立的 NodeJS 进程来并行构建(同时这些并行的进程会以 [可读的顺序](https://www.npmjs.com/package/@rushstack/stream-collator) 下显示控制台输出)。在实践中,这种多进程方式可以比所有异步函数运行在在单线程的 Gulpfile 中提供显著的速度提升。 * **子集构建和增量构建:** 如果你仅仅想构建一部分项目,可以使用 `rush rebuild --to ` 来实现一个仅包含上游依赖的清理式构建,它会重新构建该 project 及其依赖的项目;`rush rebuild --from ` 可以实现一个仅包含下游依赖的清理式构建,它会重新构建该 project 以及所有依赖该 project 的项目。如果你的工具链启用了 [package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) , `rush build` 会生成一个强有力的跨项目增量构建(也支持子集构建)。 * **循环依赖:** 当一个库间接依赖自己的旧版本时,处于循环中的项目会使用最后一个发布的版本,而其他项目仍然会获得最新的版本。 * **批量发布:** 发布时,Rush 可以检测哪些包发生了变动,同时会自动的提高相应的版本号,并在每个文件夹那执行 `npm publish`, 如果你喜欢,你可以配置你的服务器,让它每小时自动执行 `rush publish`。 * **跟踪更新日志:** 每当创建一个 PR, 你可以要求开发者为受到影响的项目提供一个 major/minor/patch 的更新条目。发布时,这些日志会被以优雅的格式整合到 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) 文件中. * **企业级政策**:想要在某个依赖被加进 package.json 前对该依赖进行审核,但是又担心重复的问题?想要让你的项目内的所有依赖都有相同版本?是否有不专业的私人邮箱混入到了你公司的 Git 历史中?Rush 可以让多人开发和多项目混合时保持一致的生态。 **还有更多!** Rush 由 [Microsoft SharePoint](http://aka.ms/spfx) 团队创建。我们每天构建数百个适用于生产环境的 NPM 包,从内部到开源的 Git 仓库,服务第三方 SDK 和实时服务的百万用户。如果在包管理上存在需要解决的重要问题,那么很有可能被 Rush 的某个功能特性解决。 --- # rush init-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/#docusaurus_skipToContent_fallback) On this page 用法: rush init-autoinstaller [-h] --name AUTOINSTALLER_NAME使用该指令可以初始化一个新的自动安装文件夹。自动安装提供了一种管理一系列相关依赖的方式,这些依赖通过被用于 "rush install" 之外的场景。可以查看 common-line.json 文档中的示例。可选参数: -h, --help 展示帮助信息并推出。 --name AUTOINSTALLER_NAME 指定自动安装目录的目录名,该目录名必须符合 NPM 包的命名规 则。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------- * [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) * [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/#%E5%8F%82%E8%80%83) --- # rush init-deploy | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/#docusaurus_skipToContent_fallback) On this page 用法: rush init-deploy [-h] -p PROJECT_NAME [-s SCENARIO]该命令可以生成用于 "rush deploy" 的配置文件。默认名为 common/config/rush/deploy.json.然而,如果你需要管理多个不同配置的部署环境,你可以使用 '--scenario" 来创建额外的配置文件。可选参数: -h, --help 展示帮助信息并退出。 -p PROJECT_NAME, --project PROJECT_NAME 指定该场景下需要被部署的项目名。它将添加到 "deploymentProjectNames" 配置中。 -s SCENARIO, --scenario SCENARIO 默认情况下,部署配置将被写到 "common/config/rush/deploy.json" 中,你可以使用 "--scenario" 来指定一个可选名,该名字必须 小写且使用破折号分开,例如,如果名字是 "web",那么配置文件 应该是 "common/config/rush/deploy-web.json". 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------ * [部署项目](https://rushjs.io/zh-cn/pages/maintainer/deploying/) * [deploy.json](https://rushjs.io/zh-cn/pages/configs/deploy_json/) 配置文件 * [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/) * [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/#%E5%8F%82%E8%80%83) --- # rush change | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_change/#docusaurus_skipToContent_fallback) On this page 用法: rush change [-h] [-v] [--no-fetch] [-b BRANCH] [--overwrite] [--email EMAIL] [--bulk] [--message MESSAGE] [--bump-type {major,minor,patch,none}]通过询问一系列的问题之后在公共文件夹中生成 -.json 文件。当变更版本号时通过 `publish` 命令来消费这些文件。注意这些变更日志最终会被放到每个项目的 changelog.md文件中。变更的类型有:MAJOR - 存在破坏性变动并且向后不兼容,例如重命名一个公共类,在公共 API 中添加或删除一个必选参数,或者重命名一个导出的变量或函数;MINOR - 存在向后兼容(但不向前兼容)的变化,例如增加一个公共 API 或者在公共 API 中增加一个可选参数;PATCH - 存在向前兼容、向后兼容的改动,例如修改一个私有 API 或者修复修复某个 API 的工作逻辑。 HOTREX(实验性的) - 在某个存在的版本上进行热修复。当增加一个热修复时,其他的变化不会增加版本号,可以通过在 rush.json 中设定参数'hotfixChangeEnabled' 来开启。可选参数: -h, --help 展示帮助信息并退出 -v, --verify 验证是否生成了有效的变更文件 --no-fetch 在执行 "git diff" 检测之前,跳过获取基准分支 -b BRANCH, --target-branch BRANCH 一旦指定该参数,会比较当前分支和目标分支的差异。如果没有指定该 参数,则默认比较 "main" 分支 --overwrite 如果某个变更日志存在,将在没有提示的情况下对该文件进行覆盖(当 --bulk 参数存在时会导致失败) --email EMAIL 邮箱地址用于变更文件中和,如果没有提供该参数,那么会在交互模式下 检测邮箱。 --bulk 一旦指定该参数,那么会将相同的变更信息和变更类型应用到所有项目。 一旦使用该参数,同时需要指定 --message 和 --bump-type 参数。 --message MESSAGE 当指定 --bulk 参数时,该参数会适用于所有变化的项目 --bump-type {major,minor,patch,none} 当指定 --bulk 参数时,变更类型会适用于所有变化的项目 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_change/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [编写变更日志](https://rushjs.io/zh-cn/pages/best_practices/change_logs/) * [rush version](https://rushjs.io/zh-cn/pages/commands/rush_version/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_change/#%E5%8F%82%E8%80%83) --- # rush build | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_build/#docusaurus_skipToContent_fallback) On this page 用法:rush build [-h] [-p COUNT] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] [-c] [--ignore-hooks]除了 "rush build" 可以增量构建外,与 "rush rebuild" 相似。换句话说,Rush build只会构建自上次成功构建后发生的代码。它需要 Git 工作树来进行分析,只关心被 Git 跟踪的源文件和在其项目下的文件(该算法的更多细节可以参考 "package-deps-hash" 包的文档)。增量构建状态会保存在每个项目中的 ".rush/temp" 文件夹,该文件夹没被 Git 记录。构建指令被 "package-deps_build.json"文件下的“参数”字段记录;当参数发生变化时(例如有或者没有 "--production" 参数),会重新执行全量构建。可选参数: -h, --help 展示帮助信息并退出。 -p COUNT, --parallelism COUNT 定义并行构建的最大并发数,COUNT 参数应该是一个正整数并且其最大 值等于 CPU 核数。如果该参数为空,那么默认值会依赖操作系统和 CPU 的核数决定。参数可以通过 RUSH_PARALLELISM 环境变量指定。 -t PROJECT, --to PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to" 参数会包含项目和其依赖的项目。"." 是当前工作目录 的简写。更多信息可以参考“选中部分项目”一文。 -T PROJECT, --to-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to-except" 参数会包含项目的依赖项目,而不包括项目 本身。"." 是当前工程目录的简写。更多信息可以参考“选中部分项目” 一文。 -f PROJECT, --from PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--from" 参数会包含项目和所有依赖它的项目,再加上这个集 合的依赖。"." 是当前工程目录的简写。更多信息可以参考“选中部分 项目”一文。 -o PROJECT, --only PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--only" 参数会选中指定的项目,而其依赖不会被添加。"." 是 当前目录的简写。注意这个参数是“不安全”的,因为它可能将某些依赖排除 在外。更多信息可以参考“选中部分项目”一文。 -i PROJECT, --impacted-by PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by" 参数会包含该项目和所有依赖该项目的项目 (因此可能会造成破坏性变动)。"." 是当前目录的简写。注意该参数是 “不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中 部分项目”一文。 -I PROJECT, --impacted-by-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by-expect" 参数会包含所有依赖该项目的项目, 而不包含本身。"." 是当前目录的简写。注意该参数是“不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中部分项目”一文。 --to-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--to-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--to", 更多信息可以参考“选中部分项目”一文。 --from-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--from-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--from", 更多信息可以参考“选中部分项目”一文。 -v, --verbose 构建期间展示更多信息,而不是仅仅展示总结性状态。 -c, --changed-projects-only 正常情况增量构建逻辑会重新构建所有直接或间接改变的项目。 指定 "--changed-projects-only" 将会忽略依赖项目,而仅构建 文件发生变化的项目。注意,该参数是“不安全”的,需要开发者确保忽略 的项目可以被忽略。 --ignore-hooks 跳过定义在 "rush.jon" 下 "eventHooks" 脚本的。确保你知道 跳过了哪些。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_build/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------ * [选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) * [rush rebuild](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_build/#%E5%8F%82%E8%80%83) --- # rush init | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_init/#docusaurus_skipToContent_fallback) On this page 用法: rush init [-h] [--overwrite-existing] [--rush-example-repo]当在一个空文件夹下调用该命令时,它会提供一系列配置模版来使用 Rush 管理项目。可选参数: -h, --help 展示帮助信息并退出。 --overwrite-existing 默认情况下,"rush init" 不会覆盖已经存在的配置文件。指定该 参数后会重写。当你将仓库的 Rush 升级到一个新版本时,它十分有 用。警告:小心使用! --rush-example-repo 当拷贝模版配置文件时,"rush-example" 的 GitHub 仓库使用了 这些不包含注释的片段,"rush-example" 是一个说明 Rush 诸多 特性的 monorepo 仓库。该参数主要用于维护该示例。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_init/#%E5%8F%82%E8%80%83 "Direct link to heading") ----------------------------------------------------------------------------------------------------- * [开始一个新仓库](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/) * GitHub 上的[rush 示例](https://github.com/microsoft/rush-example) 仓库 * [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_init/#%E5%8F%82%E8%80%83) --- # rush install-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_install-autoinstaller/#docusaurus_skipToContent_fallback) On this page 用法:rush install-autoinstaller [-h] --name AUTOINSTALLER_NAME使用该指令给一个项目安装依赖。可选参数: -h, --help 展示帮助信息并退出 --name AUTOINSTALLER_NAME 指定自动安装的包名,它必须是 common/autoinstallers 下的一个文件夹。 See also[​](https://rushjs.io/zh-cn/pages/commands/rush_install-autoinstaller/#see-also "Direct link to heading") ------------------------------------------------------------------------------------------------------------------ * [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) * [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) * [See also](https://rushjs.io/zh-cn/pages/commands/rush_install-autoinstaller/#see-also) --- # rush link | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_link/#docusaurus_skipToContent_fallback) On this page 用法: rush link [-h] [-f]给所有项目的 node_modules 创建符号连接,通常情况下该操作将会在 "rush install" 或"rush update" 后自动执行。你可以在因某些原因而执行 "rush unlink" 后,或者给 "rushinstall" 和 "rush update" 中添加 "--no-link" 参数后使用 "rush link".可选参数: -h, --help 展示帮助信息并退出。 -f, --force 删除并重新创建所有链接,甚至文件系统看起来似乎不需要重新创建。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_link/#%E5%8F%82%E8%80%83 "Direct link to heading") ----------------------------------------------------------------------------------------------------- * [rush unlink](https://rushjs.io/zh-cn/pages/commands/rush_unlink/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_link/#%E5%8F%82%E8%80%83) --- # rush purge | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_purge/#docusaurus_skipToContent_fallback) 用法: rush purge [-h] [--unsafe]"rush purge" 指令用于删除 Rush 创建的临时文件。当你遇到问题时,或者怀疑缓存有问题,便可以使用该命令.可选参数: -h, --help 展示帮助信息并退出 --unsafe (不安全)会删除存储在用户文件目录下的 ".rush" 文件夹内的共享文件,例 如包管理器。这是一个非常激进的修复方法,因为它将导致其他同时运行的 Rush 进程执行失败。 --- # rush setup | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_setup/#docusaurus_skipToContent_fallback) 用法: rush setup [-h](实验性)在投入到新的仓库前使用该命令可以确保所需的前提条件都已经安装、权限已经得到配置。并初始实现配置 NPM 源的凭证。将来会添加更多功能。可选参数: -h, --help 展示帮助信息并退出 --- # rush remove | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_remove/#docusaurus_skipToContent_fallback) On this page 用法:rush remove [-h] [-s] -p PACKAGE [--all]从当前项目(由当前工作目录确定)的依赖项中删除指定的包,并运行 "rush update"。可选参数: -h, --help 显示此帮助消息并退出。 -s, --skip-update 如果指定,将不会运行 "rush update" 命令来更新 package.json 文件。 -p PACKAGE, --package PACKAGE 要删除的包的名称。要删除多个包, 请运行 "rush remove --package foo --package bar"。 --all 如果指定,将从所有声明它的项目中删除依赖项。 参见[​](https://rushjs.io/zh-cn/pages/commands/rush_remove/#%E5%8F%82%E8%A7%81 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [修改 package.json](https://rushjs.io/zh-cn/pages/developer/modifying_package_json/) * [rush add](https://rushjs.io/zh-cn/pages/commands/rush_add/) * [参见](https://rushjs.io/zh-cn/pages/commands/rush_remove/#%E5%8F%82%E8%A7%81) --- # rush scan | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_scan/#docusaurus_skipToContent_fallback) On this page 用法: rush scan [-h]Node.js 的模块系统允许项目引入一个没有在 package.json 文件中声明的 NPM 包。像这种“幻影依赖” 便会导致问题。Rush 和 PNPM 使用符号链接来防止幻影依赖,当开发者尝试将已有项目迁移到 Rush 时,这些保护性措施可能会导致运行时错误。"rush scan" 指令就是修复这些错误的工具,它会扫描 "./src" 和 "./lib" 目录下的 import 语法,诸如 "import __from '__'", "require('__')", and "System.import('__'). 这种方法并不完美,但是在迁移项目的过程中可以节省时间。可选参数: -h, --help 展示帮助信息并退出 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_scan/#%E5%8F%82%E8%80%83 "Direct link to heading") ----------------------------------------------------------------------------------------------------- * [幻影依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_scan/#%E5%8F%82%E8%80%83) --- # rush tab-complete | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_tab-complete/#docusaurus_skipToContent_fallback) On this page 用法: rush tab-complete [-h] [--word WORD] [--position INDEX]提供 tab 补全。可选参数: -h, --help 展示帮助信息并退出 --word WORD 需要补全的单词,默认为 ""."". --position INDEX 单词中需要被补全的位置,默认为 0. 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_tab-complete/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------- * [配置 tab 补全](https://rushjs.io/zh-cn/pages/developer/tab_completion/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_tab-complete/#%E5%8F%82%E8%80%83) --- # rush unlink | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_unlink/#docusaurus_skipToContent_fallback) On this page 用法: rush unlink [-h]该命令用于移除 "rush link" 创建的符号连接。当使用 "git clean" 清理仓库时可以用次来保证不会删除源文件,或者需要在某个项目上使用 NPM 指令时很有用。可选参数: -h, --help 展示帮助信息并退出 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_unlink/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [rush link](https://rushjs.io/zh-cn/pages/commands/rush_link/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_unlink/#%E5%8F%82%E8%80%83) --- # command_line_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/command_line_json/#docusaurus_skipToContent_fallback) Redirecting... --- # common_versions_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/common_versions_json/#docusaurus_skipToContent_fallback) Redirecting... --- # version_policies_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/version_policies_json/#docusaurus_skipToContent_fallback) Redirecting... --- # rush update-autoinstaller | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/#docusaurus_skipToContent_fallback) On this page 用法:rush update-autoinstaller [-h] --name AUTOINSTALLER_NAME使用该指令该给一个自动安装文件夹生成 shrinkwrap 文件。可选参数: -h, --help 展示帮助信息并退出 --name AUTOINSTALLER_NAME 指定自动安装的包名,它必须是 common/autoinstallers 下的一个文件夹。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/#%E5%8F%82%E8%80%83 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------- * [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) * [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/#%E5%8F%82%E8%80%83) --- # rush update-cloud-credentials | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_update-cloud-credentials/#docusaurus_skipToContent_fallback) On this page 用法: rush update-cloud-credentials [-h] [-i] [--credential CREDENTIAL_STRING] [-d](实验性)如果配置了构建缓存功能,那么该指令可以可以方便的更新基于云服务商的凭证。可选参数: -h, --help 展示帮助信息并退出 -i, --interactive 如果云服务商支持的话,可以以交互形式来更新凭证。 --credential CREDENTIAL_STRING 一个将被缓存的静态凭证。 -d, --delete 一旦指定该参数,会删除存储的凭证。 参考更多[​](https://rushjs.io/zh-cn/pages/commands/rush_update-cloud-credentials/#%E5%8F%82%E8%80%83%E6%9B%B4%E5%A4%9A "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- * [启用构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) * [参考更多](https://rushjs.io/zh-cn/pages/commands/rush_update-cloud-credentials/#%E5%8F%82%E8%80%83%E6%9B%B4%E5%A4%9A) --- # rush upgrade-interactive | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_upgrade-interactive/#docusaurus_skipToContent_fallback) On this page 用法:rush upgrade-interactive [-h] [--make-consistent] [-s]用交互式命令行来升级依赖项。运行该命令将打开一个交互式提示,询问你要升级哪些项目和依赖项。它将更新 package.json 文件,然后为你运行 "rush update"。如果你使用 ensureConsistentVersions 策略,upgrade-interactive将更新所有使用你升级的依赖项的包,并且匹配它们的 SemVer 范围(如果提供的话)。如果未启用 ensureConsistentVersions,upgrade-interactive将仅更新你指定的包中的依赖项。这可以通过使用 --make-consistent 标志来覆盖。可选参数: -h, --help 显示此帮助消息并退出。 --make-consistent 当从单个项目升级依赖项时,也升级其他项目的依赖项。 -s, --skip-update 如果指定,将不会运行 "rush update" 命令来更新 package.json 文件。 参见[​](https://rushjs.io/zh-cn/pages/commands/rush_upgrade-interactive/#%E5%8F%82%E8%A7%81 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- * [修改 package.json](https://rushjs.io/zh-cn/pages/developer/modifying_package_json/) * [rush install](https://rushjs.io/zh-cn/pages/commands/rush_install/) * [参见](https://rushjs.io/zh-cn/pages/commands/rush_upgrade-interactive/#%E5%8F%82%E8%A7%81) --- # rush-pnpm | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush-pnpm/#docusaurus_skipToContent_fallback) 当使用 PNPM 包管理器时,Rush 会将 PNPM 工作区重定位到 `common/temp/` 路径下。 它还会注入一些配置钩子来支持 Rush 特定的增强功能,例如 [优先版本](https://rushjs.io/zh-cn/pages/advanced/preferred_versions/) 和更快的增量安装。 因此,如果你在 Rush 仓库中直接调用 `pnpm` 命令,它可能会因为找不到 `pnpm-workspace.yaml` 文件失败。 一些操作可能会由于与 Rush 的增强功能不兼容而发生故障。 为了避免这些问题,在你的 Rush 仓库中,无论何时都应该使用 `rush-pnpm` 来代替 `pnpm` 命令。 `@microsoft/rush` 附带了 `rush-pnpm` 二进制文件用于替代品 `pnpm` 命令。它提供了以下功能: * 设置正确的上下文/环境,以便 PNPM 命令能够正常工作 * 报告已知不兼容操作的错误 * 报告潜在不兼容操作的警告 --- # rush version | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_version/#docusaurus_skipToContent_fallback) On this page 用法: rush version [-h] [-b BRANCH] [--ensure-version-policy] [--override-version NEW_VERSION] [--bump] [--bypass-policy] [--version-policy POLICY] [--override-bump BUMPTYPE] [--override-prerelease-id ID]使用 "rush version" 指令来确保版本策略和变更版本。可选参数: -h, --help 展示帮助信息并退出。 -b BRANCH, --target-branch BRANCH 一旦指定该参数,将会把变更和删除变更的行为提交并合并到指定分 支上。 --ensure-version-policy 如果需要满足版本策略,则更新包版本。 --override-version NEW_VERSION 使用指定的 --version-policy 覆盖版本。只有当指定 --ensure-version-policy 时,该设置才会对 lock-step 版本策略起作用。 --bump 基于版本策略进行版本变更。policies. --bypass-policy 强制覆盖 rush.json 中约定的 "gitPolicy" 规定。 --version-policy POLICY 版本政策的名字 --override-bump BUMPTYPE 在 version-policy.json 中覆盖变更类型。有效的版本变更类型 包括:prerelease, patch, preminor, minor, major. 该设定只对 lock-step 版本策略有效。 --override-prerelease-id ID 覆盖 version-policy.json 中的预发布 id. 该设定只对 lock-step 版本策略有效。当带有 "--bump" 参数时,该配置 会增加预发布 id; 当带有 "--ensure-version-policy" 时,该配置会替换预发布名称。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_version/#%E5%8F%82%E8%80%83 "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [发包](https://rushjs.io/zh-cn/pages/maintainer/publishing/) * [rush change](https://rushjs.io/zh-cn/pages/commands/rush_change/) * [rush publish](https://rushjs.io/zh-cn/pages/commands/rush_publish/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_version/#%E5%8F%82%E8%80%83) --- # cobuild.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/cobuild_json/#docusaurus_skipToContent_fallback) On this page This is the template that [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) generates for the [cobuild feature](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/) . **common/config/rush/cobuild.json** /** * This configuration file manages Rush's cobuild feature. * More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", /** * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, * otherwise the cobuild feature will be disabled. */ "cobuildFeatureEnabled": false, /** * (Required) Choose where cobuild lock will be acquired. * * The lock provider is registered by the rush plugins. * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. */ "cobuildLockProvider": "redis"} See also[​](https://rushjs.io/zh-cn/pages/configs/cobuild_json/#see-also "Direct link to heading") --------------------------------------------------------------------------------------------------- * [Cobuilds](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/) * [Enabling the build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) * [See also](https://rushjs.io/zh-cn/pages/configs/cobuild_json/#see-also) --- # custom-tips.json (实验性功能) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/custom-tips_json/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 [Custom tips](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/) 功能生成的模板配置文件。 **common/config/rush/custom-tips.json** /** * 这个配置文件允许仓库维护者配置与某些 Rush 消息一起打印的额外详细信息。更多文档可在 * Rush 官方网站上找到:https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", /** * 指定 Rush 要显示的 custom tips。 */ "customTips": [ // { // /** // * (必须) 一个标识符,表示 Rush 可能打印的消息。 // * 如果打印了该消息,则将显示此 custom tip。 // * 请参阅 Rush 文档以获取可能的标识符的当前列表。 // */ // "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", // // /** // * (必须) 要为此提示显示的消息文本。 // */ // "message": "要获取额外的故障排除信息,请参阅此 wiki 文章:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" // } ]} 另请参阅[​](https://rushjs.io/zh-cn/pages/configs/custom-tips_json/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------- * [Custom tips](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/) * [另请参阅](https://rushjs.io/zh-cn/pages/configs/custom-tips_json/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85) --- # .npmrc-publish | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **.npmrc-publish** 文件: **common/config/rush/.npmrc-publish** # 该配置文件与 common/config/rush/.npmrc, 除了 .npmrc-publish 文件适用于 "rush publish" 指令,因为# 发布时可能需要不同于其他操作的凭据和源。## this avoids problems that would otherwise result due to a missing variable being replaced by# an empty string.# 在调用包管理器之前,Rush 将复制此文件到 "common/temp/publish-home/.npmrc",然后暂时架将该文件夹映射为用户的# “主目录”。这使得在每个发布的项目中应用相同的设置。复制的文件将忽略在会话中没有定义的环境变量,这是为了避免由于空字符# 串而导致的变量缺失的问题。### * * * 安全警告 * * *## 不建议在机器上存储身份验证令牌,因为其他无关进程可能会读取文件。同样,该文件也可能永久存储,例如如果机器断电。# 更安全的方式是通过环境变量来传递口令,可以通过 ${} 扩展引用到 .npmrc 中。例如:## //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}# 参考[​](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/#%E5%8F%82%E8%80%83 "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [.npmrc](https://rushjs.io/zh-cn/pages/configs/npmrc/) 配置文件 * [参考](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/#%E5%8F%82%E8%80%83) --- # .pnpmfile.cjs | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/pnpmfile_cjs/#docusaurus_skipToContent_fallback) This is the template that [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) generates for the monorepo **pnpmfile.js** file: **common/config/rush/.pnpmfile.cjs** 'use strict';/** * When using the PNPM package manager, you can use pnpmfile.js to workaround * dependencies that have mistakes in their package.json file. (This feature is * functionally similar to Yarn's "resolutions".) * * For details, see the PNPM documentation: * https://pnpm.js.org/docs/en/hooks.html * * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run * "rush update --full" so that PNPM will recalculate all version selections. */module.exports = { hooks: { readPackage }};/** * This hook is invoked during installation before a package's dependencies * are selected. * The `packageJson` parameter is the deserialized package.json * contents for the package that is about to be installed. * The `context` parameter provides a log() function. * The return value is the updated object. */function readPackage(packageJson, context) { // // The karma types have a missing dependency on typings from the log4js package. // if (packageJson.name === '@types/karma') { // context.log('Fixed up dependencies for @types/karma'); // packageJson.dependencies['log4js'] = '0.6.38'; // } return packageJson;} --- # rush-plugins.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/rush-plugins_json/#docusaurus_skipToContent_fallback) On this page This is the template for the **rush-plugins.json** file that is used to enable [Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) . **common/config/rush/command-line.json** /** * This configuration file manages Rush's plugin feature. */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item configures a plugin to be loaded by Rush. */ // { // /** // * The name of the NPM package that provides the plugin. // */ // "packageName": "@scope/my-rush-plugin", // // /** // * The name of the plugin. This can be found in the "pluginName" // * field of the "rush-plugin-manifest.json" file in the NPM package folder. // */ // "pluginName": "my-plugin-name", // // /** // * The name of a Rush autoinstaller that will be used for installation, which // * can be created using "rush init-autoinstaller". Add the plugin's NPM package // * to the package.json "dependencies" of your autoinstaller, then run // * "rush update-autoinstaller". // */ // "autoinstallerName": "rush-plugins" // } ]} See also[​](https://rushjs.io/zh-cn/pages/configs/rush-plugins_json/#see-also "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [Using Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) * [Creating a Rush plugin](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) * [See also](https://rushjs.io/zh-cn/pages/configs/rush-plugins_json/#see-also) --- # rush check | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_check/#docusaurus_skipToContent_fallback) 用法: rush check [-h] [--variant VARIANT] [--json]检查每个项目的 package.json 文件来确保仓库内所有的依赖都有相同的版本。可选参数: -h, --help 展示帮助信息并退出 --variant VARIANT Rush 命令通过使用安装配置文件变量该参数可以通过 RUSH_VARIANT 环 境变量来指定。 --json 该参数指定后会被输出 JSON 格式的文件 --- # rush deploy | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_deploy/#docusaurus_skipToContent_fallback) On this page 用法: rush deploy [-h] [-p PROJECT_NAME] [-s SCENARIO_NAME] [--overwrite] [-t PATH] [--create-archive ARCHIVE_PATH]仓库构建完成后,"rush deploy" 可以将 Rush 仓库内的某些项目和依赖部署到指定的目录下,该目录可被上传到生产服务器上。"rush deploy" 通过 "rush init-deploy" 生成的配置文件来指定该行为。可选参数: -h, --help 展示帮助信息并退出。 -p PROJECT_NAME, --project PROJECT_NAME 指定需要被部署的 Rush 项目名,它必须是部署配置文件下的 "deploymentProjectNames" 设定。 -s SCENARIO_NAME, --scenario SCENARIO_NAME 默认情况下,部署配置在 "common/config/rush/deploy.json" 中指定。你可以使用 "--scenario" 来指定一个可选名,该名必须小 写且以破折号分割。例如,如果 SCENARIO_NAME 是 "web",之后 配置文件应该是 "common/config/rush/deploy-web.json". --overwrite 默认情况下,如果目标目录为空则构建失败。当指定该参数后,会递归 的删除目标目录下存在的内容。 -t PATH, --target-folder PATH 默认情况下,文件部署在 Rush 仓库内的 "common/deploy" 目录 下。可以使用该参数来指定不同的位置。警告:当与 "--overwrite" 结合使用时需要小心。该参数可以通过 RUSH_DEPLOY_TARGET_FOLDER 环境变量来指定。 --create-archive ARCHIVE_PATH 一旦使用该参数,那么构建完成后,"rush deploy" 会创建一个目标 目录的压缩包。 新创建的压缩包被放到相对于目标文件的制定目录上, 支持的文件扩展名:.zip 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_deploy/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [部署项目](https://rushjs.io/zh-cn/pages/maintainer/deploying/) * [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_deploy/#%E5%8F%82%E8%80%83) --- # rush list | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_list/#docusaurus_skipToContent_fallback) 用法: rush list [-h] [-v] [-p] [--full-path] [--json] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME]对于记录在 rush 配置文件中的项目,该命令可以列举包名,可选列出版本(--version)和路径(--path)或者完整路径(--full-path).可选参数: -h, --help 展示帮助信息退出 -v, --version 一旦指定该参数,则项目版本会在项目名的另外一列内展示。 -p, --path 一旦指定该参数,则项目路径会在项目名的另外一列内展示。 --full-path 一旦指定该参数,则项目的完整路径会在项目名的另外一列内展示。 --json 一旦指定该参数,则以 JSON 的格式输出。 -t PROJECT, --to PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to" 参数会包含项目和其依赖的项目。"." 是当前工作目录 的简写。更多信息可以参考“选中部分项目”一文。 -T PROJECT, --to-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to-except" 参数会包含项目的依赖项目,而不包括项目 本身。"." 是当前工程目录的简写。更多信息可以参考“选中部分项目” 一文。 -f PROJECT, --from PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--from" 参数会包含项目和所有依赖它的项目,再加上这个集 合的依赖。"." 是当前工程目录的简写。更多信息可以参考“选中部分 项目”一文。 -o PROJECT, --only PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--only" 参数会选中指定的项目,而其依赖不会被添加。"." 是 当前目录的简写。注意这个参数是“不安全”的,因为它可能将某些依赖排除 在外。更多信息可以参考“选中部分项目”一文。 -i PROJECT, --impacted-by PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by" 参数会包含该项目和所有依赖该项目的项目 (因此可能会造成破坏性变动)。"." 是当前目录的简写。注意该参数是 “不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中 部分项目”一文。 -I PROJECT, --impacted-by-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by-expect" 参数会包含所有依赖该项目的项目, 而不包含本身。"." 是当前目录的简写。注意该参数是“不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中部分项目”一文。 --to-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--to-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--to", 更多信息可以参考“选中部分项目”一文。 --from-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--from-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--from", 更多信息可以参考“选中部分项目”一文。 --- # Rush MCP 服务器 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#docusaurus_skipToContent_fallback) On this page [Agent context files](https://rushjs.io/zh-cn/pages/ai/context_files/) 提供了一种简单的方式,通过发布有关 Rush 仓库的附加信息来提升人工智能(AI)**编程助手**的能力。[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) 更进一步,提供一个实时服务,可以在你的 monorepo 中响应查询并执行操作。 它是如何工作的?[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------- * 一个 [MCP host](https://modelcontextprotocol.io/clients) 通常是一个 **编程助手**,如 [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-chat-with-mcp) (可直接在 [VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) 中使用)、[Trae](https://docs.trae.ai/ide/model-context-protocol) 或 [Cursor](https://docs.cursor.com/context/model-context-protocol) 。但任何类型的软件工具都可以通过实现 **MCP client** 协议来作为客户端。 * 一个 [MCP server](https://modelcontextprotocol.io/docs/concepts/architecture) 会向客户端公布一系列能力,客户端在执行任务时通过协议调用这些能力。根据规范,服务器可以在本地运行,也可以作为远程云服务。它的能力包括: * **resources**:例如读取文件内容、查询数据库、读取日志文件、捕获屏幕截图 * **tools**:例如执行 shell 命令、修改文件、执行计算 * **prompts**:暴露特定输入表单供最终用户填写 * Rush 提供了一个现成的 MCP 服务器 [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) ,可以安装在你的 monorepo 中。它的设计目标专为大型团队量身定制: * **易于所有人安装,** 降低临时贡献者的学习曲线。 * **集中管理,** 使 monorepo 维护者能够控制其配置和安装版本,从而确保所有人获得一致的体验。在为工程师提供随叫随到的支持时,确定性行为至关重要。 * 通过 [Rush MCP 插件](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/) 实现 **可扩展性,** 这样你就可以集成公司特有的能力,而无需自行构建 MCP 服务器。 设置 MCP 服务器[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#%E8%AE%BE%E7%BD%AE-mcp-%E6%9C%8D%E5%8A%A1%E5%99%A8 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------- `@rushstack/mcp-server` 设计为在开发者的本地计算机上作为本地进程运行,而不是作为云服务运行。Rush MCP 服务器会被 VS Code、Cursor 或 Trae 等 MCP host 自动启动。MCP host 负责启动和终止该进程。进程间通信使用 `stdio` [传输方式](https://modelcontextprotocol.io/docs/concepts/transports) ,因此你可以通过在 shell 中手动调用其 CLI 来轻松测试 Rush 的 MCP 服务器。 通常有两种配置 MCP 服务器启动的方式:适用于整个机器的 **用户级别**(例如 `~/.cursor/mcp.json`),或适用于某个特定 Git 仓库的 **工作区级别**(例如 `/.cursor/mcp.json`)。对于 `@rushstack/mcp-server` 服务,我们推荐使用提交到 Git 的工作区级别配置文件。这样可以简化用户的设置过程,并确保所有人在某个分支上使用相同版本的 `@rushstack/mcp-server`,从而避免加载自定义插件时的兼容性问题。 完成基本设置后,可以考虑实现一个 [Rush MCP 插件](https://rushjs.io/zh-cn/pages/ai/rush_mcp_plugins/) ,以暴露你公司系统的特定能力。 > **如果你的编程助手不在下方列出:** 请[创建一个 pull request](https://github.com/microsoft/rushstack-websites/tree/main/websites/rushjs.io/docs/pages/ai/rush_mcp.md) > 添加设置说明! ### Cursor[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#cursor "Direct link to heading") 对于 [Cursor](https://docs.cursor.com/context/model-context-protocol) ,在你的 monorepo 中添加如下文件: **/.cursor/mcp.json** { "mcpServers": { "rush-mcp-server": { "command": "node", "args": [ "./common/scripts/install-run.js", "@rushstack/mcp-server@0.2.1", "mcp-server", "." ] } }} 将 `@rushstack/mcp-server@0.2.1` 替换为 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) 中的最新版本。 > **Cursor 注意事项** > > * Cursor 会自动将上述文件中的 `"."` 替换为工作区文件夹的绝对路径。 > * Cursor 不支持在 JSON 文件中使用 `//` 注释。 ### Trae[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#trae "Direct link to heading") 对于 [Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en#c5b33bab) ,请手动配置如下: 1. 点击侧边聊天框右上角的 **Settings 图标 \> MCP**。 2. 点击 **\+ Add MCP Servers** 按钮。 3. 点击 **"Configure Manually."**,并输入以下配置: { "mcpServers": { "rush-mcp-server": { "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} 将 `@rushstack/mcp-server@0.2.1` 替换为 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) 中的最新版本。 将 `` 替换为 Rush monorepo 根目录的绝对路径(包含 `rush.json` 的文件夹)。 ### GitHub Copilot[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#github-copilot "Direct link to heading") 对于 [GitHub Copilot](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) ,在你的 monorepo 中添加如下文件: **/.vscode/mcp.json** { "servers": { "rush-mcp-server": { "type": "stdio", "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} 将 `@rushstack/mcp-server@0.2.1` 替换为 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) 中的最新版本。 将 `` 替换为 Rush monorepo 根目录的绝对路径(包含 `rush.json` 的文件夹)。 ### Cline[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#cline "Direct link to heading") 对于 [Cline](https://docs.cline.bot/mcp/mcp-overview#getting-started) ,请手动配置如下: 1. 点击 **MCP Servers** 按钮。 2. 点击 **Installed** 按钮。 3. 点击 **Configure MCP Servers** 按钮,在新打开的 `cline_mcp_settings.json` 文件中输入以下配置: **cline\_mcp\_settings.json** { "mcpServers": { "rush-mcp-server": { "disabled": false, "timeout": 60, "type": "stdio", "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} 将 `@rushstack/mcp-server@0.2.1` 替换为 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) 中的最新版本。 将 `` 替换为 Rush monorepo 根目录的绝对路径(包含 `rush.json` 的文件夹)。 ### Windsurf[​](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#windsurf "Direct link to heading") 对于 [Windsurf](https://docs.windsurf.com/windsurf/cascade/mcp) ,请手动配置如下: 1. 点击左上角 **Settings \> Windsurf Settings**。 2. 在打开的页面中点击 **Cascade \> Manage plugins \> View raw config**。 3. 在打开的 `mcp_config.json` 文件中输入以下内容: **mcp\_config.json** { "mcpServers": { "rush-mcp-server": { "command": "npx", "args": [ "-y", "@rushstack/mcp-server@0.2.1", "" ] } }} 将 `@rushstack/mcp-server@0.2.1` 替换为 [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) 中的最新版本。 将 `` 替换为 Rush monorepo 根目录的绝对路径(包含 `rush.json` 的文件夹)。 * [它是如何工作的?](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84) * [设置 MCP 服务器](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#%E8%AE%BE%E7%BD%AE-mcp-%E6%9C%8D%E5%8A%A1%E5%99%A8) * [Cursor](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#cursor) * [Trae](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#trae) * [GitHub Copilot](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#github-copilot) * [Cline](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#cline) * [Windsurf](https://rushjs.io/zh-cn/pages/ai/rush_mcp/#windsurf) --- # rush update | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_update/#docusaurus_skipToContent_fallback) On this page 用法: rush update [-h] [-p] [--bypass-policy] [--no-link] [--network-concurrency COUNT] [--debug-package-manager] [--max-install-attempts NUMBER] [--ignore-hooks] [--variant VARIANT] [--full] [--recheck]"rush update" 命令会依据 package.json 文件安装依赖,并按需更新 shrinkwrap 文件(shrinkwrap 文件是存储仓库内所有项目的依赖和版本的中心,它被放到 "common/config/rush"文件夹下)。注意,Rush 会在一次性给仓库内的所有项目安装。 当你从 Git 上拉去文件,或者修改完 package.json 文件后,需要执行 "rush update" 才能开始工作。如果无需更新,则 "rushupdate" 会在瞬时完成。注意:在某些情况下应该使用 "rush install" 来替换 "rush update",更多信息可以参考 "rush install" 的命令行帮助。可选参数: -h, --help 展示帮助信息并退出 -p, --purge 开始执行之前执行 "rush purge". --bypass-policy 强制覆盖 rush.json 中约定的 "gitPolicy" 规定。 --no-link 一旦指定该参数,那么当安装完成后项目不会执行符号连接。你需要手动 执行 "rush link", 当想要独立的报告每个阶段,或者在两个阶段之 间进行额外的操作时,该参数十分有用。当使用 workspaces 时,不支 持该参数。 --network-concurrency COUNT 一旦指定该参数,将会限制最大的并发网络请求数。当网络出现问题时, 该参数十分有用。 --debug-package-manager 开启包管理器的详细日志。当使用该参数时,你可能想要 Rush 输出到 一个文件中。 --max-install-attempts NUMBER 覆盖默认的尝试安装的次数,默认值为 3. --ignore-hooks 跳过执行定义在 rush.json 中的 "eventHooks" 脚本。你应该知道 自己跳过了什么。 --variant VARIANT 通过一个安装配置变量来执行 Rush 命令。该参数可以通过环境变量 RUSH_VARIANT 来指定。 --full 通常 "rush update" 会尝试保留已安装的版本并会在满足 package.json 文件要求的情况下进行最小更新。这种保守的方式 可以防止 PR 被卷入到与自己无关的包更新中。当你想将所有依赖 更新到语义化兼容的最新版本时候,可以使用 "--full" 参数。 该操作应该由某个人或者机器来定期执行,进而处理潜在的升级回 归。 --recheck 如果 shrinkwrap 文件看依赖已经满足 package.json 文件, 那么 "rush update" 不再会调用包管理器。但是在某些情况 下,这种方法可能并不精准。使用 "--recheck" 参数可以强制 包管理器处理 shrinkwrap 文件。这也会更新 shrinkwrap 文件。 (为了最大限度减少 shrinkwrap 的变更,这些修复只会在临时 文件中执行) 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_update/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [rush install](https://rushjs.io/zh-cn/pages/commands/rush_install/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_update/#%E5%8F%82%E8%80%83) --- # rushx | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rushx/#docusaurus_skipToContent_fallback) On this page `rushx` 命令与 `npm run` 或者 `pnpm run` 类似,它会调用 **package.json** 文件中 `"scripts"` 字段中定义的 shell 脚本。任何额外的命令行参数都会传递给该 shell 脚本,这些参数不会经过任何验证。 例如在你的项目中: **/package.json** { "name": "my-project", "version": "0.0.0", "scripts": { "build": "rm -Rf lib && tsc", "test": "jest" }} 如果你单独调用 `rushx`,它将会显示可用的命令: 用法:rushx [-h] rushx [-q/--quiet] <命令> ...可选参数: -h, --help 展示帮助信息并退出。 -q, --quiet 隐藏 Rush 启动信息。my-project 项目中可用的命令: build: "rm -Rf lib && tsc" test: "jest" 调用 `rushx build` 等同于运行 `rm -Rf lib && tsc`。添加的参数将会被直接添加到字符串的末尾,例如 `rushx build --verbose` 等同于 `rm -Rf lib && tsc --verbose`。 使用 "rush" 还是 "rushx"?[​](https://rushjs.io/zh-cn/pages/commands/rushx/#%E4%BD%BF%E7%94%A8-rush-%E8%BF%98%E6%98%AF-rushx "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------- `rushx` 和 `rush` 这两个命令很容易混淆: * **rush** 调用一个通用的操作,它会影响整个仓库(“全局命令”)或者多个项目(“批量命令”)。这些命令[应该被仔细设计](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) 。Rush 会强制对它们的参数进行验证和文档化。 * **rushx** 为单个项目执行自定义操作。尽管一些命令用于实现批量命令,但是许多命令都是该项目开发人员独有的辅助脚本。Rush 并不严格验证这些命令。 为什么使用 "rushx" 而不是 "pnpm run" 或者 "npx"?[​](https://rushjs.io/zh-cn/pages/commands/rushx/#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8-rushx-%E8%80%8C%E4%B8%8D%E6%98%AF-pnpm-run-%E6%88%96%E8%80%85-npx "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `rushx` 命令具有与 `pnpm run` 或者 `npx` 相似的功能,但是还有一些额外的好处: * 通过使用 [Rush 版本选择器](https://rushjs.io/zh-cn/pages/contributing/) 来确定需要使用的工具链 * 基于 Rush 的配置来准备 shell 环境 * 实现了额外的验证 * [使用 "rush" 还是 "rushx"?](https://rushjs.io/zh-cn/pages/commands/rushx/#%E4%BD%BF%E7%94%A8-rush-%E8%BF%98%E6%98%AF-rushx) * [为什么使用 "rushx" 而不是 "pnpm run" 或者 "npx"?](https://rushjs.io/zh-cn/pages/commands/rushx/#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8-rushx-%E8%80%8C%E4%B8%8D%E6%98%AF-pnpm-run-%E6%88%96%E8%80%85-npx) --- # rush publish | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_publish/#docusaurus_skipToContent_fallback) On this page 用法: rush publish [-h] [-a] [-b BRANCH] [-p] [--add-commit-details] [--regenerate-changelogs] [-r REGISTRY] [-n TOKEN] [-t TAG] [--set-access-level {public,restricted}] [--pack] [--release-folder FOLDER] [--include-all] [--version-policy POLICY] [--prerelease-name NAME] [--partial-prerelease] [--suffix SUFFIX] [--force] [--apply-git-tags-on-pack] [-c COMMIT_ID]读取并处理由 "rush change" 生成的发布更改请求。默认情况下,这是一个只读操作,会在控制台输出执行的操作。为了将变更日志提交并发布包,必须使用 --commit 参数,或者 --publish 参数。可选参数 -h, --help 展示帮助信息并退出 -a, --apply 一旦指定该参数,则变更请求会被应用到 package.json 文件中。 -b BRANCH, --target-branch BRANCH 一旦指定该参数,将会把变更和删除变更的行为提交并合并到指定分 支上。 -p, --publish 一旦指定该参数,则会将变更发布到 npm 上。 --add-commit-details 在每次变更中把提交作者和哈希值都添加到 changelog.json 文 件中。 --regenerate-changelogs 基于当前的 JSON 内容重新生成所有 changelog 文件。 -r REGISTRY, --registry REGISTRY 指定发布的 NPM 源。一旦该参数指定,那么它会组织当前的提交不 带标签。 -n TOKEN, --npm-auth-token TOKEN (废弃) 发布时使用认证令牌。该参数已被废弃,因为命令行参数 可能被其他无关的进程读取。相反,更安全的做法是通过环境变量传 递该口令,之后从 common/config/rush/.npmrc-publish 文 件中读取。 -t TAG, --tag TAG 传递给 npm 的标签参数。NPM 默认使用 'latest' 标签,即使是 当前发布的版本比最近发布的版本更低,所以,对于更旧的版本发布 工作流而言,提供一个标签是很重要的。当存在热更新时,该参数会 被默认设定为 'hotfix'. --set-access-level {public,restricted} 默认情况下,当 Rush 执行 "npm publish" 时,它将发布所有访 问级别是 "restricted" 的 scope 包。访问级别是 "public" 的 scope 包可以在刚开始发布时指定标签来发布。对于那些没有 scope 包, NPM 会以 "public" 的访问级别发布。更多信息可以 参考 NPM 文档上 "npm publish" 的 "--access" 选项。 For more information, see the NPM --pack 只有使用 --include-all 时该参数才可用,它将项目打包成压缩 包,而不会将其发布到 NPM 仓库上。当指定该参数时,与 NPM 源 相关的参数想会被忽略。 --release-folder FOLDER 该参数用于给 --pack 参数提供自定义的打包位置,而不是使用默 认值。 --include-all 一旦指定该参数,则 rush.json 内所有设定 shouldPublish= true 的项目,和指定了版本策略且其版本比旧版本新的项目都会被 发布。 --version-policy POLICY 版本策略名,当使用 --include-all 时,只有存在版本策略的项目 会被发布。 --prerelease-name NAME 使用预览版命名来将其提高到预览版。不能与 --suffix 一起使用。 --partial-prerelease 与 --prerelease-name 结合使用,只会将变更的库提升到预览版。 --suffix SUFFIX 给所有变更的版本增加后缀。不能与 --prerelease-name 一起使用。 --force 如果该参数与 --publish 共同使用,那么会给 npm 带上 --force. --apply-git-tags-on-pack 该参数与 --publish 和 --pack 共同使用,git 标签将会应用到 所有包将被应用到包上,就好像在没有 --pack 的情况下发布。 -c COMMIT_ID, --commit COMMIT_ID 与 git 标签结合使用:在指定的 commit 哈希中使用 git 标签。 如果没有提供该参数,则使用当前的 HEAD. 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_publish/#%E5%8F%82%E8%80%83 "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [发布包](https://rushjs.io/zh-cn/pages/maintainer/publishing/) * [rush version](https://rushjs.io/zh-cn/pages/commands/rush_version/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_publish/#%E5%8F%82%E8%80%83) --- # .npmrc | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/npmrc/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **.npmrc** 文件: **common/config/rush/.npmrc** # Rush 使用该文件来配置安装阶段的 NPM 源,它可以用 PNPM,NPM 或者 Yarn。它被诸如 "rush install",# "rush update","install-run.js" 脚本等使用。## 注意: "rush publish" 命令使用 .npmrc-publish 文件。## 在调用包管理器之前,Rush 会拷贝该文件到执行安装命令的目录中。拷贝的文件会忽略没有在该会话中定义的环境变量;# 这避免了一些因为缺少变量而导致的问题。## * * * 安全警告 * * *## 不建议在机器上存储身份验证令牌,因为其他无关进程可能会读取文件。同样,该文件也可能永久存储,例如如果机器断电。# 更安全的方式是通过环境变量来传递口令,可以通过 ${} 扩展引用到 .npmrc 中。例如:## //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}#registry=https://registry.npmjs.org/always-auth=false .npmrc 文件优先[​](https://rushjs.io/zh-cn/pages/configs/npmrc/#npmrc-%E6%96%87%E4%BB%B6%E4%BC%98%E5%85%88 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- 普通 Rush 操作执行如下查找: 1. 为了支持不规范的情况,NPM 配置的环境变量优先于任何 **.npmrc** 配置。环境变量名以 `npm_config_` 开头,例如设置 `npm_config_registry` 可以覆盖 **.npmrc** 中的 `registry` 设置。Rush 也可以接受 NPM 标准中不规范的命名,例如 `npm_config_@example:registry`。 2. 通常的配置刚来自于 Rush 拷贝到工作目录的临时文件 **.npmrc**,这个文件拷贝自 **common/config/rush/.npmrc**,但是省略了很多没有定义的环境变量(解释如上)。对于大多数的操作,工作目录是 **common/temp**。 3. 如果包管理器没有从方法 1 或方法 2 中找到配置项,将使用用户配置中的 **~/.npmrc**。用户通常存储自己的身份验证令牌在这个文件中。 以上规则同样适用于诸如 **install-run.js** 等辅助脚本。 `rush publish` 使用独立的 **.npmrc-publish** 配置文件。详细请参考[此文档](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/) 。 上述规则不适用于直接调用 Rush 以外的包管理器的情况。例如,从 shell 中调用 `npm publish`时,将按照[包管理器的通常优先级](https://docs.npmjs.com/cli/v7/using-npm/config#npmrc-files) 寻找 **.npmrc** 文件。通常不鼓励在 Rush 仓库中执行上述行为。当执行上述行为时,你可能需要创建额外的 **.npmrc** 文件。 参考[​](https://rushjs.io/zh-cn/pages/configs/npmrc/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------ * [NPM 源认证](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/) * [.npmrc-publish](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/) 配置文件 * [.npmrc 文件优先](https://rushjs.io/zh-cn/pages/configs/npmrc/#npmrc-%E6%96%87%E4%BB%B6%E4%BC%98%E5%85%88) * [参考](https://rushjs.io/zh-cn/pages/configs/npmrc/#%E5%8F%82%E8%80%83) --- # common-versions.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/common-versions_json/#docusaurus_skipToContent_fallback) 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **command-version.json** 文件: **common/config/rush/common-versions.json** /** * 该配置项用于配置 NPM 依赖版本,它会影响 Rush 仓库内的所有项目。 * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", /** * 一张指定 NPM 包的“偏好版本”的表。该功能通常用于给间接依赖指定某个旧版本 * 或者减少间接依赖的复制数量。 * * "preferredVersions" 是一个语义化的值(例如: "~1.2.3")。Rush 将该值插入 * 到影响包管理机器计算版本的顶层 common/temp/package.json 中的 "dependencies" 字段中。 * 该字段的效果由包管理器决定,通常不会导致兼容或者违背语义化版本的问题。 * 如果你使用 PNPM, 其效果类似于 pnpmfile.js 钩子,可以查看 Rush 的文档来了解更多细节。 * * 修改完该字段后,建议执行 "rush update --full" 来使得包管理器重新计算版本。 */ "preferredVersions": { /** * 当仓库内某个依赖请求 "^1.0.0" 时,确保它们会获得 "1.2.3" * 版本,而不是最新版本。 */ // "some-library": "1.2.3" }, /** * 当设定该值为 true 时,仓库中的所有项目、所有依赖将会被自动添加到 preferredVersions 中, * 除非不同的项目为某个依赖指定了不同的版本范围。 * 对于陈旧的版本管理器而言,它们会尝试减少非直接依赖的复制数量。但是,对于不兼容 peerDependencies * 的间接依赖而言可能造成问题。 * * 该值的默认值为 true. 如果你在安装期间遇到了同级依赖导致的问题,建议 * 将它设定为 false. * * 修改完该字段后,建议执行 "rush update --full" 来使得包管理器重新计算版本。 */ // "implicitlyPreferredVersions": false, /** * "rush check" 命令用来确保每个项目中的同一版本都有相同的语义化版本。 * 然而,有时需要一些例外。 * allowedAlternativeVersions 属性列出 "rush check" 运行时允许的 * 其他版本的依赖列表。 * * 重要:这张表是针对*额外*的版本,它是通常版本(根据仓库中的所有项目推 * 断而来)的替代品。这个设计避免了该文件不必要的更新。 */ "allowedAlternativeVersions": { /** * 例如,允许某些项目使用旧版本的 TypeScript 编译器。 * (除了其他项目正在使用的“通常”版本,还包括): */ // "typescript": [ // "~2.4.0" // ] }} --- # 以开发者的身份开始 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/new_developer/#docusaurus_skipToContent_fallback) On this page 前提[​](https://rushjs.io/zh-cn/pages/developer/new_developer/#%E5%89%8D%E6%8F%90 "Direct link to heading") ---------------------------------------------------------------------------------------------------------- 为了使用 Rush, 首先需要 NodeJS, 我们推荐最新的[长期维护版本](https://nodejs.org/en/download/releases/) ,因为非稳定的 NodeJS 时常有一些 bugs, 你可以使用 [nvm-windows](https://github.com/coreybutler/nvm-windows) 和 [nvm](https://github.com/creationix/nvm) (Mac/Linux) 安装,这样你就可以方便地切换到不同的 NodeJS 版本,这些版本可能会用于不同的项目。 你也需要安装 Rush 本身,这非常简单,从你的 shell 或命令行窗口输入这个命令: $ npm install -g @microsoft/rush _注意:如果上述命令由于你没有 NPM 全局权限安装失败,你可以查看[修复你的 NPM 配置](https://docs.npmjs.com/getting-started/fixing-npm-permissions) 。_ 为了查看 Rush 的命令行帮助,你可以输入: $ rush -h 命令行帮助也被发布到[命令参考](https://rushjs.io/zh-cn/pages/commands/rush_add/) 内。 一些细节[​](https://rushjs.io/zh-cn/pages/developer/new_developer/#%E4%B8%80%E4%BA%9B%E7%BB%86%E8%8A%82 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------ 在我们开始之前,有一些重要的提示: #### 1\. Rush 仓库内不要使用某些指令[​](https://rushjs.io/zh-cn/pages/developer/new_developer/#1-rush-%E4%BB%93%E5%BA%93%E5%86%85%E4%B8%8D%E8%A6%81%E4%BD%BF%E7%94%A8%E6%9F%90%E4%BA%9B%E6%8C%87%E4%BB%A4 "Direct link to heading") Rush 会在某个中心文件夹安装所有的依赖,之后使用[符号链接](https://en.wikipedia.org/wiki/Symbolic_link) 给每个项目创建 "node\_modules" 文件夹。 **不要使用包管理工具来安装或链接依赖。**例如,`npm run` 会正常执行,但是诸如 `npm install`, `npm update`, `npm link`, `npm dedupe` 等命令会干扰 Rush 的符号链接,同样,对于其他包管理工具,也要避免使用 `pnpm install` 或者 `yarn install` 等命令。如果你想使用这些命令,首先运行 `rush unlink` 来删除 Rush 创建的符号链接。 如果你使用 `git clean -dfx` 来清理文件夹,注意它对符号链接的处理不够好。在使用 `git clean -dfx` 之前,请确保你已经运行 `rush unlink`. 最后,你可以运行 `rush update` 重新生成符号连接。(有一个单独的 `rush link` 命令,但是很少使用它。) #### 2\. 如果你怀疑安装出现问题[​](https://rushjs.io/zh-cn/pages/developer/new_developer/#2-%E5%A6%82%E6%9E%9C%E4%BD%A0%E6%80%80%E7%96%91%E5%AE%89%E8%A3%85%E5%87%BA%E7%8E%B0%E9%97%AE%E9%A2%98 "Direct link to heading") Rush 的包管理工具命令是“增量”式的,这意味着可以通过跳过不必要的安装来节省时间。因为当 Rush 运行在自动构建环境中时,有很多保障措施来确保检查的准确性。然而,当你在本地调试时,有时会导致你的 NPM “node\_modules” 文件夹变得不正确,最终导致奇怪的错误。 如果你怀疑你的安装已经出现问题,尝试执行 `rush update --purge`, 该指令会强制重新完全安装你的包,通常它会带你回到正常的状态。 * [前提](https://rushjs.io/zh-cn/pages/developer/new_developer/#%E5%89%8D%E6%8F%90) * [一些细节](https://rushjs.io/zh-cn/pages/developer/new_developer/#%E4%B8%80%E4%BA%9B%E7%BB%86%E8%8A%82) --- # 修改 package.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/modifying_package_json/#docusaurus_skipToContent_fallback) On this page 如果你需要在项目中添加一个名为 "**example-lib**" 的依赖。如果没有使用 Rush,你可以这样做: # 请不要在 Rush 仓库内使用以下命令~/my-repo$ cd apps/my-app~/my-repo/apps/my-app$ npm install --save example-lib 在 Rush 仓库内,你应该使用 [rush add](https://rushjs.io/zh-cn/pages/commands/rush_add/) 命令: ~/my-repo$ cd apps/my-app# 在 "my-app" 项目中添加 "example-lib" 的依赖,随后会自动执行 "rush update"~/my-repo/apps/my-app$ rush add --package example-lib `rush add` 命令也可以用来更新某个已有依赖的版本: # 将 "my-app" 中的 "example-lib" 版本更新为 "1.2.3"~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3# 或者将 "example-lib" 版本更新为 "^1.2.3"~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3 --caret# 这有一个更高级的示例:通过 NPM 源处查询兼容 "^1.2.0" 的最新语义化版本,然后将其添加为 "~1.5.3" 的依赖。## 注意:当在命令行中指定符号字符时,请使用引号,避免与 shell 发生冲突。~/my-repo/apps/my-app$ rush add --package "example-lib@^1.2.0"# 如果仓库内的其他项目正在使用 "example-lib", 可以一次性将其更新为 "1.2.3" 版本~/my-repo/apps/my-app$ rush add --package example-lib@1.2.3 --make-consistent 如果你想了解更多,可以查看[rush add](https://rushjs.io/zh-cn/pages/commands/rush_add/) . > **提示:VS Code 内一个有趣的功能** > > 如果你正在使用 VSCode, 也可以直接编辑 **package.json** 文件,在 dependencies 或 depDependencies 下输入 `"example-lib":`, VS Code 将自动查询 NPM 源的版本,并提供补全建议。在某些情况下,这种方式比 `rush add` 更便捷。 > > 当然,如果你手动修改了 **package.json**, 随后记得执行 `rush update`. 更新 NPM 包的版本[​](https://rushjs.io/zh-cn/pages/developer/modifying_package_json/#%E6%9B%B4%E6%96%B0-npm-%E5%8C%85%E7%9A%84%E7%89%88%E6%9C%AC "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------- `rush update --full` 指令可以安装满足 **package.json** 的最新版本。然而,如果你想更新 **package.json** 文件中的版本到较新的版本,目前 Rush 还无法在全局范围内实现。 [npm-check-update](https://www.npmjs.com/package/npm-check-updates) 会升级 Rush 仓库中的单个项目下 package.json 内版本,记得随后执行 `rush update`(而不是 `npm install`) _注意:PNPM workspace [已经推出](https://github.com/microsoft/rushstack/pull/1938) , 启用此功能后,可以使用 [pnpm update](https://pnpm.js.org/en/cli/update) 指令进行批量更新。_ * [更新 NPM 包的版本](https://rushjs.io/zh-cn/pages/developer/modifying_package_json/#%E6%9B%B4%E6%96%B0-npm-%E5%8C%85%E7%9A%84%E7%89%88%E6%9C%AC) --- # rush-plugin-manifest.json (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/#docusaurus_skipToContent_fallback) On this page This is the template for the **rush-plugin-manifest.json** file that is used when [creating a Rush plugin](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) . **/rush-plugin-manifest.json** /** * This file defines the Rush plugins that are provided by this package. */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", /** * An array of one or more plugin definitions provided by this NPM package. * * For more granular installations, it is recommended for plugins to be implemented by an * NPM package that does try to serve other roles such as providing APIs or command-line binaries. * The package name should start with "rush-". The name should end with "-plugin" or "-plugins". * For example: "@scope/rush-business-policy-plugin" */ "plugins": [ { /** * (Required) The name of the plugin. The plugin name must be comprised of letters and numbers * forming one or more words that are separated by hyphens. Note that if the plugin has a * JSON config file, that filename will be the same as the plugin name. See "optionsSchema" below * for details. * * If the manifest defines exactly one plugin, then it is suggested to reuse the name from the * NPM package. For example, if the NPM package is "@scope/rush-business-policy-plugin" * then the plugin name might be "business-policy" and with config file "business-policy.json". */ "pluginName": "example", /** * (Required) Provide some documentation that summarizes the problem solved by this plugin, * how to invoke it, and what operations it performs. */ "description": "An example plugin", /** * (Optional) A path to a JavaScript code module that implements the "IRushPlugin" interface. * This module can use the "@rushstack/rush-sdk" API to register handlers for Rush events * and services. The module path is relative to the folder containing the "package.json" file. */ // "entryPoint": "lib/example/RushExamplePlugin.js", /** * (Optional) A path to a "command-line.json" file that defines Rush command line actions * and parameters contributed by this plugin. This config file has the same JSON schema * as Rush's "common/config/rush/command-line.json" file. */ // "commandLineJsonFilePath": "lib/example/command-line.json", /** * (Optional) A path to a JSON schema for validating the config file that end users can * create to customize this plugin's behavior. Plugin config files are stored in the folder * "common/config/rush-plugins/" with a filename corresponding to the "pluginName" field * from the manifest. For example: "common/config/rush-plugins/business-policy.json" * whose schema is "business-policy.schema.json". */ // "optionsSchema": "lib/example/example.schema.json", /** * (Optional) A list of associated Rush command names such as "build" from "rush build". * If specified, then the plugin's "entryPoint" code module be loaded only if * one of the specified commands is invoked. This improves performance by avoiding * loading the code module when it is not needed. If "associatedCommands" is * not specified, then the code module will always be loaded. */ // "associatedCommands": [ "build" ] } ]} See also[​](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/#see-also "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- * [Creating a Rush plugin](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) * [Using Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) * [See also](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/#see-also) --- # 其他有用的指令 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/other_commands/#docusaurus_skipToContent_fallback) On this page 安装最新的语义化兼容的版本[​](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E5%AE%89%E8%A3%85%E6%9C%80%E6%96%B0%E7%9A%84%E8%AF%AD%E4%B9%89%E5%8C%96%E5%85%BC%E5%AE%B9%E7%9A%84%E7%89%88%E6%9C%AC "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `rush update` 通常情况下只会以最小增量更新的方式来满足项目内 **package.json** 文件,如果你想要将所有项目的依赖都更新到最新版本,可以这样做: # 它会高效地删除 shrinkwrap 文件,并会下载 package.json 文件中指定的最新兼容版本。# 注意,package.json 文件本身不会被修改。$ rush update --full 对于日常工作而言,`--full` 可能导致你的 PR 出现一些问题,例如,如果某一个依赖没有很好地遵循语义化版本规则。对于小型仓库而言,这不是什么问题,但对于大型的 monorepo,我们建议使用日常使用 `rush update`,同时在某条独立的 CI 或指定人员定期使用 `rush update --full`. 更快的构建方式[​](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E6%9B%B4%E5%BF%AB%E7%9A%84%E6%9E%84%E5%BB%BA%E6%96%B9%E5%BC%8F "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------- * **如果你用到的项目很少**:假如你的 Git 仓库内包含 50 个项目,但是你只用在 **widget** 和 **widget-demo** 项目内工作,你可以通过 `rush rebuild --to widget --to widget-demo` 来构建这两个库以及他们的依赖。 * **如果你变更了某个库**:假设你的 Git 仓库包含 50 个项目,同时你仅仅在 **widget** 库中修复了一些 bugs, 同时你需要给所有用到该库的项目进行单元测试,但是重新构建所有项目有些浪费时间,因此可以通过 `rush rebuild --from widget` 来构建只包含该库的项目。 [只选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) 一文详细描述了如何只选择部分项目。 一种更快的安装方式[​](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E4%B8%80%E7%A7%8D%E6%9B%B4%E5%BF%AB%E7%9A%84%E5%AE%89%E8%A3%85%E6%96%B9%E5%BC%8F "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 如果你的仓库正在使用 PNPM 并在 [rush.json](https://rushjs.io/zh-cn/pages/configs/rush_json/) 中启用了 `useWorkspaces=true`,那么就可以使用 “部分安装” 的功能,该功能可以通过仅在指定的项目中安装 NPM 包来减少安装时间。 例如: # 仅安装构建 "my-project" 所需的 NPM 包#(包括安装 "my-project" 在仓库内依赖的项目的依赖)$ rush install --to my-project# 与 "rush build" 类似,可以使用 "." 来指向当前 shell 所处的工作目录$ cd my-project$ rush install --to .# 该指令安装了执行 "rush build --from my-project" 所需的依赖$ rush install --from my-project 返回到一个干净的状态[​](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E8%BF%94%E5%9B%9E%E5%88%B0%E4%B8%80%E4%B8%AA%E5%B9%B2%E5%87%80%E7%9A%84%E7%8A%B6%E6%80%81 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 在使用 Rush 后,你可能需要清理一下,比如将一个目录打包成压缩文件。这里有一些清理指令: # 移除所有被 Rush 创建的链接$ rush unlink# 移除 Rush 创建的所有临时文件,包括删除公共文件夹下已下载的 NPM 包。$ rush purge * [安装最新的语义化兼容的版本](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E5%AE%89%E8%A3%85%E6%9C%80%E6%96%B0%E7%9A%84%E8%AF%AD%E4%B9%89%E5%8C%96%E5%85%BC%E5%AE%B9%E7%9A%84%E7%89%88%E6%9C%AC) * [更快的构建方式](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E6%9B%B4%E5%BF%AB%E7%9A%84%E6%9E%84%E5%BB%BA%E6%96%B9%E5%BC%8F) * [一种更快的安装方式](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E4%B8%80%E7%A7%8D%E6%9B%B4%E5%BF%AB%E7%9A%84%E5%AE%89%E8%A3%85%E6%96%B9%E5%BC%8F) * [返回到一个干净的状态](https://rushjs.io/zh-cn/pages/developer/other_commands/#%E8%BF%94%E5%9B%9E%E5%88%B0%E4%B8%80%E4%B8%AA%E5%B9%B2%E5%87%80%E7%9A%84%E7%8A%B6%E6%80%81) --- # 获取支持 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/help/support/#docusaurus_skipToContent_fallback) Rush 目前由 MS Office 团队开发,不过 Microsoft 不提供官方支持,但有许多社区选项可供您使用: * [常见问题回答](https://rushjs.io/zh-cn/pages/help/faq/) * **发现了一个 bug?** 你可以在 **rushstack** 仓库下开启一个 [issue](https://github.com/microsoft/rushstack/issues) * **Zulip**: 在 Rush Stack [Zulip chat room](https://rushstack.zulipchat.com/) 与 Rush 的开发者交流。 * **如果一个 PR 需要被关注,**尝试询问 [#contributor-helpline](https://rushstack.zulipchat.com/#narrow/stream/279883-contributor-helpline) 聊天室。我们会在合并前小心的审核每个提交,这是一项非常耗时的工作。维护者都是日常管理大型协同 monorepo 的人,所以 PR 经常被忽略。 您的贡献对我们非常重要,我们真切的希望 PR 可以被审核! --- # 为什么使用一个大仓库?! | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/intro/why_mono/#docusaurus_skipToContent_fallback) _开源的 NPM 包看起来是在许多小的 GitHub 仓库中开发的。听起来理所当然,对吧?_ 如果你正在构建毫无关系的组件,并且它们不适合整合在一起,当然可以。但是商业软件并不是这样的。它更像这样: 大多数人开始构建一个 web 应用,而不是一些库,当你的应用发布后,它的体积会逐渐增大, 直到有一天你需要在一些不同的仓库内共享一些代码,此时你发现代码已经乱成一窝,又需要花费时间重构! 显然,你必须将这些分割为可管理的组件。在 JavaScript 代码中,NPM 包是一种解决问题的方案。但查阅后才发现,NPM 似乎要求**一个 GitHub 仓库对应一个 NPM 包。**于是在一周乃至数周内,你创建了 10 个 Git 仓库来分割你的代码,并试着使用它们... ...但是使用 10 个 Git 仓库来管理代码后会出现一些让人头疼的问题: * **无暇顾及他人的工作**:如果一个同事大部分时间在 5 号和 6 号仓库工作,他看起来完全忽略了来自其他 8 个仓库的 pull requests。每天都会有新的仓库出现,而你甚至却不知道它们的存在。 * **层级式的发版**: 从 **lib3** 发布一个修复到你的应用项目需要更新/构建/发布许多 Git 仓库,顺序是:**lib3** --> **lib2** --> **lib1** --> **application**. 当 **lib3** 变动频繁时,上述过程会变的异常繁琐。人们如何记住正确的发版顺序?互联网上有地方可以询问这个问题,但是你人力有限,别人也很忙。 * **下游的受害者**:当 Bob 在 **lib3** 上做了一些改动并发布,所有的下游项目需要花费一定的时间才能升级并使用它。如果升级版本存在问题,那么可能是一周后 Alice 在 **lib1** 中尝试 "npm update" 时发现的。那时,Bob 可能动身去欧洲旅行了。为什么 Alice 要修复其他人升级导致的问题?貌似每次升级都会存在破坏性变动! * **疯狂的链接**:为了直接测试 **lib3** 的变动,解决方法看起来是使用 [npm link](https://docs.npmjs.com/cli/link) 将你的**应用**和 **lib3** 链接起来。但是 NPM 会创建一个全局范围内的符号连接,如果在同一台电脑上多个存在 **lib3** 多个分支,那么就会有问题。而且有 10+ 个库,很难记录哪两个库需要链接起来。 **一个库对应一个包**的方式对于陌生人之间维护孤立的项目是很有意义的(同样,这些库的更新频率也比较低,因此上述问题也更容易解决)。但是在我们的示例中,所有人都在同一个公司工作,这些库更多地扮演体系内的一个组件。代码会频繁的变动,某处的变动很可能破坏系统的其它部分。将多个项目整合起来构建,可以让你在每个变动中运行所有的单元测试,这样可以将修复问题的责任转移到最初更改代码的人身上。 于是,**一个 Git 仓库一个团队**的方式开始出现了,更贴切的描述是**用尽可能少的 Git 仓库来完成工作**。 ![monorepo block diagram](https://rushjs.io/images/home/mono-concept-h.svg) [Lots](https://danluu.com/monorepo/) [of](https://medium.com/@bebraw/the-case-for-monorepos-907c1361708a) [people](http://blog.shippable.com/our-journey-to-microservices-and-a-mono-repository) 许多开发大型业务软件的人,似乎最终都把所有代码放在一个大的 "monorepo" 中。JavaScript 是最后一个这么做的语言。 monorepo 策略下最大的担忧是显著的**_构建耗时_**。JavaScript 工具链明显比编译型语言慢,如果一个工程构建需要花费一分钟,那么假如你有 75 个工程,理论上构建将花费75 分钟。这看起来很吓人,但有了工业级的工具链,在构建耗时成为问题之前,你可以进行非常大的扩展。我们对Rush和**gulp-core-build**的大部分路线图都集中在构建耗时上,而且我们乐观的认为这里仍然有很大的优化空间。使用**子集构建**或**增量构建**,理论上可以避免重建所有的东西,除非一个变化真的影响到所有的东西 ,—— 对于那种变化,为了能尽早发现故障而需要等待更长的构建时间,到底值不值得,这很难说。 --- # rush rebuild | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/#docusaurus_skipToContent_fallback) On this page 用法: rush rebuild [-h] [-p COUNT] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] [--ignore-hooks]该指令假定每个项目下的 package.json 文件中的 "scripts" 字段,该字段中有 "npm run build"这样完全清洁的构建。Rush 会调用该脚本来构建每个在 rush.json 中注册过的项目。项目会尽可能的并行构建,但永远会遵循本地链接生成的依赖图。并行的进程数基于机器的核心数,除非被 --parallelism参数覆盖(对于增量构建,可以使用 "rush build" 来替换 "rush rebuild")。可选参数: -h, --help 展示帮助信息并退出 -p COUNT, --parallelism COUNT 定义并行构建的最大并发数,COUNT 参数应该是一个正整数并且其最大 值等于 CPU 核数。如果该参数为空,那么默认值会依赖操作系统和 CPU 的核数决定。参数可以通过 RUSH_PARALLELISM 环境变量指定。 -t PROJECT, --to PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to" 参数会包含项目和其依赖的项目。"." 是当前工作目录 的简写。更多信息可以参考“选中部分项目”一文。 -T PROJECT, --to-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--to-except" 参数会包含项目的依赖项目,而不包括项目 本身。"." 是当前工程目录的简写。更多信息可以参考“选中部分项目” 一文。 -f PROJECT, --from PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--from" 参数会包含项目和所有依赖它的项目,再加上这个集 合的依赖。"." 是当前工程目录的简写。更多信息可以参考“选中部分 项目”一文。 -o PROJECT, --only PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--only" 参数会选中指定的项目,而其依赖不会被添加。"." 是 当前目录的简写。注意这个参数是“不安全”的,因为它可能将某些依赖排除 在外。更多信息可以参考“选中部分项目”一文。 -i PROJECT, --impacted-by PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by" 参数会包含该项目和所有依赖该项目的项目 (因此可能会造成破坏性变动)。"." 是当前目录的简写。注意该参数是 “不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中 部分项目”一文。 -I PROJECT, --impacted-by-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by-expect" 参数会包含所有依赖该项目的项目, 而不包含本身。"." 是当前目录的简写。注意该参数是“不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中部分项目”一文。 --to-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--to-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--to", 更多信息可以参考“选中部分项目”一文。 --from-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--from-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--from", 更多信息可以参考“选中部分项目”一文。 -v, --verbose 构建期间展示更多信息,而不是仅仅展示总结性状态。 --ignore-hooks 跳过定义在 "rush.jon" 下 "eventHooks" 脚本的。确保你知道 跳过了哪些。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/#%E5%8F%82%E8%80%83 "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) * [rush build](https://rushjs.io/zh-cn/pages/commands/rush_build/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/#%E5%8F%82%E8%80%83) --- # 快速开始 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/intro/get_started/#docusaurus_skipToContent_fallback) On this page 三分钟上手[​](https://rushjs.io/zh-cn/pages/intro/get_started/#%E4%B8%89%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- 想要实际体验下 Rush? 首先你需要安装 [NodeJS](https://nodejs.org/en/download/) . **从你的 shell 中安装 Rush:** $ npm install -g @microsoft/rush (当然,不要输入 **"$"**.):-) **如果你想看 Rush 的命令行帮助,请这样做:** $ rush -h **如果你想看看 Rush 构建的真实项目,可以执行以下指令:** $ git clone https://github.com/microsoft/rushstack$ cd rushstack# 安装 NPM 包:# (如果你没有配置 Github email, 那么加上 "--bypass-policy" 选项。)$ rush update# 增量安装:$ rush update # <-- 瞬时完成!# 强制所有项目重新构建:$ rush rebuild# 增量构建:$ rush build # <-- 瞬时完成!# 使用 "--verbose" 来展示每个项目在构建过程中的日志信息。# 尽管项目是并行构建的,但是它们的日志是有序的。$ rush rebuild --verbose 让我们开始吧![​](https://rushjs.io/zh-cn/pages/intro/get_started/#%E8%AE%A9%E6%88%91%E4%BB%AC%E5%BC%80%E5%A7%8B%E5%90%A7 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- 选择适合你的教程 * [我是开发者](https://rushjs.io/zh-cn/pages/developer/new_developer/) 学习如何在 Rush 下开发。 * [我是仓库的维护者](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/) 学习如何将你的仓库托管到 Rush 下。 * [三分钟上手](https://rushjs.io/zh-cn/pages/intro/get_started/#%E4%B8%89%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B) * [让我们开始吧!](https://rushjs.io/zh-cn/pages/intro/get_started/#%E8%AE%A9%E6%88%91%E4%BB%AC%E5%BC%80%E5%A7%8B%E5%90%A7) --- # experiments.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/experiments_json/#docusaurus_skipToContent_fallback) 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 生成的模版下的 **experiments.json** 文件: **common/config/rush/experiments.json** /** * 该配置文件允许仓库开启或禁止某些实验性的功能。 * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", /** * Rush 5.14.0 改善了增量构建,它会忽略 pnpm-lock.json 文件中的一些虚假变化。 * 该优化默认开启,如果你遇到了 "rush build" 忽略构建某些项目的问题,请开启一个 * Github issue, 临时的解决方法是取消这行的注释来恢复当 package.json 变化时的 * 旧行为。 */ /*[LINE "HYPOTHETICAL"]*/ "legacyIncrementalBuildDependencyDetection": true, /** * 默认情况下,'rush install' 传给 "pnpm install" 带有 --no-prefer-frozen-lockfile 参数。 * 设定该值为 true 会传入 '--frozen-lockfile' 进而实现更快的下载。 */ /*[LINE "HYPOTHETICAL"]*/ "usePnpmFrozenLockfileForRushInstall": true, /** * 默认情况下, 'rush update' 传给 "pnpm install" 带有 --no-prefer-frozen-lockfile 参数 * 设定该值为 true 会传入 '--prefer-frozen-lockfile' 来替换最小 shrinkwrap 变动。 */ /*[LINE "HYPOTHETICAL"]*/ "usePnpmPreferFrozenLockfileForRushUpdate": true, /** * 使用 'preventManualShrinkwrapChanges' 选项限制哈希值,使其只包括对外部依赖。 * 该参数用于允许项目之间的增加/删除已经存在的依赖版本引用不会导致哈希变化。 */ /*[LINE "HYPOTHETICAL"]*/ "omitImportersFromPreventManualShrinkwrapChanges": true, /** * 若该值为 true, 临时项目的压缩文件的头信息的 chmod 字段不会被规范化。 * 规范化可以帮助压缩文件在不同平躺上保持一致。 */ /*[LINE "HYPOTHETICAL"]*/ "noChmodFieldInTarHeaderNormalization": true} --- # rush install | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/commands/rush_install/#docusaurus_skipToContent_fallback) On this page 用法: rush install [-h] [-p] [--bypass-policy] [--no-link] [--network-concurrency COUNT] [--debug-package-manager] [--max-install-attempts NUMBER] [--ignore-hooks] [--variant VARIANT] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME]"rush install" 命令会基于 "rush update" 创建/更新的 shrinkwrap 文件来给仓库内的所有项目安装依赖("shrinkwrap" 文件存储了仓库内项目的所有依赖和版本关系)。如果 shrinkwrap 文件缺失或过时后(例如,由于项目的 package.json 文件改变),"rush install" 命令会执行失败,并告诉你需要执行 "rush update" 来替代。其主要特性是只读:持续集成中应该使用 "rush install"而不是 "rush update" 来获取那些忘记在 commit 中更新 shrinkwrap 的开发者。如果想要避免shrinkwrap 文件偶然更新,那么这些谨慎的人可以使用 "rush install"可选参数: -h, --help 展示帮助信息并推出。 -p, --purge 开始执行之前执行 "rush purge". --bypass-policy 强制覆盖 rush.json 中约定的 "gitPolicy" 规定。 --no-link 一旦指定该参数,那么当安装完成后项目不会执行符号连接。你需要手动 执行 "rush link", 当想要独立的报告每个阶段,或者在两个阶段之 间进行额外的操作时,该参数十分有用。当使用 workspaces 时,不支 持该参数。 --network-concurrency COUNT 一旦指定该参数,将会限制最大的并发网络请求数。当网络出现问题时, 该参数十分有用。 --debug-package-manager 开启包管理器的详细日志。当使用该参数时,你可能想要 Rush 输出到 一个文件中。 --max-install-attempts NUMBER 覆盖默认的尝试安装的次数,默认值为 3. --ignore-hooks 跳过执行定义在 rush.json 中的 "eventHooks" 脚本。你应该知道 自己跳过了什么。 --variant VARIANT 通过一个安装配置变量来执行 Rush 命令。该参数可以通过环境变量 RUSH_VARIANT 来指定。 -t PROJECT, --to PROJECT 默认情况下将会处理仓库内的所有项目,可以通过该参数来选中部分项目。 每个 "--to" 参数会包含项目和其依赖的项目。"." 是当前工作目录的 简写。 更多信息可以参考“选中部分项目”一文。 -T PROJECT, --to-except PROJECT 默认情况下将会处理仓库内的所有项目,可以通过该参数来选中部分项目。 每个 "--to-except" 会包含项目的依赖,而不包括项目本身。"." 是 当前工作目录的简写。 更多信息可以参考“选中部分项目”一文。 -f PROJECT, --from PROJECT 默认情况下将会处理仓库内的所有项目,可以通过该参数来选中部分项目。 每个 "--from" 参数将会包含该项目和所有依赖它的项目,再加上这个 集合的依赖。"." 是当前工作目录的简写。 更多信息可以参考“选中部 分项目”一文。 -o PROJECT, --only PROJECT 默认情况下将会处理仓库内的所有项目,可以通过该参数来选中部分项目。 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--only" 参数会选中指定的项目,而其依赖不会被添加。"." 是 当前目录的简写。注意这个参数是“不安全”的,因为它可能将某些依赖排除 在外。更多信息可以参考“选中部分项目”一文。 -i PROJECT, --impacted-by PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by" 参数会包含该项目和所有依赖该项目的项目 (因此可能会造成破坏性变动)。"." 是当前目录的简写。注意该参数是 “不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中 部分项目”一文。 -I PROJECT, --impacted-by-except PROJECT 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 每个 "--impacted-by-expect" 参数会包含所有依赖该项目的项目, 而不包含本身。"." 是当前目录的简写。注意该参数是“不安全的”, 因为它可能将某些依赖排除在外。更多信息可以参考“选中部分项目”一文。 --to-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--to-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--to", 更多信息可以参考“选中部分项目”一文。 --from-version-policy VERSION_POLICY_NAME 正常情况下会构建仓库内的所有项目。通过该参数可以选中部分项目。 "--from-version-policy" 参数会给每个属于 VERSION_POLICY_NAME 的项目指定 "--from", 更多信息可以参考“选中部分项目”一文。 参考[​](https://rushjs.io/zh-cn/pages/commands/rush_install/#%E5%8F%82%E8%80%83 "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [rush update](https://rushjs.io/zh-cn/pages/commands/rush_update/) * [参考](https://rushjs.io/zh-cn/pages/commands/rush_install/#%E5%8F%82%E8%80%83) --- # rush-project.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/rush-project_json/#docusaurus_skipToContent_fallback) On this page **rush-project.json** 是可选的配置文件,该文件通过 [rig 包](https://rushstack.io/pages/heft/rig_packages/) 提供。 **/config/rush-project.json** /** * "config/rush-project.json" 文件用来给仓库内的项目单独配置 Rush-specific * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", /** * 可选参数,指定另一个 JSON 配置文件,当前文件继承自该文件。这提供了一种在多个项目内 * 共享配置文件的方法, */ // "extends": "my-rig/profiles/default/config/rush-project.json", /** * 指定工具链写入输出文件的目。启用后,Rush 构建缓存将从缓存中 * 恢复这个文件。 * * 这些字符串是根目录下的文件名,这些文件不应该被 Git 追踪。 * 它们不能包含符号连接。 */ "projectOutputFolderNames": [ // "lib", "dist" ], /** * 配置构建缓存。 */ "buildCacheOptions":{ /** * 选择性地禁用项目构建缓存,选中的项目将不能从缓存中恢复。 * * 如果项目的构建脚本与缓存有冲突,那么可以使用这个方法解决。 * 例如在项目文件夹外写文件。在可能的情况下,更好的方法是 * 改进构建脚本,使其与缓存兼容。 */ // "disableBuildCache": true, /** * 对 Rush 命令的缓存进行细粒度的控制。 */ "optionsForCommands": [ // { // /** // * Rush 指令名, 定义在 custom-commands.json 文件中 // */ // "name": "my-command", // // /** // * 选择性地禁用项目构建缓存,选中的项目将不能从缓存中恢复。 // * // * 如果项目的构建脚本与缓存有冲突,那么可以使用这个方法解决。 // * 例如在项目文件夹外写文件。在可能的情况下,更好的方法是 // * 改进构建脚本,使其与缓存兼容。 // */ // "disableBuildCache": true // } ] }} 参考[​](https://rushjs.io/zh-cn/pages/configs/rush-project_json/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------ * [开启构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) * [参考](https://rushjs.io/zh-cn/pages/configs/rush-project_json/#%E5%8F%82%E8%80%83) --- # artifactory.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/artifactory_json/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **artifactory.json** 文件: **common/config/rush/artifactory.json** /** * 该配置项用于管理 Rush 和 JFrog Artifactory 服务集成。 * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json", "packageRegistry": { /** * (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry. * When enabled, "rush install" will automatically detect when the user's ~/.npmrc * authentication token is missing or expired. And "rush setup" will prompt the user to * renew their token. * (必须)设定该值为 "true" 来使得 Rush 管理 Artifactory NPM 的口令。当开启后,"rush install" 会自动检测 * 用户的 ~/.npmrc 认证令牌是否缺失或过期,并且 "rush setup" 将会提示用户更新令牌。 * * 默认值为 false. */ "enabled": false, /** * (必须)给 NPM 源指定 URL, 它与 .npmrc 文件中的 URL 相同,应该像这样: * * https://your-company.jfrog.io/your-project/api/npm/npm-private/ */ // "registryUrl": "", /** * 一系列自定义字符串,当口令更新后 "rush setup" 将其添加到用户的 ~/.npmrc 文件中。例如,这可以配置公司源,以便 * NPM 作为一个独立命令(但是对于 "rush add" 和 "rush install" 等操作没有必要,因为它们会从 monorepo 的 * common/config/rush/.npmrc 获取) * * 注意: ~/.npmrc 设定在给定机器上是全局的,所以添加设定时要小心,防止与其他工作区冲突。 */ "userNpmrcLinesToAdd": [ // "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/" ], /** * (必须)指定 Artifactory 控制面板的 URL, 用户在此处生成一个 API 密钥。 * 该 URL 在 "visitWebsite" 后打印。其示例如: https://your-company.jfrog.io/ * 指定一个空字符串来覆盖这一行。 */ // "artifactoryWebsiteUrl": "", /** * 该配置项允许自定义 "rush setup" 交互,例如为您的团队或配置提供消息。 * 指定一个空字符串来覆盖这一行。 */ "messageOverrides": { /** * 覆盖通常所输出的消息: * “这个 monorepo 使用来自 Artifactory 私有 NPM 源的包” */ // "introduction": "", /** * 覆盖通常所输出的消息: * “请联系版本库维护者,以获得设置 Artifactory 用户账户的帮助。” */ // "obtainAnAccount": "", /** * 覆盖通常所输出的消息: * “请在浏览器中打开这个 URL:” * * 这条信息后,"artifactoryWebsiteUrl" 会打印。 */ // "visitWebsite": "", /** * 覆盖通常所输出的消息: * “您的用户名出现在 JFrog 网站的右上角” */ // "locateUserName": "", /** * 覆盖通常所输出的消息: * * “在 JFrog 网站上点击 “编辑资料”。 如果还没生成米要的话, * 请点击“生成API密钥”按钮。” * */ // "locateApiKey": "" } }} 参考[​](https://rushjs.io/zh-cn/pages/configs/artifactory_json/#%E5%8F%82%E8%80%83 "Direct link to heading") ----------------------------------------------------------------------------------------------------------- * [NPM 源认证](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/) * [参考](https://rushjs.io/zh-cn/pages/configs/artifactory_json/#%E5%8F%82%E8%80%83) --- # 日常用到的指令 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#docusaurus_skipToContent_fallback) On this page 日常的开发仅仅需要以下几个 Rush 指令: rush update[​](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-update "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- 当 **package.json** 文件发生变化时,请务必运行 `rush update`, 换句话说: * 当从 git 上拉取新的更改(例如 `git pull`)后。 * 当项目内 **package.json** 文件被手动修改后。 * 当 **common/config** 目录下可能影响版本的文件(例如 **pnpmfile.js**, **common-versions.json** 等)被修改后。 `rush update` 操作可能会改变 **common/config** 下的一些文件,当这些文件发生变化时,你需要通过 commit 到 Git 中,并在相应的 PR 中包含它们。若不确定是否需要 commit,执行 `rush update` 就可以了 —— 如果已经是最新的,则不需要等待! `rush update` 内做了些什么: 1. Rush 检查或应用各种可能会改变 **common/config** 内文件的策略。 2. Rush 会将所有项目内的 **package.json** 文件与仓库的公共 shrinkwrap 文件进行比较来检查是否有效。 3. 若无效,则包管理工具会更新 shrinkwrap 文件。 4. 无论如何,包管理工具都会将所有依赖安装到 **common/temp/node\_modules** 目录下。 5. 最后,Rush 会给每个项目下构建一个 **node\_modules** 文件夹,该文件夹下内容通过符合链接到 **common/temp/node\_modules**. (该操作等同于 `rush link`) > **shrinkwrap 文件是什么?** > > 需要项目中并没有将依赖指定为诸如 `1.2.3` 这样精确的版本,而是使用诸如 `1.x` 或者 `^1.2.3` 这样语义化版本。语义化的版本意味着依赖安装时的最新版本,这种**非确定性**的策略存在一定问题:当依赖的库新版本发布时,周一建立分支周二便可能因此而失败,这就很让人抓狂。shrinkwrap 文件就解决了这个问题,它存储了一个完整的安装计划,并会被 Git 记录。 > > shrinkwrap 文件在不同的 [包管理器](https://rushjs.io/zh-cn/pages/maintainer/package_managers/) > 中有不同的名字:**shrinkwrap.yaml**, **npm-shrinkwrap.json** 或者 **yarn.lock** 等。 你可以观察到,CI 流水线中使用 `rush install` 来替代 `rush update`, 二者的不同点是 `rush install` 不会更新任何文件,相反,如果存在过失的数据,则会在 PR 上报错,并提示你执行 `rush update` 或者提示你 commit 其结果。(一些开发者为了防止 shrinkwrap 文件中不符合预期的更新,他们选择使用 `rush install` 当作常用指令,而不是 `rush build`) rush rebuild[​](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-rebuild "Direct link to heading") ------------------------------------------------------------------------------------------------------------------ 一旦你拉取到最新的修改,那么就应该进行编译所有项目。`rush rebuild` 将给仓库内的所有项目执行一个完整的、清除式的构建。 如果你的工具链支持增量构建,那么你可以执行 `rush build` 来构建那些变动过的项目。 rushx[​](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rushx "Direct link to heading") ---------------------------------------------------------------------------------------------------- 如果你仅仅想构建一个项目,那么可以使用 `rushx` 指令。你可以在对应的项目下运行 `rushx` 指令,`rushx` 指令与 `npm run` 的指令类似,但它输入更简单、报错提示更友好、同时还有命令行帮助信息。 rush check[​](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-check "Direct link to heading") -------------------------------------------------------------------------------------------------------------- 当编辑完 **package.json** 文件后,你可以执行 `rush check` 来检查多个项目是否依赖同一个库的不同版本,在 monorepo 环境下,这种行为是不可取的。许多仓库使用 `rush check` 作为 CI 的起始,此时如果你提交的 PR 中提交了依赖不同版本,他们会报错。 rush change[​](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-change "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- 如果你从事库会被 NPM 发布,那么你的仓库可能需要你在 PR 中添加相应的变更日志。如果没有添加,你的 PR 构建会在 `rush change --verify` 步骤失败。 为了书写变更日志,首先需要把变动以 commit 的形式提交到 Git 中,之后在仓库下执行 `rush change`, 该指令会检查 Git 历史,并根据变动情况提示你为每个变化的项目书写更新日志。每一条日志会被存储在 **common/changes** 下的独立文件中。你应该把这些文件添加到 Git 中,以便于后续的提交。 随后,Rush 的自动发布工作流会检查这些文件,以确定哪些包需要发布。它会删除这些文件,并将你的更新信息复制到包的 CHANGELOG.md 文件中。 ⏵ 查看 [更新日志编写](https://rushjs.io/zh-cn/pages/best_practices/change_logs/) 来获取更多写变更记录的提示。 常见情况 ==== 上面就是 Rush 的一些常用的指令。 结合起来,日常的指令可能会像这样: # 从 Git 获取最新的代码$ git pull# 按需安装 NPM 包$ rush update# 清理并重新构建所有项目$ rush rebuild# 进入某个项目内$ cd ./my-project# 假设 package.json 内存在 "start" 指令。# (通过 "rushx" 来查看可用的命令)$ rushx start * [rush update](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-update) * [rush rebuild](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-rebuild) * [rushx](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rushx) * [rush check](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-check) * [rush change](https://rushjs.io/zh-cn/pages/developer/everyday_commands/#rush-change) --- # 使用项目标签 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/project_tags/#docusaurus_skipToContent_fallback) On this page Rush 的 **项目标签** 提供了一个很方便的办法来引用任意的 Rush 项目组, 在 **rush.json** 配置文件中使用 `"tags"` 属性可以将标签应用于项目中。 举个例子: **rush.json** . . . "projects": [ { "packageName": "my-controls", "projectFolder": "libraries/my-controls", "reviewCategory": "production", /** * 设置一个可选的自定义标签可以用于筛选这个项目 * 举例:添加 "my-custom-tag" 将允许这个项目 * 被该命令选中 "rush list --only tag:my-custom-tag" */ "tags": [ "1.0.0-release", "frontend-team" ] }, { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain", "reviewCategory": "tools", "tags": [ "tools" ] } ] . . . 关于 `tag:my-custom-tag` 选择器语法的详细信息, 参考 [选择部分项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#selectors) 。 标签语法[​](https://rushjs.io/zh-cn/pages/developer/project_tags/#%E6%A0%87%E7%AD%BE%E8%AF%AD%E6%B3%95 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- 标签名称必须是一个或者多个由连字符或者斜杠分隔的单词, 单词可能包含小写 ASCII 字母、数字、`.` 和 `@` 字符。一些例子: rush list --to tag:my-custom-tag rush list --to tag:api-extractor.com rush list --to tag:1.0.0 标签校验[​](https://rushjs.io/zh-cn/pages/developer/project_tags/#%E6%A0%87%E7%AD%BE%E6%A0%A1%E9%AA%8C "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- 在 **rush.json** 的 `"projects"` 数组中允许任意的 `"tags"` 字符串很容易出错。如果有人不小心拼错了标签,或者他们使用了现在已经过时的旧标签,那可能需要一段时间才能发现这个错误。你可以使用 `"allowedProjectTags"` 设置来定义一个在你的 monorepo 中要使用的固定标签列表,这也提供了一个集中的地方来记录它们的含义。 **rush.json** . . . /** * 这是一个可以应用于 Rust 项目里的允许标签的可选但推荐的列表 * 使用该文件中的 "tags" 设置,这个列表对于防止拼写等错误时很有用, * 并且它还提供了一个集中的地方来记录你的标签。如果 "allowedProjectTags" 列表是 * 未指定的,那么允许任何有效的标签。标签名称必须是一个或者多个单词 * 由连字符或者斜杠分隔, 单词可能包含小写 ASCII 字母、数字、 * "." 和 "@" 字符。 */ "allowedProjectTags": [ // 将此标签应用于所有是 CLI 工具的 Rust 项目 "tools", // 将此标签应用于所有属于我们公司前端团队的项目 "frontend-team", // 使用这个标签来标记包含 QA 测试通过的项目 // 用于即将推出的产品。 "1.0.0-release" ], . . . * [标签语法](https://rushjs.io/zh-cn/pages/developer/project_tags/#%E6%A0%87%E7%AD%BE%E8%AF%AD%E6%B3%95) * [标签校验](https://rushjs.io/zh-cn/pages/developer/project_tags/#%E6%A0%87%E7%AD%BE%E6%A0%A1%E9%AA%8C) --- # version-policies.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/version-policies_json/#docusaurus_skipToContent_fallback) 该文件是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 生成的 **version-policies.json** 模板: **common/config/rush/version-policies.json** /** * 该配置文件用于使用 Rush 发布时的高级配置。 * 更多信息可以参考 Rush 官网: https://rushjs.io *//** * 一系列版本策略的定义。“版本政策”是一个自定义的包,它会影响 "rush change", * "rush version", 和 "rush publish". 这个策略适用于在 rush.json 下指定了 * "versionPolicyName" 字段的项目。 */[ // { // /** // * (必须) 表明版本政策的种类。 // * ("lockStepVersion" 或 "individualVersion") // * // * "lockStepVersion" 模式是指项目将会使用 "lock-step versioning". 该策略 // * 适用于一组作为同一个产品的可选择组件的包。整套包是一期发布,并使用相同的 NPM // * 版本号。当这组内的某个包依赖其他时,语义化版本通常被限制为单一版本。 // */ // "definitionName": "lockStepVersion", // // /** // * (必须)政策名将被用于 rush.json 下的 "versionPolicyName" 字段。 // * 该字段同样被用于命令行参数中,例如 "--version-policy" 和 "--to-version-policy". // */ // "policyName": "MyBigFramework", // // /** // * (必须)当前版本。当前分支下,集合内的所有包应当都是当前版本,当版本号变化时候 // * Rush 用此来决定下一个版本。 // * (不考虑 package.json 下 "version" 字段。) // */ // "version": "1.0.0", // // /** // * (必须) 变更类型,适用于发布下一个版本。 // * 当在 Git 上创建发布分支时,该字段应当根据发布类型更新。 // * // * 有效值: "prerelease", "release", "minor", "patch", "major" // */ // "nextBump": "prerelease", // // /** // * (可选)一旦指定,集合内的所有包共享 CHANGELOG.md 文件。 // * 该文件存储了所有被指定为 "main" 的项目,这些项目属于该集合。 // * // * 如果该文件被忽略,那么集合内的每个项目会维护单独的 CHANGELOG.md. // */ // "mainProject": "my-app" // }, // // { // /** // * (必须) 表明版本政策的种类。 // * ("lockStepVersion" 或 "individualVersion") // * // * "individualVersion" 模式表明项目将使用“单独的版本”。 // * 这是典型的 NPM 模式,每个项目都有独立的版本号和 CHANGELOG.md 文件。 // * 尽管单个 CI 负责发包,但是它们没有任何特殊关系。版本变更会依照开发者 // * 回答的 "rush change" 的问题。 // */ // "definitionName": "individualVersion", // // "policyName": "MyRandomLibraries", // // /** // * (可选)该属性确保集合内的所有包使用一个主版本号。例如因为相同的主版本分支。 // * 他还可以阻止人们不小心对 "major" 语义版本进行了不适当的更改。 "minor" 或 // * "patch" 版本会依据 "rush change" 来给每个变化的项目进行独立的更改。 // */ // "lockedMajor": 3, // // /** // * (可选)当使用 Rush 管理发布时, 默认使用 "rush change" 命令来为每个被修改 // * 的项目进行版本变更。这些变更会产生 CHANGELOG.md 文件。如果你授权你的 CHANGELOG.md // * 由手动管理或者其他的方式,那么设定 "exemptFromRushChange" 为 true 来告诉 "rush // * change" 忽略这些项目。 // */ // "exemptFromRushChange": false // }]; --- # subspaces.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/subspaces_json/#docusaurus_skipToContent_fallback) On this page **common/config/rush/subspaces.json** /** * 此配置文件管理 Rush 的实验性“subspaces”功能, * 它允许在一个 Rush 工作区中使用多个 PNPM 锁定文件。 * 有关完整文档,请参阅 https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", /** * 将此标志设置为“true”以启用 subspaces 功能。 */ "subspacesEnabled": false, /** * (已弃用)这是从该功能的早期原型迁移的临时解决方案: * https://github.com/microsoft/rushstack/pull/3481 * 它允许只有一个项目的 subspace 将其配置文件存储在项目文件夹中。 */ "splitWorkspaceCompatibility": false, /** * 当没有使用“--subspace”或“--to”参数调用诸如“rush update”之类的命令时, * Rush 将安装所有 subspaces。在拥有大量 subspaces 的巨大 monorepo 中, * 这将非常缓慢。将“preventSelectingAllSubspaces”设置为 true 以避免这种错误, * 通过始终要求选择参数来运行诸如“rush update”之类的命令。 */ "preventSelectingAllSubspaces": false, /** * subspace 名称列表,应该是由连字符分隔的小写字母数字单词, * 例如“my-subspace”。相应的配置文件路径将类似于 * “common/config/subspaces/my-subspace/package-lock.yaml”。 */ "subspaceNames": []} 另见[​](https://rushjs.io/zh-cn/pages/configs/subspaces_json/#%E5%8F%A6%E8%A7%81 "Direct link to heading") --------------------------------------------------------------------------------------------------------- * [Rush subspaces](https://rushjs.io/zh-cn/pages/advanced/subspaces/) * [另见](https://rushjs.io/zh-cn/pages/configs/subspaces_json/#%E5%8F%A6%E8%A7%81) --- # 配置 tab 补全 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/tab_completion/#docusaurus_skipToContent_fallback) On this page 在 5.34.0 版本中,Rush 支持 tab 补全,这样可以让用户按下 TAB 键来快速输入 shell 命令。以下内容参考自 [.NET Core CLI 的 tab 补全](https://docs.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete) 。 PowerShell[​](https://rushjs.io/zh-cn/pages/developer/tab_completion/#powershell "Direct link to heading") ----------------------------------------------------------------------------------------------------------- 为了在 PowerShell 中开启 tab 补全,需要创建或编辑 `$PROFILE` 中的变量,更多信息可以参考:[如何创建 profile](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles#how-to-create-a-profile) 和 [Profile 的执行原理](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles#profiles-and-execution-policy) . 在你的 profile 中添加以下代码: # 适用于 Rush CLI 的 PowerShell 参数补全工具Register-ArgumentCompleter -Native -CommandName rush -ScriptBlock { param($commandName, $commandAst, $cursorPosition) [string]$value = $commandAst.ToString() # Handle input like `rush install; rush bui` + Tab [int]$position = [Math]::Min($cursorPosition, $value.Length) rush tab-complete --position $position --word "$value" | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } Bash[​](https://rushjs.io/zh-cn/pages/developer/tab_completion/#bash "Direct link to heading") ----------------------------------------------------------------------------------------------- 为了在 Bash 中开启自动补全,需要在 **.bashrc** 文件中添加以下代码: # 适用于 Rush CLI 的 bash 参数补全工具_rush_bash_complete(){ local word=${COMP_WORDS[COMP_CWORD]} local completions completions="$(rush tab-complete --position "${COMP_POINT}" --word "${COMP_LINE}" 2>/dev/null)" if [ $? -ne 0 ]; then completions="" fi COMPREPLY=( $(compgen -W "$completions" -- "$word") )}complete -f -F _rush_bash_complete rush Zsh[​](https://rushjs.io/zh-cn/pages/developer/tab_completion/#zsh "Direct link to heading") --------------------------------------------------------------------------------------------- [Zsh](https://www.zsh.org/) 的环境变量会稍有不同,需要在 **~/.zshrc** 文件中添加以下代码: (( ${+commands[rush]} )) && { _rush_completion() { compadd -- $(rush tab-complete --position ${CURSOR} --word "${BUFFER}" 2>>/dev/null) } compdef _rush_completion rush} 它会检查 rush 命令是否存在,因此这段代码需要添加在 PATH 已经设置好之后(或者在 [nvm](https://github.com/nvm-sh/nvm) 初始化之后)。或者,你也可以删除第一行的 rush 命令检查。 * [PowerShell](https://rushjs.io/zh-cn/pages/developer/tab_completion/#powershell) * [Bash](https://rushjs.io/zh-cn/pages/developer/tab_completion/#bash) * [Zsh](https://rushjs.io/zh-cn/pages/developer/tab_completion/#zsh) --- # 推荐设定 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#docusaurus_skipToContent_fallback) On this page 当你的仓库构建并运行后,**rush.json** 中还有一些建议开启的配置项,这些严格的设定可以提高仓库的健康程度和减少维护成本。由于这些配置项要求你修改代码,因此默认是关闭的,同时,这些配置并不适用于所有场景。 repository.url[​](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#repositoryurl "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- 如果仓库使用 `rush change` 来记录更新日志,那么强烈建议在 **rush.json** 中设定 **repository.url**, 它可以确保 `rush change` 找到准确的基础分支,尤其是当仓库被其他人 "fork" 的情况下。 **rush.json** 示例如下: "repository": { // 将下面的 URL 为你的仓库的 "git clone" 时使用的 URL "url": "https://github.com/microsoft/rush-example" } ensureConsistentVersions[​](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#ensureconsistentversions "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------- 我们推荐将 **rush.json** 内的 `ensureConsistentVersions` 设定为 `true`,它会使得 Rush 在执行以下指令时前执行 `rush check`: * `rush update` * `rush link` * `rush version` * `rush publish` 该指令会去检查每个项目的 **package.json** 文件并保证所有的依赖都是同一个版本,该配置可以避免版本不一致导致的问题,因此推荐你打开。 在某些特殊情况下不同版本可能更适用些,例如,你可能希望逐步更新项目内的 TypeScript 版本,而不是一次性的,在此期间,你需要使用两个不同的 `typescript` 版本。对于该情况,你可以在 **common-versions.json** 中添加一个 `allowedAlternativeVersions` 字段。 > NOTE: 注意:在早期的 Rush 版本中,CI 脚本示例将 `rush check` 视为一个单独的构建步骤;如果开启 `ensureConsistentVersions`,那么你可以将 `rush check` 从 CI 构建步骤中删除。 strictPeerDependencies[​](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#strictpeerdependencies "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------ 如果你使用 PNPM 包管理器,那么强烈建议你将 **rush.json** 中的 `strictPeerDependencies` 设定为 `true`,它会使得 Rush 在安装时开启 PNPM 的 `--strict-peer-dependencies` 配置项。开启后,如果出现不兼容的依赖版本时候,即不满足 peerDependencies 时,`rush install` 将会执行失败(出于历史原因,JavaScript 的包管理器通常不会将其视为一个错误)。 * [repository.url](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#repositoryurl) * [ensureConsistentVersions](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#ensureconsistentversions) * [strictPeerDependencies](https://rushjs.io/zh-cn/pages/maintainer/recommended_settings/#strictpeerdependencies) --- # Autoinstallers | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#docusaurus_skipToContent_fallback) On this page A monorepo will often need to install NPM packages that provide tools such as shell commands. In most cases, these tooling dependencies can be declared as the `devDependencies` of some Rush project, and then they will be installed by `rush install` using its centralized shrinkwrap file (package manager lock file). However, sometimes such dependencies are needed in situations where `rush install` has not been invoked, or where `rush install` might fail if a person's unfinished work includes some **package.json** modifications. For these situations, Rush's **autoinstallers** feature provides an isolated mechanism for installing tooling dependencies. An autoinstaller is defined as folder under **common/autoinstallers/** with a **package.json** file and its own private shrinkwrap file. This folder is added to Git, but it is not a normal Rush project: It is not installed by `rush install`, nor does it contain any buildable source code for `rush build`. An autoinstaller is purely a container for installing NPM dependencies. Autoinstallers can be associated with Rush features such as [custom commands](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) or [Rush plugins](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) ; when the associated feature is invoked, Rush will automatically install the dependencies. When to use autoinstallers[​](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#when-to-use-autoinstallers "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------- If you're enabling a Rush plugin, you must configure an autoinstaller. If you are creating a [Rush custom command](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) whose script needs NPM dependences, there are several possible approaches to consider: * **rush install**: Typically most dependencies in a Rush monorepo will get installed all together by `rush install` using the centralized shrinkwrap file. For most needs, this is the simplest approach and easiest to maintain. If some dependencies are irrelevant to a particular task, you can skip installing them by using [project selection parameters](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) such as `rush install --to example-project`. * **install-run.js**: The [install-run.js](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#install-runjs-for-other-commands) script enables you to install NPM packages outside of `rush install`. This is useful for commands that run in contexts where `rush install` is not invoked at all, or where `rush install` may be broken. For example, a Git commit hook script gets run on branches where `rush install` might fail: developers often commit work in progress, or a Git rebase may introduce broken commits that get fixed up by a later commit. * **autoinstallers**: A limitation of **install-run.js** is that it only installs one NPM package. For example, if your custom command needs multiple packages (for example the `pretty-quick` driver, the `prettier` engine, and some Prettier plugins), you could add them to the **package.json** file of an autoinstaller. Autoinstallers typically have a small dependency tree and thus install much faster than `rush install`. Some potential downsides of autoinstallers: In situations that require multiple autoinstallers and/or `rush install`, the package manager will be invoked multiple times and may need to install the same dependency from different shrinkwrap files. This can be significantly slower than if `rush install` could install everything together using the centralized shrinkwrap file. Also, autoinstallers are not validated or updated by `rush update`, so they require extra maintenance for upgrades. Creating an autoinstaller[​](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#creating-an-autoinstaller "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------ 1. Use the [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) command to create the folder: # This creates the common/autoinstallers/my-autoinstaller/package.json filerush init-autoinstaller --name my-autoinstaller 2. Edit the **my-autoinstaller/package.json** file to add your dependencies. 3. Run [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) to update the shrinkwrap file. You should redo this step whenever you modify the **package.json** file. # Create or update common/autoinstallers/my-autoinstaller/pnpm-lock.yaml# This file should be committed and tracked by Git.rush update-autoinstaller --name my-autoinstaller 4. Commit the updated files to git git add common/autoinstallers/my-autoinstaller/git commit -m "Updated autoinstaller" To associate an autoinstaller with a custom command, specify its name in the `autoinstallerName` field in [command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) . To associate an autoinstaller with a Rush plugin, see the [Creating Rush plugins](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) documentation. Maintaining an autoinstaller[​](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#maintaining-an-autoinstaller "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------ * To modify an autoinstaller, edit its **package.json** file. # This will also upgrade any indirect dependencies.rush update-autoinstaller --name my-autoinstaller# Commit the updated pnpm-lock.yamlgit commit -m "Updated autoinstaller" * To delete the autoinstaller, simply delete its folder: # BE CAREFUL WHEN RECURSIVELY DELETING FOLDERSrm -Rf common/autoinstallers/my-autoinstaller# Commit the changes to Gitgit add common/autoinstallersgit commit -m "Deleted autoinstaller" See also[​](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#see-also "Direct link to heading") -------------------------------------------------------------------------------------------------------- * [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) * [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) * [Enabling Prettier](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/) * [Custom commands](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) * [Creating Rush plugins](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) * [When to use autoinstallers](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#when-to-use-autoinstallers) * [Creating an autoinstaller](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#creating-an-autoinstaller) * [Maintaining an autoinstaller](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#maintaining-an-autoinstaller) * [See also](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/#see-also) --- # 安装 Git 钩子 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/#docusaurus_skipToContent_fallback) On this page Git 版本管理系统允许配置一些钩子脚本,这些脚本将在某个行为执行前唤起(参考 [自定义 Git](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) ),最基本的实现方式是创建一个带有通用名称的 shell 脚本,例如 **pre-commit**,**post-update**,**prepare-commit-msg** 等等。如果 Git 发现这些脚本在本地的 **.git/hooks** 目录中,它将在对应的操作执行前执行这些脚本。 出于安全性考虑,当你克隆一个仓库时候,这些脚本不会被 Git 自动拷贝下来,相反,每个开发者必须手动创建这些文件夹并将其权限设定为可执行,Rush 可以帮你自动完成这个工作。 配置 Rush 来安装一个 Git 钩子脚本[​](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/#%E9%85%8D%E7%BD%AE-rush-%E6%9D%A5%E5%AE%89%E8%A3%85%E4%B8%80%E4%B8%AA-git-%E9%92%A9%E5%AD%90%E8%84%9A%E6%9C%AC "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 作为示例,假设我们发现开发者写了一个没有很好描述其工作的 commit, 这会导致 Git 记录难以理解。为了解决这个问题,可以添加一个 `commit-msg` 钩子,该钩子要求 commit 需要满足一定要求,例如,这个简单的 Bash 脚本要求至少有 3 个单词: **common/git-hooks/commit-msg** #!/bin/sh## 这是一个 Rush 内使用 Git 示例的示例,为了开启这个钩子,需要将文件名重命名为 "commit-msg"# 之后执行 `rush install`, 将它从 common/git-hooks 拷贝到 .git/hooks 目录下。## 了解更多 Git 钩子## Git 的文档可以参考: https://git-scm.com/githooks# 一些有用的资源: https://githooks.com## 关于这个示例## 这个 commit-msg 钩子被 "git commit" 传入一个参数后并调用,该参数是 commit 消息文件的名称。# 当遇到问题后,该钩子会以非零状态码退出并显示出合适的消息。# 该钩子被允许编辑 commit 消息。# 该示例强制要求 commit 消息中至少包含一定数量的单词。if [ `cat $1 | wc -w` -lt 3 ]; then echo "" echo "Invalid commit message: The message must contain at least 3 words." exit 1fi `rush init` 后生成的示例文件中含有上述事例,你可能需要将 [common/git-hooks/commit-msg.sample](https://github.com/microsoft/rush-example/blob/main/common/git-hooks/commit-msg.sample) 拷贝到自己的仓库。 你可以按照如下方式使用它。 1. 在 **common/git-hooks** 目录下添加该文件,并在 Git 上提交。 2. 当开发者执行 `rush install` 时,Rush 将会拷贝该文件到 **.git/hooks/commit-msg** 目录下。 3. 当你执行 `git commit` 时,Git 将找到该脚本并调用它。 4. 如果 commit 消息过短,脚本会返回非零状态码,Git 显示 `Invalid commit message` 提示并且拒绝操作。 使用 Rush 来安装这个钩子脚本需要避免使用 [Husky](https://www.npmjs.com/package/husky) 等独立解决方案。注意 Husky 预期你的仓库在根目录上有一个 **package.json** 和 **node\_modules** 目录,并且 Husky 将会执行每个 Git 操作的 shell 命令(即使未使用的钩子);使用 Rush 来安装钩子可以避免这些限制。 > **注意:**如果你需要卸载钩子,可以删除你的 **.git/hooks/** 目录下的文件。 在 "git commit" 时调用 Prettier[​](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/#%E5%9C%A8-git-commit-%E6%97%B6%E8%B0%83%E7%94%A8-prettier "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Prettier 工具保证代码遵守统一的缩进、逗号等格式。通过配置一个 `git commit` 钩子来自动调用 Prettier, 便可以在不影响其他开发者的情况下进行修复。 [启用 Prettier](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/) 一文有手把手的教学。 * [配置 Rush 来安装一个 Git 钩子脚本](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/#%E9%85%8D%E7%BD%AE-rush-%E6%9D%A5%E5%AE%89%E8%A3%85%E4%B8%80%E4%B8%AA-git-%E9%92%A9%E5%AD%90%E8%84%9A%E6%9C%AC) * [在 "git commit" 时调用 Prettier](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/#%E5%9C%A8-git-commit-%E6%97%B6%E8%B0%83%E7%94%A8-prettier) --- # build-cache.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/build-cache_json/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **build-cache.json** 文件: **common/config/rush/build-cache.json** /** * 该配置项用于管理 Rush 的构建缓存功能。 * 更多信息可以参考 Rush 官网: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", /** * (必须)实验性 - 设定该值为 true 来开启构建缓存功能。 * * 参考 https://rushjs.io/pages/maintainer/build_cache/ 来获取该实验性功能的更多细节。 */ "buildCacheEnabled": false, /** * (必须)选择把构建缓存放到哪里。 * * 可选的值: "local-only", "azure-blob-storage", "amazon-s3" */ "cacheProvider": "local-only", /** * 设定该值覆盖缓存入口 ID. * 如果设定该值,那么它必须包含一个 [hash] 占位符, * 它也可以包含 [projectName], [projectName:normalize], [phaseName], [phaseName:normalize], [phaseName:trimPrefix] */ // "cacheEntryNamePattern": "[projectName:normalize]-[hash]" /** * 该配置项用于配置 "cacheProvider"="azure-blob-storage" */ "azureBlobStorageConfiguration": { /** * (必须)用于构建缓存的 Azure storage 账户。 */ // "storageAccountName": "my-account", /** * (必须)用于构建缓存的容器名。 */ // "storageContainerName": "my-container", /** * Azure 环境内的账户。默认为 AzurePublicCloud. * * 可选的值: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" */ // "azureEnvironment": "AzurePublicCloud", /** * 缓存项目的前缀名。 */ // "blobPrefix": "my-prefix", /** * 如果设定为 true, 允许写入到缓存中。 * 默认为 false. */ // "isCacheWriteAllowed": true }, /** * 该配置项用于配置 "cacheProvider"="amazon-s3" */ "amazonS3Configuration": { /** * (必备) 用于建立缓存的亚马逊 S3 的桶(例如 "us-east-1")。 */ // "s3Region": "us-east-1", /** * 用于建立缓存的Amazon S3中的桶的名称。 */ // (Required) "s3Bucket": "my-bucket", /** * 缓存项目的可选前缀("文件夹")。 */ // "s3Prefix": "my-prefix", /** * 如果设置为true,允许写入缓存。 * 默认为false。 */ // "isCacheWriteAllowed": true }} 参考[​](https://rushjs.io/zh-cn/pages/configs/build-cache_json/#%E5%8F%82%E8%80%83 "Direct link to heading") ----------------------------------------------------------------------------------------------------------- * [开启构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) * [参考](https://rushjs.io/zh-cn/pages/configs/build-cache_json/#%E5%8F%82%E8%80%83) --- # 环境变量 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/environment_vars/#docusaurus_skipToContent_fallback) On this page Rush 的环境变量可以通过终端环境变量来定制: RUSH\_ABSOLUTE\_SYMLINKS[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_absolute_symlinks "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------- 如果该变量设定为 `true`, Rush 会使用绝对路径创建符号链接而不是相对路径。当仓库被移动时,或者仓库的部分内容被移动到沙盒时,该参数可能会很有用。 RUSH\_ALLOW\_UNSUPPORTED\_NODEJS[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_allow_unsupported_nodejs "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------- 如果该变量设定为 `true`, 当运行的 Node 版本不符合 **rush.json** 中 `odeSupportedVersionRange` 字段指定的范围时,Rush 不会失败。 RUSH\_BUILD\_CACHE\_CREDENTIAL(实验性)[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_credential%E5%AE%9E%E9%AA%8C%E6%80%A7 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 该环境变量用于 [构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) 这个实验性的功能。 配置后将会给远端的构建缓存提供一个凭证。这个凭证可以被缓存或覆盖。 如果使用 Azure Blob Storage, 在序列化的参数重必须有一个 SAS 口令。关于其更多细节可以参考[这篇文章](https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview) 。 RUSH\_BUILD\_CACHE\_ENABLED (实验性)[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_enabled-%E5%AE%9E%E9%AA%8C%E6%80%A7 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 该环境变量用于 [构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) 这个实验性的功能。 覆盖定义在 `build-cache.json` 中的 `buildCacheEnabled` 值。这个环境变量必须是 `1`(表示 true)或者 `0`(表示 false)。如果没有配置构建缓存,那么该环境变量将被忽略。 RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED(实验性)[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_write_allowed%E5%AE%9E%E9%AA%8C%E6%80%A7 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 该环境变量用于 [构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) 这个实验性的功能。 覆盖定义在 `build-cache.json` 中的 `isCacheWriteAllowed` 值。这个环境变量必须是 `1`(表示 true)或者 `0`(表示 false)。如果没有配置构建缓存,那么该环境变量将被忽略。 RUSH\_DEPLOY\_TARGET\_FOLDER[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_deploy_target_folder "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------- 该环境变量用于给 [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/) 指令指定 `--target-folder` 参数。 RUSH\_GIT\_BINARY\_PATH[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_git_binary_path "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- 显式的指定 Rush 执行时候的 Git 执行文件的路径。 RUSH\_GLOBAL\_FOLDER[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_global_folder "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- 覆盖了 Rush 中的 `~/.rush` 全局目录的路径,它用于存储临时文件。 为了避免并发问题和兼容性问题,Rush 中的大部分临时文件都是存储在仓库内每个项目中的独立目录中。然而,一小部分文件(例如 `@microsoft/rush-lib` 引擎和包管理器)被存储在全局文件夹下来加速安装。在 POSIX 风格的操作系统上的默认路径为 `~/.rush`, 在 Windows 上的默认路径为 `C:\Users\YourName`.(POSIX 是 IEEE 公司的一个商标)。 使用 `RUSH_GLOBAL_FOLDER` 可以指定不同的目录路径,如果 Windows 租政策禁止安装在用户目录时,该环境变量很有用。 RUSH\_INVOKED\_FOLDER[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_invoked_folder "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------- 当 Rush 执行脚本时,有时候需要改变工作目录,例如从一个项目文件到仓库根目录。起初的工作目录(Rush 命令被调用的目录)被 子进程的 `RUSH_INVOKED_FOLDER` 环境变量赋值,以便在脚本中按需使用。`RUSH_INVOKED_FOLDER` 与包管理器执行生命周期脚本时的 `INIT_CWD` 相同。 RUSH\_PARALLELISM[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_parallelism "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ 约定构建期间最大的并行进程数,更多信息可以参考 [rush build](https://rushjs.io/zh-cn/pages/commands/rush_build/) 的 `--parallelism` 参数的命令行帮助。 RUSH\_PNPM\_STORE\_PATH[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_pnpm_store_path "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- 当使用 pnpm 作为包管理器时,该变量可以用于配置 pnpm 使用的存储目录。 如果使用相对路径,那么存储路径将被解析为相对于进程当前工作目录。推荐使用绝对路径。 RUSH\_PREVIEW\_VERSION[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_preview_version "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- 该命令变量可以覆盖版本选择器将要安装的 Rush 的版本。默认值由 `rushVersion` 字段来确定。 例如,如果你想在升级前尝试不同版本的 Rush, 你可以这样做: $ set RUSH_PREVIEW_VERSION=5.0.0-dev.25$ rush install RUSH\_TEMP\_FOLDER[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_temp_folder "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- 该变量覆盖了 Rush 的临时目录。默认值是仓库根目录下的 **common/temp**。 RUSH\_VARIANT[​](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_variant "Direct link to heading") ---------------------------------------------------------------------------------------------------------------- 该变量设定了当安装和链接包依赖时 Rush 使用的安装变种。 更多信息可以参考[安装变种](https://rushjs.io/zh-cn/pages/advanced/installation_variants/) 。 * [RUSH\_ABSOLUTE\_SYMLINKS](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_absolute_symlinks) * [RUSH\_ALLOW\_UNSUPPORTED\_NODEJS](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_allow_unsupported_nodejs) * [RUSH\_BUILD\_CACHE\_CREDENTIAL(实验性)](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_credential%E5%AE%9E%E9%AA%8C%E6%80%A7) * [RUSH\_BUILD\_CACHE\_ENABLED (实验性)](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_enabled-%E5%AE%9E%E9%AA%8C%E6%80%A7) * [RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED(实验性)](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_build_cache_write_allowed%E5%AE%9E%E9%AA%8C%E6%80%A7) * [RUSH\_DEPLOY\_TARGET\_FOLDER](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_deploy_target_folder) * [RUSH\_GIT\_BINARY\_PATH](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_git_binary_path) * [RUSH\_GLOBAL\_FOLDER](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_global_folder) * [RUSH\_INVOKED\_FOLDER](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_invoked_folder) * [RUSH\_PARALLELISM](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_parallelism) * [RUSH\_PNPM\_STORE\_PATH](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_pnpm_store_path) * [RUSH\_PREVIEW\_VERSION](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_preview_version) * [RUSH\_TEMP\_FOLDER](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_temp_folder) * [RUSH\_VARIANT](https://rushjs.io/zh-cn/pages/configs/environment_vars/#rush_variant) --- # The "rush-lib" API | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/extensibility/api/#docusaurus_skipToContent_fallback) On this page Rush provides an API for use by automation scripts. It is documented in the integrated API reference for all Rush Stack projects:      [API Reference: @microsoft/rush-lib package](https://api.rushstack.io/pages/rush-lib/) Below are some usage examples. > Although these code samples are presented as plain JavaScript, we strongly recommend to use TypeScript and model your scripts as regular Rush projects. It is more work to set up initially, but it generally saves time and simplifies maintenance in the long run. Reading the rush.json configuration[​](https://rushjs.io/zh-cn/pages/extensibility/api/#reading-the-rushjson-configuration "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------- Rather than trying to load **rush.json** as a JSON file, it is recommended to use the [RushConfiguration](https://api.rushstack.io/pages/rush-lib.rushconfiguration/) class which provides a richer set of data views. For example, this script will show all the Rush projects and their folders: const rushLib = require('@microsoft/rush-lib');// loadFromDefaultLocation() will search parent folders to find "rush.json" and then// take care of parsing it and loading related config files.const rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});for (const project of rushConfiguration.projects) { console.log(project.packageName + ':'); console.log(' ' + project.projectRelativeFolder);} Modifying package.json files[​](https://rushjs.io/zh-cn/pages/extensibility/api/#modifying-packagejson-files "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------- If you want to modify a **package.json** file, the [PackageJsonEditor](https://api.rushstack.io/pages/rush-lib.packagejsoneditor/) class provides helpful validation and normalization: const rushLib = require('@microsoft/rush-lib');const rushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd()});// This will find "@rushstack/ts-command-line" in rush.json, without needing to specify the NPM scopeconst project = rushConfiguration.findProjectByShorthandName('ts-command-line');// Add lodash as an optional dependencyproject.packageJsonEditor.addOrUpdateDependency('lodash', '4.17.15', 'optionalDependencies');// Save the modified package.json fileproject.packageJsonEditor.saveIfModified(); Generating a README.md summary[​](https://rushjs.io/zh-cn/pages/extensibility/api/#generating-a-readmemd-summary "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------- For a more realistic example, the [repo-toolbox/src/ReadmeAction.ts](https://github.com/microsoft/rushstack/blob/main/repo-scripts/repo-toolbox/src/ReadmeAction.ts) tool uses these APIs to generate the [README.md](https://github.com/microsoft/rushstack/blob/main/README.md#published-packages) inventory for the Rush Stack monorepo. * [Reading the rush.json configuration](https://rushjs.io/zh-cn/pages/extensibility/api/#reading-the-rushjson-configuration) * [Modifying package.json files](https://rushjs.io/zh-cn/pages/extensibility/api/#modifying-packagejson-files) * [Generating a README.md summary](https://rushjs.io/zh-cn/pages/extensibility/api/#generating-a-readmemd-summary) --- # deploy.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/deploy_json/#docusaurus_skipToContent_fallback) On this page 这是 [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/) 为 **deploy.json** 和 **deploy-\>.json** 生成的模版文件: **common/config/rush/deploy.json** /** * 这个配置文件约定了使用 "rush deploy" 时的部署场景。 * 默认的文件是 "deploy.json"; 其他的文件名匹配 "deploy-.json". * 更全的文档可以参考:https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/deploy-scenario.schema.json", /** * "rush deploy" 命令准备了一个构建文件夹,用于从主项目开始收集其所 * 有依赖(包括 NPM 包和 Rush 工程), 主项目被 "--project" 参数指定。 * "deploymentProjectNames" 列出了 "--project" 参数可选的列表,它 * 记录了仓库内想要部署的项目,并帮助 "rush deploy" 正确的调用。如果 * "deploymentProjectNames" 列表内只有一个项目,那么 "--project" * 参数可以被忽略,同时,其列表内的项目名应该是是 rush.json 中声明的包 * 名。 * * 如果住项目包含其他无关的 Rush 工程,那么添加它们到 "projectSettings" * 中,之后在 "additionalProjectsToInclude" 指定它们。 */ "deploymentProjectNames": [ /* 在这添加你的工程 */ ], /** * 当部署一个本地 Rush 工程时,package.json 中的 "devDependencies" * 会被排除在外。如果你想包含它们,则设定 "includeDevDependencies" 为 * true. * * 该参数默认值为 false. */ // "includeDevDependencies": true, /** * 当部署一个本地 Rush 项目,通常将过滤 .npmignore 中内容,所以 Rush * 只会复制哪些被 "npm pack" 打包的文件。设定 "includeNpmIgnoreFiles" * 为 true 会禁止掉这些过滤,以至于所有文件都会被复制(诸如 "node_modules" * 等例外)。 * * 该参数默认值为 false. */ // "includeNpmIgnoreFiles": true, /** * 为了提高遗留包的后向兼容性,PNPm 会在 node_modules 中下载额外的链接 * 来使得包可以引入没被声明的链接。某些情况下这种方式可能会创建双倍的链接。 * 如果你的部署不需要这种变通方式,可以设定 "omitPnpmWorkaroundLinks" * 为 true 来避免创建额外的链接。 * * 该参数默认值为 false. */ // "omitPnpmWorkaroundLinks": true, /** * 指定创建部署目录时如何链接(符号连接,硬链接,或者 NTFS 链接): * * - "default": 默认行为是创建文件时创建链接。 * - "script": 写入一个名为 "create-links.js" 的 Node.js 脚本。执行时,这个脚本会创建 "deploy-metadata.json" 中描述的链接。 * - "none": 什么都不做,稍后使用其他工具创建链接。 */ // "linkCreation": "script", /** * 一旦指定该参数,那么 "rush deploy" 会递归地将文件夹中的文件复制到 * 部署的目标文件夹中 (common/deploy). 这可以用来提供额外的配置文件 * 或者部署时所需的脚本。该路径相对于仓库根目录。 */ // "folderToCopy": "repo-tools/assets/deploy-config", /** * 自定义 Rush 项目在部署阶段如何处理。 */ "projectSettings": [ // { // /** // * 项目的包名,必须在 rush.json 中声明。 // */ // "projectName": "@my-scope/my-project", // // /** // * 一系列与该项目一起部署的 本地 项目(除了 package.json // * dependencies)。指定在 rush.json 中声明的完整包名。 // */ // "additionalProjectsToInclude": [ // // "@my-scope/my-project2" // ], // // /** // * 当部署一个项目时,其包含的依赖通常基于 package.json 中的 // * "dependencies", "peerDependencies" 和 "optionalDependencies" // * 字段自动决定,受制于 "includeDevDependencies" 等部署设置。 // * 然而,当某些信息不准确时,可以使用 "additionalDependenciesToInclude" // * 来在这个列表中加更多的包 However, in cases where // * // * 这个列表包含了 Rush 安装,Node.js 模块解析的所有包。 // * 如果指向本地 Rush 项目, "additionalProjectsToInclude" // * 字段不会递归地应用。 // */ // "additionalDependenciesToInclude": [ // // "@rushstack/node-core-library" // ], // // /** // * 此设置可以防止部署特定的依赖。它只会过滤项目中 package.json // * 中明确声明的依赖关系。不会影响通过 "additionalProjectsToInclude" // * "additionalDependenciesToInclude" 添加的依赖,也不会影响见解 // * 依赖。 // * // * "*" 用于匹配任意字符。例如,如果你的项目将依赖打包,那么指定 // * "dependenciesToExclude": [ "*" ] 排除 package.json // * 中的所有依赖。 // */ // "dependenciesToExclude": [ // // "@types/*" // ] // } ]} 参考[​](https://rushjs.io/zh-cn/pages/configs/deploy_json/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------ * [构建项目](https://rushjs.io/zh-cn/pages/maintainer/deploying/) * [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/) command-line parameters * [参考](https://rushjs.io/zh-cn/pages/configs/deploy_json/#%E5%8F%82%E8%80%83) --- # rush-alerts_json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/rush-alerts_json/#docusaurus_skipToContent_fallback) On this page 这是[rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 Rush 警报功能生成的模板。 > **注意:** 由于此功能为实验性功能,您必须调用 `rush init --include-experiments`。 **common/config/rush/rush-alerts.json** /** * 此配置文件管理Rush警报功能。 * 更多文档可在Rush网站上查看:https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-alerts.schema.json", /** * 设置如 `startTime` 和 `endTime` 将使用此时区。 * 如果省略,默认时区为UTC(`+00:00`)。 */ "timezone": "-08:00", /** * 触发它们的警报消息和条件的数组。 */ "alerts": [ // { // /** // * 当警报显示时,此标题将出现在消息框的顶部。 // * 应该是一行文字,尽可能简洁。 // */ // "title": "Node.js upgrade soon!", // // /** // * 当警报显示时,此文本出现在消息框中。为了使JSON文件更易于阅读,如果文本超过一行, // * 你可以提供一个字符串数组,这些字符串将被串联。你的文本可能包含换行符, // * 但通常这是不必要的,因为会自动应用自动换行。 // */ // "message": [ // "This Thursday, we will complete the Node.js version upgrade. Any pipelines that", // " still have not upgraded will be temporarily disabled." // ], // // /** // * (可选)为避免对用户进行轰炸,应尽可能保持 `title` 和 `message` 的简洁。 // * 如果需要提供更多细节,使用此设置打印指向具有进一步指导的网页的超链接。 // */ // // "detailsUrl": "https://contoso.com/team-wiki/2024-01-01-migration", // // /** // * (可选)如果指定了 `startTime`,则在该时间之前不会显示此警报。 // * // * 请记住,不能保证在此时间或根本就显示警报: // * 只有在Rush命令触发了获取最新的rush-alerts.json配置之后才会显示警报。 // * 此外,为避免对用户轰炸太多信息,警报的显示是受到限制的。如果你需要测试你的警报, // * 设置环境变量 `RUSH_ALERTS_DEBUG=1` 来禁用限制。 // * // * `startTime` 应指定为 `YYYY-MM-DD HH:MM` 使用24小时格式, // * 或者 `YYYY-MM-DD` 在这种情况下时间部分将是 `00:00`(那天的开始)。 // * 时区从上面的 `timezone` 设置获取。 // */ // // "startTime": "2024-01-01 15:00", // // /** // * (可选)如果当前时间晚于 `endTime`,则不会显示此警报。 // * 格式与 `startTime` 相同。 // */ // // "endTime": "2024-01-05", // // /** // * (可选)确定是否可以显示此警报的脚本的文件名, // * 位于“common/config/rush/alert-scripts”文件夹中。脚本必须定义 // * 一个名为 `canShowAlert` 的CommonJS导出,返回一个布尔值,例如: // * // * ``` // * module.exports.canShowAlert = function () { // * // (你的逻辑在这里) // * return true; // * } // * ``` // * // * Rush将调用此脚本,工作目录设置为monorepo根文件夹, // * 没有保证已运行 `rush install`。为确保警报的最新,Rush // * 可能会在不可预测的临时路径中获取和检出“common/config/rush-alerts”文件夹。 // * 因此,你的脚本应避免从其文件夹外部导入依赖, // * 通常应保持尽可能简单、可靠和快速。对于更复杂的条件, // * 我们建议设计一些其他过程来准备一个数据文件或环境变量, // * 该变量可以由你的条件脚本便宜地检查。 // */ // // "conditionScript": "rush-alert-node-upgrade.js" // } ]} 另见[​](https://rushjs.io/zh-cn/pages/configs/rush-alerts_json/#%E5%8F%A6%E8%A7%81 "Direct link to heading") ----------------------------------------------------------------------------------------------------------- * [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) * [另见](https://rushjs.io/zh-cn/pages/configs/rush-alerts_json/#%E5%8F%A6%E8%A7%81) --- # 使用 Sparo 加速 Git | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/integrations/sparo/#docusaurus_skipToContent_fallback) On this page Monorepos 经常会随着越来越多的项目被合并而迅速增长。虽然 Rush 提供了多种机制来加速[安装时间](https://rushjs.io/zh-cn/pages/advanced/subspaces/) 和[构建时间](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/) ,但对于非常大的仓库,即使是基本操作如 `git clone` 和 `git checkout` 也可能变得异常缓慢。 Git 优化[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#git-%E4%BC%98%E5%8C%96 "Direct link to heading") ------------------------------------------------------------------------------------------------------------- Git 提供了一些内置功能,这些功能可能足以加速中等大小的仓库: * [浅克隆](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-code--depthcodeemltdepthgtem) 允许只克隆几个提交,但通常只适用于临时克隆,如 CI 作业。 * [部分克隆](https://git-scm.com/docs/partial-clone) 允许在没有文件内容("blobless" 克隆)或甚至没有提交详细信息("treeless" 克隆)的情况下克隆,大大加速了您的 `git clone` 时间,并允许在 `git checkout` 期间获取这些详细信息。 * [大文件存储 (LFS)](https://git-lfs.com/) 可以将大型二进制文件移至单独的服务器,在检出时根据需要下载它们。然而,使用 LFS 是棘手的,因为这个功能依赖于外部于 Git 的 `.gitattributes` 过滤:您的 `.gitattributes` 规则可以根据文件扩展名选择什么是“大”的,但没有简单的方法可以根据实际文件大小或更新频率进行选择。如果您不小心选择了太多文件,性能可能会比没有 LFS 更糟。此外,对 `.gitattributes` 的更改不能在不重写整个 Git 历史记录的情况下追溯应用 — 这对于一个活跃的仓库来说是一种非常破坏性的行为。 幸运的是,Git 提供了更多高级功能,如**稀疏检出**、**单分支克隆**、**文件系统监视器**、**后台维护**,以及多种可选择设置以调整行为。这些功能可以直接通过 Git 命令行访问,但配置可能复杂。非专业用户经常在采用上遇到困难。 如何通过 Sparo 帮助[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E5%A6%82%E4%BD%95%E9%80%9A%E8%BF%87-sparo-%E5%B8%AE%E5%8A%A9 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------- 作为应用高级 Git 优化的更简单替代方法,尝试使用 [Sparo](https://tiktok.github.io/sparo) 工具。它直接与 Rush 集成并自动优化 Git。基本策略是_只获取您需要的_,通过三个维度:(1)跳过无关分支,(2)跳过无关历史(部分克隆),(3)跳过无关项目文件夹的检出(稀疏检出)。 Sparo 通过使用 [Sparo 配置文件](https://tiktok.github.io/sparo/pages/guide/sparo_profiles/) 简化稀疏检出,这些配置文件可以指定智能选择,例如:_"只检出我团队正在工作的两个应用程序,以及 Rush 工作区中的所有依赖项。"_这样,工程师就不需要花时间确定确切的文件夹路径进行检出。Sparo 检出总是包括一组基本的["骨架文件夹"](https://tiktok.github.io/sparo/pages/reference/skeleton_folders/) ;这确保每个项目的 **package.json** 文件始终可用。Sparo 还可以选择性地收集匿名 Git 时间度量,帮助您的构建团队随时间分析性能。 [Sparo 网站](https://tiktok.github.io/sparo/zh-cn/) 提供了更多背景。 使用 Sparo[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E4%BD%BF%E7%94%A8-sparo "Direct link to heading") ----------------------------------------------------------------------------------------------------------------- Git 和 Sparo 命令行可以互换使用。唯一的要求是您的工作目录必须最初使用 `sparo clone` 而不是 `git clone` 来克隆。 这里有一个快速指南,使用 [azure-sdk-for-js](https://github.com/Azure/azure-sdk-for-js.git) ,这是 GitHub 上的一个大型公共 RushJS monorepo: ### 第 1 步:克隆仓库[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-1-%E6%AD%A5%E5%85%8B%E9%9A%86%E4%BB%93%E5%BA%93 "Direct link to heading") # 安装 Sparo 命令行npm install -g sparo# 克隆您的 Rush 仓库 -- 只克隆最小的“骨架”sparo clone https://github.com/Azure/azure-sdk-for-js.git ### 第 2 步:创建配置文件[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-2-%E6%AD%A5%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6 "Direct link to heading") cd azure-sdk-for-js# 创建一个稀疏检出配置文件,保存在 common/sparo-profiles/my-team.jsonsparo init-profile --profile my-team 编辑创建的 **my-team.json** 文件以添加[项目选择器](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) 。例如: **common/sparo-profiles/my-team.json** { "selections": [ { // 这个演示配置文件将检出 "@azure/arm-commerce" 项目 // 及其所有依赖: "selector": "--to", "argument": "@azure/arm-commerce" } ]} ### 第 3 步:检出您的配置文件[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-3-%E6%AD%A5%E6%A3%80%E5%87%BA%E6%82%A8%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6 "Direct link to heading") 保存更改到 **my-team.json** 之后,现在是应用它的时候了: sparo checkout --profile my-team 试试看!例如: rush install# 构建应该成功,因为 Sparo 确保了依赖项目# 被包括在稀疏检出中:rush build --to @azure/arm-commerce 对于日常工作,考虑选择如 `sparo revert` 这样的镜像子命令代替 `git revert`。Sparo 包装提供(1)更好的默认设置,(2)更好性能的建议,以及(3)可选的匿名性能度量。 示例: sparo pullsparo commit -m "Example command" 另请参阅[​](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------- * [Sparo 网站](https://tiktok.github.io/sparo/zh-cn/) * [为前端 Monorepos 提供更快的 Git:介绍 Sparo](https://developers.tiktok.com/blog/2024-sparo-faster-git-for-frontend-monorepos) - 来自 Sparo 维护者的博客文章 * [Git 优化](https://rushjs.io/zh-cn/pages/integrations/sparo/#git-%E4%BC%98%E5%8C%96) * [如何通过 Sparo 帮助](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E5%A6%82%E4%BD%95%E9%80%9A%E8%BF%87-sparo-%E5%B8%AE%E5%8A%A9) * [使用 Sparo](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E4%BD%BF%E7%94%A8-sparo) * [第 1 步:克隆仓库](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-1-%E6%AD%A5%E5%85%8B%E9%9A%86%E4%BB%93%E5%BA%93) * [第 2 步:创建配置文件](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-2-%E6%AD%A5%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) * [第 3 步:检出您的配置文件](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E7%AC%AC-3-%E6%AD%A5%E6%A3%80%E5%87%BA%E6%82%A8%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) * [另请参阅](https://rushjs.io/zh-cn/pages/integrations/sparo/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85) --- # 在 Rush 中使用 Mergify | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/integrations/mergify/#docusaurus_skipToContent_fallback) On this page [Mergify](https://mergify.com/) 为 GitHub 提供附加服务,扩展了**合并队列**功能。 如果您对合并队列不熟悉,可以从 Rush 文档的 [最佳实践:启用合并队列](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/) 和 Mergify 的 [什么是合并队列,为什么使用它?](https://blog.mergify.com/whats-a-merge-queue-and-why-use-it/) 开始。 优化队列的一般问题涉及许多权衡和启发式方法,用于选择哪些工作进行并行处理或合并。 这为优化和不同实施者之间的差异化创造了许多机会。Mergify 的服务针对大规模、高速度的单体仓库。 他们的 [合并队列基准测试](https://mergify.com/alternative/merge-queue-benchmark) 展示了各种系统之间的功能差异矩阵。 一个基本示例[​](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E4%B8%80%E4%B8%AA%E5%9F%BA%E6%9C%AC%E7%A4%BA%E4%BE%8B "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------- [Mergify 配置文件](https://docs.mergify.com/configuration/file-format) 通常称为 `.mergify.yml`,定义了大部分行为。让我们总结一下拉取请求的基本生命周期: 一旦在您的仓库中创建了 PR,Mergify 将检测到它并根据 [`pull-request-rules`](https://docs.mergify.com/configuration/file-format/#pull-request-rules) 检查它。此规则集 允许您自动化和适应各种工作流程。 `pull-request-rules` 包含条件和动作,特别是 [`queue`](https://docs.mergify.com/workflow/actions/queue/) 动作。一旦 PR 验证了 拉取请求规则的条件,它将触发其动作,导致 PR 排队。 以下是一个示例配置文件: **.mergify.yml** queue_rules: - name: default merge_conditions: - '#approved-reviews-by>=2' - check-success=Travis CI - Pull Requestpull_request_rules: - name: merge using the merge queue conditions: - base=main - label=queue actions: queue: 在上面,我们定义了一个名为 `default` 的唯一合并队列及其自己的一套条件。这些 `merge_conditions` 必须在 PR 能够合并之前得到验证。 使用分区增加并行性[​](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E4%BD%BF%E7%94%A8%E5%88%86%E5%8C%BA%E5%A2%9E%E5%8A%A0%E5%B9%B6%E8%A1%8C%E6%80%A7 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 优化合并队列的关键是识别可以并行执行的作业, 因为它们的 Git 差异是独立的。两个 PR 是“独立的”,如果 (1) 它们的差异不涉及相同的文件 以及 (2) 由两个差异“影响”的文件不重叠,根据依赖图。 Rush 的依赖分析以 Rush 项目的粒度进行,而不是单个文件。 就 [Rush 项目选择器](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/) 而言,这意味着 `rush list --impacted-by git:origin/main` 在两个 PR 之间不得有任何重叠。 Mergify 的 [分区](https://docs.mergify.com/merge-queue/partitions/) 类似于 Rush 项目 在此分析中;每个分区定义了一组文件,并具有声明分区之间的依赖关系的能力, 然后可以确定作业是并行构建还是不构建。 例如,假设您的 Rush 工作区包含名为 `project-a`、`project-b` 和 `project-c` 的三个项目。 这是一个样本硬编码配置: **.mergify.yml** partition_rules: - name: project-a conditions: - files~=^apps/project-a - name: project-a conditions: - files~=^apps/project-a - name: project-a conditions: - files~=^apps/project-cqueue_rules: - name: default merge_conditions: - and: - or: - queue-partition-name!=project-a - check-success=ciA - or: - queue-partition-name!=project-a - check-success=ciB - or: - queue-partition-name!=project-a - check-success=ciCpull_request_rules: - name: merge using the merge queue conditions: - base=main - label=queue actions: queue: 在这个例子中,如果一个 PR 修改了 `project-a` 文件夹下的文件,用于检查和自动合并 PR 的分区和合并队列 将是 `project-a` 的。 如果一个 PR 同时修改了两个或更多项目的文件,PR 将在每个相应的分区中进行检查。 在大型单体仓库中,手动编码 `files~=` 条件是不切实际的;它将需要使用脚本生成。 > 💡**即将推出** > > 我们正在合作开发一个厂商无关的 [project-impact-graph.yaml](https://github.com/tiktok/project-impact-graph) > 规范 和相应的 Rush 插件,这将使诸如 Mergify 之类的服务能够直接查询 **rush.json** 依赖图。 自动化操作[​](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E8%87%AA%E5%8A%A8%E5%8C%96%E6%93%8D%E4%BD%9C "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------- Mergify 还包括一个工作流自动化功能,可以自动执行任务,如添加评论、 指派审阅者或添加标签。例如: **.mergify.yml** pull_request_rules: - name: comment on project-a pull request conditions: - files~=^apps/project-a actions: comment: message: This pull request modifies a file in project-a - name: assign review to a project-b reviewer conditions: - files~=^apps/project-b actions: assign: add_users: - projectb_reviewer - name: add label on project-c pull request conditions: - files~=^apps/projectC actions: label: toggle: - project-c 其他有用的操作: * [回传](https://docs.mergify.com/workflow/actions/backport/) :一旦合并,将拉取请求复制到另一个分支。 * [更新](https://docs.mergify.com/workflow/actions/update/) :用其基础分支更新拉取请求分支。 另请参阅[​](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------- * Rush 文档中的 [最佳实践:启用合并队列](https://rushjs.io/zh-cn/pages/best_practices/merge_queue/) * [Mergify 文档](https://docs.mergify.com/) * [一个基本示例](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E4%B8%80%E4%B8%AA%E5%9F%BA%E6%9C%AC%E7%A4%BA%E4%BE%8B) * [使用分区增加并行性](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E4%BD%BF%E7%94%A8%E5%88%86%E5%8C%BA%E5%A2%9E%E5%8A%A0%E5%B9%B6%E8%A1%8C%E6%80%A7) * [自动化操作](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E8%87%AA%E5%8A%A8%E5%8C%96%E6%93%8D%E4%BD%9C) * [另请参阅](https://rushjs.io/zh-cn/pages/integrations/mergify/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85) --- # 创建一个新的仓库 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#docusaurus_skipToContent_fallback) On this page 创建一个新的仓库该教程讲述了将几个项目合并成一个新的 Rush monorepo 的过程(如果你想看最终结果,可以在 GitHub 上查看 [rush 示例](https://github.com/microsoft/rush-example) )。 假设我们有三个项目目录: * **my-app**: 一个页面应用。 * **my-controls**: 页面应用使用的控件库。 * **my-toolchain**: NodeJS 实现的用于编译其他项目的工具。 起初每个项目在自身的目录下,它们都是通过这样的繁琐的方式来构建的: ~$ cd my-toolchain~/my-toolchain$ npm run build~/my-toolchain$ npm link~/my-toolchain$ cd ../my-controls~/my-controls$ npm link my-toolchain~/my-controls$ npm run build~/my-controls$ npm link~/my-app$ cd ../my-app~/my-app$ npm link my-toolchain~/my-app$ npm link my-controls~/my-app$ npm run build 现在让我们将其打造为 Rush 项目 步骤 1: 检查你的 Rush 版本[​](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-1-%E6%A3%80%E6%9F%A5%E4%BD%A0%E7%9A%84-rush-%E7%89%88%E6%9C%AC "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 开始之前,首先确定全局安装了最新的 Rush 版本: ~$ npm install -g @microsoft/rush _注意:如果由于缺少权限而导致访问 NPM 全局目录失败,可以查阅 [修复 NPM 配置](https://docs.npmjs.com/getting-started/fixing-npm-permissions) 。_ 步骤 2: 使用 "rush init" 初始化你的仓库[​](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-2-%E4%BD%BF%E7%94%A8-rush-init-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BD%A0%E7%9A%84%E4%BB%93%E5%BA%93 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 假定你已经创建了一个空的 GitHub 仓库,该仓库用于拷贝上述项目。先将仓库克隆到本地,然后运行 `rush init` 来生成 Rush 的配置文件: ~$ git clone https://github.com/my-team/my-repo~$ cd my-repo~/my-repo$ rush init 它将会生成以下文件:(更多信息可查阅 [配置文件参考](https://rushjs.io/zh-cn/pages/advanced/config_files/) ) | 文件 | 用途 | | --- | --- | | **rush.json** | Rush 内主要的配置文件 | | **.gitattributes** | _(如果你不用 Git 可以删除)_
告诉 Git 不要对哪些 shrinkwrap 文件进行合并,因为该操作并不安全 | | **.gitignore** | _(如果你不用 Git 可以删除)_
告知 Git 不要跟踪哪些文件 | | **.travis.yml** | _(如果你不用 Travis 可以删除)_
配置 [Travis CI](https://travis-ci.com/)
服务来在 PR 中使用 Rush | | **common/config/rush/.npmrc** | Rush 用该文件配置源,无论是 PNPM, NPM 或者 Yarn | | **common/config/rush/command-line.json** | 用于自定义 Rush 的命令行命令或参数 | | **common/config/rush/common-versions.json** | 用于指定 NPM 包的版本,它影响 Rush 仓库下所有项目 | | **common/config/rush/pnpmfile.js** | _(如果不使用 PNPM 可以删除)_
用于解决 package.json 文件下错误的依赖关系 | | **common/config/rush/version-policies.json** | 用于定义发布配置 | **注意:**如果你的分支中已经存在这些文件,`rush init` 将会发出警告并且不会覆盖已有的文件。 接着,将生成的文件添加到 Git 仓库并且提交到你的分支: ~/my-repo$ git add .~/my-repo$ git commit -m "Initialize Rush repo" 步骤 3: 自定义配置[​](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-3-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 这些模版文件有大量的文档和注释的示例。我们建议你仔细查看它们,以便于你能够理解基本的选项和功能。 你可以随时修改你的选项,但是 **rush.json** 中有一些配置项需要一些了解: * **选择包管理器**: 模版默认使用 PNPM,但是你也可以使用 NPM 或者 Yarn. 可以参考 [NPM vs PNPM vs Yarn](https://rushjs.io/zh-cn/pages/maintainer/package_managers/) . * **检查你的 Rush 版本**:确保 `rushVersion` 是最新版本,版本列表可查看 [NPM 源](https://www.npmjs.com/package/@microsoft/rush) . * **检查其他的版本属性**: 同样需要检查下其他的版本字段,例如 `pnpmVersion`, `npmVersion`, `yarnVersion`, `nodeSupportedVersionRange` * **是否使用“类别目录”模型**:参考 **rush.json** 中的 `projectFolderMinDepth` 和 `projectFolderMaxDepth` 的注释,并计划好 monorepo 内的项目目录如何组织。 * **配置源的访问权限**:初始的 **.npmrc** 被配置为使用公开的 NPM 源。如果你将要使用[私有源](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/) ,你应该更新 **common/config/rush/.npmrc** 文件。 * [步骤 1: 检查你的 Rush 版本](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-1-%E6%A3%80%E6%9F%A5%E4%BD%A0%E7%9A%84-rush-%E7%89%88%E6%9C%AC) * [步骤 2: 使用 "rush init" 初始化你的仓库](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-2-%E4%BD%BF%E7%94%A8-rush-init-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BD%A0%E7%9A%84%E4%BB%93%E5%BA%93) * [步骤 3: 自定义配置](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/#%E6%AD%A5%E9%AA%A4-3-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE) --- # 常见问题回答 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/help/faq/#docusaurus_skipToContent_fallback) On this page ### 我的项目都放在一个大的仓库里?这是一个好主意吗?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE%E9%83%BD%E6%94%BE%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%A4%A7%E7%9A%84%E4%BB%93%E5%BA%93%E9%87%8C%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A5%BD%E4%B8%BB%E6%84%8F%E5%90%97 "Direct link to heading") _回答在 [这篇文章](https://rushjs.io/zh-cn/pages/intro/why_mono/) 中。_ ### 我该如何报告错误或请求新功能?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E6%88%91%E8%AF%A5%E5%A6%82%E4%BD%95%E6%8A%A5%E5%91%8A%E9%94%99%E8%AF%AF%E6%88%96%E8%AF%B7%E6%B1%82%E6%96%B0%E5%8A%9F%E8%83%BD "Direct link to heading") 在 **rushstack** 仓库下开启一个 [issue](https://github.com/microsoft/rushstack/issues) , 并在 issue 标题中包含 "Rush"。 ### 在一个大的仓库里有很多项目,"npm install" 将会花很长时间?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%A4%A7%E7%9A%84%E4%BB%93%E5%BA%93%E9%87%8C%E6%9C%89%E5%BE%88%E5%A4%9A%E9%A1%B9%E7%9B%AEnpm-install-%E5%B0%86%E4%BC%9A%E8%8A%B1%E5%BE%88%E9%95%BF%E6%97%B6%E9%97%B4 "Direct link to heading") 您可能会想:“Hmm.. 如果我的当前安装需要 3 分钟,而您想把 20 个项目放在一个仓库里,我的 NPM 安装时间会不会涨到 60 分钟?” 哦,不对。Rush 会将您的依赖放在一个 "common" 目录下,并且只会执行一次 "npm install",它与你安装单个应用耗时基本相同。 ### Rush 将会使我的工具非标准化吗?[​](https://rushjs.io/zh-cn/pages/help/faq/#rush-%E5%B0%86%E4%BC%9A%E4%BD%BF%E6%88%91%E7%9A%84%E5%B7%A5%E5%85%B7%E9%9D%9E%E6%A0%87%E5%87%86%E5%8C%96%E5%90%97 "Direct link to heading") 不对!Rush 会在现有的系统和标准中工作。它只会更好地做事,更快。 * 每个项目目录依然是自成一体的(没有模糊包的界限) * 依然可以在没有 Rush 的情况下构建项目;仅需要执行 `npm install` 和 `gulp`. * 可以在任何一个时间内将项目移动到单独的目录中,而不用任何代码变化。 Rush Stack 是否和 Rush 相同?[​](https://rushjs.io/zh-cn/pages/help/faq/#rush-stack-%E6%98%AF%E5%90%A6%E5%92%8C-rush-%E7%9B%B8%E5%90%8C "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------ 不。**Rush Stack** 是一组项目,由一组共同使命为构建大规模 TypeScript 专业工具链的开发人员维护。Rush 时 Rush Stack 的一部分。其他部分都是可选的。 Rush 本身是无关的工具链,它可以单独工作得很好。更多细节可以在 [Rush Stack](https://rushstack.io/) 网站上查看。 ### 安装完 Rush 之后,还是看到旧版本了?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E5%AE%89%E8%A3%85%E5%AE%8C-rush-%E4%B9%8B%E5%90%8E%E8%BF%98%E6%98%AF%E7%9C%8B%E5%88%B0%E6%97%A7%E7%89%88%E6%9C%AC%E4%BA%86 "Direct link to heading") 问题并不是 Rush 上,但是我们听到了很多关于此的问题因为 Rush 是开始在仓库工作钱第一个需要调用的工具,其症状如下: $ npm install -g @microsoft/rushC:\Program Files\nodejs\rush -> C:\Program Files\nodejs\node_modules\@microsoft\rush\bin\rushC:\Program Files\nodejs`-- @microsoft/rush@3.0.1$ rushRush Multi-Package Build Tool 2.5.0 - http://aka.ms/rush NPM 看起来表示安装了 3.0.1 版本,但是我们执行指令时,展示的是 2.5.0 版本,发生了什么? 问题在于当你在输入诸如 "gulp" 和 "rush" 的命令时,它们在你的系统路径中被发现,这可能指向了以前安装的 NodeJS 或 NPM 的目录。 修复方法: 1. 运行 `npm ls -g --depth 0` 来确定你的 NPM 包被安装在哪里。 2. 运行 `set` 命令,检查你的 PATH 环境变量。 3. 确保你从步骤 1 拿到的 PATH 环境变量中没有其他 NPM 或 NodeJS 目录。 4. 在 PATH 中删除无用的目录,例如从 NPM 之前的安装,NodeJS,nodist,nvm-windows,等等。 5. 如果你之前使用过这些另一种引擎,很有可能你的硬盘上还有一些无用的 NPM 包。建议你跟踪它们并删除它们。 查看: C:\Program Files\nodejsC:\Program Files (x86)\nodist%APPDATA%\npm%APPDATA%\nvm ### "npm install" 步骤报告网络错误,该怎么办?[​](https://rushjs.io/zh-cn/pages/help/faq/#npm-install-%E6%AD%A5%E9%AA%A4%E6%8A%A5%E5%91%8A%E7%BD%91%E7%BB%9C%E9%94%99%E8%AF%AF%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E "Direct link to heading") 如果你从一个自定义的 NPM 源安装包(例如公司的私有服务),那么你的项目需要在 .npmrc 中添加特殊的配置。如果这些配置不正确,"npm install" 可能会报告一些令人迷惑的错误,这些错误看起来像是网络问题。NPM 会在多个位置上寻找 ".npmrc" 文件,并忽略其他位置,理解这一点很重要。 没有 Rush 时,NPM 会在两个地方寻找 "**.npmrc**",_并合并它们的内容_: * 你当前 package.json 的目录下(适用于在 Git 中存储项目特定的配置) * 你的用户主目录(这里存放着你的认证令牌) 当使用 Rush 调用 "npm install", 将在两个地方寻找 "**.npmrc**": * "**./common/config/rush/.npmrc**" (安装期间拷贝了 "**./common/temp/.npmrc**") * 你的用户主目录 ### 为什么 Rush 的 JSON 配置文件中包含 `//` 注释,GitHub 在红色显示?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E4%B8%BA%E4%BB%80%E4%B9%88-rush-%E7%9A%84-json-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%8C%85%E5%90%AB--%E6%B3%A8%E9%87%8Agithub-%E5%9C%A8%E7%BA%A2%E8%89%B2%E6%98%BE%E7%A4%BA "Direct link to heading") JSON 起初是用于作为数据交换格式,不支持代码注释。最近 JSON 这样人类可编辑的配置文件格式得到了广泛的流行,很明显它必须要求注释。因此,大多数严格的 JSON 库都可以处理注释,而不会有任何问题。(一个显而易见的例外是 `JSON.parse()`;不要使用它 -- 它不能验证范式,他的错误报告也很糟糕) VS Code 默认会将 JSON 注释高亮为错误,但是它提供了一个 "[JSON with comments](https://code.visualstudio.com/docs/languages/json#_json-with-comments) " 模式。要启用这个模式,在 **settings.json** 中添加这行: "files.associations": { "*.json": "jsonc" } 默认情况下,Github 以错误的形式高亮注释。为了修复此问题,你可以在 **.gitattributes** 文件中添加这行(为解决 Github 缓存问题,你也可能需要提交一个改变): *.json linguist-language=JSON-with-Comments _讨论其他更多的可能性,参考 [issue #1088](https://github.com/microsoft/rushstack/issues/1088) ._ ### 为了避免与其他工具干扰,如何清理 Rush 的安装?[​](https://rushjs.io/zh-cn/pages/help/faq/#%E4%B8%BA%E4%BA%86%E9%81%BF%E5%85%8D%E4%B8%8E%E5%85%B6%E4%BB%96%E5%B7%A5%E5%85%B7%E5%B9%B2%E6%89%B0%E5%A6%82%E4%BD%95%E6%B8%85%E7%90%86-rush-%E7%9A%84%E5%AE%89%E8%A3%85 "Direct link to heading") 通常建议使用 Rush 来管理所有的 monorepo. Rush 在项目 `node_modules` 文件夹下创建的符号链接可能会干扰诸如 NPM 或 Yarn 的其他工具,因为它们不同的安装模式而导致故障。然而,有时这是不可避免的。例如,当迁移一个 repo 到 Rush 下时,CI 系统可能需要重用一个现有的工作文件夹来使用不同的安装方式构建不同的分支。为了防止干扰,你的 CI 任务首先需要调用一个命令来删除以前的文件。 对于 Yarn 或 NPM, 类似 `git clean -dfx` 的命令通常足够。(改操作会删除文件 -- 调用前请[参考手册](https://git-scm.com/docs/git-clean) ) 为了清理 Rush 安装,并不推荐 `git clean`, 这是因为它们不能很可靠的处理符号连接。相反,使用 [rush purge](https://rushjs.io/zh-cn/pages/commands/rush_purge/) 来删除由 Rush 创建的 `node_modules` 文件夹。 * [我的项目都放在一个大的仓库里?这是一个好主意吗?](https://rushjs.io/zh-cn/pages/help/faq/#%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE%E9%83%BD%E6%94%BE%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%A4%A7%E7%9A%84%E4%BB%93%E5%BA%93%E9%87%8C%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A5%BD%E4%B8%BB%E6%84%8F%E5%90%97) * [我该如何报告错误或请求新功能?](https://rushjs.io/zh-cn/pages/help/faq/#%E6%88%91%E8%AF%A5%E5%A6%82%E4%BD%95%E6%8A%A5%E5%91%8A%E9%94%99%E8%AF%AF%E6%88%96%E8%AF%B7%E6%B1%82%E6%96%B0%E5%8A%9F%E8%83%BD) * [在一个大的仓库里有很多项目,"npm install" 将会花很长时间?](https://rushjs.io/zh-cn/pages/help/faq/#%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%A4%A7%E7%9A%84%E4%BB%93%E5%BA%93%E9%87%8C%E6%9C%89%E5%BE%88%E5%A4%9A%E9%A1%B9%E7%9B%AEnpm-install-%E5%B0%86%E4%BC%9A%E8%8A%B1%E5%BE%88%E9%95%BF%E6%97%B6%E9%97%B4) * [Rush 将会使我的工具非标准化吗?](https://rushjs.io/zh-cn/pages/help/faq/#rush-%E5%B0%86%E4%BC%9A%E4%BD%BF%E6%88%91%E7%9A%84%E5%B7%A5%E5%85%B7%E9%9D%9E%E6%A0%87%E5%87%86%E5%8C%96%E5%90%97) * [Rush Stack 是否和 Rush 相同?](https://rushjs.io/zh-cn/pages/help/faq/#rush-stack-%E6%98%AF%E5%90%A6%E5%92%8C-rush-%E7%9B%B8%E5%90%8C) * [安装完 Rush 之后,还是看到旧版本了?](https://rushjs.io/zh-cn/pages/help/faq/#%E5%AE%89%E8%A3%85%E5%AE%8C-rush-%E4%B9%8B%E5%90%8E%E8%BF%98%E6%98%AF%E7%9C%8B%E5%88%B0%E6%97%A7%E7%89%88%E6%9C%AC%E4%BA%86) * ["npm install" 步骤报告网络错误,该怎么办?](https://rushjs.io/zh-cn/pages/help/faq/#npm-install-%E6%AD%A5%E9%AA%A4%E6%8A%A5%E5%91%8A%E7%BD%91%E7%BB%9C%E9%94%99%E8%AF%AF%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E) * [为什么 Rush 的 JSON 配置文件中包含 `//` 注释,GitHub 在红色显示?](https://rushjs.io/zh-cn/pages/help/faq/#%E4%B8%BA%E4%BB%80%E4%B9%88-rush-%E7%9A%84-json-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%8C%85%E5%90%AB--%E6%B3%A8%E9%87%8Agithub-%E5%9C%A8%E7%BA%A2%E8%89%B2%E6%98%BE%E7%A4%BA) * [为了避免与其他工具干扰,如何清理 Rush 的安装?](https://rushjs.io/zh-cn/pages/help/faq/#%E4%B8%BA%E4%BA%86%E9%81%BF%E5%85%8D%E4%B8%8E%E5%85%B6%E4%BB%96%E5%B7%A5%E5%85%B7%E5%B9%B2%E6%89%B0%E5%A6%82%E4%BD%95%E6%B8%85%E7%90%86-rush-%E7%9A%84%E5%AE%89%E8%A3%85) --- # 启用 CI | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#docusaurus_skipToContent_fallback) On this page 持续集成要求在提交 PR 时设定一个构建行为,这个自动化的脚本可以一些运行类似于开发人员手动执行的命令。这里会展示一些有用的额外配置项。 如果手动执行以下指令,其效果类似于: # 获取主分支代码$ git fetch origin main:refs/remotes/origin/main -a# (可选)如果开发者没有创建更新日志则失败。# 这意味着脚本因为 Rush 返回非零状态码而终止。$ rush change -v# 在公共文件夹下安装 NPM 包安装 NPM 包,但是并没有自动执行 "rush link"$ rush install --no-link# 单独执行 "rush link", 这样 CI 可以将其作为一个单独的步骤来计算开销$ rush link# 全量构建并实时输出细节日志# (假定 "--ship" 已在 common/config/rush/command-line.json 中被定义)$ rush rebuild --ship --verbose 这里有个小插曲 —— 如果你的 CI 环境没有预先安装 Rush, 则可以在项目的根目录下放置一个 **package.json**, 然后通过 `npm install` 来安装 Rush. 但这样也会引入一个 **node\_modules** 目录, 进而导致 Rush 的防止[幻影依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) 的功能失效。 install-run-rush.js 来启动 Rush[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#install-run-rushjs-%E6%9D%A5%E5%90%AF%E5%8A%A8-rush "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 幸运的是,这里有更优雅的方式来在 CI 上安装 Rush, 所有的 Rush 仓库都会有一个 `common/scripts/install-run-rush.js` 脚本, 它会: * 寻找 **rush.json** 文件 * 读取指定在该文件内的 `rushVersion` * 自动在 **common/temp/install-run** 目录下安装该版本的 Rush * 使用仓库内的 .npmrc 文件进行适当的设置 * 之后调用 Rush 工具链,并传递给它任何你提供的命令行参数 上述安装过程是有缓存的,所以上述操作并不会比直接调用 Rush 慢,事实上,对于保存之前运行结果的 CI 系统而言, **install-run-rush.js** 比 `npm install` 更快,因为它可以缓存 Git 分支上构建的不同版本的 Rush. 尝试从你的 shell 中执行脚本: ~$ cd my-repo~/my-repo$ node common/scripts/install-run-rush.js --help~/my-repo$ node common/scripts/install-run-rush.js install 下面我们将介绍如何将这个脚本包含到 Travis 构建定义中。 install-run.js 来执行其他命令[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#install-runjs-%E6%9D%A5%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E5%91%BD%E4%BB%A4 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 此外,Rush 也提供了第二个脚本 **install-run.js** 允许你借此来执行任意的 NPM 包。例如,下面时一个打印 Rush 站点二维码的指令: :-) ~/my-repo$ node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io 注意 **install-run.js** 指令有一些不同:它必须要包含包名和其版本(可以是语义化版本,但最好写确定版本),它还需要第二个参数来指令可执行文件的具体名称(通常而言,可执行文件名与包名相同),在上述事例中,我们调用 `qrcode` 的可执行文件并指定起参数为 `https://rushjs.io`. 当然,更直接的方式是将 **qrcode** 视为某个 **package.json** 内的一个依赖,例如将其 **package.json** 放到 **tools/repo-scripts** 项目下,这种方式会被视为日常安装的一步,并被仓库的 shrinkwrap 文件记录。但是在诸如不需要 `rush install` 的 CI 任务或者即使 `rush install` 出现故障时 Git hooks 依旧可用的情况下,这种方式是不可取的。 "rush init" 中的 Travis 示例[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#rush-init-%E4%B8%AD%E7%9A%84-travis-%E7%A4%BA%E4%BE%8B "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [Travis CI](https://travis-ci.com/) 是一个整合了 Github 的持续集成工具,它开源且免费,`rush init` 会创建一个便于使用的 **.travis.yml** 文件。注意,它使用 **install-run-rush.js** 来调用 Rush 工具。 language: node_jsnode_js: - '8.9.4'script: - set -e - echo 'Checking for missing change logs...' && echo -en 'travis_fold:start:change\\r' - git fetch origin main:refs/remotes/origin/main -a - node common/scripts/install-run-rush.js change -v - echo -en 'travis_fold:end:change\\r' - echo 'Installing...' && echo -en 'travis_fold:start:install\\r' - node common/scripts/install-run-rush.js install - echo -en 'travis_fold:end:install\\r' - echo 'Building...' && echo -en 'travis_fold:start:build\\r' - node common/scripts/install-run-rush.js rebuild --verbose - echo -en 'travis_fold:end:build\\r' 关于使用 Azure Devops 构建的示例,你可以参考用于部署 Rush 的 [build.yaml 文件](https://github.com/microsoft/rushstack/blob/main/common/config/azure-pipelines/templates/build.yaml) . * [install-run-rush.js 来启动 Rush](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#install-run-rushjs-%E6%9D%A5%E5%90%AF%E5%8A%A8-rush) * [install-run.js 来执行其他命令](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#install-runjs-%E6%9D%A5%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E5%91%BD%E4%BB%A4) * ["rush init" 中的 Travis 示例](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/#rush-init-%E4%B8%AD%E7%9A%84-travis-%E7%A4%BA%E4%BE%8B) --- # Custom tips (实验性功能) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#docusaurus_skipToContent_fallback) On this page Custom tips 允许您为 Rush 打印的命令行消息添加为您的特定单仓库量身定制的建议 (tips)。 以下是一个 custom tips 能够帮忙的例子:假设您的公司使用一个私有的 NPM registry,该注册表定期从上游的 `npmjs.com` 服务器同步最新的包版本。有时用户可能试图安装刚刚发布的版本,而该版本尚未同步,此时 `rush update` 可能会显示以下错误: Progress: resolved 0, reused 1, downloaded 0, added 0/users/example/code/my-repo/apps/my-app: ERR_PNPM_NO_MATCHING_VERSION  No matching version found for example-library@1.2.3This error happened while installing a direct dependency of my-appThe latest release of example-library is "1.1.0". 此错误有些令人困惑,因为 npm 上的最新发布版本确实是 `1.2.3`,而错误是因为您公司私有的 NPM registry 同步的最新最新版本还在 `1.1.0`。如果您的团队为 monorepo 维护一个帮助热线(比如 oncall 群),您可能会经常收到关于这个错误的 on-call。这可以通过显示 custom tip 来避免。 配置 custom tip[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E9%85%8D%E7%BD%AE-custom-tip "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------- 上面的 `ERR_PNPM_NO_MATCHING_VERSION` 代码来自 PNPM。Rush 对应的提示 ID 是 `TIP_PNPM_NO_MATCHING_VERSION`。我们可以如下定义提示: **common/config/rush/custom-tips.json** /** * 这个配置文件允许仓库维护者配置与某些 Rush 消息一起打印的额外详细信息。更多文档可在 * Rush 官方网站上找到:https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", /** * 指定 Rush 要显示的 custom tips。 */ "customTips": [ // { // /** // * (必须) 一个标识符,表示 Rush 可能打印的消息。 // * 如果打印了该消息,则将显示此 custom tip。 // * 请参阅 Rush 文档以获取可能的标识符的当前列表。 // */ // "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", // // /** // * (必须) 要为此提示显示的消息文本。 // */ // "message": "要获取额外的故障排除信息,请参阅此 wiki 文章:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" // } { "tipId": "TIP_PNPM_NO_MATCHING_VERSION", "message": "PNPM 的这个“no matching version”的错误经常是由于新版本尚未同步到我们公司的内部 NPM registry所导致的。\n\n要获取故障排除指南,请查阅我们的团队 wiki:\n\nhttps://example.com/wiki/npm-syncing" } ]} > 如果您没有此文件,您可以使用 `rush init` 生成它。 随着这次更改,用户现在将在原始错误旁边看到 custom tip: Progress: resolved 0, reused 1, downloaded 0, added 0/users/example/code/my-repo/apps/my-app: ERR_PNPM_NO_MATCHING_VERSION  No matching version found for example-library@1.2.3This error happened while installing a direct dependency of my-appThe latest release of example-library is "1.1.0".| Custom Tip (TIP_PNPM_NO_MATCHING_VERSION)|| PNPM 的这个“no matching version found”的错误经常是由于新版本尚未同步到我们公司的内部 NPM registry 所导致的。|| 要获取故障排除指南,请查阅我们的团队 wiki:|| https://example.com/wiki/npm-syncing 请注意,Rush 用 `|` 前缀 custom tips,以将其与 Rush 软件的官方消息区分开。 贡献新的 tips[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E8%B4%A1%E7%8C%AE%E6%96%B0%E7%9A%84-tips "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------- 有没有你想自定义的 Rush 消息,但没有可用的 `tipId`?实现新的 tips 相对容易。代码位于 [rush-lib/src/api/CustomTipsConfiguration.ts](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/api/CustomTipsConfiguration.ts) , 请随时创建拉取请求来提议新的 tips。 Custom tip 标识符[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#custom-tip-%E6%A0%87%E8%AF%86%E7%AC%A6 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- ### TIP\_PNPM\_INVALID\_NODE\_VERSION[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_invalid_node_version "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_INVALID\_NODE\_VERSION](https://pnpm.io/errors#err_pnpm_invalid_node_version) 。 ### TIP\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_mismatched_release_channel "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL](https://pnpm.io/errors#err_pnpm_mismatched_release_channel) 。 ### TIP\_PNPM\_NO\_MATCHING\_VERSION[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_NO\_MATCHING\_VERSION](https://pnpm.io/next/errors) 。 ### TIP\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version_inside_workspace "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE](https://pnpm.io/errors#err_pnpm_no_matching_version_inside_workspace) 。 ### TIP\_PNPM\_OUTDATED\_LOCKFILE[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_outdated_lockfile "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_OUTDATED\_LOCKFILE](https://pnpm.io/errors#err_pnpm_outdated_lockfile) 。 ### TIP\_PNPM\_PEER\_DEP\_ISSUES[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_peer_dep_issues "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_PEER\_DEP\_ISSUES](https://pnpm.io/errors#err_pnpm_peer_dep_issues) 。 ### TIP\_PNPM\_TARBALL\_INTEGRITY[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_tarball_integrity "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_TARBALL\_INTEGRITY](https://pnpm.io/errors#err_pnpm_tarball_integrity) 。 ### TIP\_PNPM\_UNEXPECTED\_STORE[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_unexpected_store "Direct link to heading") 对应于 PNPM 的 [ERR\_PNPM\_UNEXPECTED\_STORE](https://pnpm.io/errors#err_pnpm_unexpected_store) 。 ### TIP\_RUSH\_INCONSISTENT\_VERSIONS[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_rush_inconsistent_versions "Direct link to heading") 当项目有不一致的依赖版本时,此消息由 `rush install` 或 `rush update` 打印,前提是你的项目在 **rush.json** 中启用了 `ensureConsistentVersions`(我们也推荐如此)。 **Rush 输出示例:** Found 5 mis-matching dependencies! 另请参阅[​](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- * [custom-tips.json](https://rushjs.io/zh-cn/pages/configs/custom-tips_json/) 文档 * [配置 custom tip](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E9%85%8D%E7%BD%AE-custom-tip) * [贡献新的 tips](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E8%B4%A1%E7%8C%AE%E6%96%B0%E7%9A%84-tips) * [Custom tip 标识符](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#custom-tip-%E6%A0%87%E8%AF%86%E7%AC%A6) * [TIP\_PNPM\_INVALID\_NODE\_VERSION](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_invalid_node_version) * [TIP\_PNPM\_MISMATCHED\_RELEASE\_CHANNEL](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_mismatched_release_channel) * [TIP\_PNPM\_NO\_MATCHING\_VERSION](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version) * [TIP\_PNPM\_NO\_MATCHING\_VERSION\_INSIDE\_WORKSPACE](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_no_matching_version_inside_workspace) * [TIP\_PNPM\_OUTDATED\_LOCKFILE](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_outdated_lockfile) * [TIP\_PNPM\_PEER\_DEP\_ISSUES](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_peer_dep_issues) * [TIP\_PNPM\_TARBALL\_INTEGRITY](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_tarball_integrity) * [TIP\_PNPM\_UNEXPECTED\_STORE](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_pnpm_unexpected_store) * [TIP\_RUSH\_INCONSISTENT\_VERSIONS](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#tip_rush_inconsistent_versions) * [另请参阅](https://rushjs.io/zh-cn/pages/maintainer/custom_tips/#%E5%8F%A6%E8%AF%B7%E5%8F%82%E9%98%85) --- # Using Rush plugins (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#docusaurus_skipToContent_fallback) On this page Rush plugins enable you to: * Share common Rush configuration across multiple monorepos * Extend Rush's base functionality with custom features * Prototype new feature ideas before officially contributing them to Rush Plugins are distributed via an NPM package, which we call a **plugin package**. A single package may define one or more Rush plugins. (If you are interested in creating your plugin package, see the article [Creating rush plugins](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) .) Enabling a Rush plugin[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#enabling-a-rush-plugin "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- There are three steps for enabling a Rush plugin in your monorepo. For this tutorial, let's configure a hypothetical plugin called `"example"` that is provided by the NPM package `@your-company/rush-example-plugin`. ### Step 1: Configure an autoinstaller[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-1-configure-an-autoinstaller "Direct link to heading") Plugins rely on Rush's [autoinstaller](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/) feature for on-demand installation of their NPM package. Here's how to create a new autoinstaller called `rush-plugins`: rush init-autoinstaller --name rush-plugins This will create an autoinstaller **package.json** file. Add your plugin's NPM package as a dependency: **common/autoinstallers/rush-plugins/package.json** { "name": "rush-plugins", "version": "1.0.0", "private": true, "dependencies": { "@your-company/rush-example-plugin": "^1.0.0" 👈 👈 👈 }} Next, generate the shrinkwrap file: # Creates the shrinkwrap file common/autoinstallers/rush-plugins/pnpm-lock.yamlrush update-autoinstaller --name rush-plugins Commit these files to Git. ### Step 2: Update rush-plugins.json[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-2-update-rush-pluginsjson "Direct link to heading") In order for the plugin to be loaded, we need to register it in **rush-plugins.json**. Continuing our example: **common/config/rush/rush-plugins.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item defines a plugin to be loaded by Rush. */ { /** * The name of the NPM package that provides the plugin. */ "packageName": "@your-company/rush-example-plugin", /** * The name of the plugin. This can be found in the "pluginName" * field of the "rush-plugin-manifest.json" file in the NPM package folder. */ "pluginName": "example", /** * The name of a Rush autoinstaller that will be used for installation, which * can be created using "rush init-autoinstaller". Add the plugin's NPM package * to the package.json "dependencies" of your autoinstaller, then run * "rush update-autoinstaller". */ "autoinstallerName": "rush-plugins" } ]} The `pluginName` field can be found in the [rush-plugin-manifest.json](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/) of the plugin package. ### Step 3: Optional config file[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-3-optional-config-file "Direct link to heading") Some plugins can be customized via their own config file; if so, their **rush-plugin-manifest.json** will specify the `optionsSchema` field. The config filename will have the same as the `pluginName`, for example: **common/config/rush-plugins/example.json** First-party plugins[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#first-party-plugins "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- | NPM Package | Description | | --- | --- | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-amazon-s3-build-cache-plugin) | Cloud build cache provider for Amazon S3 | | [@rushstack/rush-azure-storage-build-cache-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-azure-storage-build-cache-plugin) | Cloud build cache provider for Azure Storage | | [@rushstack/rush-serve-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-serve-plugin) | (Experimental) A Rush plugin that hooks into action execution and runs an express server to serve project outputs | > **NOTE:** The `@rushstack/rush-amazon-s3-build-cache-plugin` and `@rushstack/rush-azure-storage-build-cache-plugin` packages are currently built-in to Rush and enabled automatically. For now, you should NOT register them in **rush-plugins.json**. > > This is a temporary accommodation while the plugin framework is still experimental. In the next major release of Rush, the build cache packages will need to be configured in standard way. Third-party plugins[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#third-party-plugins "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- Here's a gallery of some community contributed plugins. | NPM Package | Description | | --- | --- | | [rush-archive-project-plugin](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-archive-project-plugin) | Archive Rush projects that are no longer maintained | | [rush-init-project-plugin](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-init-project-plugin) | Initialize new Rush projects | | [rush-lint-staged-plugin](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-lint-staged-plugin) | Integrate [lint-staged](https://www.npmjs.com/package/lint-staged)
with a Rush monorepo | | [rush-print-log-if-error-plugin](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-print-log-if-error-plugin) | Print a project's entire log file when an error occurs | | [rush-sort-package-json](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-sort-package-json) | Sort the package.json file entries for Rush projects | | [rush-upgrade-self-plugin](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-upgrade-self-plugin) | A helper for upgrading to the latest release of Rush | If you created an interesting plugin for Rush, let us know in a GitHub issue. Thanks! See also[​](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#see-also "Direct link to heading") ------------------------------------------------------------------------------------------------------------ * [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) * [rush update-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_update-autoinstaller/) * [Creating a Rush plugin](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/) * [Enabling a Rush plugin](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#enabling-a-rush-plugin) * [Step 1: Configure an autoinstaller](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-1-configure-an-autoinstaller) * [Step 2: Update rush-plugins.json](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-2-update-rush-pluginsjson) * [Step 3: Optional config file](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#step-3-optional-config-file) * [First-party plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#first-party-plugins) * [Third-party plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#third-party-plugins) * [See also](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/#see-also) --- # NPM 仓库认证 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#docusaurus_skipToContent_fallback) On this page **私有 NPM 源**可以让你的 NPM 包在内部发布并使用,除了私有源需要授权外,其工作方式与公开的 [https://www.npmjs.com/](https://www.npmjs.com/) 类似。每个用户需要获取一个访问口令,通常口令会被保存在 [~/.npmrc 文件](https://docs.npmjs.com/cli/v6/configuring-npm/npmrc) 内。 需要私有 NPM 源的大型项目往往有利于: * 在团队内以私有的形式分享代码 * 代理公开仓库的代码来提高可靠性,并审计公开库,并进行安全筛选 * 通过安装预编译的工具包加速 CI 操作,而不是在每次调用工具前执行 `rush install && rush build` * 在发布到公开的 NPM 仓库前进行安装测试 * 发布包装后的第三方库 (与 [GitHub URL dependencies](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#github-urls) 相比,NPM 包提供了更好的 SemVer 版本管理和更好的缓存机制。) 常用的提供商有: 对于以测试为目的的私有源头,[Verdaccio](https://verdaccio.org/) 是一个基于 Node.js 的轻量级 Node.js 服务器,可以运行在 `http://localhost` 上,并实现了完整的私有仓库功能。 源的映射[​](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E6%BA%90%E7%9A%84%E6%98%A0%E5%B0%84 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------- 私有源的映射被定义在 [monorepo .npmrc 文件](https://rushjs.io/zh-cn/pages/configs/npmrc/) 中。 下面的示例将从私有源中安装公司的库,从公共源中获取其他包,公司的库的 NPM scope 为 `@example`. **common/config/rush/.npmrc** # 将公司的 NPM scope ("@example")映射到私有源:@example:registry=https://my-registry.example.com/npm-private/# 否则,使用公共 NPM 仓库registry=https://registry.npmjs.org/always-auth=false# 此处介绍如何在私有源中进行身份校验。# 出于安全性的考虑,CI 任务需要从环境变量中获取口令,具体内容由私有源决定。# 如果某一行的环境变量时未定义的,那么 Rush 会忽略这一行,这是为了避免从 ~/.npmrc. 中获取口令时产生一个无效的字符串。//my-registry.example.com/npm-private/:_password=${MY_CI_TOKEN}//my-registry.example.com/npm-private/:username=${MY_CI_USER}//my-registry.example.com/npm-private/:always-auth=true 普遍的是,私有源会有**缓存代理**,它可以从公共仓库中拿到包,此时,就不需要 NPM scopes 映射了,你的配置项就会是如下: **common/config/rush/.npmrc** # 将所有都映射到私有源registry=https://my-registry.example.com/npm-private/always-auth=true# 此处介绍如何在私有源中进行身份校验。# 出于安全性的考虑,CI 任务需要从环境变量中获取口令,具体内容由私有源决定。# 如果某一行的环境变量时未定义的,那么 Rush 会忽略这一行,这是为了避免从 ~/.npmrc. 中获取口令时产生一个无效的字符串。//my-registry.example.com/npm-private/:_password=${MY_CI_TOKEN}//my-registry.example.com/npm-private/:username=${MY_CI_USER} > 可以通过 [.npmrc](https://rushjs.io/zh-cn/pages/configs/npmrc/) > 页来了解一些比 **.npmrc** 优先级更高的配置。 使用 "rush setup" 来获取口令[​](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E4%BD%BF%E7%94%A8-rush-setup-%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%8F%A3%E4%BB%A4 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush 近期引入了一个实验性的功能:`rush install` 可以检测用户的源权限缺失或过期,如果过期,则会询问是否执行 "rush setup", 该命令会引导用户来获取口令,然后更新他们的 **~/.npmrc** 文件,新的配置会被合并到以前的配置中。 "rush setup" 交互示例如下: NPM credentials are missing or expired==> Fix this problem now? (y/N) YesThis monorepo consumes packages from an Artifactory private NPM registry.==> Do you already have an Artifactory user account? (y/n) YesPlease open this URL in your web browser: https://my-company.jfrog.io/Your user name appears in the upper-right corner of the JFrog website.==> What is your Artifactory user name? example-userClick "Edit Profile" on the JFrog website. Click the "Generate API Key" button if you haven't already done sopreviously.==> What is your Artifactory API key? ***************Fetching an NPM token from the Artifactory service...Adding Artifactory token to: /home/example-user/.npmrc 该实现目前只支持 [JFrog Artifactory](https://jfrog.com/artifactory/) , 其他服务将在未来支持。 需要在 `artifactory.json` 配置文件中设置 `"registryUrl"` 字段,并设置 `"enabled": true` 后就可以使用该功能。文件模版包含其他可选配置的文档,这些可以用来自定义该交互。 参考更多[​](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E5%8F%82%E8%80%83%E6%9B%B4%E5%A4%9A "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------- * [rush setup](https://rushjs.io/zh-cn/pages/commands/rush_setup/) * [artifactory.json](https://rushjs.io/zh-cn/pages/configs/artifactory_json/) 配置文件 * [.npmrc](https://rushjs.io/zh-cn/pages/configs/npmrc/) 配置文件 * [.npmrc-publish](https://rushjs.io/zh-cn/pages/configs/npmrc-publish/) 配置文件 * [源的映射](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E6%BA%90%E7%9A%84%E6%98%A0%E5%B0%84) * [使用 "rush setup" 来获取口令](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E4%BD%BF%E7%94%A8-rush-setup-%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%8F%A3%E4%BB%A4) * [参考更多](https://rushjs.io/zh-cn/pages/maintainer/npm_registry_auth/#%E5%8F%82%E8%80%83%E6%9B%B4%E5%A4%9A) --- # 发布包 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/publishing/#docusaurus_skipToContent_fallback) On this page 如何在构建流程中使用 Rush 来自动发布更新的包 ========================= Rush 的发布流程中包含两个阶段:第一阶段是在开发期间,开发者需要提供一个变更文件来记录需要发布的变动;第二阶段是在发布期间,Rush 可以收集所有的变更新文件来更新版本、更新发布日志,并发布新的包到 npm 仓库。 1\. 跟踪变更[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#1-%E8%B7%9F%E8%B8%AA%E5%8F%98%E6%9B%B4 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- 只有当公共的包发生变化时候需要被记录,开发者可以在 rush.json 的 [shouldPublish](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/) 字段中指定哪些项目需要被发布,哪些不需要被发布。一旦定义公共库后,仓库管理者可以强制开发者更改公开的库后提供变更文件。开发者可以使用一个工具来生成变更文件,并在答题后提交。 ### 如果让开发者强制提供变更文件[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%A6%82%E6%9E%9C%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%BC%BA%E5%88%B6%E6%8F%90%E4%BE%9B%E5%8F%98%E6%9B%B4%E6%96%87%E4%BB%B6 "Direct link to heading") rush change --verify 如果开发者修改了公开的仓库后但没有提供相关的变更文件,该指令会执行失败。建议将该指令添加到 CI 中,可以使没有变更文件时执行失败。 ### 开发者如何生成变更文件[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%BC%80%E5%8F%91%E8%80%85%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E5%8F%98%E6%9B%B4%E6%96%87%E4%BB%B6 "Direct link to heading") rush change 执行 `rush change` 后会向开发者提出几个问题,并根据开发者的回答生成变更记录。变更记录文件包含了版本变化的类型和其描述,该文件应该被提交的仓库中。 2\. 发布包[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#2-%E5%8F%91%E5%B8%83%E5%8C%85 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------ rush publish 当发布更新的包时候,`rush publish` 指令会增加包的版本,并发布更新的包,它内部会处理很多事:收集所有的日志文件来确定版本变化的类型、确定需要发布的包、增加依赖包的版本,清理变更文件等。 该指令有他自己的定义,所以开发者可以在发布包的时候触发它。 对于不同的目标,`rush publish` 有一些不同的参数,例如,它支持一个模拟发布模式,该模式下可以验证变更文件并测试变更包,其用例可以参考: ### 模拟发布模式[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E6%A8%A1%E6%8B%9F%E5%8F%91%E5%B8%83%E6%A8%A1%E5%BC%8F "Direct link to heading") rush publish有几种模拟运行的方式,允许您执行发布过程的中间步骤,而不会实际发布到npm上。这对于测试以及在没有npm源用于发布的情况下创建版本增量和更改日志非常有用。 rush publish 当没有任何参数运行时,它以只读模式执行整个过程,这意味着更改不会保存到磁盘,不会提交到源代码仓库,也不会真正发布软件包。如果您想检查版本增加和更改日志更新是否正确,这将非常有用。 rush publish --apply 在这种模式下,更改会添加到CHANGELOG文件中,并且package.json文件会更新为新的版本号,但不会提交到源代码仓库或发布。如果您希望在提交到源代码仓库或发布到软件包存储库之前查看或编辑其中任何文件,这将非常有用。 rush publish --apply --target-branch targetBranch 在这种模式下,更改会被提交到一个新的Git分支(以publish- 为前缀),该分支将基于 targetBranch 创建。如果将 targetBranch 设置为 repository.defaultBranch 中指定的分支,运行此命令将实际上执行几乎与“实时”发布相同的操作(包括提交到Git源),只是没有实际发布到npm源。 ### 发布模式[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%8F%91%E5%B8%83%E6%A8%A1%E5%BC%8F "Direct link to heading") 发布模式下还有一些额外的参数:发布到哪个源上,使用哪个 token,是否包含提交信息。 rush publish --apply --target-branch targetBranch --publish 上述指令将增加版本号,commit 记录到目标分支上,以及基于环境中的 npm 源来将包发布到指定源上。 rush publish --apply --target-branch targetBranch --publish --registry registryUrl --npm-auth-token npmToken 除了之前指令的效果外,上述指令还可以使用指定的 token 来发布到指定源上。 rush publish --apply --target-branch targetBranch --publish --registry registryUrl --npm-auth-token npmToken --add-commit-details 除了之前指令的效果外,上述指令还将包含变更日志中的提交信息。 ### 打包模式[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E6%89%93%E5%8C%85%E6%A8%A1%E5%BC%8F "Direct link to heading") 除了发布外,还可以将输出打包到 `.tgz` 文件中。 rush publish --pack --include-all --publish > 注意:`--publish` 参数将禁运掉模拟发布模式,这样可以将文件内容写入到磁盘上。 > > 你也可以将该命令与 `--release-folder` 结合使用,来指定输出文件的位置。 3. 版本策略 当 Rush 内仓库数量逐渐增加时,就需要考虑如何通知项来进行不同类型的版本变更,此时,引入了版本策略这个新概念。举例来看,rush 和 rush-lib 应该是用相同的版本进行发布,这两个版本应该同时被增加;另一个例子是当开发者创建不同的分支来给不同的主版本服务,再次分支上,开发者不应该修改其主版本。版本策略解决了这种问题,它强制 rush 和 rush-lib you 相同的版本,而其他分支的主版本不可以被修改。 ### 版本策略是什么[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E6%98%AF%E4%BB%80%E4%B9%88 "Direct link to heading") 版本策略是一系列定义版本如何被变更的规则,它被定义在 common/config/rush/version-policies.json 内,可以参考示例 [here](https://github.com/microsoft/rushstack/blob/main/common/config/rush/version-policies.json) . 一个公开的仓库可以通过在 rush.json 中指定 versionPolicyName 来指定版本策略,示例可以参考示例 [rush 和 rush-lib 的工程配置](https://github.com/microsoft/rushstack/blob/7d05f64c3275da074825bb98d3e49ea920fcfa8f/rush.json#L482) 。如果多个仓库遵循相同的规则,则可以使用一个版本策略。当你个库被指定版本策略后,它就是变成公开仓库,并可以被 "rush publish" 发布。 version-policies.json 的范式定义在 [here](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/version-policies.schema.json) . ### 版本策略的两种类型[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E7%9A%84%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B "Direct link to heading") 版本策略支持两种类型:lockStepVersion 和 individualVersion. 使用 lockStepVersion 的项目都有一致的版本;使用 individualVersion 的项目会根据变更文件和版本限制来自增版本。 [ { "policyName": "myPublic", "definitionName": "lockStepVersion", "version": "1.0.0-dev.6", "nextBump": "prerelease" }, { "policyName": "myInternal", "definitionName": "individualVersion", "lockedMajor": 3 }] ### 当使用版本策略时的发布过程[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%BD%93%E4%BD%BF%E7%94%A8%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E6%97%B6%E7%9A%84%E5%8F%91%E5%B8%83%E8%BF%87%E7%A8%8B "Direct link to heading") 当使用版本策略时发布新版本需要两步:第一步是增加包的版本,第二部是将其发布。这两步骤分开是因为很多时候你需要在版本变更后、发包之前进行测试。 #### 增加版本的命令[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%A2%9E%E5%8A%A0%E7%89%88%E6%9C%AC%E7%9A%84%E5%91%BD%E4%BB%A4 "Direct link to heading") `rush version --bump` 执行 `rush version --bump` 将会基于其版本策略来增版本号。 #### 发布包的命令[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%8F%91%E5%B8%83%E5%8C%85%E7%9A%84%E5%91%BD%E4%BB%A4 "Direct link to heading") `rush publish --include-all` 执行 `rush publish --include-all` 将会发布所有已经增加版本的公开包。 4\. 总结[​](https://rushjs.io/zh-cn/pages/maintainer/publishing/#4-%E6%80%BB%E7%BB%93 "Direct link to heading") -------------------------------------------------------------------------------------------------------------- 总而言之,仓库内的整个发布流程都可以通过 Rush 实现自动化。 * [1\. 跟踪变更](https://rushjs.io/zh-cn/pages/maintainer/publishing/#1-%E8%B7%9F%E8%B8%AA%E5%8F%98%E6%9B%B4) * [如果让开发者强制提供变更文件](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%A6%82%E6%9E%9C%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%BC%BA%E5%88%B6%E6%8F%90%E4%BE%9B%E5%8F%98%E6%9B%B4%E6%96%87%E4%BB%B6) * [开发者如何生成变更文件](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%BC%80%E5%8F%91%E8%80%85%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E5%8F%98%E6%9B%B4%E6%96%87%E4%BB%B6) * [2\. 发布包](https://rushjs.io/zh-cn/pages/maintainer/publishing/#2-%E5%8F%91%E5%B8%83%E5%8C%85) * [模拟发布模式](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E6%A8%A1%E6%8B%9F%E5%8F%91%E5%B8%83%E6%A8%A1%E5%BC%8F) * [发布模式](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%8F%91%E5%B8%83%E6%A8%A1%E5%BC%8F) * [打包模式](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E6%89%93%E5%8C%85%E6%A8%A1%E5%BC%8F) * [版本策略是什么](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E6%98%AF%E4%BB%80%E4%B9%88) * [版本策略的两种类型](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E7%9A%84%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B) * [当使用版本策略时的发布过程](https://rushjs.io/zh-cn/pages/maintainer/publishing/#%E5%BD%93%E4%BD%BF%E7%94%A8%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5%E6%97%B6%E7%9A%84%E5%8F%91%E5%B8%83%E8%BF%87%E7%A8%8B) * [4\. 总结](https://rushjs.io/zh-cn/pages/maintainer/publishing/#4-%E6%80%BB%E7%BB%93) --- # 仓库中添加项目 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#docusaurus_skipToContent_fallback) On this page _该文章是 [创建一个新的仓库](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/) 的继续。(如果你想看最终结果,可以在 GitHub 上查看 [rush 示例](https://github.com/microsoft/rush-example) )_ 步骤 4: 添加第一个项目[​](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-4-%E6%B7%BB%E5%8A%A0%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A1%B9%E7%9B%AE "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 我们建议每次只添加或验证单个项目,而不是一次性将所有项目都添加到 **rush.json** 中。将你的项目想象成一张[依赖图](https://en.wikipedia.org/wiki/Dependency_graph) ,可以从“叶子”项目(不依赖仓库内的其他项目),之后逐步推进。如果你遇到了任何错误,这种方法可以让错误更容易理解和调查。如果每次提交单个项目,这也会使你的 Git 历史更加易于理解。 对于这个示例,首先添加 **my-toolchain** 项目,它是其他所有项目的基础。我们将使用“种类目录”模式(其含义可以参考 **rush.json** 中的注释),所以将其移动到一个名为 "tools" 的文件夹下,我们最终的计划是将所有 NodeJS 工具包都放到 "tools" 文件夹中。 ~/my-repo$ mkdir tools~/my-repo$ cd tools~/my-repo/tools$ cp -R ~/my-toolchain/ .~/my-repo/tools$ cd my-toolchain 接下来需要删除项目下的一些文件: * 删除本地的 shrinkwrap 文件,因为它会被 Rush 的 shrinkwrap 文件代替。 * 考虑删除 **.npmrc** 文件,因为 Rush 使用了 **common/config/rush/.npmrc**. * 考虑删除项目的 Git 配置文件,除非该项目有单独的配置。 ~/my-repo/tools/my-toolchain$ rm -f shrinkwrap.yaml npm-shrinkwrap.json package-lock.json yarn.lock~/my-repo/tools/my-toolchain$ rm -f .npmrc # (如果存在的话)~/my-repo/tools/my-toolchain$ rm -f .gitattributes # (如果存在的话)~/my-repo/tools/my-toolchain$ rm -f .gitignore # (如果存在的话) > **关于 “shrinkwrap 文件”** > > 依据不同的包管理工具,shrinkwrap 文件可能是 **shrinkwrap.yaml**, **npm-shrinkwrap.json**, **package-lock.json**, 或 **yarn.lock**.(一些包管理工具使用了 "lock" 文件, 但该 “lock” 与文件的访问权限并无关系。在该文档中,由于我们并不知道你使用了哪种包管理工具,因此使用 "shrinkwrap" 来泛指这些文件。 > > 通常,包管理工具会在每个项目文件夹内创建 shrinkwrap 文件,但是在 Rush 中,整个项目共用存储在 \*\*common/config/rush" 目录下的一个 shrinkwrap 文件,它会被存储在 Git 内。 将所有依赖信息整合到单独一个 shrinkwrap 内有一些优势,例如减少冲突、方便查看 diff, 还能提高安装速度。 提交新的项目文件到 Git: ~/my-repo/tools/my-toolchain$ cd ../..~/my-repo$ git add .~/my-repo$ git commit -m "Adding my-toolchain" 步骤 5: 第一次运行 "rush update"[​](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-5-%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%BF%90%E8%A1%8C-rush-update "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 当将项目文件拷贝完后,我们需要编辑 **rush.json**, 应该在 `projects` 字段下增加一个对象: "projects": [ { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain" } ] 这告知 Rush 需要接管 my-toolchain 这个项目。 > **为什么 Rush 不能自动检测到这个项目?** > > Rush 并不会使用通配符来检测项目。该设计有以下考虑: > > 1. 深度优先搜索开销太大,尤其是需要重复收集列表时; > 2. 在带有缓存的 CI 机器上,搜索可能会遗漏掉之前构建中的文件; > 3. 集中式的管理所有项目以及其重要的元数据是很有用的,例如,可以让审批等策略更简单。 随后通过执行 `rush update` 来安装 **my-toolchain** 的依赖,该命令可以在 Rush 仓库内的任何子目录下运行。 ~/my-repo$ rush update~/my-repo$ git add .~/my-repo$ git commit -m "rush update" 因为这是仓库内的第一个项目,你将会发现 `rush update` 创建了一些新文件: * **common/config/rush/shrinkwrap.yaml**: 公共的 shrinkwrap 文件 (此处假定使用了 PNPM) * **common/scripts/install-run-rush.js**: 用于在 CI 任务中以一种可靠的方式来启动 Rush * **common/scripts/install-run.js**: 用于在 CI 任务中以一种可靠的方式来启动任意工具 步骤 6: 验证新项目是否构建成功[​](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-6-%E9%AA%8C%E8%AF%81%E6%96%B0%E9%A1%B9%E7%9B%AE%E6%98%AF%E5%90%A6%E6%9E%84%E5%BB%BA%E6%88%90%E5%8A%9F "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 为了构建项目,Rush 会寻找项目内的 **package.json** 文件内 `"scripts"` 字段下的 `"build"` 指令,在 [rush 示例](https://github.com/microsoft/rush-example) 中,使用简单的 shell 脚本 `"rimraf ./lib/ && tsc"` 来执行构建。 { "name": "my-toolchain", "version": "1.0.0", "description": "An example toolchain used to build projects in this repo", "license": "MIT", "bin": { "my-build": "bin/my-build.js" }, "scripts": { "build": "rimraf ./lib/ && tsc" }, "dependencies": { "colors": "^1.3.2" }, "devDependencies": { "@types/node": "^10.9.4", "rimraf": "^2.6.2", "typescript": "^3.0.3" }} 当创建 `"build"` 指令时,需要注意以下几件事: Rush 通常会使用系统的 PATH 环境变量来查找脚本,然而,如果你制定了诸如 "gulp" 或者 "make" 等单个单词的指令,Rush 会首先在 `common\temp\node_modules\.bin` 目录下查找该指令。 如果进程返回非零退出码,Rush 将判定为失败,并阻塞随后的构建。 如果指令对 `stderr` 存在任意输入,则 Rush 将以错误、警告报告等形式来解释该输入。这将会中断构建流程(设计如此,如果你允许开发者以这种 “狼来了” 的形式合并 PR,很快你就会发现,报警提示很快就会堆积到没人再去看它们)。诸如 Jest 等的工具库认为向 `stderr` 写入信息是常见操作,对此需要你[重定向它们的输出](https://github.com/microsoft/rushstack-legacy/blob/main/core-build/gulp-core-build/src/tasks/JestReporter.ts#L14) . 即使某个项目不需要被 `rush build` 处理,你依然需要保留 `build` 字段,将其设定为空字符串(`""`) 后 Rush 会忽略它们。 现在我们来构建你的项目,在 Rush 仓库下的任何子目录都可以执行下面命令(它将会构建仓库内的所有项目): $ rush build Rush 提供了大量命令行选项来构建项目,可以参考 [rush build](https://rushjs.io/zh-cn/pages/commands/rush_build/) 和 [rush rebuild](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/) . > **幻影依赖错误** > > Rush 和 PNPM 使用符号连接来防止项目中引入[幻影依赖](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) > ,如果一个 NPM 依赖并没有在项目内的 **package.json** 中声明,那么当你尝试引入它时会有一个运行时报错。当你将项目迁移到 Rush 时,幻影依赖报错是最常见的问题之一。通常的解决方案是将缺失的依赖添加到 **package.json** 文件中。 > > [rush scan](https://rushjs.io/zh-cn/pages/commands/rush_scan/) > 指令可以快速地检查出这些问题。 步骤 7: 添加更多的项目[​](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-7-%E6%B7%BB%E5%8A%A0%E6%9B%B4%E5%A4%9A%E7%9A%84%E9%A1%B9%E7%9B%AE "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 你可以依据步骤 4 来添加更多的项目,在我们的事例中,接下来将会添加 **my-controls** 工程(因为它依赖 **my-toolchain**),最后是 **my-application**(因为它依赖其他两个项目)。由于我们的设想的场景中可能有更多这类项目,因此预期会添加一些类别文件夹("libraries" 和 "apps"),因为我们的场景中会有更多这类项目。完整的 `"projects"` 字段示例如下: "projects": [ { "packageName": "my-app", "projectFolder": "apps/my-app" }, { "packageName": "my-controls", "projectFolder": "libraries/my-controls", "reviewCategory": "production" }, { "packageName": "my-toolchain", "projectFolder": "tools/my-toolchain", "reviewCategory": "tools" } ] 如果你已经成功添加了所有项目,便可以开始考虑启用其他功能。配置文件中包含大量的代码片段,你可以将它们注释掉后使用。[rush 示例](https://github.com/microsoft/rush-example) 中使用了这些代码片段。 * [步骤 4: 添加第一个项目](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-4-%E6%B7%BB%E5%8A%A0%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%A1%B9%E7%9B%AE) * [步骤 5: 第一次运行 "rush update"](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-5-%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%BF%90%E8%A1%8C-rush-update) * [步骤 6: 验证新项目是否构建成功](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-6-%E9%AA%8C%E8%AF%81%E6%96%B0%E9%A1%B9%E7%9B%AE%E6%98%AF%E5%90%A6%E6%9E%84%E5%BB%BA%E6%88%90%E5%8A%9F) * [步骤 7: 添加更多的项目](https://rushjs.io/zh-cn/pages/maintainer/add_to_repo/#%E6%AD%A5%E9%AA%A4-7-%E6%B7%BB%E5%8A%A0%E6%9B%B4%E5%A4%9A%E7%9A%84%E9%A1%B9%E7%9B%AE) --- # Creating Rush plugins (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#docusaurus_skipToContent_fallback) On this page Rush plugins enable repository maintainers to: * Share common Rush configuration across multiple monorepos * Extend Rush's base functionality with custom features * Prototype new feature ideas before officially contributing them to Rush Creating a plugin package[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#creating-a-plugin-package "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------- A **plugin package** is an NPM package that provides one or more **Rush plugins**. The plugins are described by a **plugin manifest** file. This file is always named [rush-plugin-manifest.json](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/) and found in same folder as the **package.json** file. Common extensibility scenarios[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#common-extensibility-scenarios "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------- ### Defining a Rush custom command[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#defining-a-rush-custom-command "Direct link to heading") A plugin can define new commands and parameters that extend Rush's command-line, using the same **command-line.json** file format that is used to implement [Rush custom commands](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) . Here's an example: **rush-example-plugin/rush-plugin-manifest.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", "plugins": [ { "pluginName": "check-readme", "description": "Adds a custom command \"rush check-readme\" that validates each project's README.md", /** * (Optional) A path to a "command-line.json" file that defines Rush command line actions * and parameters contributed by this plugin. This config file has the same JSON schema * as Rush's "common/config/rush/command-line.json" file. */ "commandLineJsonFilePath": "./command-line.json" } ]} **rush-example-plugin/command-line.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", "commands": [ { "name": "check-readme", "commandKind": "bulk", "summary": "Validates a project's README.md to make sure it conforms to company policy", "shellCommand": "node /lib/start.js", "safeForSimultaneousRushProcesses": true } ]} Example project for this scenario: [rush-sort-package-json](https://github.com/bytesfriends/rush-plugins/tree/main/rush-plugins/rush-sort-package-json) from **bytesfriends** ### Loading a code module[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#loading-a-code-module "Direct link to heading") A plugin can use the [@rushstack/rush-sdk](https://www.npmjs.com/package/@rushstack/rush-sdk) APIs to register handlers for Rush events and services. This is specified using the `entryPoint` setting in the plugin manifest: **rush-example-plugin/rush-plugin-manifest.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", "plugins": [ { "pluginName": "check-readme", "description": "Adds a custom command \"rush check-readme\" that validates each project's README.md", /** * (Optional) A path to a JavaScript code module that implements the "IRushPlugin" interface. * This module can use the "@rushstack/rush-sdk" API to register handlers for Rush events * and services. The module path is relative to the folder containing the "package.json" file. */ "entryPoint": "lib/RushExamplePlugin.js" } ]} The plugin module should have a `default` export that is an implementation of the [IRushPlugin](https://api.rushstack.io/pages/rush-lib.irushplugin/) interface. For example: **rush-example-plugin/src/RushExamplePlugin.ts** import type { IRushPlugin, RushSession, RushConfiguration } from '@rushstack/rush-sdk';export interface IRushExamplePluginOptions {}export class RushExamplePlugin implements IRushPlugin { public readonly pluginName: string = 'RushExamplePlugin'; public constructor(options: IRushExamplePluginOptions) { // Add your initialization here } public apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void { rushSession.hooks.initialize.tap(this.pluginName, () => { const logger: ILogger = rushSession.getLogger(this.pluginName); logger.terminal.writeLine('Add your custom logic here'); }); }}export default { RushExamplePlugin }; The [RushSession.hooks](https://api.rushstack.io/pages/rush-lib.rushsession/) API exposes various [lifecycle hooks](https://api.rushstack.io/pages/rush-lib.rushlifecyclehooks/) that your plugin can use to register its handlers. The hook system is based on the popular [tapable](https://www.npmjs.com/package/tapable) framework familiar from Webpack. Example project for this scenario: [@rushstack/rush-amazon-s3-build-cache-plugin](https://github.com/microsoft/rushstack/blob/main/rush-plugins/rush-amazon-s3-build-cache-plugin) > **Note:** If your code module is only used with certain Rush commands, use the `"associatedCommands"` setting to improve performance by avoiding loading the module when it is not needed. ### Defining a config file for your plugin[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#defining-a-config-file-for-your-plugin "Direct link to heading") Often a plugin will need to be configured using its own custom settings. Rush's convention is that the plugin's config file should be stored in the folder **common/config/rush-plugins** with the same filename as the `"pluginName"` field from the manifest. Here's a complete example of this naming pattern: | Plugin component | Example naming pattern | | --- | --- | | NPM package name: | `@your-company/rush-policy-plugins` | | `"pluginName"` in **rush-plugin-manifest.json**: | `"email-policy"` | | end user config file: | **/common/config/rush-plugins/email-policy.json** | | config file JSON schema: | **src/schemas/email-policy.schema.json** | | code module: | **src/RushEmailPolicyPlugin.ts** | To enable Rush's automatic validation of your plugin's config file, specify the `optionsSchema` setting in your plugin manifest: **rush-policy-plugins/rush-plugin-manifest.json** . . . /** * (Optional) A path to a JSON schema for validating the config file that end users can * create to customize this plugin's behavior. Plugin config files are stored in the folder * "common/config/rush-plugins/" with a filename corresponding to the "pluginName" field * from the manifest. For example: "common/config/rush-plugins/business-policy.json" * whose schema is "business-policy.schema.json". */ "optionsSchema": "lib/schemas/email-policy.schema.json", . . . See also[​](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#see-also "Direct link to heading") ------------------------------------------------------------------------------------------------------------- * [Using Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) * [rush-plugin-manifest.json](https://rushjs.io/zh-cn/pages/configs/rush-plugin-manifest_json/) config file documentation * [command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) * [Rush custom commands](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) * [Creating a plugin package](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#creating-a-plugin-package) * [Common extensibility scenarios](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#common-extensibility-scenarios) * [Defining a Rush custom command](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#defining-a-rush-custom-command) * [Loading a code module](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#loading-a-code-module) * [Defining a config file for your plugin](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#defining-a-config-file-for-your-plugin) * [See also](https://rushjs.io/zh-cn/pages/extensibility/creating_plugins/#see-also) --- # 选择部分项目 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#docusaurus_skipToContent_fallback) On this page 诸如 `rush build` 和 `rush rebuild` 等 [Bulk 指令](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) 默认会操作该 monorepo 内的所有项目。当你的项目越来越多时,这种操作变得十分耗时,为了加速这一过程,Rush 提供了一系列命令行参数来选择部分项目。 假设我们的 Rush 工程形式如下图: ![a sample monorepo](https://rushjs.io/images/docs/selection-intro.svg) 上图中圆圈表示本地项目,并没有 NPM 依赖,从 `D` 到 `C` 的箭头表示 `D` 依赖 `C`, 这意味着如果想要构建 `D`, 则 `C` 要首先被构建。我们会在下面的示例中使用 `rush build` 命令,但这些参数可以用于任何 Bulk 指令。 \--to[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--to "Direct link to heading") --------------------------------------------------------------------------------------------------- **场景:**假设我们刚刚克隆了 monorepo 仓库,现在想在项目 `B` 中进行开发,则需要构建 `B` 和 `B` 依赖的所有项目。 我们可以这样做: # 构建项目 B 以及 B 依赖的所有项目$ rush build --to B 上面的命令选择了 `A`, `B` 和 `E` 三个项目: ![rush build --to B](https://rushjs.io/images/docs/selection-to.svg) \--to-except[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--to-except "Direct link to heading") ----------------------------------------------------------------------------------------------------------------- **场景:**很多时候我们不需要使用 `rush build` 来处理项目 `B`, 因为我们的下一步将会是在调用 Webpack 或者 Jest 的 "watch mode" 模式来处理项目 `B`. 此时可以使用 `--to-except` 来代替 `--to`, 该参数会仅构建项目 `B` 的依赖。 # 构建 B 依赖的所有项目,但不包括项目 `B`$ rush build --to-except B# 在项目 `B` 中调用 Jest 的 watch 模式来构建$ heft test --watch 该指令选择了 `A` 和 `E` 两个项目: ![rush build --to-except B](https://rushjs.io/images/docs/selection-to-except.svg) \--from[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--from "Direct link to heading") ------------------------------------------------------------------------------------------------------- **场景:**假设现在我们完成了对项目 `B` 的修改,我们想要构建下游的 `C` 和 `D` 项目来保证没有破坏性的变动。为了构建项目 `D`, 我们同样需要构建其依赖 `G`. `--from` 的作用就是这样,它也会包括 `A` 和 `E`,因为它们是 `B` 的依赖。(因为 `rush build` 是增量构建,所以 `A` 和 `E` 可能会被跳过,因为它们可能还没有变化) # 构建 B 下游的所有项目,包括任何潜在的依赖$ rush build --from B 该命令选中了除 `F` 的所有项目。 ![rush build --from B](https://rushjs.io/images/docs/selection-from.svg) > **兼容性提示:** 如何在 **rush.json** 中设定的 `rushVersion` 小于 5.38.0, 则 `--from` 的行为类似于 `--impacted-by`, 在 Rush 5.38.0 版本中,该命令的含义有些变化,因为许多用户预期 `--from` 包含它的依赖。 \--impacted-by (不安全)[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--impacted-by-%E4%B8%8D%E5%AE%89%E5%85%A8 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------- **场景:**假如为完成 `B` 内所需的工作需要改动对项目 `E`, 那么 Rush 的增量构建会假设 `E` 内的所有下游项目都需要被重新构建,例如 `F`. 这影响面可能会很大。也许你自己对他们了解更多——也许你稍后会撤回在 `E` 上的修改,也或者你会手动调用 `E` 的工具链,也许你对 `E` 的变动与现阶段所需无关。 这种情况下 `--impacted-by` 便可发挥作用:它意味着 _“只选择那些可能带给 B 破坏性变动的项目,信任那些依赖处于可用状态下的依赖。”_ # 构建 B 以及 B 下游的项目,但不包括这些项目的依赖$ rush build --impacted-by B 该命令选中的项目是 `B`, `C` 和 `D`. ![rush build --impacted-by B](https://rushjs.io/images/docs/selection-impact.svg) \--impacted-by-expect (不安全)[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--impacted-by-expect-%E4%B8%8D%E5%AE%89%E5%85%A8 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------- **场景:**与 `--impacted-by` 相同,但是不包括 `B` 本身。 # 构建 B 下游的项目,但不包括这些项目的依赖$ rush build --impacted-by-except B 该命令会选中 `C` 和 `D` 两个项目。 ![rush build --impacted-by-except B](https://rushjs.io/images/docs/selection-impact-except.svg) \--only (不安全)[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--only-%E4%B8%8D%E5%AE%89%E5%85%A8 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------- **场景:**正如该参数名所示:`--only` 参数只会选择指定的一个项目,忽略依赖。 # 只构建 B$ rush build --only B ![rush build --only B](https://rushjs.io/images/docs/selection-only.svg) `--only` 可以与其他参数一起使用。例如在上文中,当我们使用 `rush build --impacted-by B` 时,可能还没有构建 `G`, 我们可以通过 `rush build --impacted-by B --only G` 来包含它。 > **“不安全”参数:** 如果所需的依赖没有被构建,那么诸如 `--only`, `--impacted-by` 和 `--impacted-by-except` 等命令可能执行失败 当你比 Rush 更了解哪些项目需要构建时,可以通过上述三个参数来节省时间。如果该前提不存在,则可以使用 `rush build`. 选择器格式[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E9%80%89%E6%8B%A9%E5%99%A8%E6%A0%BC%E5%BC%8F "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------- 当你指定上述参数之一时,你可以使用各种不同的格式来指定你需要的项目。 ### 项目名[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E9%A1%B9%E7%9B%AE%E5%90%8D "Direct link to heading") 最直接的方式是使用项目名(在 `rush.json` 文件中所列)。 示例: rush build --to my-project-namerush build --from my-project-namerush list --impacted-by my-project-name ### 在当前项目下使用 `.`[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E5%9C%A8%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E4%B8%8B%E4%BD%BF%E7%94%A8- "Direct link to heading") 如果你的的终端位于某个项目目录下,可以使用 `.`来表示当前项目。 示例: rush build --to .rush list --to-except . ### commit 之后发生变动的项目[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#commit-%E4%B9%8B%E5%90%8E%E5%8F%91%E7%94%9F%E5%8F%98%E5%8A%A8%E7%9A%84%E9%A1%B9%E7%9B%AE "Direct link to heading") 你通过提供一个 git (分支、标签或 commit 哈希)来指定该节点以来所有修改过的项目。这种查询的类型与 `rush change` 使用了相同的逻辑来记录变化。 rush build --to git:origin/mainrush list --impacted-by git:release/v3.0.0 ### 子空间成员:`subspace:`[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E5%AD%90%E7%A9%BA%E9%97%B4%E6%88%90%E5%91%98subspace "Direct link to heading") [子空间](https://rushjs.io/zh-cn/pages/advanced/subspaces/) 功能使 Rush 项目能够分组到各自使用自己的 PNPM 锁定文件的子空间中。`subspace:` 选择器会匹配属于指定子空间的所有项目。 示例: # 构建所有属于 "install-test" 子空间的项目,以及它们的依赖:rush build --to subspace:install-test ### 标记的项目:`tag:`[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E6%A0%87%E8%AE%B0%E7%9A%84%E9%A1%B9%E7%9B%AEtag "Direct link to heading") Rush [项目标记](https://rushjs.io/zh-cn/pages/developer/project_tags/) 使您能够定义任意的项目集合,然后可以使用 `tag:` 选择器引用这些集合。 示例: # 构建所有带有 "shipping" 项目标记的项目。rush build --to tag:shipping # 打印报告,显示带有 "frontend-team-libs" 项目标记的项目集。rush list --only tag:frontend-team-libs --detailed 组合参数[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E7%BB%84%E5%90%88%E5%8F%82%E6%95%B0 "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------- * 你可以在指令中组合任何参数,其结果是所有参数的并集。 * 相同的参数可以重复多次,例如 `rush build --only A --only B --only C` 会选中 `A`, `B`, `C`. * 注意 Rush 不会提供任何可能会减少选中项目的参数。在 [#1241](https://github.com/microsoft/rushstack/issues/1241) 中我们会实现更复杂的选择。 这里有一些复杂的组合指令: $ rush build --only A --impacted-by-except B --to F $ rush build --only A --impacted-by-except B --to F 上述示例中选中的项目为 `A`, `C`, `D`, `E` 以及 `F`: ![rush build --only A --impacted-by-except B --to F](https://rushjs.io/images/docs/selection-multi.svg) 更多[​](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E6%9B%B4%E5%A4%9A "Direct link to heading") -------------------------------------------------------------------------------------------------------------- * [增量构建](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/) * [watch 模式](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/) * [rush build](https://rushjs.io/zh-cn/pages/commands/rush_build/) * [rush rebuild](https://rushjs.io/zh-cn/pages/commands/rush_rebuild/) * [\--to](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--to) * [\--to-except](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--to-except) * [\--from](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--from) * [\--impacted-by (不安全)](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--impacted-by-%E4%B8%8D%E5%AE%89%E5%85%A8) * [\--impacted-by-expect (不安全)](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--impacted-by-expect-%E4%B8%8D%E5%AE%89%E5%85%A8) * [\--only (不安全)](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#--only-%E4%B8%8D%E5%AE%89%E5%85%A8) * [选择器格式](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E9%80%89%E6%8B%A9%E5%99%A8%E6%A0%BC%E5%BC%8F) * [项目名](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E9%A1%B9%E7%9B%AE%E5%90%8D) * [在当前项目下使用 `.`](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E5%9C%A8%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E4%B8%8B%E4%BD%BF%E7%94%A8-) * [commit 之后发生变动的项目](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#commit-%E4%B9%8B%E5%90%8E%E5%8F%91%E7%94%9F%E5%8F%98%E5%8A%A8%E7%9A%84%E9%A1%B9%E7%9B%AE) * [子空间成员:`subspace:`](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E5%AD%90%E7%A9%BA%E9%97%B4%E6%88%90%E5%91%98subspace) * [标记的项目:`tag:`](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E6%A0%87%E8%AE%B0%E7%9A%84%E9%A1%B9%E7%9B%AEtag) * [组合参数](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E7%BB%84%E5%90%88%E5%8F%82%E6%95%B0) * [更多](https://rushjs.io/zh-cn/pages/developer/selecting_subsets/#%E6%9B%B4%E5%A4%9A) --- # 自定义指令 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#docusaurus_skipToContent_fallback) On this page 如果你的工具链有特殊的模式或功能,你可以将它们作为自定义指令或 Rush 工具的参数来暴露出来。 自定义指令和参数[​](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E5%92%8C%E5%8F%82%E6%95%B0 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- **common/config/rush/command-line.json** 下有一个配置文件用于自定义指令和参数,你的配置文件应该满足 [command-line.schema.json](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/command-line.schema.json) 范式,考虑以下示例: { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", "commands": [ { /** * (必须)用于确定自定义指令的类型。 * Rush 的 "bulk" 类型指令将会在每个项目中都被调用,Rush 会寻找项目 package.json 内的 "scripts" 字段中匹配该命令行的字段。 * 默认情况下,Rush 会根据依赖图来确定要运行的项目(与 "rush build" 的工作原理类似)。 * 也可以通过诸如 "--to" 或 "--from" 参数来限制项目集合。 */ "commandKind": "bulk", "name": "import-strings", "summary": "Imports translated strings into each project.", "description": "Requests translated strings from the translation service and imports them into each project.", "enableParallelism": true }, { /** *(必须)用于确定自定义指令的类型。 * Rush 的 "global" 类型的指令会在整个仓库调用一次。 */ "commandKind": "global", "name": "deploy-app", "summary": "Deploys the application", "description": "Run this command to deploy the application", "shellCommand": "node common/scripts/deploy-app.js" } ], "parameters": [ { /** * (必须) 决定自定义参数的类型 * "flag" 类型的参数是一个布尔属性的参数 */ "parameterKind": "flag", "longName": "--ship", "shortName": "-s", "description": "Perform a production build, including minification and localization steps", "associatedCommands": [ "build", "rebuild", "import-strings" ], }, { "parameterKind": "flag", "longName": "--minimal", "shortName": "-m", "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", "associatedCommands": [ "build", "rebuild" ] }, { /** * (必须) 决定自定义参数的类型 * "choice" 类型的参数需要从可供选择的参数中选取一个 */ "parameterKind": "choice", "longName": "--locale", "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", "associatedCommands": [ "build", "rebuild", "import-strings" ], "alternatives": [ { "name": "en-us", "description": "US English" }, { "name": "fr-fr", "description": "French (France)" }, { "name": "es-es", "description": "Spanish (Spain)" }, { "name": "zh-cn", "description": "Chinese (China)" } ] } ]} **自定义指令:**你可以像 Rush 内置的指令(例如 `rush build`, `rush check` 等)一样自定义自己的指令,这有两种类型: * **bulk**: bulk 类型的指令会在每个项目中被调用,其原理与 `rush build`. 设定 `"enableParallelism": true` 后,项目可以并行运行。 * **global**: global 类型的指令会在整个仓库内执行指定的脚本文件。 你也可以自定义命令行“参数”。一个参数可以通过 `associatedCommands` 来被一个或多个指令关联。你甚至可以将自定义参数关联到 Rush 内置的 `build` 和 `rebuild` 指令上。在上述示例中,我们将 `--ship` 参数关联到 `rush build`, `rush rebuild` 和自定义的 `rush import-strings` 上。 目前有三种 `parameterKind` 类型: * **flag**: **flag** 是一个布尔属性的参数,例如 `--ship`. * **choice**: **choice** 是一个从列表选择的额外参数,例如 `--locale fr-fr`. * **string**: **string** 是一个可以接受任何字符串值的参数,例如 `--name my-new-package`. 未来会支持更多参数类型(它们使用 [ts-command-line](https://www.npmjs.com/package/@microsoft/ts-command-line) 来解析) 使用自定义命令和选项[​](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E5%91%BD%E4%BB%A4%E5%92%8C%E9%80%89%E9%A1%B9 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 你可以自定义指令和其描述将被会被 Rush 的命令行帮助中(当在仓库的工作目录中调用时),继续上述示例,如果我们运行 `rush import-strings --help`,我们将看到这样的内容: Rush Multi-Project Build Tool 5.1.0 - https://rushjs.iousage: rush import-strings [-h] [-p COUNT] [-t PROJECT1] [--to-version-policy VERSION_POLICY_NAME] [-f PROJECT2] [-v] [-s] [--locale {en-us,fr-fr,es-es,zh-cn}]Requests translated strings from the translation service and imports theminto each project.Optional arguments: -h, --help Show this help message and exit. -p COUNT, --parallelism COUNT Specify the number of concurrent build processes The value "max" can be specified to indicate the number of CPU cores. If this parameter omitted, the default value depends on the operating system and number of CPU cores. -t PROJECT1, --to PROJECT1 Run command in the specified project and all of its dependencies --to-version-policy VERSION_POLICY_NAME Run command in all projects with the specified version policy and all of their dependencies -f PROJECT2, --from PROJECT2 Run command in all projects that directly or indirectly depend on the specified project -v, --verbose Display the logs during the build, rather than just displaying the build status summary -s, --ship Perform a production build, including minification and localization steps --locale {en-us,fr-fr,es-es,zh-cn} Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds. 如果实现一个自定义指令和自定义参数?对于 global 指令而言,Rush 仅仅会唤起其 `shellCommand` 并传递参数;对于 bulk 指令,Rush 会在 **package.json** 中查找对应的脚本。假设我们有以下内容: **example/package.json** { "name": "example", "version": "1.0.0", "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { "import-strings": "./node_modules/.bin/loc-importer", "build": "./node_modules/.bin/gulp" }} 如果执行 `rush import-strings --locale fr-fr`,Rush 将会读取 "import-strings" 脚本体并执行如下: ./node_modules/.bin/loc-importer --locale fr-fr (Rush 直接在 shell 中执行,并不依赖 `npm run`.)因为这个 choice 参数有默认值,如果我们运行 `rush import-strings`,那么 **loc-importer** 将会执行如下: ./node_modules/.bin/loc-importer --locale en-us 换句话说,Rush 的自定义参数只是简单的在 **package.json** 中的脚本内添加一些内容,这意味着当你使用诸如 "`rimraf ./lib && rimraf ./temp`" 等 shell 脚本时,可能会出现问题,因为这些脚本不支持这些参数,或者需要在中间插入这些参数。这是因为设计的原因在于:我们不建议在 JSON 中写入复杂的构建脚本。相反,最好把这些操作移到一个方便注释和审查的脚本文件中。当 monorepo 仓库逐渐扩大时,你也许想要将这个脚本移动到一个可以在多个项目中共享的库里。 参考[​](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------- * [command-line.json](https://rushjs.io/zh-cn/pages/configs/command-line_json/) * [自定义指令和参数](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E5%92%8C%E5%8F%82%E6%95%B0) * [使用自定义命令和选项](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E5%91%BD%E4%BB%A4%E5%92%8C%E9%80%89%E9%A1%B9) * [参考](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/#%E5%8F%82%E8%80%83) --- # NPM vs PNPM vs Yarn | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#docusaurus_skipToContent_fallback) On this page 当你安装 JavaScript 库之前,你需要选择一个包管理工具(由于 JavaScript 社区非常自由活跃,因此包管理工具不止一个)。Rush 支持目前最流行的三种包管理工具,按照时间顺序依次为: * [NPM](https://docs.npmjs.com/getting-started/what-is-npm) : 它是当今最广泛的 JavaScript 包管理工具,它开创了包管理标准,其开发者还维护了世界上最多人使用的分布式开源 JavaScript 包管理网站 npmjs.com. * [Yarn](https://yarnpkg.com/en/) : 它重新实现了 NPM, 与之相比,Yarn 具有相同的管理方式,但是安装速度更快,稳定性更好,而且提供了一些新特性(例如 Yarn workspaces),用于大型开发。 * [PNPM](https://rushjs.io/zh-cn/pages/maintainer/package_managers/pnpm.js.org/) : 它提供了一个全新的包管理模式,该模式解决了[“幻影依赖”和“ NPM 分身”](https://rushjs.io/zh-cn/pages/advanced/phantom_deps/) 的问题,同时[符号链接](https://en.wikipedia.org/wiki/Symbolic_link) 使之与 NodeJS 模块解析标准保持 100% 兼容。 当使用 Rush 时应该选择哪个?[​](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E5%BD%93%E4%BD%BF%E7%94%A8-rush-%E6%97%B6%E5%BA%94%E8%AF%A5%E9%80%89%E6%8B%A9%E5%93%AA%E4%B8%AA "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 看你需求而定,Rush 开发者并不宣传特定的包管理工具,但是基于 monorepo 的管理经验而言,我们有以下观点: #### 关于 NPM 的思考[​](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E5%85%B3%E4%BA%8E-npm-%E7%9A%84%E6%80%9D%E8%80%83 "Direct link to heading") * NPM 是最具兼容性的选择,并且一些“不友好”的库也可以得到处理。 * 如果你选择 NPM, 如果你选择使用旧版本,NPM 5.x 和 6.x 都可能导致 Rush 仓库出现问题。NPM **4.5.0** 是最新的可靠版本,但是它实在是太旧了(我们使用 [GitHub issue #886](https://github.com/microsoft/rushstack/issues/886) 来记录进展,非常欢迎并感谢大家来帮助解决目前的问题)。 _如果使用 Rush 与 NPM 结合出现问题时,首先尝试下降级到 `"npmVersion": "4.5.0`, 如果这样解决了问题,那么你的问题可能就是 NPM 导致的,并且不太方便在 Rush 中解决,我们仍然处理这些问题,但追踪这些问题的方式不同。_ #### 关于 PNPM 的思考[​](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E5%85%B3%E4%BA%8E-pnpm-%E7%9A%84%E6%80%9D%E8%80%83 "Direct link to heading") * PNPM 是解决 [NPM 分身](https://rushjs.io/zh-cn/pages/advanced/npm_doppelgangers/) 的唯一选择。在复杂的 monorepo 项目中,NPM 分身 可能会导致很多麻烦,PNPM 在这方面有一个重要的优势。 * 尽管 PNPM 的链接策略遵循了当下 NodeJS 版本解析辨准,但是很多老包并没有,这可能存在一些兼容性问题。当尝试从 Yarn/NPM 迁移到 PNPM 时,团队需要对一些存在“问题的包”进行一些处理。不兼容性问题经常会出现在:(1) 忘记在 **package.json** 中列出依赖项;(2) 不以标准的方式实现符号链接。这些“问题”包有非常直接的解决方式,但是对于小团队而言可能比较艰难([PNPM Discord 聊天室](https://discord.gg/mThkzAT) 是一个很好寻求帮助的地方)。 * PNPM 比 NPM 或 Yarn 更新,更少人用,但是它是一个很优秀的软件,微软内有上百个仓库使用了 Rush + PNPM 的组合,我们发现它迅速且可靠。 * PNPM 是目前唯一支持 `--strict-peer-dependencies` 的包管理器(参考 **rush.json** 中的 `"strictPeerDependencies"` 在 **rush.json** 中)的选择。 #### 关于 Yarn 的思考[​](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E5%85%B3%E4%BA%8E-yarn-%E7%9A%84%E6%80%9D%E8%80%83 "Direct link to heading") * Rush 对 Yarn 的支持尚处于起步阶段,我们非常希望看到一些反馈并解决它们。 * Yarn 的安装速度比 NPM 更快(但是比 PNPM 要慢)。 * Yarn 的 "workspaces" 并没有被 Rush 采用,因为它们的安装方式并没有解决幻影依赖,然而 Rush 链接策略与 workspaces 相似。 指定你的包管理器[​](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E6%8C%87%E5%AE%9A%E4%BD%A0%E7%9A%84%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 在 **rush.json** 中可以选定包管理器,可以通过编辑三个字段中的一个来指定((`npmVersion`, `pnpmVersion`, 或 `yarnVersion`): **rush.json** /** * 以下字段是用来选定包选择器及其版本。 * Rush 会安装适用于自身版本的包管理器,这可以保证构建过程和本地环境隔离。 * * 选中一个包选择器:"pnpmVersion", "npmVersion", 或 "yarnVersion"。详细信息请参考 Rush 文档。 */"pnpmVersion": "2.15.1",// "npmVersion": "4.5.0",// "yarnVersion": "1.9.4", 选完后,删除 **common/config/rush** 中之前的 shrinkwrap 文件和其他包管理器相关文件。(否则 Rush 将会报告不支持配置文件),然后运行 `rush update --full --purge`. * [当使用 Rush 时应该选择哪个?](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E5%BD%93%E4%BD%BF%E7%94%A8-rush-%E6%97%B6%E5%BA%94%E8%AF%A5%E9%80%89%E6%8B%A9%E5%93%AA%E4%B8%AA) * [指定你的包管理器](https://rushjs.io/zh-cn/pages/maintainer/package_managers/#%E6%8C%87%E5%AE%9A%E4%BD%A0%E7%9A%84%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8) --- # 部署项目 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/deploying/#docusaurus_skipToContent_fallback) On this page 假定你的 monrepo 项目含有一个 web 服务器的 Node.js 服务,举例来说,本地 Rush 仓库内的 Node.js 服务的项目名为 `app1`, 该仓库的组织如下: * **apps/app1**: * dependencies 为 NPM 上的 `ext-lib7` 和本地 `lib3` * devDependencies 为 NPM 上的 `ext-tool8` 和本地 `tool6` * **apps/app2**: 依赖 `lib3` 和 `lib4` * **libraries/lib3**: 依赖 `lib5` * **libraries/lib4**: 没有依赖 * **libraries/lib5**: 同级依赖 `ext-lib7` * **tools/tool6**: 没有依赖 一个构建方式是执行 `rush install` 和 `rush build`, 但是该操作会将整个仓库传递到 Node 服务上,然而,这也会引入很多无关的文件和 NPM 包。相反,我们可以只处理 `app1` 和其依赖 `ext-lib7`, `lib3`, `lib5`, 我们并不想引入诸如 `ext-tool8` 等开发依赖。 [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/) 指令可以将这组文件传入到指定的服务器上。 配置 "rush deploy"[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E9%85%8D%E7%BD%AE-rush-deploy "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- `rush deploy` 指令从 [common/config/rush/deploy.json](https://rushjs.io/zh-cn/pages/configs/deploy_json/) 中读取配置,该文件并不是 `rush init` 生成的,而是需要执行 [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/) 来创建。 继续我们的示例,我们可以使用下面指令来创建文件 # 创建用于 "app1" 的配置文件:common/config/rush/deploy.json$ rush init-deploy --project app1 当 **deploy.json** 配置完成后,需要对其执行 Git commit. 准备构建[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%87%86%E5%A4%87%E6%9E%84%E5%BB%BA "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------- 为了将文件复制到构建目录中,需要执行: # 安装依赖$ rush install# 构建 monorepo$ rush build# 拷贝 app1 及其依赖到默认的目录 common/deploy$ rush deploy 这将通过复制 `app1` 及其依赖到目标目录下来准备部署环境,复制后的目录结构与 monorepo 的文件结构类似: * **common/deploy/apps/app1/...** * **common/deploy/common/temp/node\_modules/ext-lib7/...** * **common/deploy/libraries/lib3/...** * **common/deploy/libraries/lib4/...** 你可以在构建产物的目录中执行 `app1` 来验证是否有问题。 # 将工作目录切换到产物下的 app1 路径$ cd common/deploy/apps/app1# 通过 package.json 中的脚本来唤起网络服务$ rushx start 如果项目运行失败(但是原本 **apps/app1** 下可以正常运行),那么你可能需要配置下 **deploy.json**, 一旦可以运行,下依旧就是将 **common/deploy** 上传到服务器上。 处理链接[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%A4%84%E7%90%86%E9%93%BE%E6%8E%A5 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------- 执行 `rush install` 会给 **common/deploy** 目录创建符号链接,例如,如果你使用 PNPM, 那么 **common/deploy/apps/app1/node\_modules/ext-lib7** 可能是指向 **common/deploy/common/temp/node\_modules/.pnpm/...** 目下的一个链接,使用诸如 `tar` 和 `ftp` 等工具上传时可能出现问题。 **deploy.json** 下中字段 `linkCreation` 下有三个处理链接的选项。 * `"default"`: 拷贝文件时创建链接,这是默认选项,如果你的上传工具可以正确处理这些链接,则可以使用该选项。 * `"scripts"`: 将会在目录下写入一个名为 **create-links.js** 的脚本,该配置会在上传后的服务器上创建链接。 * `"none"`: 什么都不会,一些其他基于 **deploy-metadata.json** 的脚本可能在随后创建链接。 **deploy-metadata.json** 被写入部署文件中,它包含一个需要被创建链接的清单,其实力如下: { "scenarioName": "deploy.json", "mainProjectName": "app1", "links": [ { "kind": "folderLink", "linkPath": "common/deploy/apps/app1/node_modules/ext-lib7", "targetPath": "common/deploy/common/temp/node_modules/.pnpm/registry.npmjs.org/ext-lib7/1.0.0/node_modules/ext-lib7" }, . . . ]} 如果你使用 `"linkCreation": "script"` 之后执行 `rush deploy` 会创建没有链接的 **common/deploy** 的目录,当你将这些文件上传到服务器后,你可以调用下面脚本来创建链接: # 当文件被上传后在服务器上执行下面命令$ node create-links.js create > 注意:当使用 `"linkCreation": "script"` 时,目前的实现还没在 **node\_modules/.bin** 下生成可执行命令,如果你对该问题有兴趣,请参考该 [PR](https://github.com/microsoft/rushstack/pull/2010#issuecomment-656900649) > . 引入另外的项目[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%BC%95%E5%85%A5%E5%8F%A6%E5%A4%96%E7%9A%84%E9%A1%B9%E7%9B%AE "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------- 继续我们的示例,假设我们想要将 `app1` 和 `app2` 合并成一个部署,由于 `app2` 并不是 `app1` 的依赖,因此不会被自动包含进去。我们可以考虑将 `app1` 放到“主项目”中(在 `deploymentProjectNames` 内配置),之后创建 `app2` 为“额外的项目”,配置文件如下: **common/config/rush/deploy.json** { . . . // 主项目 "deploymentProjectNames": ["app1"], . . . "projectSettings": [ { "projectName": "app1", // 当部署 "app1" 时同时部署 "app2", // 我们需要明确指明它,因为 "app2" 不是 "app1" 的依赖 "additionalProjectsToInclude": [ "app2" ] } ]} 使用同一个配置文件进行多部署[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E4%BD%BF%E7%94%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%BF%9B%E8%A1%8C%E5%A4%9A%E9%83%A8%E7%BD%B2 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 继续我们的示例,假定我们想要 `app1` 和 `app2` 分别部署到两个不同的 web 服务器上。如果设置相同,我们可以简单地将它们添加到 `deploymentProjectNames` 数组中,如下: **common/config/rush/deploy.json** . . . "deploymentProjectNames": [ "app1", "app2" ], . . . 部署时,使用 `--project` 参数选择需要被部署的项目。例如: # 将 app1 和其依赖项复制到 /mnt/deploy/app1$ rush deploy --project app1 --target-folder /mnt/deploy/app1# 将 app2 和其依赖项复制到 /mnt/deploy/app2$ rush deploy --project app2 --target-folder /mnt/deploy/app2 `--target-folder` 参数用于将文件复制到自定义目录下,其默认值为 **common/deploy/**. 使用不同的配置文件进行多部署[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%BF%9B%E8%A1%8C%E5%A4%9A%E9%83%A8%E7%BD%B2 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 继续我们的示例,假定 `app2` 单独部署,同时它的设置与 `app1` 不同。例如,假设 `app1` 的 `"linkCreation": "default"`, 但是 `app2` 的 `"linkCreation": "script"`. 我们创建两个配置文件: * **common/config/rush/deploy.json** - 默认配置文件,它将被用于 `app1`. * **common/config/rush/deploy-app2-example.json** - 适用于 `app2-example` 的配置文件, 它将被用于 `app2`. 上述文件都可以被 `rush init-deploy` 创建: # 创建 common/config/rush/deploy.json$ rush init-deploy --project app1# 创建 common/config/rush/deploy-app2-example.json$ rush init-deploy --project app2 --scenario app2-example 在 **deploy-app2-example.json** 中指定 `"linkCreation": "script"`, 然后同时使用 `--scenario` 和 `rush deploy`: # 使用 common/config/rush/deploy.json 将 app1 和其依赖复制到 /mnt/deploy/app1$ rush deploy --target-folder /mnt/deploy/app1# 使用 common/config/rush/deploy-app2-example.json 将 app2 和其依赖复制到 /mnt/deploy/app2$ rush deploy --target-folder /mnt/deploy/app2 --scenario app2-example 注意,`rush deploy` 不需要 `--project` 参数,因为每个配置文件中只有一个项目在 `"deploymentProjectNames"` 数组中。 参考[​](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------- * [common/config/rush/deploy.json](https://rushjs.io/zh-cn/pages/configs/deploy_json/) 配置文件 * [rush deploy](https://rushjs.io/zh-cn/pages/commands/rush_deploy/) 命令行参数 * [rush init-deploy](https://rushjs.io/zh-cn/pages/commands/rush_init-deploy/) 命令行参数 * [配置 "rush deploy"](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E9%85%8D%E7%BD%AE-rush-deploy) * [准备构建](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%87%86%E5%A4%87%E6%9E%84%E5%BB%BA) * [处理链接](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%A4%84%E7%90%86%E9%93%BE%E6%8E%A5) * [引入另外的项目](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%BC%95%E5%85%A5%E5%8F%A6%E5%A4%96%E7%9A%84%E9%A1%B9%E7%9B%AE) * [使用同一个配置文件进行多部署](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E4%BD%BF%E7%94%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%BF%9B%E8%A1%8C%E5%A4%9A%E9%83%A8%E7%BD%B2) * [使用不同的配置文件进行多部署](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%BF%9B%E8%A1%8C%E5%A4%9A%E9%83%A8%E7%BD%B2) * [参考](https://rushjs.io/zh-cn/pages/maintainer/deploying/#%E5%8F%82%E8%80%83) --- # Enabling phased builds | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#docusaurus_skipToContent_fallback) On this page By default, Rush builds each project by running a build script (similar to `npm run build`) separately in each project folder, processing projects in parallel when the dependency graph allows. From Rush's perspective, everything that happens inside that build script is a single operation. _Phased builds_ are a way to increase parallelism, by defining individual operations as _phases_ that can be executed on a project. As an example, if project B depends on project A, we could first build project A, and then begin building project B while running the unit tests for project A in parallel. > NOTE: Phased builds are built on top of, and require, the build cache feature -- if you haven't already enabled the build cache for your monorepo, see [Enabling build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) > . Enable the experiment[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#enable-the-experiment "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- In `common/config/rush/experiments.json`, enable the `"phasedCommands"` experiment. { "phasedCommands": true} Define phases[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#define-phases "Direct link to heading") ----------------------------------------------------------------------------------------------------------------- In `common/config/rush/command-line.json`, add a section `"phases"`, as follows: { "phases": [ { /** * The name of the phase. Note that this value must start with the \"_phase:\" prefix. */ "name": "_phase:build", /** * The dependencies of this phase. */ "dependencies": { "upstream": ["_phase:build"] }, /** * Normally Rush requires that each project's package.json has a \"scripts\" entry matching the phase name. To disable this check, set \"ignoreMissingScript\" to true. */ "ignoreMissingScript": true, /** * By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is set to \"true\", Rush will return a zero exit code if warnings occur during the execution of this phase. */ "allowWarningsOnSuccess": false }, { "name": "_phase:test", "dependencies": { "self": ["_phase:build"] }, "ignoreMissingScript": true, "allowWarningsOnSuccess": false } ]} In this example, we define two phases -- `_phase:build` and `_phase:test`. The `_phase:build` operation depends on the `_phase:build` operation of its upstream projects (using the traditional Rush dependency graph). The `_phase:test` operation does not depend on any upstream projects, but requires the `_phase:build` operation of its _own_ project to be completed first. Note that phase names must start with `_phase:`. Individual projects can choose not to implement a phase (if `ignoreMissingScript` is enabled), but they cannot define their own phases, or change the dependencies of phases. This ensures that phases will behave consistently within your monorepo, regardless of what subset of projects you are building. Redefine the build and test commands[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#redefine-the-build-and-test-commands "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------- In `common/config/rush/command-line.json`, in the `"commands"` section, redefine the `"build"` command to be a `phased` command instead of a `bulk` command, and specify what phases you would like it to run. In the example below we also define a `"test"` command. { "commands": [ { "commandKind": "phased", "name": "build", "phases": ["_phase:build"], "enableParallelism": true, "incremental": true }, // No need to define "rebuild", by default, it is the same as build // but with incremental=false. { "commandKind": "phased", "name": "test", "summary": "Build and test all projects.", "phases": ["_phase:build", "_phase:test"], "enableParallelism": true, "incremental": true }, { "commandKind": "phased", "name": "retest", "summary": "Build and test all projects.", "phases": ["_phase:build", "_phase:test"], "enableParallelism": true, "incremental": false } ]} This command definition shows off another useful feature of phased builds: we can create our "phase" building blocks and then build commands out of them. Instead of `rush build` running builds and tests for all projects, we can define `rush build` to mean "build everything without tests", and `rush test` to mean "build everything and run tests". Assign parameters to phases[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#assign-parameters-to-phases "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- If you have defined any custom parameters for your build command in `command-line.json`, you'll now need to associate them to phases, so Rush knows which phases can accept your parameter. Here are some examples: { "parameters": [ { "longName": "--production", "parameterKind": "flag", "description": "Perform a production build, including minification and localization steps", "associatedCommands": ["build", "rebuild", "test", "retest"], "associatedPhases": ["_phase:build"] }, { "longName": "--update-snapshots", "parameterKind": "flag", "description": "Update unit test snapshots for all projects", "associatedCommands": ["test", "retest"], "associatedPhases": ["_phase:test"] } ]} Here, we've defined one flag (`--production`) that can be specified on all 4 variations of our build command, but it will only be passed to the _build_ phase. And, we've defined anothe flag (`--update-snapshots`) that can be specified only on the `test` and `retest` commands, and is only passed to the `test` phase. So, if we were to execute this command: rush test --production --update-snapshots Rush will pass the `--production` parameter to the `_phase:build` script for each project, and then pass the `--update-snapshots` parameter to the `_phase:test` script for each project. Add the phase scripts to your projects[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#add-the-phase-scripts-to-your-projects "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------- Within the `package.json` file for every project in your monorepo, add the new `_phase:` scripts: { "scripts": { "_phase:build": "heft build --clean", "_phase:test": "heft test --no-build", "build": "heft build --clean", "test": "heft test --clean" }} The example above attempts to align developer expectations for the `build` and `test` commands: * Moving into the project folder and running `rushx build` cleans and builds the project, without testing. * Moving into the project folder and running `rushx test` cleans, builds, and tests the project. * Running `rush build --only ` cleans and builds the project, without testing. * Running `rush test --only ` cleans, builds, and tests the project. Where possible, for any custom phases you define, keep this pattern in mind -- what's important isn't that phases are implemented identically to rushx commands, but rather that `rush ` and `rushx ` produce similar results, if applicable. Some projects may not have any meaningful work to do for a phase, in which case you can define it as an empty operation (`""`), or leave it off entirely, if `ignoreMissingScript` was specified in the phase definition. Define per-phase output folder names[​](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#define-per-phase-output-folder-names "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------- Within the `rush-project.json` configuration file of each project (or, preferably, each rig profile), redefine your `operationSettings` so that each folder is specified in only one phase. For example: { "operationSettings": [ // Old configuration (before phases) { "operationName": "build", "outputFolderNames": ["lib", "lib-commonjs", "dist", "temp"] }, // New configuration (after phases) { "operationName": "_phase:build", "outputFolderNames": ["lib", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", "outputFolderNames": ["temp/coverage", "temp/jest-reports"] } ]} Note how there's no overlap between the output folders specified by `_phase:build` and `_phase:test` -- this is an important new requirement for phased builds. In general, it's not possible for Rush to reliably cache the output of an operation if that output can be modified by a different operation, so you should structure your operations such that if `_phase:build` produces a `"lib"` folder, no other operation will put output in that folder. > The phased builds feature is still under development. Feedback is welcome! > > Some relevant GitHub issues to follow: > > * [Design proposal: "phased" custom commands](https://github.com/microsoft/rushstack/issues/2300) > * [Enable the experiment](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#enable-the-experiment) * [Define phases](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#define-phases) * [Redefine the build and test commands](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#redefine-the-build-and-test-commands) * [Assign parameters to phases](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#assign-parameters-to-phases) * [Add the phase scripts to your projects](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#add-the-phase-scripts-to-your-projects) * [Define per-phase output folder names](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/#define-per-phase-output-folder-names) --- # 启用构建缓存(实验性) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#docusaurus_skipToContent_fallback) On this page Rush 一直支持 [增量分析](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/) 功能,它允许 `rush build` 来跳过一些自上次构建后没有文件修改的项目(该优化同样适用于自定义指令,只要在 **custom-commands.json** 中开启 `incremental` 即可)。然而,构建产物并没有并时刻保存,因此当切换到另外一个分支时,通常需要执行 rebuild 来重新构建。 Rush 中实验性的**构建缓存**将在每个项目的构建产物中创建一个 tar 文件,该文件会被缓存,如果 `rush build` 可以匹配到缓存,则会从缓存中读取该文件,从而避免了重新构建。这就可以显著提高构建速度,例如将一个 30 分钟的构建耗时缩短到 30 秒。缓存的键值是源文件和 NPM 依赖的哈希值,与增量分析的[基本规则](https://rushjs.io/zh-cn/pages/advanced/incremental_builds/) 相同。 构建缓存的文件将保存在两个地方: * **本地磁盘的缓存目录下。**这样做可以在切换分支时候不会丢掉数据,你甚至可以在机器上配置一个共享的缓存目录,其默认位置是 **common/temp/build-cache**. * **云端(可选)。**一般而言,CI 系统可以配置成允许写入云端存储,同时每个用户只有可读权限。例如,每次 PR 被合并到 `main` 分支时,CI 系统会以此为基准进行构建并将其上传到云上。这样,对于即使是 `git clone` 的开发者而言,他们的 `rush build` 也是非常快的。 > 构建缓存被认为是跳过构建的替代方案,一旦被启动,支持增量构建的指令将从缓存中读取数据,而不是之前的“跳过”。 如果项目没有配置构建缓存,或者故意的禁止掉构建缓存,将会使用默认的跳过。 启用本地磁盘缓存[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E5%90%AF%E7%94%A8%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E7%BC%93%E5%AD%98 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 在 [build-cache.json](https://rushjs.io/zh-cn/pages/configs/build-cache_json/) 中可以开启本地构建缓存,你可以从该页面拷贝或者使用 `rush init` 创建这个文件。 本地构建缓存有两个配置项: **common/config/rush/build-cache.json** { . . . /** * (必须)实验性 -当该值为 true 时将会启动构建缓存。 * * 可以查阅 https://rushjs.io/pages/maintainer/build_cache/ 了解更多 */ "buildCacheEnabled": true, /** * (必须)选择哪些项目的构建产物需要被缓存。 * * 可能的值:"local-only","azure-blob-storage","amazon-s3" */ "cacheProvider": "local-only", . . .} > **升级提示:**早期版本的该功能需要在 **experiments.json** 中设定 `"buildCache": true`. 这个配置项已经被 **build-cache.json** 下的 `"buildCacheEnabled"` 替代。 配置项目的输出目录[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9B%AE%E7%9A%84%E8%BE%93%E5%87%BA%E7%9B%AE%E5%BD%95 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 当你运行 `rush rebuild --verbose` 时,会看到如下警告: Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching. 构建缓存需要知道哪些目录需要被存储在 tar 的压缩包中,这些细节可能由于工具链的不同而不同,因此每个项目都需要使用 [rush-project.json](https://rushjs.io/zh-cn/pages/configs/rush-project_json/) 来单独配置。 例如: **/config/rush-project.json** . . . /** * 指定你的工具链的产物输出目录,如果此字段开启,Rush 构建缓存将从缓存中恢复这些目录。 * * 字符串是项目根目录下的目录名,这些项目不应被 Git 记录到,并且必须不能包含符号链接。 */ "projectOutputFolderNames": ["lib", "dist"] . . .} 建议使用 [rig 包](https://rushstack.io/pages/heft/rig_packages/) 来避免每个项目目录中都拷贝一份。 测试构建缓存[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E6%B5%8B%E8%AF%95%E6%9E%84%E5%BB%BA%E7%BC%93%E5%AD%98 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------- 当开启缓存后项目的输出日志示例为: $ rush rebuild --verbose. . .==[ example-project ]==============================================[ 1 of 5 ]==This project was not found in the build cache.Invoking: heft test --clean. . .Caching build output folders: libSuccessfully set cache entry."example-project" completed successfully in 11.27 seconds. 当第二次执行相同的命令时,Rush 会将压缩包解压,而不是再次执行构建任务。 $ rush rebuild --verbose. . .==[ example-project ]==============================================[ 1 of 5 ]==Build cache hit.Clearing cached folders: lib, distSuccessfully restored output from the build cache.example-project was restored from the build cache. 注意 `rush rebuild` 将不会再读取缓存。将 [`RUSH_BUILD_CACHE_WRITE_ALLOWED`](https://rushjs.io/zh-cn/pages/configs/environment_vars/) 的环境变量设置为 `0` 可以禁止在 `rush rebuild` 时阶段写入缓存, 默认而言,缓存的 tar 压缩包存储在 **common/temp/build-cache** 目录中,因此可以被 `rush purge` 删除。 启用云端存储[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E5%90%AF%E7%94%A8%E4%BA%91%E7%AB%AF%E5%AD%98%E5%82%A8 "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------------- 目前 `cacheProvider` 有三个选项:[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E7%9B%AE%E5%89%8D-cacheprovider-%E6%9C%89%E4%B8%89%E4%B8%AA%E9%80%89%E9%A1%B9 "Direct link to heading") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * `"local-only"`:不启用云端存储,压缩包只保存在本地磁盘上 * `"azure-blob-storage"`:Microsoft Azure [blob storage container](https://docs.microsoft.com/en-us/azure/storage/blobs/) * `"amazon-s3"`:Amazon [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) (以上能力由 [modeled as Rush plugins](https://github.com/microsoft/rushstack/tree/main/rush-plugins) . 自定义的云存储服务可参考该插件实现) 例如,这里是如何配置 Azure blob 容器的方法: **common/config/rush/build-cache.json** { . . . /** * (必须)实验性的 - 设定为 true 启用构建缓存功能。 * * 更多信息可参考 https://rushjs.io/pages/maintainer/build_cache/ */ "buildCacheEnabled": true, /** * (必须)选择哪些项目的构建产物需要被缓存。 * * 可能的值:"local-only","azure-blob-storage","amazon-s3" */ "cacheProvider": "azure-blob-storage", /** * 设定 "azure-blob-storage" 时使用此配置 */ "azureBlobStorageConfiguration": { /** * (必须) Azure 账户名 */ "storageAccountName": "example", /** * Azure 存储账户中的容器名称 */ "storageContainerName": "my-container" /** * 当其值为 true 时候,允许像 cache 中写入 * 默认为 false */ "isCacheWriteAllowed": false . . . 注意,当设定 `"isCacheWriteAllowed": false` 时,可以防止普通用户写入容器。(稍后会使用环境变量覆盖此配置,以便 CI 任务能够写入容器。) 用户权限[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------- 如果你的仓库并不关心安全性,那么你可以简单地配置容器以允许匿名访问。容器可以通过包含随机字符串的 HTTPS 协议的 URL 来访问,这个 URL 很难背猜到,除非其他人可以在 Git 仓库中查看。这点通过[隐蔽性来保障安全](https://en.wikipedia.org/wiki/Security_through_obscurity) 。 更安全的组织方式是对于即使只读的情况也要用户认证,Rush 提供了 [rush update-cloud-credentials](https://rushjs.io/zh-cn/pages/commands/rush_update-cloud-credentials/) 指令来让用户进行更简单的配置: $ rush update-cloud-credentials --interactiveRush Multi-Project Build Tool 5.45.6 (unmanaged) - https://rushjs.ioNode.js version is 12.20.1 (LTS)Starting "rush update-cloud-credentials" ╔═════════════════════════════════════════════════════════════════════════╗ ║ To sign in, use a web browser to open the page ║ ║ https://microsoft.com/devicelogin and enter the code XAYBQEGRK ║ ║ to authenticate. ║ ╚═════════════════════════════════════════════════════════════════════════╝ 认证信息会被保存在用户的主目录下的 `~/.rush-user/credentials.json`. CI 设置[​](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#ci-%E8%AE%BE%E7%BD%AE "Direct link to heading") --------------------------------------------------------------------------------------------------------------- 通常配置下,用户只有只读权限,缓存通常被一个账号自动更新。例如,每次 PR 被合并到 `main` 后会执行一个 CI 任务。在上述事例中,`"isCacheWriteAllowed": false` 是为了防止了用户写入缓存。CI 任务可以通过设置 [RUSH\_BUILD\_CACHE\_WRITE\_ALLOWED](https://rushjs.io/zh-cn/pages/configs/environment_vars/) 环境变量来覆盖此配置,并通过 [RUSH\_BUILD\_CACHE\_CREDENTIAL](https://rushjs.io/zh-cn/pages/configs/environment_vars/) 环境变量来提供认证信息。 对于 Azure 而言,必须使用序列化的 SAS 口令来充当一个 query 参数,可以查看[此篇文章](https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview) 来获取更多信息,你可以通过 [设置 > 访问密钥](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) 页面来获取你的存储账号的访问密钥。 > 构建缓存功能依然在开发中,有意见或者建议请联系我们! > > 一些相关的 GitHub 提问: > > * [Build cache feature #2393](https://github.com/microsoft/rushstack/issues/2393) > - the original feature spec > * [Build Cache: split apart RUSH\_BUILD\_CACHE\_WRITE\_CREDENTIAL #2642](https://github.com/microsoft/rushstack/issues/2642) > > * [Allow project config to specify non-build-related files #2618](https://github.com/microsoft/rushstack/issues/2618) > > * ["tar" exited with code 1 while attempting to create the cache entry #2622](https://github.com/microsoft/rushstack/issues/2622) > * [启用本地磁盘缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E5%90%AF%E7%94%A8%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E7%BC%93%E5%AD%98) * [配置项目的输出目录](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9B%AE%E7%9A%84%E8%BE%93%E5%87%BA%E7%9B%AE%E5%BD%95) * [测试构建缓存](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E6%B5%8B%E8%AF%95%E6%9E%84%E5%BB%BA%E7%BC%93%E5%AD%98) * [启用云端存储](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E5%90%AF%E7%94%A8%E4%BA%91%E7%AB%AF%E5%AD%98%E5%82%A8) * [目前 `cacheProvider` 有三个选项:](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E7%9B%AE%E5%89%8D-cacheprovider-%E6%9C%89%E4%B8%89%E4%B8%AA%E9%80%89%E9%A1%B9) * [用户权限](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90) * [CI 设置](https://rushjs.io/zh-cn/pages/maintainer/build_cache/#ci-%E8%AE%BE%E7%BD%AE) --- # 启用一些策略 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#docusaurus_skipToContent_fallback) On this page [rush-schema.json](https://github.com/microsoft/rushstack/blob/main/libraries/rush-lib/src/schemas/rush.schema.json) 是可以给 **rush.json** 中定义了一些额外配置项的 JSON 文件。 projectFolderMinDepth: 控制文件夹大小[​](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#projectfoldermindepth-%E6%8E%A7%E5%88%B6%E6%96%87%E4%BB%B6%E5%A4%B9%E5%A4%A7%E5%B0%8F "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Rush 仓库可能变得非常大,当你有很多项目时(可能有几个仓库),`projectFolderMinDepth` 非常利于你指定一个标准的目录结构,以便于你可以瞬间看到哪些文件夹包含可构建的项目,我们建议约定如下: * 仓库的顶层文件夹是 "类别文件夹"(例如:"**~/demo/libraries**") * 项目目录永远被签到在类别文件夹下(例如:"**~/demo/libraries/lib1**") * 项目文件夹永远处于第二级(例如:禁止嵌套成 "**~/demo/libraries/lib1/lib2**") * 交叉项目文件都永远被存储在公共文件夹中(例如:"**~/demo/common/docs**", "**~demo/common/scripts**" 等) * 没有其他例外 如果你想在 demo 项目尝试此政策,我们可以将项目移动到类别文件夹,比如: **~/demo/apps/application** **~/demo/libraries/lib1** **~/demo/libraries/lib2** 之后,在 **~/demo/rush.json** 中强制项目必须是第二级,比如: // 项目文件夹的最小深度 //(默认值为 1, 即要求路径名中不能有斜杠) "projectFolderMinDepth": 2, // 项目文件夹的最大深度 //(默认值为 2, 即要求路径名中只能有一个斜杠) "projectFolderMaxDepth": 2, allowedEmailRegExps: 避免私人邮件地址[​](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#allowedemailregexps-%E9%81%BF%E5%85%8D%E7%A7%81%E4%BA%BA%E9%82%AE%E4%BB%B6%E5%9C%B0%E5%9D%80 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Git 要求每一个 commit 必须有姓名和邮件地址,然而,Git 并没有办法校验这些字段,它们的默认从 PC 上全局进行获取,这很容易被忽略。当使用 Git 工作时,人们有时会使用不符合预期的邮箱来进行 commit. 如果仓库由 Github 托管,那么邮箱地址会立即可被 GitHub REST API 可查询的,这样做很容易受到垃圾邮件的侵扰。(GitHub 账户的隐私设置不会影响 "git commit") Rush 可以帮你解决问题,在 **rush.json** 的 "gitPolicy" 字段中允许你指定一系列邮箱匹配规则,这些规则是正则表达式。(由于它们是 JSON 字符串字面量,所以注意反斜杠的书写) "gitPolicy": { // Git commit 的允许的可用邮箱的匹配符 // 它们是不区分大小写的 JavaScript 正则表达式 // Example: ".*@example\\.com" "allowedEmailRegExps": [ // Require GitHub scrubbed e-mails "[^@]+@users\\.noreply\\.github\\.com" ], // 满足 allowedEmailRegExps 的示例,以 "Mr. Example" 来讲,其有效邮箱为 "mr-example@contoso.com" "sampleEmail": "mrexample@users.noreply.github.com" }, 当开发者执行 `rush install` 时,Rush 会检查邮箱地址是否符合匹配规则,如果不符合,会显示如下警告: $ rush installRush Multi-Package Build ToolChecking Git policy for this repository.Hey there! To keep things tidy, this repo asks you to submit your Git commmitsusing an e-mail like this pattern: [^@]+@users\.noreply\.github\.com...but yours is configured like this: Bob To fix it, you can use commands like this: git config --local user.name "Mr. Example" git config --local user.email "mrexample@users.noreply.github.com"Aborting, so you can go fix your settings. (Or use --bypass-policy to skip.) approvedPackagesPolicy: 检查新的 NPM 包[​](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#approvedpackagespolicy-%E6%A3%80%E6%9F%A5%E6%96%B0%E7%9A%84-npm-%E5%8C%85 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 你的团队中的是否存在一些人会经常发现一些振奋人心的库,并尝试将它添加到 package.json 中?但是当需要对外部代码进行法律和安全审查时,这种行为可能会马上不可控。**approvedPackagesPolicy** 功能可以在新的 NPM 包被引入时进行检查。 由于需要不同程度的安全审查(例如对外发布的产品与内部项目、内部库不同),Rush 区分了“审查类别”。这使得我们可以依据项目类别来批准一个包,然而当该包被应用在其他地方时仍然被提醒。 以[创建一个新仓库](https://rushjs.io/zh-cn/pages/maintainer/setup_new_repo/) 为基础,下面来看如何在 rush.json 中定义一些审查类别,用于“发布”项目与“内部项目”: { "rushVersion": "4.0.0", "npmVersion": "5.5.1", "nodeSupportedVersionRange": ">=8.9.0 <9.0.0", "approvedPackagesPolicy": { "reviewCategories": [ "published", "internal" ], // 我们不需要审查 @types 包,因为我们可以假定非类型的库已经被批准 "ignoredNpmScopes": [ "@types" ] }, "projects": [ { "packageName": "application", "projectFolder": "application", "reviewCategory": "internal" }, { "packageName": "lib1", "projectFolder": "lib1", "reviewCategory": "internal" }, { "packageName": "lib2", "projectFolder": "lib2", "reviewCategory": "published" } ]} 当你执行 `rush install` 时,会生成两个文件来报告你的依赖。这些文件应该添加到 Git 中,并且可以配置为需要审批后才能被修改: * **~/demo/common/config/rush/browser-approved-packages.json**: 该包被批准用在浏览器内使用,这通常比较严格,所以所有新包将被默认添加到这里。对于这些依赖而言,关注点在:_压缩后的体积有多大?_ _许可协议是什么?_ _是否存在安全性问题?_ * **~/demo/common/config/rush/nonbrowser-approved-packages.json**: 该包被批准用在除了浏览器的任何地方,这些包的关注点在于: _它是否会给扰乱 node\_modules 目录?_ _是否有其他功能类似的包?_ _它是另一个包的包装还是其中有有效的代码?_ 当执行完 `rush install` 后,**browser-approved-packages.json** 文件将会像这样: { "packages": [ { "name": "@microsoft/gulp-core-build", "allowedCategories": [ "internal" ] }, { "name": "@microsoft/node-library-build", "allowedCategories": [ "internal", "published" ] }, { "name": "gulp", "allowedCategories": [ "internal", "published" ] } ]} 对于这个示例而言,上述文件展示了外部依赖 **@microsoft/gulp-core-build** 在 一个内部项目的 package.json 文件中找到了(假设是 **~/demo/lib1**),但是没有在任何一个 "public" 项目中找到(例如 **~/demo/application**)。 Rush 没有办法判断一个 NPM 是否用于浏览器,因此对于那些不用于浏览器的文件,你必须手动将它们移动到 **browser-approved-packages.json** 内。 #### 审批的工作方式[​](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#%E5%AE%A1%E6%89%B9%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%96%B9%E5%BC%8F "Direct link to heading") `rush install` 执行时,文件的内容将来匹配当前 package.json 的内容,这个文件应该被提交到 Git 中。当开发者创建了一个 PR 时,PR diff 可以被用于触发一个特殊的审批。 * [projectFolderMinDepth: 控制文件夹大小](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#projectfoldermindepth-%E6%8E%A7%E5%88%B6%E6%96%87%E4%BB%B6%E5%A4%B9%E5%A4%A7%E5%B0%8F) * [allowedEmailRegExps: 避免私人邮件地址](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#allowedemailregexps-%E9%81%BF%E5%85%8D%E7%A7%81%E4%BA%BA%E9%82%AE%E4%BB%B6%E5%9C%B0%E5%9D%80) * [approvedPackagesPolicy: 检查新的 NPM 包](https://rushjs.io/zh-cn/pages/maintainer/setup_policies/#approvedpackagespolicy-%E6%A3%80%E6%9F%A5%E6%96%B0%E7%9A%84-npm-%E5%8C%85) --- # 启用 Prettier | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#docusaurus_skipToContent_fallback) On this page Rush 中的[格式化策略](https://rushstack.io/pages/heft_tasks/eslint/) 推荐使用 [Prettier](https://prettier.io/) 来确保代码的一致性,该方法下,ESLint 和 Prettier 具有互补的作用: 推荐的 ESLint 使用方式: * ESLint 通过一组规则来保障代码的规范性。 _例如:“函数名应该使用骆驼式命名”。_ * 修复这些问题可能会导致测试失败或者 API 不符合约定,ESLint 可能会导致构建失败。 * 规则是高度可定制的,不同的项目可能需要不同的规则。 * 因此,我们建议在不同的项目中分开调用 ESLint,作为构建该项目的一部分。 推荐的 Prettier 使用方式: * Prettier 可以优化代码格式。 _例如:缩进和逗号放置_ * 修复这些问题永远不应该影响代码含义,Prettier 可以自动运行并且不可见。 * Prettier 不建议自定义,一个规范就够了。 * 因此,我们建议将 Prettier 应用到整个项目中。 在这篇文章中,我们将说明如何配置 Prettier, 最终让它在 `git commit` 时自动运行。我们也建议开发者安装 [Prettier 的 VS Code 插件](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) , 它会在每次保存时自动格式化文件。 准备 Prettier[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#%E5%87%86%E5%A4%87-prettier "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------- 我们处理 Git 钩子之前,首先配置 Prettier, 并以此让你的文件格式化。 1. 由于 Prettier 的运行范围是所有文件,它的[配置文件](https://prettier.io/docs/en/configuration.html) 应该放到仓库的根目录上,Prettier 允许多个不同的配置文件名,但 JSON 不能写注释,因此推荐使用 `.js` 文件扩展名: **/.prettierrc.js** // 配置可参考 https://prettier.io/en/configuration.htmlmodule.exports = { // 使用较大的打印宽度,因为 Prettier 的换行设置似乎是针对没有注释的 JavaScript. printWidth: 110, // 使用 .gitattributes 来管理换行 endOfLine: 'auto', // 单引号代替双引号 singleQuote: true, // 对于 ES5 而言, 尾逗号不能用于函数参数,因此使用它们只能用于数组 trailingComma: 'none'}; 2. 你也可以使用 `.prettierignore` 来告知 Prettier 跳过哪些文件,注意,Git 钩子将会自动过滤掉哪些没有被 commit 的文件,然而诸如 [Prettier extension for VS Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) 等其他工具并不是如此,因此建议将 `.prettierignore` 中的内容与 `.gitingore` 一致: **/.prettierignore** #-------------------------------------------------------------------------------------------------------------------# 保持与 .gitignore 同步#-------------------------------------------------------------------------------------------------------------------👋 (此处将你的 .gitignore 文件内容复制粘贴过来) 👋#-------------------------------------------------------------------------------------------------------------------# Prettier 通用配置#-------------------------------------------------------------------------------------------------------------------# Rush 文件common/changes/common/scripts/common/config/CHANGELOG.*# 包管理文件pnpm-lock.yamlyarn.lockpackage-lock.jsonshrinkwrap.json# 构建产物distlib# 在 Markdown 中,Prettier 将会对代码块进行格式化,这会影响输出*.md 3. 配置完后,下一步需要手动调用 Prettier 并将代码格式化,你可以通过查看 Git diff 来调整 `.prettierignore` 配置,如下: # 安装 prettier$ npm install --global prettier# 进入仓库根目录$ cd my-repo# 查看 Prettier 会操作哪些文件;并据此该个命令来调整你的 .prettierignore 规则$ prettier . --list-different# 当你准备好时,这个命令将会批量修复所有的源文件$ prettier . --write 如果你的仓库有很多文件,那么第一次执行 Prettier 时,可能会生成一个巨大的 diff. 在这种情况下,你可以将这些变更合并到一个 PR 中,这样可以方便下一步的审核。 Git 钩子的要求[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#git-%E9%92%A9%E5%AD%90%E7%9A%84%E8%A6%81%E6%B1%82 "Direct link to heading") ----------------------------------------------------------------------------------------------------------------------------------------------------- 这次我们将实现一个 [Git 钩子](https://rushjs.io/zh-cn/pages/maintainer/git_hooks/) ,它会在 commit 时自动调用 Prettier。 注意,`git commit` 是最关键的操作,因此需要保持它快速且可靠,开发者也许想在没有运行 `rush install` 前提交更改。在某些情况下,`rush install` 不能被执行,因为分支可能处于工作状态,因此我们的 Git 钩子不应该依赖于 monorepo 的安装机制。 我们可以使用 Rush 的 [install-run.js](https://rushjs.io/zh-cn/pages/maintainer/enabling_ci_builds/) 脚本来启动按需 Prettier, 但是它会涉及到一些依赖: * `pretty-quick`: 为了加速操作,我们使用 [pretty-quick](https://www.npmjs.com/package/pretty-quick) 来计算出需要 commit 的文件,只有这些文件需要处理,Prettier 不能处理这一部分,因为它不能与 Git 交互。 * `prettier`: `pretty-quick` 的依赖 Prettier. * **可选插件:**如果你使用了 Prettier 的任何插件,它们需要被 `prettier` 解析到。 对于上述情况,Rush 的 "autoisntaller" 功能提供了一个替代 **install-run.js** 的方案。 启用 Git 钩子[​](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#%E5%90%AF%E7%94%A8-git-%E9%92%A9%E5%AD%90 "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------------------------- 1. 首先,使用 [rush init-autoinstaller](https://rushjs.io/zh-cn/pages/commands/rush_init-autoinstaller/) 来创建一个自动安装程序: # 下面指令会创建 common/autoinstallers/rush-prettier/package.json 文件$ rush init-autoinstaller --name rush-prettier 2. 安装依赖并创建 **pnpm-lock.yaml** 文件: $ cd common/autoinstallers/rush-prettier# 可以不过下面指令来安装依赖, 也可以直接编辑 package.json 中 'dependencies" 字段$ pnpm install prettier$ pnpm install pretty-quick# (如果你需要插件,也可以安装它们)# 完成上面步骤后,执行以下步骤来确保 common/autoinstallers/rush-prettier/ppnpm-lock.yaml 文件是最新的$ rush update-autoinstaller --name rush-prettier 3. 现在,在 **common/autoinstallers/rush-prettier** 应该有两个文件:**package.json** 和 **pnpm-lock.yaml**, 将它们添加到 Git 仓库中,并且提交。 $ git add package.json$ git add pnpm-lock.yaml$ git commit -m "Create rush-prettier autoinstaller" 4. 之后,我们可以创建自定义指令 `rush prettier` 来唤起 `pretty-quick`, 将这些指令添加到 **command-line.json** 文件中: **common/config/rush/command-line.json** . . . "commands": [ { "name": "prettier", "commandKind": "global", "summary": "Used by the pre-commit Git hook. This command invokes Prettier to reformat staged changes.", "safeForSimultaneousRushProcesses": true, "autoinstallerName": "rush-prettier", // 它将会唤起 common/autoinstallers/rush-prettier/node_modules/.bin/pretty-quick "shellCommand": "pretty-quick --staged" } . . .\ \ `"autoinstallerName": "rush-prettier"` 确保在执行 shell 命令之前安装 Prettier, `pretty-quick --staged` 将会在 **common/autoinstallers/rush-prettier** 目录中执行。\ \ 5. 保存完变化后,来通过执行 `rush prettier` 来测试自定义指令,你可以看到 Rush 会在第一次运行时自动执行一些步骤:(1) 安装正确的 Rush 版本;(2) 安装正确的 PNPM 版本;(3) 安装 **rush-prettier/package.json** 和它的依赖;(4) 调用 `pretty-quick --staged`。但当第二次运行时,第一步和第二步已经完成,所以步骤 (4) 不会有任何延迟。\ \ 6. 最后一步是添加一个 Git 钩子,该钩子在 `git commit` 执行完后自动调用 `rush prettier`, 为了实现该功能,在 **common/git-hooks** 目录下创建 **pre-commit** 文件:\ \ **common/git-hooks/pre-commit**\ \ #!/bin/sh# 在 "git commit" 执行时,该钩子会被调用,并且没有参数。如果该钩子想要阻止提交,那么它应该以返回非零状态推出。# Invoke the "rush prettier" custom command to reformat files whenever they# are committed. The command is defined in common/config/rush/command-line.json# and uses the "rush-prettier" autoinstaller.# 当 commit 时调用自定义指令 "rush prettier" 来重新格式化文件。该指令定义在 common/config/rush/command-line.json, 并通过 "rush-prettier" 自动安装并使用。node common/scripts/install-run-rush.js prettier || exit $?\ \ 7. 安装钩子,运行 `rush install`。\ \ 8. 在最后合并 PR 之前,你可能想运行 `prettier . --write` 来重新格式化安装钩子之前的所有文件。\ \ \ 完成!当 Git 中的更改被提交时,它们将被自动格式化。\ \ * [准备 Prettier](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#%E5%87%86%E5%A4%87-prettier)\ \ * [Git 钩子的要求](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#git-%E9%92%A9%E5%AD%90%E7%9A%84%E8%A6%81%E6%B1%82)\ \ * [启用 Git 钩子](https://rushjs.io/zh-cn/pages/maintainer/enabling_prettier/#%E5%90%AF%E7%94%A8-git-%E9%92%A9%E5%AD%90) --- # pnpm-config.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/pnpm-config_json/#docusaurus_skipToContent_fallback) > 注意:此配置文件在 Rush 5.79.0 中引入。在此版本之前,PNPM 设置存储在 **rush.json** 文件的 `"pnpmOptions"` 部分。为了向后兼容,Rush 5 仍然接受 `"pnpmOptions"` 部分。如果您正在升级旧的 monorepo,为了访问这些新的 PNPM 设置,必须手动删除 **rush.json** 文件中的 `"pnpmOptions"` 设置并创建 **pnpm-config.json** 文件。 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 **pnpm-config.json** 生成的模板: **common/config/rush/pnpm-config.json** /** * 此配置文件提供 PNPM 包管理器的特定设置。 * 更多文档可在 Rush 网站上找到:https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", /** * 如果为 true,那么 `rush install` 和 `rush update` 将使用 PNPM workspaces 功能进行安装, * 而不是采用旧模式,由 Rush 为每个项目的 node_modules 文件夹生成符号链接。 * * 使用工作区时,Rush 会生成一个 `common/temp/pnpm-workspace.yaml` 文件,引用要安装的所有本地项目。 * Rush 还将生成 `.pnpmfile.cjs` 插件,以实现 Rush 特定的功能,例如首选版本。用户的 `common/config/rush/.pnpmfile.cjs` * 会通过插件调用。 * * 强烈建议启用此选项。默认值为 false。 */ "useWorkspaces": true, /** * 此设置决定了 PNPM 在 `rush update` 期间如何选择版本号。 * 例如,假设 `lib-x@3.0.0` 依赖于 `"lib-y": "^1.2.3"`,其最新的主要版本为 `1.8.9` 和 `2.3.4`。 * `lowest-direct` 模式可能会选择 `lib-y@1.2.3`,而 `highest` 将选择 1.8.9,`time-based` 则会选择 * 在发布 `lib-x@3.0.0` 时与之兼容的最高版本,以确保此版本经过“lib-x”维护人员的测试。 * 对于本地工作区项目,`time-based` 模式类似于 `lowest-direct`,避免除非明确要求的升级。 * 虽然 `time-based` 是最稳健的选项,但在某些未实现优化的注册表(如 npmjs.com)上可能稍慢。 * * 重要提示:请注意,PNPM 8.0.0 最初默认为 `lowest-direct` 而非 `highest`, * 但 PNPM 在 8.6.12 版中更改了此决定,因为它让用户感到困惑。Rush 5.106.0 及更新版本 * 通过在 pnpm-config.json 或 .npmrc 中未明确设置 `resolutionMode` 时始终默认为 `highest` * 来避免此困惑,无论您使用的 PNPM 版本如何。 * * PNPM 文档:https://pnpm.io/npmrc#resolution-mode * * 可选值为:`highest`、`time-based` 和 `lowest-direct`。 * 默认值为 `highest`。 */ // "resolutionMode": "time-based", /** * 此设置决定 PNPM 是否会自动安装(非可选)缺失的 peer 依赖项,而不是报告错误。 * 这样可以避免在 package.json 中指定 peer 版本的麻烦,但在大型 monorepo 中通常会产生更严重的问题。 * 这是因为 peer 依赖行为本质上很复杂,比隐形启发式更容易排查明确版本的后果。 * 原始的 NPM RFC 讨论中指出了此功能的其他问题:https://github.com/npm/rfcs/pull/43 * 重要提示:在没有 Rush 的情况下,PNPM 8 及更新版本的默认设置为 true; * 但从 Rush 5.109.0 版开始,默认值始终为 false,除非在 pnpm-config.json 或 .npmrc 中指定 `autoInstallPeers`, * 而不管您的 PNPM 版本如何。 * PNPM 文档:https://pnpm.io/npmrc#auto-install-peers * 默认值为 false。 */ // "autoInstallPeers": false, /** * 如果为 true,则 Rush 在调用 PNPM 时将添加 `--strict-peer-dependencies` 命令行参数。 * 这会导致 `rush update` 在未满足 peer 依赖项的情况下失败,这是一种无效状态,可能导致构建失败或不兼容的依赖版本。 * (由于历史原因,JavaScript 包管理器通常不会将此无效状态视为错误。) * * PNPM 文档:https://pnpm.io/npmrc#strict-peer-dependencies * * 默认值为 false,以避免旧版兼容性问题。 * 强烈建议设置 `strictPeerDependencies=true`。 */ // "strictPeerDependencies": true, /** * 提供给 PNPM 的环境变量。 */ // "environmentVariables": { // "NODE_OPTIONS": { // "value": "--max-old-space-size=4096", // "override": false // } // }, /** * 指定 PNPM 存储的路径。可能有两种值: * * - `local` - 使用当前配置的临时文件夹下的 `pnpm-store` 文件夹:默认情况下为 `common/temp/pnpm-store`。 * - `global` - 使用 PNPM 的全局存储,它的优势是可以跨多个 repo 文件夹共享,但缺点是构建隔离性较差 * (例如,当两个 repo 使用不同的 PNPM 版本时可能出现错误或不兼容性) * * 在这两种情况下,可以通过环境变量 `RUSH_PNPM_STORE_PATH` 覆盖存储路径。 * * 默认值为 `local`。 */ // "pnpmStore": "global", /** * 如果为 true,则 `rush install` 将报告在未运行 `rush update` 的情况下对 PNPM 缩减文件进行手动修改的错误。 * * 此功能可防止由于手动编辑 PNPM 缩减文件(`pnpm-lock.yaml`)而引入的意外不一致。 * 启用此功能时,`rush update` 会将一个哈希值作为 YAML 注释添加到文件中,然后 `rush update` 和 `rush install` 会验证该哈希值。 * 请注意,这并不禁止手动修改,只是要求在此之后运行 `rush update`,以确保 PNPM 能够报告或修复任何潜在的不一致。 * * 在调用 `rush install` 时,可使用 `--bypass-policy` 命令行参数暂时禁用此验证。 * * 默认值为 false。 */ // "preventManualShrinkwrapChanges": true, /** * 当项目使用 `workspace:` 依赖另一个 Rush 项目时,PNPM 通常通过在 `node_modules` 下创建符号链接进行安装。 * 这通常效果不错,但在某些情况下,例如不同的 `peerDependencies` 版本,符号链接可能会导致问题,如不正确满足的版本。 * 对于这种情况,可以将依赖项声明为“injected”,使 PNPM 像从注册表中真实安装一样将其构建输出复制到 `node_modules`。 * 详情参见:https://rushjs.io/pages/advanced/injected_deps/ * * 使用 Rush subspaces 时,如果 `workspace:` 引用来自其他 subspace 的项目,这类版本问题更有可能发生。 * 这是因为符号链接将指向由另一个 PNPM 锁定文件安装的独立 `node_modules` 树。 * 全面解决方案是启用 `alwaysInjectDependenciesFromOtherSubspaces`,这会自动将其他 subspace 中的所有项目视为 * injected 依赖项,而无需手动配置它们。 * * 注意:请谨慎使用 —— 如果有太多依赖成为 injected,过多的文件复制会减慢 `rush install` 和 `pnpm-sync` 操作。 * * 默认值为 false。 */ "alwaysInjectDependenciesFromOtherSubspaces": false, /** * 定义 `pnpm-lock.yaml` 文件的政策。 */ "pnpmLockfilePolicies": { /** * 此策略会导致 "rush update" 在 `pnpm-lock.yaml` 中包含任何 SHA1 完整性哈希时报告错误。 * * 对于每个 NPM 依赖项,`pnpm-lock.yaml` 通常会存储一个 `integrity` 哈希。 * 虽然它的主要目的是检测网络请求损坏或截断,但此哈希值还可作为安全指纹,防止攻击者替换恶意的 tarball, * 例如,如果配置错误的 .npmrc 导致机器意外地从 npmjs.com 下载与私有 NPM 注册表匹配的包名和版本。 * NPM 最初使用 SHA1 哈希;由于攻击者可以轻松地制作具有匹配指纹的 tarball,因此它不安全。 * 因此,NPM 后来弃用了 SHA1,并改用加密强度高的 SHA512 哈希。 * 尽管如此,SHA1 哈希偶尔会在 "rush update" 期间重新出现,例如由于缺少元数据回退(https://github.com/orgs/pnpm/discussions/6194) * 或者迁移不完整的私有注册表。 * `disallowInsecureSha1` 策略防止这种情况发生,避免潜在的安全/合规警报。 */ // "disallowInsecureSha1": { // /** // * 启用 "disallowInsecureSha1" 策略。默认值为 false。 // */ // "enabled": true, // // /** // * 在极少数情况下,私有 NPM 注册表可能会继续为非常旧的包版本提供 SHA1 哈希, // * 这可能是由于缓存问题或数据库迁移故障。 // * 为避免因整个 monorepo 禁用 "disallowInsecureSha1" 策略, // * 可以单独忽略有问题的包版本。`exemptPackageVersions` 键是包名称, // * 数组值列出确切的版本号。 // */ // "exemptPackageVersions": { // "example1": ["1.0.0"], // "example2": ["2.0.0", "2.0.1"] // } // } }, /** * "globalOverrides" 设置为覆盖 monorepo 工作区中所有项目的所有依赖项的版本选择提供了简单的机制。 * 这些设置将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件的 `pnpm.overrides` 字段中。 * * 优先顺序:`.pnpmfile.cjs` 拥有最高优先级,然后是 `unsupportedPackageJsonSettings`、`globalPeerDependencyRules`、 * `globalPackageExtensions`,`globalOverrides` 拥有最低优先级。 * * PNPM 文档:https://pnpm.io/package_json#pnpmoverrides */ "globalOverrides": { // "example1": "^1.0.0", // "example2": "npm:@company/example2@^1.0.0" }, /** * `globalPeerDependencyRules` 设置为 `strictPeerDependencies=true` 安装期间报告的验证错误提供了各种设置。 * 这些设置将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件的 `pnpm.peerDependencyRules` 字段中。 * * 优先顺序:`.pnpmfile.cjs` 拥有最高优先级,然后是 `unsupportedPackageJsonSettings`、`globalPeerDependencyRules`、 * `globalPackageExtensions`,`globalOverrides` 拥有最低优先级。 * * https://pnpm.io/package_json#pnpmpeerdependencyrules */ "globalPeerDependencyRules": { // "ignoreMissing": ["@eslint/*"], // "allowedVersions": { "react": "17" }, // "allowAny": ["@babel/*"] }, /** * `globalPackageExtension` 设置提供了一种方法来修补 monorepo 中任何 PNPM 依赖项的 package.json 字段。 * 这些设置将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件的 `pnpm.packageExtensions` 字段中。 * `globalPackageExtension` 设置具有与 `.pnpmfile.cjs` 类似的功能,但没有可执行脚本的缺点(不确定性、不可靠的缓存、性能问题)。 * * 优先顺序:`.pnpmfile.cjs` 拥有最高优先级,然后是 `unsupportedPackageJsonSettings`、`globalPeerDependencyRules`、 * `globalPackageExtensions`,`globalOverrides` 拥有最低优先级。 * * PNPM 文档:https://pnpm.io/package_json#pnpmpackageextensions */ "globalPackageExtensions": { // "fork-ts-checker-webpack-plugin": { // "dependencies": { // "@babel/core": "1" // }, // "peerDependencies": { // "eslint": ">= 6" // }, // "peerDependenciesMeta": { // "eslint": { // "optional": true // } // } // } }, /** * `globalNeverBuiltDependencies` 设置会抑制指定 NPM 依赖项的 `preinstall`、`install` 和 `postinstall` 生命周期事件。 * 这对于实践较差的脚本非常有用,例如在没有重试的情况下下载大型二进制文件,或尝试调用 C++ 编译器等操作系统工具。 * (PNPM 的术语将这些生命周期事件称为“构建”包;它与构建系统操作 `rush build` 或 `rushx build` 无关。) * 这些设置将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件的 `pnpm.neverBuiltDependencies` 字段中。 * * PNPM 文档:https://pnpm.io/package_json#pnpmneverbuiltdependencies */ "globalNeverBuiltDependencies": [ // "fsevents" ], /** * `globalAllowedDeprecatedVersions` 设置抑制 NPM 注册表报告为已弃用的包版本的安装警告。 * 如果弃用的包是尚未发布修复的外部包的间接依赖项,这会很有用。 * 这些设置将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件的 `pnpm.allowedDeprecatedVersions` 字段中。 * * PNPM 文档:https://pnpm.io/package_json#pnpmalloweddeprecatedversions * * 如果您正在努力消除已弃用的版本,最好在各个 Rush 项目的 package.json 文件中指定 `allowedDeprecatedVersions`。 */ "globalAllowedDeprecatedVersions": { // "request": "*" }, /** * (此字段是机器生成的) "globalPatchedDependencies" 字段由 `rush-pnpm patch-commit` 命令自动更新。 * 它是一个字典,其中键是 NPM 包名称和确切版本,值是关联补丁文件的相对路径。 * * PNPM 文档:https://pnpm.io/package_json#pnpmpatcheddependencies */ "globalPatchedDependencies": { }, /** * (自担风险使用) 这是一个自由形式的属性集合,将被复制到 Rush 在安装过程中生成的 `common/temp/package.json` 文件中。 * 这为实验新的 PNPM 功能提供了一种方法。 * 这些设置将覆盖与给定 JSON 字段关联的任何其他 Rush 配置,除了 `.pnpmfile.cjs`。 * * RUSH 维护人员不支持此设置的使用,可能导致 RUSH 故障。 * 如果您遇到缺少的 PNPM 设置,认为应该得到支持,请创建 GitHub 问题或 PR。 * 请注意,Rush 不旨在支持所有可能的 PNPM 设置,而是提供一种经过实战检验的安装策略, * 以确保大型团队和项目的良好体验。 */ "unsupportedPackageJsonSettings": { // "dependencies": { // "not-a-good-practice": "*" // }, // "scripts": { // "do-something": "echo Also not a good practice" // }, // "pnpm": { "futurePnpmFeature": true } }} --- # command-line.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/command-line_json/#docusaurus_skipToContent_fallback) On this page 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 为 monorepo 生成的模版下的 **command-line.json** 文件: **common/config/rush/command-line.json** /** * 该配置项配置 "rush" 的自定义命令。 * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", /** * 自定义“命令”为命令行引入了新的变量。可以通过 "rush --help", "rush my-bulk-command --help", 或 * "rush my-global-command --help" 来看更多的帮助。 */ "commands": [ // { // /** // * (必须)决定自定义命令的类型 // * Rush 的 "bulk" 命令会在每个项目中单独执行。Rush 会寻找每个项目内的 package.json 文件下的 // * 符合命令的 "script' 脚本。默认情况下,命令会按照依赖图在仓库内的每个项目执行(与 "rush build" // * 工作流类似)。 // * 可以限定一些子项目,例如使用 "--to" 或 "--from" 参数。 // */ // "commandKind": "bulk", // // /** // * (必须) 输入的名称被视为命令行的一部分。 这也项目内 package.json 中 // * "scripts" 的钩子。 // * 该名称必须是大写字母、数字和下划线的组合,它应当包含一个英语动词(例如: "deploy") // * 使用连字符来分割单词(例如: "upload-docs")。一组相关的命令可以以冒号为前缀。 // * (例如:"docs:generate", "docs:deploy", "docs:serve" 等等) // * // * 注意,如果此处覆盖了 "rebuild" 命令,它就与 "build" 指令分割开了, // * 同时会调用 "rebuild" 而不是 "build" 脚本。 // */ // "name": "my-bulk-command", // // /** // * (必须)该自定义命令的简短总结,它将被展示在命令行帮助中。 // * 例如 "rush --help". // */ // "summary": "Example bulk custom command", // // /** // * 当打印命令行帮助时的更细节的描述。(例如:"rush --help my-command") // * 如果为空,则使用 "summary" 字段。 // * // * 无论何时引入指令或参数,花些时间来写一些有意义的文档会给开发体验带来巨大提升。 // */ // "description": "This is an example custom command that runs separately for each project", // // /** // * Rush 操作需要一个锁文件来防止同一个仓库被多个指令同时处理。(例如:同时执行 "rush install" 和 // * "rush build" 会出错)。如果你的命令可以与其他操作同时执行,那么设定 "safeForSimultaneousRushProcesses" // * 为 true 来禁用这种保护。 // * // * 对于调用其他 Rush 命令的脚本而言,这一点是尤为需要的。 // */ // "safeForSimultaneousRushProcesses": false, // // /** // * (必须)如果为真,那么该指令可以安全的并行执行,例如同时在多个项目内执行。 // * 与 "rush build" 类似,无论是否开启并行,在其依赖完成前,该项目都不会 // * 开始执行。 // */ // "enableParallelism": false, // // /** // * 通常项目会依照依赖顺序处理,对于某个项目而言,直到其依赖处理完成后才会处理 // * 该项目。但对于某个特定的操作而言,该限制并不适用,例如 "clean" 任务来删除 // * 输出文件。在这种情况下,可以设定 "ignoreDependencyOrder" 为 true 来 // * 提高并行度。 // */ // "ignoreDependencyOrder": false, // // /** // * 通常情况下,Rush 会要求每个项目的 package.jso 文件下都有对应的 "script" // * 匹配自定义指令名。设定 "ignoreMissingScript" 为 true 可以禁止此检查, // * 缺少相应定义的项目会被跳过。 // */ // "ignoreMissingScript": false, // // /** // * 当调用 shell 脚本时,Rush 将用以下方法来从警告信息中区分出错误信息: // * - 如果脚本返回非 0 状态码,那么 Rush 会认为存在“一个或多个错误”,之后以红色输 // * 出错误信息,它会阻止 Rush 继续处理其他项目。 // * - 如果脚本的状态码为 0, 但是向 stderr 流写入了一些数据,Rush 会认为存在 “一 // * 个或多个警告”,之后以黄色输出警告信息,但是不会阻止 Rush 继续处理其他项目。 // * // * 因此,警告信息不会阻碍本地开发,但在 Rush 的设计中,当存在任何警告或报错信息, // * Rush进程会返回非 0 状态码,进而会导致 CI 任务失败, // * 在一个活跃的 monorepo 中,我们发现如果你的主干分支允许警告,那么就会在不经 // * 意间交给开发者忽略警告,这很快会导致存在非常多“预期”的警告信息以至于这些信息 // * 没有任何提示性作用的状态。 // * // * 有时,尽管操作是成功的,但由于某个行为存在问题的任务会被写入到 stderr 流中。 // * 在这种情况下,强烈建议修复这个任务,然而,你可以设定 allowWarningsInSuccessfulBuild // * =true 来进行变通,这会导致 Rush 只会对错误信息才返回非 0 的状态码。 // * // * 注意: 默认值为 false. 在 5.7.x 以及更旧的版本中,默认值为 true. // */ // "allowWarningsInSuccessfulBuild": false, // // /** // * 该参数为 true 时,其行为类似于内置的 "build" 命令的增量构建。 // */ // "incremental": false, // // /** // * (实验性)通常 Rush 会在命令完成后终止。如果该值被设定为 "true", Rush 会进入 // * 到一个监听指定项目文件的循环中。当检测到文件变动时,指令会被唤醒,且其范围是选 // * 中的项目以及依赖。 // * // * 更多信息,可以参考“使用监听模式”一文。 // */ // "watchForChanges": false, // // /** // * (实验性)对于该行为禁止掉缓存。如果该命令会影响到项目自身目录以外的状态时,该 // * 命令很有用。 // */ // "disableBuildCache ": false // }, // // { // /** // * (必须)自定义指令的类型。 // * Rush 的 "global" 指令会在整个项目内唤醒一次。 // */ // "commandKind": "global", // // "name": "my-global-command", // "summary": "Example global custom command", // "description": "This is an example custom command that runs once for the entire repo", // // "safeForSimultaneousRushProcesses": false, // // /** // * (必须)一个使用操作系统 shell 调用的脚本。工作目录是含有 rush.json 的 // * 目录。如果自定义指令与该指令有关,那么它们的值应该被添加到字符串的尾部。 // */ // "shellCommand": "node common/scripts/my-global-command.js", // // /** // * 如果你的 "shellCommand" 依赖 NPM 包,那么推荐将其写成 Rush 内的一 // * 个项目,使得工作链可以正常构建。某些情况下该指令应该在没有首次执行 // * "rush build" 的情况下正常工作,推荐的方式是将该项目发布到 NPM 源 // * 上,并使用 common/scripts/install-run.js 来调用它。 // * // * 自动安装功能提供了另外一种可能:在 "common/autoinstallers" 下的目 // * 录都有一个 package.json 文件和 shrinkwrap 文件。在被调用前,Rush // * 会自动调用包管理器来安装这些依赖。自动下载有一个优势:即使所在的分支的 Autoinstallers have the // * "rush isntall" 出现了问题,它们也能正常工作,这使得该功能可以实现 // * Git 的钩子脚本。但是该功能也有一个缺点,它们不能用于构建项目,并且会增 // * 加仓库的安装量。 // * // * "autoinstallerName" 属性不能包含路径,并必须是一个有效的 NPM 包名。 // * 例如, "my-task" 是映射到 "common/autoinstallers/my-task/package.json" // * 的包名,当调用该 "shellCommand" 时,"common/autoinstallers/my-task/node_modules/.bin" // * 应当被添加到环境变量中。 // */ // // "autoinstallerName": "my-task" // } ], /** * 自定义“参数”给指定的 Rush 命令行指令引入了参数。 * 例如,你也许会给 "rush build" 命令增加 "production" 参数。 */ "parameters": [ // { // /** // * (必须)自定义参数的类型 // * "flag" 类型表明该参数的作用是一个开关。 // */ // "parameterKind": "flag", // // /** // * (必须)参数的全名。必须是小写并使用破折号分割。 // */ // "longName": "--my-flag", // // /** // * 该参数的缩写,该属性可选。它必须是在破折号后跟有一个 // * 大小写敏感的字母, // * // * 注意:推荐使用全名来增加可读性。缩写仅仅是为了方便。 // * 字母表很容易被占用完,并且不方便记忆,所以*仅仅*当 // * 遇到非常频繁的操作时才使用简写。 // */ // "shortName": "-m", // // /** // * (必须) 在命令帮助中显示的描述信息。 // * // * 无论何时引入指令或参数,花些时间来写一些有意义的文档会给开发体验带来巨大提升。 // */ // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", // // /** // * (必须)该列表内存储了这个参数可被哪些自定义指令或内置指令使用。 // */ // "associatedCommands": ["build", "rebuild"] // }, // // { // /** // * (必须)自定义参数的类型 // * 一个“字符串”类型的自定义命令行参数是指参数为一个简单的文本。 // */ // "parameterKind": "string", // "longName": "--my-string", // "description": "A custom string parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // // /** // * 参数名,在命令帮助中将被显示。 // * // * 例如,参数名一个 "--count", 其类型为 "NUMBER", 那么命令行 // * 帮助信息应该展示 "--count NUMBER". 该参数必须由大写字母、数字 // * 下划线组成,应该尽可能的短。 // */ // "argumentName": "SOME_TEXT", // // /** // * 当该属性为 true 时,参数必须包含在命令中。默认为 false. // */ // "required": false // }, // // { // /** // * (必须)自定义参数的类型 // * "choice" 参数类型是指参数必须是给定列表内的某个值。 // */ // "parameterKind": "choice", // "longName": "--my-choice", // "description": "A custom choice parameter for the \"my-global-command\" custom command", // // "associatedCommands": ["my-global-command"], // // /** // * 当该属性为 true 时,参数必须包含在命令中。默认为 false. // */ // "required": false, // // /** // * 正常情况下若某个参数被省略掉,那么它将不会被传到 shell 中。 // * 该属性用于插入一个默认值,若 "defaultValue" 定义后,参数永远会被 // * 传入到 shell 中,若未指定则使用默认值。该值必须是定义在可选列表中 // * 的一个。 // */ // "defaultValue": "vanilla", // // /** // * (必须)一系列用于选择的可选参数。 // */ // "alternatives": [ // { // /** // * 用于选择参数的一个可选值。 // * 例如,在 "--flavor vanilla" 使用了 "vanilla". // */ // "name": "vanilla", // // /** // * // * 在命令行帮助中显示的可选参数的详细描述。 // * // * 无论何时引入指令或参数,花些时间来写一些有意义的文档会给开发体验带来巨大提升。 // * // */ // "description": "Use the vanilla flavor (the default)" // }, // // { // "name": "chocolate", // "description": "Use the chocolate flavor" // }, // // { // "name": "strawberry", // "description": "Use the strawberry flavor" // } // ] // } ]} 参考[​](https://rushjs.io/zh-cn/pages/configs/command-line_json/#%E5%8F%82%E8%80%83 "Direct link to heading") ------------------------------------------------------------------------------------------------------------ * [可选参数](https://rushjs.io/zh-cn/pages/maintainer/custom_commands/) * [参考](https://rushjs.io/zh-cn/pages/configs/command-line_json/#%E5%8F%82%E8%80%83) --- # Cobuilds (experimental) | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#docusaurus_skipToContent_fallback) On this page Rush's "cobuild" feature (cooperative builds) provides a lightweight solution for distributing work across multiple machines. The idea is a simple extension of what you're already doing: just spawn multiple instances of the same CI pipeline on different machines, allowing them to share work via Rush's [build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) . For example, suppose your job runs `rush install && rush build`, and we launch this command on two machines. If machine #1 has already built a project, then machine #2 will skip that project, instead fetching the result from the build cache. In this way, the building gets divided between the two pipelines, and with perfect parallelism the build might finish in half the time. But there is a flaw in this idea: What if machine #2 reaches a project that machine #1 already started building but has not finished yet? This cache miss will cause machine #2 to start building the same project, when it may have been better to work on something else while waiting for machine #1 to finish that project. We can solve this by using a simple key/value store to communicate progress between machines. (In this tutorial we'll use Rush's [Redis](https://redis.io/) provider, but if your company already hosts some other service such as [Memcached](https://www.memcached.org/) , it's [fairly easy](https://github.com/microsoft/rushstack/blob/main/rush-plugins/rush-redis-cobuild-plugin/src/RedisCobuildLockProvider.ts) to implement your own provider.) When to use cobuilds?[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#when-to-use-cobuilds "Direct link to heading") --------------------------------------------------------------------------------------------------------------------------- Without cobuilds, Rush already parallelizes your jobs on a single machine. (This may not be immediately obvious, since Rush's output is "collated" for readability, making it appear as if projects are getting built one at a time.) You can fine-tune the maximum parallelism using the `--parallelism` command-line parameter, but keep in mind that projects can only build concurrently if they don't depend on each other. Thus, cobuilds will only help if you've already reached the limits for a single machine (considering cpu cores, disk I/O rates, and available memory). And only if further parallelism is actually possible for your monorepo's project dependency graph. The cobuild feature launches multiple instances of a CI pipeline, under the assumption that machines will be readily available. For example, if your cobuild allocates 4 machines, and your machine pool has 40 machines, then pool contention would not become a concern until 10 pull requests are waiting in the queue. By contrast, an extremely large monorepo might need thousands of machines, at which point it would make more sense to use a "build accelerator" such as [BuildXL](https://github.com/microsoft/BuildXL/blob/main/Documentation/Wiki/Frontends/js-rush-options.md) instead of cobuilds. (There are also plans to integrate Rush with [bazel-buildfarm](https://github.com/bazelbuild/bazel-buildfarm) ; Bazel is Google's equivalent of BuildXL.) Build accelerators generally require you to replace your CI system with their centralized job scheduler that manages its own dedicated pool of machines. Such systems require nontrivial maintenance and can have steeper learning curves, so we generally recommend to start with cobuilds first. Before adopting cobuilds, we recommend to try these things first: 1. **Enable the build cache**: The [build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) is a prerequisite for cobuilds. 2. **Identify bottlenecks:** If your monorepo's dependency graph does not actually allow lots of projects to be built in parallel, that must be fixed first before considering distributed builds. You can use Rush's `--timeline` parameter to identify bottlenecks that are causing too many projects to wait before they can start building. These bottlenecks can be solved by: * eliminating unnecessary dependencies between projects * introducing [Rush phases](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/) to break up build steps into multiple operations * refactoring code to break up big projects into smaller projects 3. **Upgrade your hardware:** If your builds are slow, it can help to add more machines. We generally recommend to choose high end hardware with the maximum amount of RAM and CPU cores for your plan, based on typical behavior of `rush install` and `rush build`. But every monorepo is different, so collect benchmarks on different hardware configurations to inform your decision. Speeding up the build makes everybody more productive; however, because hardware upgrades usually come from a different budget than engineering salaries, management sometimes may need some help to see this connection. 4. **Cache state between runs:** CI machines often start `rush install && rush build` with a completely clean machine image. For example, `rush install` time can be improved by using `RUSH_PNPM_STORE_PATH` to save the PNPM store and restore it between runs. Some environments permit the machine to be reused for multiple jobs, so that other Rush caches are preserved. 5. **Consider using a merge queue**: If two pull requests are waiting to get merged, normally a CI system will build a hot merge of `pr1+main` and `pr2+main`, to ensure that each PR branch is tested with the latest `main`. However after `pr1+main` has merged, we generally won't force `pr2+main` to be redone with the new `main`; this lack of safety can occasionally cause build breaks. (For example, suppose `pr1` deleted an API, but `pr2` added another call to that API.) A "merge queue" (also known as "commit queue") improves safety by instead building `pr1+main` and `pr1+pr2+main`; if the first PR fails, then it will retry with `pr2+main`. Advanced merge queues support "batches", where they directly test a "train" of pull requests `pr1+pr2+main` and only test `pr1+main` if there is a failure. This can speed up builds and/or reduce machine contention, while still guaranteeing safety. GitHub's [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) doesn't support batches at the time of this writing, however, the [Mergify](https://mergify.com/) third-party service [implements batches](https://docs.mergify.com/actions/queue/#batch-size) and has been tested with Rush. > **Prerequisites** > > In order to use the cobuild feature, you will need: > > * The Rush [build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) > enabled with a cloud storage provider. > > * A [Redis server](https://redis.io/) > . If your company uses some other key/value service, you can implement a plugin by following the example of [rush-redis-cobuild-plugin](https://github.com/microsoft/rushstack/tree/main/rush-plugins/rush-redis-cobuild-plugin) > . (And consider contributing it back to Rush Stack!) > > * A CI system that is able to allocate multiple machines when a CI pipeline is triggered. For example, with GitHub Actions, a "workflow" can launch multiple "jobs" whose "runner" is a separate machine. With Azure DevOps, "pipelines" can run jobs on multiple "agents" that can be on different machines. > > * [Rush phases](https://rushjs.io/zh-cn/pages/maintainer/phased_builds/) > are suggested to increase parallelism, but are _not required_ for cobuilds. > Enabling the cobuild feature[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#enabling-the-cobuild-feature "Direct link to heading") ------------------------------------------------------------------------------------------------------------------------------------------ 1. Upgrade `rushVersion` in your **rush.json** to `5.104.1` or newer. 2. Create an autoinstaller for the Rush plugin: rush init-autoinstaller --name cobuild-plugin It's also okay to use an existing autoinstaller. For more about Rush plugins and autoinstallers, see [Using Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) and [Autoinstallers](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/) . 3. Add the `@rushstack/rush-redis-cobuild-plugin` plugin to the autoinstaller. (We'll use Redis for this tutorial.) **common/autoinstallers/cobuild-plugin/package.json** { "name": "cobuild-plugin", "version": "1.0.0", "private": true, "dependencies": { "@rushstack/rush-redis-cobuild-plugin": "5.104.0" }} > 👉 **IMPORTANT:** > > Over time, make sure to keep the version of `@rushstack/rush-redis-cobuild-plugin` in sync with the `rushVersion` from your **rush.json**. 4. Update the autoinstaller's lockfile: rush update-autoinstaller --name cobuild-plugin# Remember to commit the updated pnpm-lock.yaml file to git 5. Next, we need to update **rush-plugins.json** to load the plugin from our `rush-plugins` autoinstaller. **common/config/rush/rush-plugins.json** { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", "plugins": [ /** * Each item defines a plugin to be loaded by Rush. */ { /** * The name of the NPM package that provides the plugin. */ "packageName": "@rushstack/rush-redis-cobuild-plugin", /** * The name of the plugin. This can be found in the "pluginName" * field of the "rush-plugin-manifest.json" file in the NPM package folder. */ "pluginName": "rush-redis-cobuild-plugin", /** * The name of a Rush autoinstaller that will be used for installation, which * can be created using "rush init-autoinstaller". Add the plugin's NPM package * to the package.json "dependencies" of your autoinstaller, then run * "rush update-autoinstaller". */ "autoinstallerName": "cobuild-plugin" } ]} 6. Configure `rush-redis-cobuild-plugin` by creating its config file: **common/config/rush-plugins/rush-redis-cobuild-plugin.json** { /** * The URL of your Redis server */ "url": "redis://server.example.com:6379", /** * An environment variable that your CI pipeline will assign, * which the plugin uses to authenticate with Redis. */ "passwordEnvironmentVariable": "REDIS_PASSWORD"} 7. You can use `rush init` to create the **cobuild.json** [config file](https://rushjs.io/zh-cn/pages/configs/cobuild_json/) that is used to enable the cobuild feature. Make sure to set `"cobuildFeatureEnabled": true` as shown below: **common/config/rush/cobuild.json** /** * This configuration file manages Rush's cobuild feature. * More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", /** * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, * otherwise the cobuild feature will be disabled. */ "cobuildFeatureEnabled": true, /** * (Required) Choose where cobuild lock will be acquired. * * The lock provider is registered by the rush plugins. * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. */ "cobuildLockProvider": "redis"} 8. Run `rush update` which should now install the `cobuild-plugin` autoinstaller. This downloads its manifest file: **common/autoinstallers/cobuild-plugin/rush-plugins/@rushstack/rush-redis-cobuild-plugin/rush-plugin-manifest.json** Commit this file to Git as well. (As part of the plugin system, this file caches important information so that Rush can access it without having to install the plugin's NPM package.) Configuring build pipelines[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#configuring-build-pipelines "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------- Each CI system has different ways of defining jobs. For this tutorial, we'll use a [GitHub Actions workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) since it's included with the free plan for public projects. Suppose our non-cobuild CI pipeline looks like this (with build cache writes enabled): **.github/workflows/ci-single.yml** name: ci-single.ymlon: #push: # branches: ['main'] #pull_request: # branches: ['main'] # Allows you to run this workflow manually from the Actions tab workflow_dispatch:jobs: build: name: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - name: Rush Install run: node common/scripts/install-run-rush.js install - name: Rush build (install-run-rush) run: node common/scripts/install-run-rush.js build --verbose --timeline env: RUSH_BUILD_CACHE_WRITE_ALLOWED: 1 RUSH_BUILD_CACHE_CREDENTIAL: ${{ secrets.RUSH_BUILD_CACHE_CREDENTIAL }} Here's how we would convert that into a cobuild with 3 runners: **.github/workflows/ci-cobuild.yml** name: ci-cobuild.ymlon: #push: # branches: ['main'] #pull_request: # branches: ['main'] # Allows you to run this workflow manually from the Actions tab workflow_dispatch:jobs: build: name: cobuild runs-on: ubuntu-latest strategy: matrix: runner_id: [runner1, runner2, runner3] steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - name: Rush Install run: node common/scripts/install-run-rush.js install - name: Rush build (install-run-rush) run: node common/scripts/install-run-rush.js build --verbose --timeline env: RUSH_BUILD_CACHE_WRITE_ALLOWED: 1 RUSH_BUILD_CACHE_CREDENTIAL: ${{ secrets.RUSH_BUILD_CACHE_CREDENTIAL }} RUSH_COBUILD_CONTEXT_ID: ${{ github.run_id }}_${{ github.run_number }}_${{ github.run_attempt }} RUSH_COBUILD_RUNNER_ID: ${{ matrix.runner_id }} REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }} The `runner_id` matrix causes the job to be run on 3 separate machines. The `REDIS_PASSWORD` variable name is what we defined earlier in **rush-redis-cobuild-plugin.json**. The `RUSH_COBUILD_CONTEXT_ID` and `RUSH_COBUILD_RUNNER_ID` variables are explained below. Cobuild environment variables in detail[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#cobuild-environment-variables-in-detail "Direct link to heading") ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ### `RUSH_COBUILD_CONTEXT_ID`[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#rush_cobuild_context_id "Direct link to heading") Cobuild runners must define this environment variable; without it, Rush will perform a regular build without any cobuild logic. The `RUSH_COBUILD_CONTEXT_ID` variable controls caching: Imagine that a pull request validation has failed because a project had errors. Without cobuilds, a project with errors is NOT saved to the build cache. If a person goes to the GitHub website and clicks a button to **"Re-run this job"**, the successful projects will be pulled from the cache, but that failed project will be forced to build again, which is good because maybe it was a transient failure. Whereas with cobuilds, if a project has errors, we don't want the other two machines to try to build that project. The error logs are saved to the build cache, and will be restored and printed by the other runners (to provide a complete log on every machine). But if a person clicks **"Re-run this job"**, how do we force the failing projects to get rebuild in that case? The `RUSH_COBUILD_CONTEXT_ID` identifier solves this. Rush adds it to the build cache key for failing projects to ensure they are rebuilt if the job is reattempted. `RUSH_COBUILD_CONTEXT_ID` is specified differently for each system. It can be any string with these properties: * `RUSH_COBUILD_CONTEXT_ID` must be the same across every machine for a given pipeline * `RUSH_COBUILD_CONTEXT_ID` must be different each time the pipeline is run, including "reattempts" and "retries" * It must be a short string, because it becomes part of a cache key Some examples: | CI system | Suggested value for `RUSH_COBUILD_CONTEXT_ID` | | --- | --- | | [Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/run-number?view=azure-devops&tabs=yaml) | `$(Build.BuildNumber)_$(System.Attempt)` | | [CircleCI](https://circleci.com/docs/variables/) | `${CIRCLE_WORKFLOW_ID}_${CIRCLE_WORKFLOW_JOB_ID}` | | [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables) | `${{ github.run_id }}_${{ github.run_number }}_${{ github.run_attempt }}` | ### `RUSH_COBUILD_RUNNER_ID`[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#rush_cobuild_runner_id "Direct link to heading") This environment variable uniquely identifies each machine. If this variable is not defined, Rush will generate a random identifier on each run. In the example, we specified it as `RUSH_COBUILD_RUNNER_ID: ${{ matrix.runner_id }}` for readability. Technical details[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#technical-details "Direct link to heading") -------------------------------------------------------------------------------------------------------------------- ### Build cache correctness[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#build-cache-correctness "Direct link to heading") You will find that the cobuild feature increases the requirement that every project's output is accurately saved and restored by the cache. To see why, suppose that project `A` directly depends on project `B`. There are several ways that an inaccurate cache might still produce a successful build: 1. Project `A` and `B` are both cache misses, so no caching occurs. **\- OR -** 2. Project `A` and `B` are both cache hits. `B` does not get restored accurately. `A` would have failed to compile, except that we didn't need to build `A`. The final result of `A` is still usable. **\- OR -** 3. Only project `A` is a cache miss. `B` does not get restored accurately, but the missing files are still on disk from a previous build on the same machine. Thus `A` compiles without errors. These lucky situations are relatively common in non-cobuild scenarios. If you're unlucky, reattempting the job may cause the problem to "clear up" (due to new cache hits). The underlying problem won't be noticed consistently until this situation: 4. Only project `A` is a cache miss. `B` does not get restored accurately, and our build starts with a clean disk. Cobuilds greatly increase the likelihood of encountering #4, because as much as possible, their aim is to build cache misses that depend on a cache hit. In short, after first enabling the cobuilds feature, you may need to spend some time fixing incorrect build cache configurations. > 👉 **Troubleshooting build cache inaccuracies** > > If you suspect that files are not getting accurately saved/restored by the Rush build cache, try the [rush-audit-cache-plugin](https://www.npmjs.com/package/rush-audit-cache-plugin) > . It detects such problems by monitoring file writes during your build operation. The written file paths are then compared with the project's cache configuration, producing a report of file paths that aren't being cached correctly. Then you can resolve the problem by correcting the cache configuration or fixing the tool to write its outputs in a cacheable location. ### What gets stored in Redis?[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#what-gets-stored-in-redis "Direct link to heading") The cobuild feature uses Redis for two main purposes: 1. **A reentrant locking mechanism.** The key corresponding to the lock is in the format of `cobuild:lock::`, and the corresponding value is ``. When setting the lock key, a 30-second expiration time is also set. This ensures that the same runner can reacquire the lock when attempting to obtain it again, while also automatically releasing the lock if the runner does not respond for a certain period of time. 2. **Track completed operations.** The key corresponding to the completed state is in the format of `cobuild:completed::`, and the corresponding value is a string in a serialized form of the operation's execution result and the corresponding `cache_id`. Before attempting to acquire a lock, a machine will first query this completion result information. If there is a completion result available, the result is reused based on the parsed information. See also[​](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#see-also "Direct link to heading") -------------------------------------------------------------------------------------------------- * [Enabling the build cache](https://rushjs.io/zh-cn/pages/maintainer/build_cache/) * [Environment variables](https://rushjs.io/zh-cn/pages/configs/environment_vars/) * [Using Rush plugins](https://rushjs.io/zh-cn/pages/maintainer/using_rush_plugins/) * [Autoinstallers](https://rushjs.io/zh-cn/pages/maintainer/autoinstallers/) * [When to use cobuilds?](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#when-to-use-cobuilds) * [Enabling the cobuild feature](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#enabling-the-cobuild-feature) * [Configuring build pipelines](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#configuring-build-pipelines) * [Cobuild environment variables in detail](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#cobuild-environment-variables-in-detail) * [`RUSH_COBUILD_CONTEXT_ID`](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#rush_cobuild_context_id) * [`RUSH_COBUILD_RUNNER_ID`](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#rush_cobuild_runner_id) * [Technical details](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#technical-details) * [Build cache correctness](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#build-cache-correctness) * [What gets stored in Redis?](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#what-gets-stored-in-redis) * [See also](https://rushjs.io/zh-cn/pages/maintainer/cobuilds/#see-also) --- # rush.json | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/pages/configs/rush_json/#docusaurus_skipToContent_fallback) 这是 [rush init](https://rushjs.io/zh-cn/pages/commands/rush_init/) 生成的模版下的 **rush.json** 文件(在项目根目录下): **rush.json** /** * 这是 Rush 的主要配置文件。 * 更多信息可以参考 Rush 官网: https://rushjs.io */{ "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", /** * (必须)指定仓库内 Rush 引擎的版本。 * Rush 的“版本选择”功能可以确保无论全局安装的哪个版本,都会在使用时用指定的版本。 * * common/scripts/install-run-rush.js 也会使用这个版本。 * * 注意:如果你升级了 Rush 的主版本,那么你应该所有 Rush 配置文件中替换 "$schema" 字段中的 "v5". 它可以在诸如 VSCode 的编辑器内确保 tab 补全、错误捕获等功能正确运行。 */ "rushVersion": "5.40.0", /** * 下面的字段选定了使用哪个包管理器及其版本。 * Rush 会在自己的本地安装包管理器的副本,以确保构建过程与本地环境的工具完全隔离。 * * 选择 "pnpmVersion", "npmVersion", 或 "yarnVersion" 中一个,可以查阅 * Rush 文档来获取更多细节。 */ "pnpmVersion": "5.15.2", // "npmVersion": "4.5.0", // "yarnVersion": "1.9.4", /** * 当使用 PNPM 时的选项。 */ "pnpmOptions": { /** * PNPM 存储的位置,这里有两个选择: * * - "local" - 默认使用临时文件夹 "common/temp/pnpm-store" 中的 "pnpm-store" 目录。 * - "global" - 使用 PNPM 的全局存储,其优点是可以在多个仓库中共享,缺点是构建的隔离性较差(例如,当两个仓库使用不同版本的 PNPM 时,会出现 bug 或兼容问题)。 * * RUSH_PNPM_STORE_PATH 可以重写使用哪个目录来存储 * * 在所有情况下,存储路径将会被环境变量 RUSH_PNPM_STORE_PATH 所覆盖。 * * 默认值为 "local". */ // "pnpmStore": "local", /** * 若为 true, Rush 调用 pnpm 会增加 "--strict-peer-dependencies" 参数。 * 如果不满足同级依赖时,此时 "rush install" 会执行失败。 * (由于历史原因,JavaScript 的包管理器不会视作无效状态为一个错误) * * 默认值为 false 来避免避免的兼容性问题,强烈推荐设定 strictPeerDependencies=true. */ // "strictPeerDependencies": true, /** * 该配置项用于指定安装期间的版本选择策略。 * * 该功能需要 PNPM 的版本新于 3.1, 它对应了 PNPM 中 "--resolution-strategy" * 的选项。可选的值为 "fast" 和 "fewer-dependencies". PNPM 的默认值为 "fast" * 但是不兼容某些库,例如 DefinitelyTyped 中的 "@types" 库。Rush 默认采用了 * "fewer-dependencies", 这会导致 PNPM 在某个版本已经安装的情况下不再安装新版本。 * 这与 NPM 算法类似。 * * 修改完该字段后,建议执行 "rush update --full" 来使得包管理器重新计算版本。 */ // "resolutionStrategy": "fast", /** * 如果设定为 true, 当 PNPM shrinkwrap 文件变动后没有执行 "rush update", * 会导致 `rush install` 抛出一个错误。 * * 该功能可以防止 pnpm 的 shrinkwrap 文件("pnpm-lock.yaml") 手动修改后导致 * 的不一致的问题。开启该功能后,"rush update" 会把哈希值作为注释附加到 shrinkwrap * 文件中。之后 "rush update" 和 "rush install" 会校验哈希值。注意,这不会 * 禁止手动修改,只需要执行 "rush update" 后确保 PNPM 能报告或修复潜在的不一致。 * * 使用 "--bypass-policy" 可以暂时在调用 "rush install" 时关闭校验。 * * 默认值为 false. */ // "preventManualShrinkwrapChanges": true, /** * 若为 true, `rush install` 会使用 PNPM 的 workspace 功能。 * * 该功能使用 PNPM 来执行安装。当使用 workspace 时,Rush 会生成 "pnpm-workspace.yaml" * 文件,它引用了本地所有安装的项目。 * Rush 会生成 "pnpmfile.js" 来支持优先版本功能。当安装时,pnpmfile * 被用来替换依赖版本中的较小的子集。如果优先版本并不是原有版本的子集,那么会保持原状。再次之前, * 仓库内 pnpmfile.js(如果存在)将被调用来修改依赖。 * * This option is experimental. 默认值为 false. */ // "useWorkspaces": true }, /** * 老版本的 Node.js 或许缺失所需功能,其他版本的功能可能会有 bug. * 尤其是“最新”版本不是长期支持的版本,可能出现倒退。 * * 指定语义化版本来确保开发者使用恰当的 Node.js 版本。 * * LTS 日程: https://nodejs.org/en/about/releases/ * LTS 版本: https://nodejs.org/en/download/releases/ */ "nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0", /** * Node.js 奇数位的版本是实验版本。偶数位的版本在成为 LTS 前,有六个月的稳定期。 * 例如, 8.9.0 是 Node.js 8 的第一个 LTS 版本,由于 bug 不推荐生产环境下使 * 用 LTS 前的版本,这些 bug 可能导致 Rush 出现问题。 * * 正常情况下 Rush 一旦检测到 LTS 前的 Node 版本将会发出警告。 * 如果你正在测试 LTS 前的版本,可以设置该选项来关闭警告 * */ // "suppressNodeLtsWarning": false, /** * 如果你希望依赖版本是一致的, 可以关闭注释,它类似于在以下指令前 * 执行 "rush check". * * rush install, rush update, rush link, rush version, rush publish * * 有时你想要开启该功能,但是需要某个包使用不同的版本,则可以使用 * common-versions.json 中的 "allowedAlternativeVersions". */ // "ensureConsistentVersions": true, /** * 如果项目目录不遵循一致的、可识别的模式,那么大型 monorepo 会令新人生畏。 * 当系统允许文件树嵌套时,我们发现团队经常使用子目录来创建隔离的新项目。这阻止了 * 协作与代码共享。 * * Rush 开发者推荐使用“种类目录”模式,可构建的项目必须永远放到根目录下的第二层。 * 父亲树扮演着种类的效果。它提供了一个划分相关项目的基本设施(例如:"apps", "libraries", "tools", "prototypes"),这同时鼓励团队将其项目使用统一的分类。限制成两层在初 * 期看起来很严格,但当你有了 20 个目录,每个种类有 20 个项目后,这个范式可以轻松地 * 支持大型项目。实践中,你会发现文件夹的层次结构偶尔需要重新平衡,但是如果这个过程非常痛苦, * 那么可能是你的开发风格不适合重构。重新组织种类应该是一个启发人心的讨论,它将人聚集在一起, * 同时也可能发现不好的代码习惯(例如,在不使用 Node.js 模块解析的情况下将文件饮用到其他项 * 目中)。 * * 默认是 projectFolderMinDepth=1 和 projectFolderMaxDepth=2. * * 为了移除这个限制,可以设定 projectFolderMinDepth=1, 同时 * 设定 projectFolderMaxDepth 为一个更大的数字。 */ // "projectFolderMinDepth": 2, // "projectFolderMaxDepth": 2, /** * 如果 npmjs.com 源中醒了严格的包命名规则,但是早期并没有标准。 * 一些遗留的包依旧使用非标准的包名,有时私有源也会允许这样。 * 设定 "allowMostlyStandardPackageNames" 为 true 会降低 Rush 的 * 包命名标准,会允许使用大写字母和未来可能放宽的规则,然而我们想要减少这 * 些异常。许多流行的工具使用某些标点符号作为分隔符,是因为猜测它们永远不 * 会出现在包名中,因此如果我们放松规则,很有可能出现非常混乱的问题。 * * 默认值为 false. */ // "allowMostlyStandardPackageNames": true, /** * 该功能帮助你审查和批准仓库内某些新引入的。例如,你也许担心许可证、 * 代码质量、性能、或者叠加功能相同的库。在两个配置文件 "browser-approved-packages.json" * 和 "nonbrowser-approved-packages.json" 中可以跟踪审查情况。 * 查看 Rush 的文档来获取更多细节。 */ // "approvedPackagesPolicy": { // /** // * 审查种类,例如:“这个库允许在原型中使用,但不允许在生产中使用”。 // * // * 每个项目可以通过 rush.json 下 "project" 的 "reviewCategory" // * 字段关联一个审查类别。审查行为被记录在 // * "common/config/rush/browser-approved-packages.json" 和 // * "nonbrowser-approved-packages.json" 文件中,它们会由 "rush // * update" 自动生成。 // * // * 对于你审查而言,指定任何颗粒度的种类都是合适的,或者你可以仅仅添 // * 加一个名为 "default" 的类别。 // */ // "reviewCategories": [ // // 一些示例类别: // "production", // 生产模式下的项目 // "tools", // 非生产模式,只是开发者的工具链 // "prototypes" // 多数情况下应该被忽略的项目 // ], // // /** // * 一系列 NPM 包 scope 可以被排除在审查中。 // * 我们建议排出 TypeScript 的类型(@type), 因为如果它对应的代码包 // * 被批准,那么类型包也应该被批准。 // */ // // "ignoredNpmScopes": ["@types"] // }, /** * 如果使用 Git 作为版本公知,那么该字段可以提供一些 * 额外的功能。 */ "gitPolicy": { /** * 在一个大公司工作? 疲惫于在工作中发现了 Git 提交中不专业的邮箱,诸如 * "beer-lover@my-college.edu? Rush 可以在开发者开始工作前校验 * 邮箱。 * * 定义一系列正则表达式的列表,它们表示允许的提交到 Git 上的邮箱格式。 * 它们是不区分大小写的 JavaScript 正则。 例子:".*@example\.com" * * 重要: 由于正则表达式被编码为 JSON 字符串字面量,因此 * 正则表达式中的转义字符需要两个反斜线,即 "\\.". */ // "allowedEmailRegExps": [ // "[^@]+@users\\.noreply\\.github\\.com", // "travis@example\\.org" // ], /** * 当 Rush 报告邮箱有问题时,这条通过可以包含一个推荐邮箱写法的示例 * 确保它符合 allowedEmailRegExps 表达式。 */ // "sampleEmail": "mrexample@users.noreply.github.com", /** * "rush publish" 期间提交修改的提交信息 * * 例如,如果你希望阻止这些提交触发 CI, 那么你可以配置你的系统 * 遇到诸如 "[skip-ci]" 的特殊字符串来指示 CI 应该跳过,之后 * 自定义的 Rush 消息中含有这个字符串。 */ // "versionBumpCommitMessage": "Applying package updates. [skip-ci]", /** * "rush version" 期间提交修改的提交信息 * * 例如,如果你希望阻止这些提交触发 CI, 那么你可以配置你的系统 * 遇到诸如 "[skip-ci]" 的特殊字符串来指示 CI 应该跳过,之后 * 自定义的 Rush 消息中含有这个字符串。 */ // "changeLogUpdateCommitMessage": "Applying package updates. [skip-ci]" }, "repository": { /** * Git 仓库的 URL, 被 "rush change" 使用来决定那个是你 PR 的基础分支。 * * "rush change" 指令需要确定你的 PR 影响了哪些文件。 * 如果你的 PR 中从主分支合并或 cherry-picked 了一些提交,那么这些提交 * 将会被排除在 diff 中(因为它们属于别的 PR)。为了做到这点,Rush * 知道如何在 PR 中到照基础分支。这个信息不能从 Git 中单独获取,因为 * "pull request" 不是 Git 的概念。理想情况是 Rush 使用了特定的协议 * 来从诸如 Github, Azure DevOps 上获取这些信息。 * 但为了简单,"rush change" 只是假设你的 PR 只是针对 rush.json 中的 * repository.url 的仓库的主分支。如果你从 Github 上 "fork" 了一个 * 仓库,那么该设定就不同于你的 PR 分支的仓库 URL, 此时 "rush change" * 会自动掉哟过 "git fetch" 来检索远程主分支的最新活动。 * */ // "url": "https://github.com/microsoft/rush-example", /** * 默认分支名,它告知 "rush change" 要与远程按个分支进行比较。 * 默认值为 "main". */ // "defaultBranch": "main", /** * 默认的远端。当 URL 没提供时候, * 它告知 "rush change" 要从哪个远端来进行比较。 */ // "defaultRemote": "origin" }, /** * 事件钩子是指自定义的脚本。当指定事件发生时, Rush 会执行这些钩子。 */ "eventHooks": { /** * Rush install 发生前执行的一系列脚本。 */ "preRushInstall": [ // "common/scripts/pre-rush-install.js" ], /** * Rush install 完成后执行的一系列脚本。 */ "postRushInstall": [], /** * Rush build 发生前执行的一系列脚本。 */ "preRushBuild": [], /** * Rush build 完成后执行的一系列脚本。 */ "postRushBuild": [] }, /** * 安装变种允许你维护一套平行的配置文件,它们可以用于以另一套依赖来构建整个仓库。 * 例如,假设你将你所有的项目使用的一个重要框架的升级到新版本,但是在此期间你想要 * 维持与旧版本的兼容性。此时,你也许想让你的 CI 两次校验整个仓库的构建产物:一次是 * 旧版本,一次是新版本。 * * Rush 的 "安装变种" 对应于以下文件夹的配置文件: * * common/config/rush/variants/ * * 变种文件夹包含一系列可供选择的 common-version.json 文件。其“优先版本” * 字段可以用来选择依赖的旧版本(在 package.json 中语义版本的范围内) * 执行 "rush install --variant ". 来安装一个变量。 * * 更多信息,可以参考 https://rushjs.io/pages/advanced/installation_variants/ */ "variants": [ // { // /** // * 变种名。 // */ // "variantName": "old-sdk", // // /** // * 详实的描述 // */ // "description": "Build this repo using the previous release of the SDK" // } ], /** * Rush 可以匿名收集开发者日常数据,例如安装、构建和其他操作。你可以用它来识别工具链或 * Rush 本身的问题。这些数据不会与微软共享。 * 它会以 JSON 的形式被写入 common/temp 目录下。 你可以读写这些 JSON 文件并对其进行 * 处理,这些处理脚本通常放到 "eventHooks" 中。 */ // "telemetryEnabled": false, /** * 允许热修复。该功能目前处于实验阶段,因此默认关闭。 * 如果设定该属性,那么 'rush change' 只会允许被指定为“热修复”类型。该类型会 * 在随后发布时使用到。 */ // "hotfixChangeEnabled": false, /** * (必须)Rush 中的项目清单 * * Rush 不会使用通配符自动扫描项目,有以下原因: * 1. 深度优先搜索开销太大,尤其是需要重复收集列表时; * 2. 在带有缓存的 CI 机器上,搜索可能会遗漏掉之前构建中的文件; * 3. 集中式的管理所有项目以及其重要的元数据是很有用的。 */ "projects": [ // { // /** // * 项目的 NPM 包名(必须与 package.json 匹配) // */ // "packageName": "my-app", // // /** // * 项目的路径,相对于 rush.json 所在的目录而言。 // */ // "projectFolder": "apps/my-app", // // /** // * 仅当 subspaces.json 中的 "subspacesEnabled" 为 true 时使用。 // * 它指定该项目所属的子空间。如果省略,则该项目属于 "default" 子空间。 // */ // "subspaceName": "my-subspace", // // /** // * 可选的种类,它用于 "browser-approved-packages.json" // * 和 "nonbrowser-approved-packages.json" 文件。该值必须 // * 是上文 "reviewCategories" 中定义的字符串。 // */ // "reviewCategory": "production", // // /** // * 本地项目列表,它们以 devDependencies 的形式出现,但是不能被被本地链接, // * 因为它会创建一个循环依赖。相反,最后发布的版本将会被安装到公共目录下。 // */ // "cyclicDependencyProjects": [ // // "my-toolchain" // ], // // /** // * 如果该值为 true, 那么项目将会被 "rush check" 忽略。 // * 默认值为 false. // */ // // "skipRushCheck": false, // // /** // * 一个参数表明该项目是否需要被发布到 npm 上,它将影响到 Rush change // * 和发布工作流,默认结果为 false. // * 注意: "versionPolicyName" 和 "shouldPublish" 是二选一的,你不能 // * 同时定义这两个。 // */ // // "shouldPublish": false, // // /** // * 便于发布前对项目文件进行处理。 // * // * 一旦指定,"publishFolder" 是项目子目录的相对路径。 // * "rush publish" 会发布子目录而不是项目目录。子目录必须包括 // * "package.json", 它通常是构建输出。 // */ // // "publishFolder": "temp/publish", // // /** // * 可选参数,是指项目的版本策略。版本策略定义在 "version-policies.json" // * 文件内。可以查阅 "rush publish" 文档了解更多。 // * 注意: "versionPolicyName" 和 "shouldPublish" 是二选一的,你不能同时定义二者 // */ // // "versionPolicyName": "" // }, // // { // "packageName": "my-controls", // "projectFolder": "libraries/my-controls", // "reviewCategory": "production" // }, // // { // "packageName": "my-toolchain", // "projectFolder": "tools/my-toolchain", // "reviewCategory": "tools" // } ]} --- # 未找到页面 | Rush ![](https://rushjs.io/images/suitenav/rs-waffle.svg) [Rush Stack](https://rushstack.io/) [Shop](https://rushstack.io/pages/shop/) [Blog](https://rushstack.io/blog/) [Events](https://rushstack.io/community/events/) [Skip to main content](https://rushjs.io/zh-cn/404#docusaurus_skipToContent_fallback) 未找到页面 ===== 我们没有找到您正在寻找的页面。 请联系本站点的拥有者并附上原始链接以便让他们知道他们的链接失效了。 ---