1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00
Files
browser/docs/using-nx-to-build-projects.md
Addison Beck 31aa5f4d5b refactor(nx): remove unneeded tsconfig.build.json & adjust nx docs (#16864)
* cleanup: remove unneeded tsconfig.build.json

* cleanup: nx docs
2025-10-14 11:07:23 -04:00

210 lines
7.5 KiB
Markdown

# Using Nx to Build Projects
Bitwarden uses [Nx](https://nx.dev/) to make building projects from the monorepo easier. To build, lint, or test a project you'll want to reference the project's `project.json` file for availible commands and their names. Then you'll run `npx nx [your_command] [your_project] [your_options]`. Run `npx nx --help` to see availible options, there are many.
Please note: the Nx implementation is a work in progress. CI still uses the old npm builds, and we have many "legacy" libraries that use hacks to get them into the Nx project graph.
## Quick Start
### Basic Commands
```bash
# Build a project
npx nx build cli
npx nx build-native desktop # Some apps have special build commands
npx nx build state # Modern libs and apps have simple, all lowercase target names
npx nx build @bitwarden/common # Legacy libs have a special naming convention and include the @bitwarden prefix
# Test a project
npx nx test cli
# Lint a project
npx nx lint cli
# Serve/watch a project (for projects with serve targets)
npx nx serve cli
# Build all projects that differ from origin/main
nx affected --target=build --base=origin/main
# Build, lint, and test every project at once
npx nx run-many --target=build,test,lint --all
# Most projects default to the "oss-dev" build, so if you need the bitwarden license build add a --configuration
npx nx build cli --configuration=commercial-dev
# If you need a production build drop the "dev" suffix
npx nx build cli --configuration=oss # or "commercial"
# Configurations can also be passed to run-many
# For example: to run all Bitwarden licensed builds
npx nx run-many --target=build,test,lint --all --configuration=commercial
# Outputs are distrubuted in a root level /dist/ folder
# Run a locally built CLI
node dist/apps/cli/oss-dev/bw.js
```
### Global Commands
```bash
# See all projects
npx nx show projects
# Run affected projects only (great for local dev and CI)
npx nx affected:build
npx nx affected:test
npx nx affected:lint
# Show dependency graph
npx nx dep-graph
```
## Library Projects
Our libraries use two different Nx integration patterns depending on their migration status.
### Legacy Libraries
Most existing libraries use a facade pattern where `project.json` delegates to existing npm scripts. This approach maintains backward compatibility with the build methods we used before introducing Nx. These libraries are considered tech debt and Platform has a focus on updating them. For an example reference `libs/common/project.json`.
These libraries use `nx:run-script` executor to call existing npm scripts:
```json
{
"targets": {
"build": {
"executor": "nx:run-script",
"options": {
"script": "build"
}
}
}
}
```
#### Available Commands for Legacy Libraries
All legacy libraries support these standardized commands:
- **`nx build <library>`** - Build the library
- **`nx build:watch <library>`** - Build and watch for changes
- **`nx clean <library>`** - Clean build artifacts
- **`nx test <library>`** - Run tests
- **`nx lint <library>`** - Run linting
### Modern Libraries
Newer libraries like `libs/state` use native Nx executors for better performance and caching.
```json
{
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/state"
}
}
}
}
```
## What Happens When You Run An Nx Command
```mermaid
flowchart TD
Start([You just ran an nx command]) --> ParseCmd[Nx parses command args]
ParseCmd --> ReadWorkspace[Nx reads nx.json, workspace configuration, cache settings, and plugins]
ReadWorkspace --> ReadProject[Nx reads project.json, finds the target configuration, and checks executor to use]
ReadProject --> CheckCache{Nx checks the cache: has this exact build been done before?}
CheckCache -->|Cache hit| UseCached[Nx uses cached outputs, copies from .nx/cache, and skips execution]
UseCached --> Done([Your command is done])
CheckCache -->|Cache miss| DetermineExecutor{Which executor is configured?}
DetermineExecutor -->|nx:run-script| FacadePattern[Legacy Facade Pattern]
DetermineExecutor -->|nx/webpack:webpack| WebpackExecutor[Webpack Executor]
DetermineExecutor -->|nx/js:tsc| TypeScriptExecutor[TypeScript Executor]
DetermineExecutor -->|nx/jest:jest| JestExecutor[Jest Executor]
DetermineExecutor -->|nx/eslint:lint| ESLintExecutor[ESLint Executor]
%% Facade Pattern Flow
FacadePattern --> ReadPackageJson[The run-script executor finds npm script to run in package.json]
ReadPackageJson --> RunNpmScript[Npm script is executed]
RunNpmScript --> NpmDelegates{What does the npm script do?}
NpmDelegates -->|TypeScript| TSCompile[TypeScript compiles to JavaScript using tsconfig.json]
NpmDelegates -->|Webpack| WebpackBuild[Webpack bundles and optimizes code]
NpmDelegates -->|Jest| JestTest[Jest executes unit tests]
TSCompile --> FacadeOutput[Outputs written to libs/LIB/dist/]
WebpackBuild --> FacadeOutput
JestTest --> FacadeOutput
FacadeOutput --> CacheResults1[Nx caches results in .nx/cache/]
%% Webpack Executor Flow
WebpackExecutor --> ReadWebpackConfig[Webpack config read from apps/cli/webpack.config.js or bit-cli/webpack.config.js]
ReadWebpackConfig --> ConfigureWebpack[Webpack configured with entry points, TypeScript paths, and plugins]
ConfigureWebpack --> WebpackProcess[Webpack resolves paths, compiles TypeScript, bundles dependencies, and applies optimizations]
WebpackProcess --> WebpackOutput[Single executable bundle written to dist/apps/cli/]
WebpackOutput --> CacheResults2[Nx caches results in .nx/cache/]
%% TypeScript Executor Flow
TypeScriptExecutor --> ReadTSConfig[TypeScript reads tsconfig.lib.json compilation options]
ReadTSConfig --> TSProcess[TypeScript performs type checking, emits declarations, and compiles to JavaScript]
TSProcess --> TSOutput[Outputs written to dist/libs/LIB/]
TSOutput --> CacheResults3[Nx caches results in .nx/cache/]
%% Jest Executor Flow
JestExecutor --> ReadJestConfig[Jest reads jest.config.js test configuration]
ReadJestConfig --> JestProcess[Jest finds test files, runs suites, and generates coverage]
JestProcess --> JestOutput[Test results and coverage reports output]
JestOutput --> CacheResults4[Nx caches results in .nx/cache/]
%% ESLint Executor Flow
ESLintExecutor --> ReadESLintConfig[ESLint reads .eslintrc.json rules and configuration]
ReadESLintConfig --> ESLintProcess[ESLint checks code style, finds issues, and applies auto-fixes]
ESLintProcess --> ESLintOutput[Lint results with errors and warnings output]
ESLintOutput --> CacheResults5[Nx caches results in .nx/cache/]
%% All paths converge
CacheResults1 --> UpdateGraph[Dependency graph updated to track project relationships]
CacheResults2 --> UpdateGraph
CacheResults3 --> UpdateGraph
CacheResults4 --> UpdateGraph
CacheResults5 --> UpdateGraph
UpdateGraph --> Done
```
## Caching and Performance
### Nx Caching
Nx automatically caches build outputs and only rebuilds what changed:
```bash
# First run builds everything
npx nx build cli
# Second run uses cache (much faster)
npx nx build cli
```
### Clearing Cache
```bash
# Clear all caches
npx nx reset
```
## Additional Resources
- [Nx Intro Documentation](https://nx.dev/getting-started/intro)
- [Nx CLI Commands Reference](https://nx.dev/docs/reference/nx-commands)
- [Nx Workspace Configuration](https://nx.dev/reference/project-configuration)