Getting Started with Integrated Repos
Example repository/nrwl/nx-recipes/tree/main/integrated
Create a New Workspace
Start by creating a new workspace. We can use the following command that will help us set it up.
โฏ
npx create-nx-workspace@latest myorg --preset=ts
The file structure should look like this:
1myorg/
2โโโ packages/
3โโโ tools/
4โโโ nx.json
5โโโ package.json
6โโโ README.md
7โโโ tsconfig.base.json
8
Create a Package
Nx comes with generators that can help with scaffolding applications. Run this generator to make a new library named is-even
:
โฏ
npx nx generate @nx/js:library is-even \
โฏ
--directory=libs/is-even \
โฏ
--publishable \
โฏ
--importPath=@myorg/is-even
This command:
- Uses the
@nx/js
plugin'slibrary
generator to scaffold a new library namedis-even
. - The
--publishable
flag makes sure we also get apackage.json
generated and apublish
target we can invoke to publish to NPM. - The
--importPath
allows us to define the name of the NPM package.
You should now have the following structure:
1packages/
2โโโ is-even/
3 โโโ src/
4 | โโโ lib/
5 | | โโโ is-even.spec.ts
6 | | โโโ is-even.ts
7 | โโโ index.ts
8 โโโ project.json
9 โโโ package.json
10 โโโ ...
11 โโโ tsconfig.json
12
Update is-even.ts
with this content:
1export function isEven(x: number): boolean {
2 return x % 2 === 0;
3}
4
The Nx plugins use a project-level project.json
to manage the metadata around the available targets that can be run for a given project. The generated project.json
for is-even
contains build
, publish
, lint
and test
targets:
1{
2 "name": "is-even",
3 "targets": {
4 "build": {
5 /* ... */
6 },
7 "publish": {
8 /* ... */
9 },
10 "lint": {
11 /* ... */
12 },
13 "test": {
14 /* ... */
15 }
16 }
17}
18
You can dive into the various settings to fine-tune the options used for building, publishing, linting or testing the package. The low-level details are being taken care of by the plugin.
Running
npx nx build is-even
builds the src files and places a ready-to-be-published package indist/packages/is-even
at the root of your workspacenpx nx publish is-even
runs a publish script fromdist/packages/is-even
to push your package to NPMnpx nx test is-even
runs the pre-configured Jest tests for the packagenpx nx lint is-even
runs the pre-configured ESLint checks for the package
Local Linking of Packages
The local linking of packages in an integrated monorepo style is handled by Nx automatically by leveraging TypeScript path mappings in the tsconfig.base.json
file.
To illustrate that, let's create another package is-odd
. We can again run the generator for that:
โฏ
npx nx generate @nx/js:library is-odd \
โฏ
--directory=libs/is-odd \
โฏ
--publishable \
โฏ
--importPath=@myorg/is-odd
Note how the tsconfig.base.json
now has two entries:
1{
2 "compileOnSave": false,
3 "compilerOptions": {
4 ...
5 "paths": {
6 "@myorg/is-even": ["packages/is-even/src/index.ts"],
7 "@myorg/is-odd": ["packages/is-odd/src/index.ts"]
8 }
9 }
10}
11
Update the is-odd.ts
implemention in the is-odd
package to import isEven
from the @myorg/is-even
package:
1import { isEven } from '@myorg/is-even';
2
3export function isOdd(x: number): boolean {
4 return !isEven(x);
5}
6
This is all that needs to be done.
Typescript PathsWhen a library is created, Nx adds a new Typescript path to the tsconfig.base.json
file. The running Typescript server process inside of your editor sometimes doesn't pick up these changes and you have to restart the server to remove inline errors on your import statements. This can be done in VS Code from the command palette when viewing a typescript file (Command-Shift-P) "Typescript: Restart TS server"
Task Dependencies
In a monorepo there are not just dependencies among packages, but also among their tasks.
For example, whenever we build is-odd
we need to ensure that is-even
is built beforehand. Nx can define such task dependencies by adding a targetDefaults
property to nx.json.
In an integrated monorepo style this is already being dealt with by the generators. The current nx.json
file already comes with defaults that work out of the box:
1{
2 ...
3 "targetDefaults": {
4 "build": {
5 "dependsOn": ["^build"],
6 ...
7 },
8 ...
9 },
10 ...
11}
12
This tells Nx to run the build
target of all the dependent projects first, before the build
target of the package itself is being run.
Remove any existing dist
folder at the root of the workspace and run:
โฏ
npx nx build is-odd
It will automatically first run npx nx build is-even
, so you should end up with both packages in your dist folder. Note that if is-even
has been built before, it would just be restored out of the cache.
Cache Build Results
To build the is-even
package run:
โฏ
npx nx build is-even
Run the same command a second time and you'll see the build cache is being used:
~/workspaceโฏ
npx nx build is-even
1> nx run is-even:build
2
3Compiling TypeScript files for project "is-even"...
4Done compiling TypeScript files for project "is-even".
5
6 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
7
8 > NX Successfully ran target build for project is-even (713ms)
9
Running Multiple Tasks
To run the build
target for all the packages in the workspace, use:
โฏ
npx nx run-many -t build
What you would get is the following:
~/workspaceโฏ
npx nx run-many -t build
1 โ nx run is-even:build [existing outputs match the cache, left as is]
2 โ nx run is-odd:build (906ms)
3
4 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
5
6 > NX Successfully ran target build for 2 projects (914ms)
7
8 Nx read the output from the cache instead of running the command for 1 out of 2 tasks.
9
Note how on the is-even:build
it didn't run the build but rather pulled it out of the cache because the build has ran before. If you re-run the run-many
command all of the builds would be cached.
You can also only run tasks on packages that got changed by using
โฏ
npx nx affected -t build
Learn More
Read about the core features of Nx.
Get a deeper understanding of the mental model.
Learn how to add Nx to your existing repo.
Learn about two styles of monorepos.
A step-by-step tutorial showing how to build an integrated monorepo with React applications sharing code.