Getting Started with Package-Based Repos
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 package-based --preset=npm
The file structure should look like this:
myorg/
├── packages/
├── nx.json
└── package.json
Create a Package
The packages
folder is where we host our monorepo libraries. Create a new is-even
folder with the following structure:
packages/
└── is-even/
├── index.ts
└── package.json
Before proceeding, make sure you install TypeScript as we're going to use it to build our package. While we could install TypeScript at the package-level, it is more convenient to have it globally for the entire monorepo. Run the following command at the root of your workspace.
npm i typescript -D -W
Now update the content of the files to match the following:
export const isEven = (x: number) => x % 2 === 0;
Update the .gitignore
file to make sure you have a dist
entry (without a leading slash) to ignore the dist
folder inside the is-even
package.
Note, the build
uses TypeScript to compile the index.ts
file into a project-level ./dist
folder. To run it use:
npx nx build is-even
Local Linking of Packages
Linking packages locally in a package-based monorepo style is done with NPM/Yarn/PNPM workspaces. In this specific setup we use NPM workspaces (see package.json
at the root of this monorepo).
To illustrate how packages can be linked locally, let's create another package is-odd
. You can copy the existing is-even
package:
packages/
└── is-even/
├── ...
└── is-odd/
├── index.ts
└── package.json
Here's what the content of the files should look like:
import { isEven } from '@package-based/is-even';
export const isOdd = (x: number) => !isEven(x);
is-odd
imports the isEven
function from @package-based/is-even
. Therefore its package.json
file should list the is-even
package in its package.json
file as a dependency.
The workspaces
property in the root-level package.json
tells NPM (and it similar for Yarn or PNPM workspaces) to locally-link the two packages, without the need to publish them first to a NPM registry.
At the root of your workspace run
npm install
This allows the NPM workspace to properly link the new is-odd
package.
Task Dependencies
Most monorepos have dependencies not only among different 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
.
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
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 and run:
npx nx build is-odd
It will automatically first run npx nx build is-even
and then the build for is-odd
. 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
nx run is-even:build
@package-based/is-even@0.0.0 build
tsc index.ts --outDir dist
—————————————————————————————————————————————————————————————————
NX Successfully ran target build for project is-even (1s)
Running Multiple Tasks
To run the build
target for all the packages in the workspace, use:
npx nx run-many --target=build
What you would get is the following:
~/workspace❯
npx nx run-many --target=build
✔ nx run is-even:build [existing outputs match the cache, left as is]
✔ nx run is-odd:build (906ms)
—————————————————————————————————————————————————————————————————
> NX Successfully ran target build for 2 projects (914ms)
Nx read the output from the cache instead of running the command for 1 out of 2 tasks.
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 --target=build
Learn More
- Read about the core features of Nx
- Get a deeper understanding of the mental model behind Nx.
- Adopt Nx in your existing repo