nx/docs/shared/recipes/generators/local-generators.md
Jack Hsu 8fa7065cf1
docs(misc): update generator examples to use new directory/path positional args (#28144)
This PR updates examples in `.md` files (both docs and blog posts) to
use positional args. Nx 20 changes the position arg to be either
`directory` for apps/libs or `path` for artifacts (e.g. components).

So before you'd do this:

```
nx g app myapp --directory=apps/myapp
nx g lib mylib --directory=libs/mylib
nx g lib mylib --directory=libs/nested/mylib
nx g lib @acme/foo --directory=libs/@acme/foo --importPath=@acme/foo
nx g component foo --directory=libs/ui/src/foo --pascalCaseFiles
```

Will now be simplified to

```
nx g app apps/myapp
nx g lib libs/mylib
nx g lib libs/nested/mylib
nx g lib libs/@acme/foo # name and import path are both "@acme/foo"
nx g component libs/ui/src/foo/Foo
```

For cases where `name` and `importPath` need to be changed, you can
always manually specify them.

```
nx g lib libs/nested/foo # name is foo
nx g lib libs/nested/foo --name=nested-foo # specify name with prefix
nx g lib libs/@acme/foo --name # use "foo" as name and don't match importPath
nx g lib libs/@internal/foo --importPath=@acme/foo # different importPath from name

<!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR -->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is merged. -->

Fixes #
2024-09-30 13:20:10 -04:00

4.4 KiB

Local Generators

Local plugin generators provide a way to automate many tasks you regularly perform as part of your development workflow. Whether it is scaffolding out components, features, or ensuring libraries are generated and structured in a certain way, generators help you standardize these tasks in a consistent, and predictable manner.

Nx provides tooling around creating, and running custom generators from within your workspace. This guide shows you how to create, run, and customize generators within your Nx workspace.

{% youtube src="https://www.youtube.com/embed/myqfGDWC2go" title="Scaffold new Pkgs in a PNPM Workspaces Monorepo" caption="Demoes how to use Nx generators in a PNPM workspace to automate the creation of libraries" /%}

Creating a generator

If you don't already have a local plugin, use Nx to generate one:

nx add @nx/plugin
nx g @nx/plugin:plugin tools/my-plugin

Note that latest should match the version of the nx plugins installed in your workspace.

Use the Nx CLI to generate the initial files needed for your generator.

nx generate @nx/plugin:generator tools/my-plugin/src/generators/my-generator

After the command is finished, the generator is created in the plugin generators folder.

happynrwl/
├── apps/
├── tools/
│   ├── my-plugin
│   │   ├── src
│   │   │   ├── generators
│   │   │   |   └── my-generator/
│   │   │   |   |    ├── generator.spec.ts
│   │   │   |   |    ├── generator.ts
│   │   │   |   |    ├── schema.d.ts
│   │   │   |   |    └── schema.json
├── nx.json
├── package.json
└── tsconfig.base.json

The generator.ts provides an entry point to the generator. The file contains a function that is called to perform manipulations on a tree that represents the file system. The schema.json provides a description of the generator, available options, validation information, and default values.

The initial generator function creates a library.

import { Tree, formatFiles, installPackagesTask } from '@nx/devkit';
import { libraryGenerator } from '@nx/js';

export default async function (tree: Tree, schema: any) {
  await libraryGenerator(tree, { name: schema.name });
  await formatFiles(tree);
  return () => {
    installPackagesTask(tree);
  };
}

To invoke other generators, import the entry point function and run it against the tree. async/await can be used to make code with Promises read like procedural code. The generator function may return a callback function that is executed after changes to the file system have been applied.

In the schema.json file for your generator, the name is provided as a default option. The cli property is set to nx to signal that this is a generator that uses @nx/devkit and not @angular-devkit.

{
  "cli": "nx",
  "id": "test",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Library name",
      "$default": {
        "$source": "argv",
        "index": 0
      }
    }
  },
  "required": ["name"]
}

The $default object is used to read arguments from the command-line that are passed to the generator. The first argument passed to this schematic is used as the name property.

Running a generator

To run a generator, invoke the nx generate command with the name of the generator.

nx generate @myorg/my-plugin:my-generator mylib

{% callout type="warning" title="string" %}

Nx uses the paths from tsconfig.base.json when running plugins locally, but uses the recommended tsconfig for node 16 for other compiler options. See https://github.com/tsconfig/bases/blob/main/bases/node16.json

{% /callout %}

Debugging generators

With Visual Studio Code

  1. Open the Command Palette and choose Debug: Create JavaScript Debug Terminal. This will open a terminal with debugging enabled.
  2. Set breakpoints in your code
  3. Run nx g my-generator in the debug terminal.

vscode-schematics-debug

Generator Utilities

The @nx/devkit package provides many utility functions that can be used in generators to help with modifying files, reading and updating configuration files, and working with an Abstract Syntax Tree (AST).