Skip to content

Nx Docs #603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/contributing/development-tooling/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Development Tooling
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
---
title: Basic Library Generator
---

# Using the basic-lib Generator

The `basic-lib` generator creates a new library with Bitwarden's standard configuration and
structure. It sets up all the necessary files, configurations, and hooks with global configuration
files.

## Command Syntax

You can use the basic lib generator by running this command:

```bash
npx nx g @bitwarden/nx-plugin:basic-lib
```

## Available Options

All fields are required, but do not need to be supplied as CLI flags. Generator users will be asked
interactively for each of these if they are not supplied as CLI flags.

| Option | Description | Required | Default |
| --------------- | ----------------------------------------------- | -------- | ------- |
| `--name` | The name of the library | Yes | - |
| `--description` | A brief description of the library | Yes | none |
| `--team` | The team responsible for the library | Yes | none |
| `--directory` | The directory where the library will be created | Yes | "libs" |

## Step-by-Step Example

Let's create a new utility library called "password-insulter":

1. Open your terminal and navigate to the root of the Bitwarden clients repository
2. Run the generator command:
```bash
nx g @bitwarden/nx-plugin:basic-lib --name=password-insulter --description="Like the password strength meter, but more judgemental" --team=tools
```
3. The generator will create the library structure and update necessary configuration files
4. The new library is now ready to use

## What Gets Generated

The generator creates the following:

- **Library Structure**:

- `libs/password-insulter/`
- `src/`
- `index.ts` - Main entry point
- `README.md` - With the provided description
- `package.json` - Very minimal
- `tsconfig.json` - TypeScript configuration
- `tsconfig.lib.json` - Library-specific TypeScript configuration
- `tsconfig.spec.json` - Test-specific TypeScript configuration
- `jest.config.js` - Test configuration
- `.eslintrc.json` - Linting rules

- **Configuration Updates**:

The generator then updates `tsconfig.base.json` to reference your new library, updates CODEOWNERS to
assign the team to the new folder, and runs `npm i` to link everything up.

## Post-Generation Next Steps

After generating your library:

1. Review the generated README.md and update it with more detailed information if needed
2. Implement your library code in the `src/` directory, using whatever subfolder structure you
prefer
3. Export public APIs through the `src/index.ts` file
4. Write tests for your library
5. Build your library with `npx nx build password-insulter`
6. Lint your library with `npx nx lint password-insulter`
7. Test your library with `npx nx test password-insulter`

## Troubleshooting Common Issues

### Issue: Generator fails with path errors

**Solution**: Ensure you're running the command from the root of the repository.

### Issue: TypeScript path mapping not working

**Solution**: Run `nx reset` to clear the Nx cache, then try importing from your library again.

## Extending the Generated Code

The generated library provides a basic structure that you can extend:

- Add additional directories for specific features
- Create subdirectories in `src/` for better organization
- Modify the Jest configuration for specialized testing needs

## Designing a Library

There are a few ways you and your team may want to design a library, there are a lot of factors to
take into account like clean organization, ease of onboarding new members, simplicity of moving
ownership to a new team, and optimizing for module size. Below are a few ways you might want to
design a library.

### Option 1: Feature-based libraries

One strategy to employ is a feature-scoped library.

The import for such a library would be `@bitwarden/[feature]`. For example the `global-state`
feature would be imported with `@bitwarden/global-state`.

If the feature has both a UI component and needs to be used in the CLI it would probably result in a
`@bitwarden/[feature]-ui` or `@bitwarden/[feature]-angular` library as well.

:::note

With more things being added to the SDK and the CLI eventually being written directly in Rust there
will become less and less need to have a package with an Angular dependency and without it.

:::

Pros

- You'll have smaller libraries that have minimal dependencies, making them easier for another team
to depend on without a circular reference.
- If your team is ever split or a feature you own is moved to another team this can likely be done
with just an update to the GitHub `CODEOWNERS` file.
- You'll have a clearer dependency graph.
- Your modules will be smaller.

Cons

- YOu have to spend the time to think about and define what a feature is.
- You have to create libraries somewhat often.
- You MAY need "glue" libraries still.
- It is not as clear who owns what feature from looking at library names.

:::info Glue libraries

A "Glue" library is a library that might not exist other than the need for two teams to collaborate
on a cross cutting feature. The glue library might exist to hold an interface that team B is
expected to implement but team A will be responsible for consuming. This helps glue 2 features
together while still allowing for team A to consume other things that exist in team B's library but
still avoid a circular dependency.

:::

### Option 2: Team-based libraries

Another strategy would be to have a library for the vast majority of your teams code in a single
package.

There are many ways you may choose to design the library, but if it's one library you will need to
be dependent on everything that makes all your features tick.

**If all teams go this route it will be impossible to only have these team libraries**. Why? Because
the team grouping is very likely to result in circular dependencies. For example, if team A depends
on team B's library then team B cannot depend on anything in team A's library. If team B did need
something they would need to request that team A move it "downstream". Team A would need to move
their code and come up with a name for it. If they don't want to also re-export those pieces of code
they will need to update the import for every other place that code of used. You may also have to
deal with the code now being separated from similar code or you may decide to move that code too.

Pros

- You have fewer libraries to maintain.
- All your teamโ€™s code is in one place.

Cons

- You'll need to move code ad-hoc more often to make glue libraries, and each time try to think
about how to design the package abstraction.
- If your team splits you will need to move a lot more code.
- Youโ€™ll have larger modules.

### Option 3: Type-based libraries

You can also split libraries based on the primary kind of file that it holds. For example, you could
have a library holding all `type`โ€™s, one for `abstractions`, and on more `services`. Since one
library for all typeโ€™s would be mean having a library that has multiple owners it would be highly
discouraged and therefore this would likely be split by team as well, resulting in packages like
`@bitwarden/platform-types`; this library strategy is really a subset of the team-based one.

Pros

- Youโ€™ll be less likely to have circular dependencies within your teamโ€™s code, since generally Types
< Abstractions < Services where < means lower level.
- Itโ€™s most similar to the organization strategy weโ€™ve had for a while.

Cons

- There is no guarantee that all the types for a given team are lower level than all the types of
another team that they need to depend on. Circular dependencies can still happen amongst teams.
- Itโ€™s also possible for a type to need to depend on an abstraction,
- We are generally discouraging teams from making abstractions unless needed (link).

### Option 4: Feature/type hybrid

Another strategy could be to split libraries by the kind of item in feature-scoped libraries.

Pros

- Lowest chance of circular dependencies showing up later.
- Pretty easy to move ownership.

Cons

- The most libraries to maintain.
- Consumers will likely have to import multiple modules in order to use your feature.

### Platform Recommendation

Given the options available with Nx and the pros and cons of each, Platform is planning on using
[feature-based libraries](#option-1-feature-based-libraries) and we recommend other teams do as
well.

We understand that we might have a domain that is a little easier to split into features, but we
believe that the work is worthwhile for teams to do.

There will be some instances that our libraries may only contain abstractions and very simple types
which would then resemble the type-based approach. We will be forced to do this because we have some
things like storage where itโ€™s only really useful which the implementations made in the individual
apps.

Example Platform feature libraries (all of these would be imported like `@bitwarden/[feature]`:

- `storage-core`
- `user-state`
- `global-state`
- `state` (will have its own code but also a meta package re-exporting `user-state` and
`global-state`)
- `clipboard`
- `messaging`
- `ipc`
- `config`
- `http`
- `i18n`
- `environments`
- `server-notifications`
- `sync`

Hopefully these will give you some ideas for how to split up your own features.

## Further Learning

For more information about Nx libraries and generators:

- [Nx Library Generation](https://nx.dev/plugin-features/create-libraries)
- [Nx Library Types](https://nx.dev/more-concepts/library-types)
- [Nx Project Configuration](https://nx.dev/reference/project-configuration)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: Bitwarden Nx Plugin
---

# @bitwarden/nx-plugin

The `@bitwarden/nx-plugin` is a custom Nx plugin developed specifically for Bitwarden projects. It
provides generators tailored to Bitwarden's architecture and coding standards.

## Overview

This plugin extends Nx's capabilities with Bitwarden-specific generators that help maintain
consistency across the codebase. It automates the creation of libraries, components, and other
project elements according to Bitwarden's established patterns.

## How It Fits Into the Project Architecture

The `@bitwarden/nx-plugin` is designed to:

1. Enforce Bitwarden's architectural decisions and code organization
2. Streamline the creation of new libraries and components
3. Ensure consistent configuration across the project
4. Automate updates to project metadata and configuration files
5. Reduce the learning curve for new contributors

By using this plugin, we maintain a consistent approach to code organization and structure across
the entire project.

## Installation and Setup

The plugin is included as a development dependency in the project. If you're working with a fresh
clone of the repository, it will be installed when you run:

```bash
npm install
```

No additional setup is required to use the generators provided by the plugin.

## Available Generators

The plugin currently includes the following generators:

- `basic-lib`: Creates a new library with standard configuration and structure

Additional generators may be added in the future to support other common patterns in the Bitwarden
codebase.

## Further Learning

To learn more about Nx plugins and how they work:

- [Nx Plugin Development](https://nx.dev/extending-nx/creating-nx-plugins)
- [Nx Plugins Overview](https://nx.dev/extending-nx/intro)
64 changes: 64 additions & 0 deletions docs/contributing/development-tooling/nx/generators/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Nx Generators
---

# Nx Generators

Nx generators are powerful tools that automate the creation of code, configuration, and other files
in your project. They help maintain consistency across your codebase and reduce the manual effort
required to scaffold new components, libraries, or applications.

## What are Nx Generators?

Nx generators (previously known as schematics) are code generation tools that follow templates to
create or modify files in your project. They can:

- Create new files from templates
- Modify existing files
- Update configuration files
- Ensure consistent project structure
- Automate repetitive tasks

Generators can be run using the Nx CLI with the `nx generate` command (or the shorthand `nx g`).

## When to Use Generators

Use generators when:

- Creating new libraries, components, or features that follow a standard pattern
- You want to ensure consistency across similar parts of your application
- You need to automate repetitive setup tasks
- You want to reduce the chance of human error in project setup

## Why Use Generators Instead of Manual Creation

- **Consistency**: Generators ensure that all generated code follows the same patterns and
conventions
- **Efficiency**: Save time by automating repetitive tasks
- **Reduced Errors**: Minimize human error in project setup
- **Maintainability**: Easier to maintain code that follows consistent patterns
- **Onboarding**: Help new team members create code that follows project standards

## How Bitwarden Uses Generators

Platform maintains a Nx plugin (`@bitwarden/nx-plugin`) with custom generators for our monorepo. We
may at times also use stock generators from dependencies such as Nx's own generator for generating
nx plugins (a generator generator generator, if you will).

## Creating A Nx Generator

It may be useful at some point to create a new Nx generator. The platform team maintains a nx plugin
in `libs/nx-plugin` that has a generators folder. If you need to create a new generator please do so
by following these steps.

1. Run
`npx nx generate @nx/plugin:generator libs/nx-plugin/src/generators/your-generator-name-here}`.
This will create a basic generator structure for you to get started with.

## Further Learning

For more information about Nx generators, check out these resources:

- [Nx Generators Documentation](https://nx.dev/plugin-features/use-code-generators)
- [Creating Custom Generators](https://nx.dev/recipes/generators/creating-files)
- [Nx Generator Examples](https://nx.dev/plugin-features/use-code-generators#examples)
Loading