|
1 | 1 | # @microsoft/rush |
2 | 2 |
|
3 | | -## Why Rush? |
4 | | -A typical web project may consume hundreds of NPM packages, each developed |
5 | | -independently by a random stranger somewhere on the internet. Each project |
6 | | -has its own Git repository, is conceptually self-contained, and tries to |
7 | | -maintain an API contract conforming to [SemVer](http://semver.org/). When |
8 | | -there is a bug in one of these packages, a pull request is merged, the version |
9 | | -is bumped, and a new release is published. The new release then begins a |
10 | | -slow propagation across the internet, as each downstream project upgrades |
11 | | -and reacts to any incompatibilities that may arise in a delightful symphony |
12 | | -of distributed collaboration. |
13 | 3 |
|
14 | | -At the root of this massive dependency tree is your client-side web application. |
15 | | -Unlike everything else, it is one huge monolith. The bigger it grows, |
16 | | -the more you begin to think "This is stupid -- we should break this thing up |
17 | | -into 30 small NPM packages that can be reused and versioned independently." |
18 | | -One heroic Saturday night, you create 30 Git repos and refactor everything. |
| 4 | + |
| 5 | +<br /> |
| 6 | + https://aka.ms/rush |
19 | 7 |
|
20 | | -Eventually people start complaining. Your team isn't 30 strangers making |
21 | | -frivolous little "left-pad" utilities. They are application developers |
22 | | -creating a mission-critical product with messy business logic. The components |
23 | | -interact in complex ways, and every time you change one package, you seem |
24 | | -to be breaking other packages. It feels wrong to be cloning and building |
25 | | -30 different Git repositories every day, when there's only 10 people on your team. |
26 | | -Publishing is getting tedious. Running "npm link" is a minefield. This is no |
27 | | -way to work! |
| 8 | +<!-- -------------------------------------------------------------------------- --> |
| 9 | +<!-- Text below this line should stay in sync with Rush.md from the GitHub wiki --> |
| 10 | +<!-- -------------------------------------------------------------------------- --> |
28 | 11 |
|
29 | | -And so, you consolidate all your NPM packages into one central Git repository, and |
30 | | -write a script that runs "npm install", "npm link", and "gulp" 30 times, in the |
31 | | -right order. This is way better! In the past, when Bob made a big change to a |
32 | | -core library and then left for a backpacking trip across Europe, it could take |
33 | | -a week for Alice to upgrade to the new version and realize that something was broken. |
34 | | -Even though Bob caused the trouble, his victims unfairly had to shoulder the cost |
35 | | -of debugging it. Having a unified build means that Bob _cannot even merge his PR_ |
36 | | -(let alone publish a new release) without passing all the unit tests for every |
37 | | -downstream project. Catching problems early makes everyone more efficient. |
38 | | -Having a central repository forces library owners pay attention to the source code |
39 | | -and PRs that consume their APIs; no more "out of sight, out of mind." |
| 12 | +**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: |
40 | 13 |
|
41 | | -There is just one problem... Builds are slowwwww. If "npm install" takes |
42 | | -1 minute (on a good day), then 30 installs take 30 minutes. Building 30 small projects |
43 | | -is slower than building one big project. Other details like managing |
44 | | -[shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap) and publishing can be tricky. |
| 14 | +- **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. |
45 | 15 |
|
46 | | -## Rush is here to help! |
| 16 | +- **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. |
47 | 17 |
|
48 | | -Rush formalizes this model and makes it quick. It works completely within |
49 | | -the conventional NPM system: Each package will still have its own Gulpfile. |
50 | | -Each package can still run "npm install" without Rush if desired. |
51 | | -You are always free to move your projects around between Git repositories |
52 | | -without any changes to package.json. |
| 18 | +- **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 showing live console output in a [readable order](https://www.npmjs.com/package/@microsoft/stream-collator)). In practice this multi-process approach can yield more significant gains than all those async functions in your single-threaded Gulpfile. |
53 | 19 |
|
54 | | -But when you use Rush, you get some big improvements: |
| 20 | +- **Subset and incremental builds:** If you only plan to work with a few projects from your repo, `rush rebuild --to <project>` does a clean build of just your upstream dependencies. After you make changes, `rush rebuild --from <project>` does a clean build of the affected downstream projects. And if your toolchain is [package-deps-hash](https://www.npmjs.com/package/@microsoft/package-deps-hash) enabled, `rush build` delivers a powerful cross-project incremental build (that also supports subset builds). |
55 | 21 |
|
56 | | -- Save time by installing all dependencies for all packages via a single |
57 | | - "npm install" invocation |
| 22 | +- **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. |
58 | 23 |
|
59 | | -- Rush automatically generates a shrinkwrap file for the entire repository. |
60 | | - NPM shrinkwrap is the only way to avoid maddening problems of "what are you talking |
61 | | - about, it works on my PC!" |
| 24 | +- **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. |
62 | 25 |
|
63 | | -- All projects are automatically hooked up with "npm link" (using local |
64 | | - symlinks so multiple Git folders won't get cross-linked) |
| 26 | +- **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/web-build-tools/blob/master/core-build/web-library-build/CHANGELOG.md) file. |
65 | 27 |
|
66 | | -- A dependency solver uses package.json to automatically determine |
67 | | - the build order. |
| 28 | +- **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 dorky personal e-mail addresses 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. |
68 | 29 |
|
69 | | -- Since each project has its own Gulpfile, Rush can spawn multiple NodeJS |
70 | | - processes in parallel, making the build go significantly faster. (No matter |
71 | | - how many promises you write, your Gulpfile is still fundamentally single-threaded.) |
| 30 | +- **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. |
72 | 31 |
|
73 | | -- Use a single command to run "npm publish" for many packages |
| 32 | +# 3 Minute Demo |
74 | 33 |
|
75 | | -- Git-based incremental builds, so you only rebuild a project if a source file |
76 | | - in that project folder has changed. |
77 | | - |
78 | | -- Support for cyclic dependencies: For example, suppose that **my-gulp-task** |
79 | | - depends on **my-library**, but **my-library**'s Gulpfile has a devDependency |
80 | | - on **my-gulp-task**. Rush can install the last published version of these |
81 | | - packages for the Gulpfile, while still creating local links for other |
82 | | - projects outside the cyclic dependency. |
83 | | - |
84 | | -- Support for enforcing certain Git policies, such as enforcing that Git committer |
85 | | - email addresses conform to a well-defined pattern. |
86 | | - |
87 | | -# Usage |
88 | | - |
89 | | -At any time, you can see the `--help` flag to find command-line usage information. |
90 | | - |
91 | | -## Building a repo that is configured for Rush |
92 | | - |
93 | | -1. Run "**npm install -g @microsoft/rush**". To confirm that it's working, |
94 | | - run "rush -h" which prints the version number and usage information. |
95 | | - |
96 | | -2. From anywhere in your git working folder, run "**rush install**". This |
97 | | - will install NPM modules in Rush's "Common" folder. |
98 | | - |
99 | | - NOTE: If you are troubleshooting build issues, try |
100 | | - "**rush install --full-clean**" instead. |
101 | | - |
102 | | -3. From anywhere in your Git working folder, run "**rush link**". This creates |
103 | | - symlinks so that all the projects will reuse the packages from "common/node_modules" |
104 | | - (rather than having to run "npm install" in each project folder). It will |
105 | | - also link projects to the folders for their local dependencies, so that you don't need |
106 | | - to do "npm publish" to test your changes. |
107 | | - |
108 | | - NOTE: The "**rush.json**" config file specifies how this linking is performed. |
109 | | - |
110 | | - > IMPORTANT: DO NOT run "npm install" inside project folders that have been linked |
111 | | - > by the Rush tool. If you want to do that, you need to "**rush unlink**" first. |
112 | | -
|
113 | | -4. Do your initial build by running "**rush rebuild**" . This will |
114 | | - recurse through each project folder and run "gulp clean", "gulp", |
115 | | - and "gulp test", and then give you a report of anything that failed to build. |
116 | | - |
117 | | - NOTE: To suppress verbose output, use "**rush rebuild -q**". |
118 | | - |
119 | | -## Pull -> Edit -> Build -> Run -> Push |
120 | | - |
121 | | -The above steps are only necessary when you need to do a clean full build (e.g. |
122 | | -after pulling changes that affected common/package.json). Otherwise, you can |
123 | | -run "gulp" in individual project folders as usual. Your daily workflow will |
124 | | -look like this: |
125 | | - |
126 | | -1. Pull the latest changes from git. |
127 | | - |
128 | | -2. If something changed in the **common** folder, then you may need to update |
129 | | - your NPM: |
130 | | - |
131 | | - > C:\MyRepo> **rush install** |
132 | | - > |
133 | | - > C:\MyRepo> **rush link** |
134 | | - > |
135 | | - > C:\MyRepo> **rush rebuild -q** |
136 | | -
|
137 | | -3. Debug a project: |
138 | | - |
139 | | - > C:\MyRepo> **cd my-project** |
140 | | - > |
141 | | - > C:\MyRepo\my-project> **gulp serve** |
142 | | -
|
143 | | -## Configuring a project to be built by Rush |
144 | | - |
145 | | -Once a project has been added to the `rush.json` file, several commands must be defined in the |
146 | | -project's `package.json` file, under the `scripts` section. Every project must define a `clean` |
147 | | -script. Additionally, every project must define either a `test` or `build` command. By default, |
148 | | -Rush will default to using the `test` command if both are defined, but will fall back to `build` |
149 | | -if `test` is missing. |
150 | | - |
151 | | -The defined commands should either reference something on the `PATH` or should be an absolute path. |
152 | | -If the command is defined simply as `gulp`, the version of gulp from the common folder's `node_modules/.bin` |
153 | | -folder will be used. |
154 | | - |
155 | | -An example configuration is below: |
156 | | - |
157 | | -```json |
158 | | -{ |
159 | | - "name": "my-project", |
160 | | - "version": "1.0.0", |
161 | | - "scripts": { |
162 | | - "clean": "gulp clean", |
163 | | - "build": "gulp", |
164 | | - "test": "/usr/bin/testcommand --compile --things" |
165 | | - } |
166 | | -} |
| 34 | +See Rush in action! From your shell, install the tool like this: |
167 | 35 | ``` |
168 | | - |
169 | | -## If you need to modify your package.json |
170 | | - |
171 | | -If you need to add new dependencies to your package.json, you will need to |
172 | | -regenerate the files in the common folder. Use these commands: |
173 | | - |
174 | | -> C:\MyRepo> **rush generate** |
175 | | -> |
176 | | -> C:\MyRepo> **rush link** |
177 | | -
|
178 | | -This will change various generated files in common folder. You should include these |
179 | | -changes in your Pull Request. |
180 | | - |
181 | | -The "**rush generate**" command takes a long time. To speed up debugging, you can use |
182 | | -"**rush generate --lazy**" instead; however you must run the full "**rush generate**" |
183 | | -before submitting your PR. |
184 | | - |
185 | | -## Publishing your NPM packages |
186 | | - |
187 | | -To publish all NPM projects in your repository, run "**rush publish**". You |
188 | | -can select a subset of projects using the "**--include**" option followed by |
189 | | -a [glob](https://en.wikipedia.org/wiki/Glob_(programming)) pattern. You can |
190 | | -use the "**--registry**" option to specify a custom NPM registry, e.g. if you |
191 | | -are testing with [Verdaccio](https://github.com/verdaccio/verdaccio). |
192 | | - |
193 | | -## Converting a repo to build with Rush |
194 | | - |
195 | | -Currently you need to manually create an "rush.json" configuration file |
196 | | -at the root of your repository, which specifies the list of projects |
197 | | -to be built. You also need to set up your "common" folder, and add the |
198 | | -appropriate files to Git. (We are working on an "rush init" command to |
199 | | -simplify this.) |
200 | | - |
201 | | -## Detecting when new NPM dependencies are introduced |
202 | | - |
203 | | -Suppose that your Rush repo has 30 different projects, and you want to keep track of |
204 | | -what NPM packages people are using. When someone finds a new package and tries to add |
205 | | -it to their project, you want to ask questions like: "Is this a good quality package?" |
206 | | -"Are we already using a different library that does the same thing?" "Is the license |
207 | | -allowed?" "How many other dependencies will this pull into our node_modules folder?" |
208 | | -Rush can alert you when this happens. |
209 | | - |
210 | | -In your **rush.json** file, add these optional fields: |
211 | | - |
212 | | -```json |
213 | | - "reviewCategories": [ "published", "internal", "experiment" ], |
214 | | - "packageReviewFile": "common/PackageDependencies.json", |
| 36 | +$ npm install -g @microsoft/rush |
215 | 37 | ``` |
216 | 38 |
|
217 | | -In this example, we defined three kinds of projects that we care about: |
218 | | -Projects that we publish externally, projects kept internal to our company, |
219 | | -and throwaway experiments. For each project in the repo, we will assign one |
220 | | -of these categories as the "reviewCategory" field. |
221 | | - |
222 | | -The **PackageDependencies.json** file contains the list of approved packages. |
223 | | -This file should be added to Git. It might look like this: |
| 39 | +For command-line help, do this: |
| 40 | +``` |
| 41 | +$ rush -h |
| 42 | +``` |
224 | 43 |
|
225 | | -```json |
226 | | -{ |
227 | | - "browserPackages": [ |
228 | | - { |
229 | | - "name": "lodash", |
230 | | - "allowedCategories": [ "internal", "experiment" ] |
231 | | - } |
232 | | - ], |
233 | | - "nonBrowserPackages": [ |
234 | | - { |
235 | | - "name": "gulp", |
236 | | - "allowedCategories": [ "published", "internal", "experiment" ] |
237 | | - }, |
238 | | - { |
239 | | - "name": "some-tool", |
240 | | - "allowedCategories": [ "experiment" ] |
241 | | - } |
242 | | - ] |
243 | | -} |
| 44 | +To see Rush build some real projects, try running these commands: :-) |
| 45 | +``` |
| 46 | +$ git clone https://github.com/Microsoft/web-build-tools |
| 47 | +$ cd web-build-tools |
| 48 | +$ rush install --bypass-policy |
| 49 | +$ rush rebuild |
244 | 50 | ``` |
245 | 51 |
|
246 | | -Above, we specified that only our internal projects and experiments are allowed |
247 | | -to use "lodash", whereas "gulp" is allowed everywhere. The "some-tool" library |
248 | | -is being used by an experimental prototype, but should never be used in real projects. |
| 52 | +<!-- -------------------------------------------------------------------------- --> |
| 53 | +<!-- Text above this line should stay in sync with Rush.md from the GitHub wiki --> |
| 54 | +<!-- -------------------------------------------------------------------------- --> |
249 | 55 |
|
250 | | -Note that Rush distinguishes "**browserPackages**" from "**nonBrowserPackages**", |
251 | | -since the approval criteria is generally different for these environments. |
| 56 | +# Getting Started |
252 | 57 |
|
253 | | -Now, suppose someone changes their package.json to add "lodash" to a project that |
254 | | -was designated as "published". When they run "rush generate", Rush will automatically |
255 | | -rewrite the **PackageDependencies.json** file, appending "published" to the |
256 | | -"allowedCategories" for "lodash". In other words, it automatically broadens the rules |
257 | | -so that they describe reality. When the pull request is created, reviewers will spot this diff |
258 | | -and can ask appropriate questions. Since our criteria is based on generalized categories, |
259 | | -the reviewers aren't hassled about every little package.json change; a **PackageDependencies.json** |
260 | | -diff only appears for genuinely interesting changes. |
| 58 | +The GitHub wiki has complete, up-to-date documentation: https://aka.ms/rush |
0 commit comments