nx/docs/shared/nx-plugin.md

9.5 KiB

Creating a Nx Plugin

Generating a Plugin

To get started with building a Nx Plugin, you can run the following command:

npx create-nx-plugin my-org --pluginName my-plugin

This command will create a brand new workspace, and set up a pre-configured plugin with the specified name.

Workspace Structure

After executing the above command, the following tree structure will be created:

my-org/
├── apps/
│   └── my-plugin-e2e/
│       ├── jest.config.js
│       ├── tests/
│       │   └── my-plugin.test.ts
│       ├── tsconfig.json
│       └── tsconfig.spec.json
├── jest.config.js
├── libs/
│   └── my-plugin/
│       ├── README.md
│       ├── builders.json
│       ├── collection.json
│       ├── jest.config.js
│       ├── package.json
│       ├── src/
│       │   ├── builders/
│       │   │   └── my-plugin/
│       │   │       ├── builder.spec.ts
│       │   │       ├── builder.ts
│       │   │       ├── schema.d.ts
│       │   │       └── schema.json
│       │   ├── index.ts
│       │   └── schematics/
│       │       └── my-plugin/
│       │           ├── files/
│       │           │   └── src/
│       │           │       └── index.ts.template
│       │           ├── schema.d.ts
│       │           ├── schema.json
│       │           ├── schematic.spec.ts
│       │           └── schematic.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       └── tsconfig.spec.json
├── nx.json
├── package.json
├── tools
│   ├── schematics/
│   └── tsconfig.tools.json
├── tsconfig.json
├── workspace.json
└── yarn.lock

If you do not want to create a new workspace, you can install install the @nrwl/nx-plugin dependency in an already existing workspace with npm or yarn. Then run nx g @nrwl/nx-plugin:plugin [pluginName].

Whenever a new plugin is created, it will include a default schematic, builder, and e2e app.

Schematic

The generated schematic will contain boilerplate that will do the following:

  • Normalize a schema (the options that the schematic will accept)
  • Update the workspace.json (or angular.json if you would like your plugin be used in a Angular CLI workspace)
  • Add the plugin's project to the nx.json file
  • Add files to the disk using templates

To change the type of project the plugin will generate, you can change the projectType const with the ProjectType enum. This will ensure that generated projects with your plugin will go in to the correct workspace directory (libs/ or apps/).

const projectType = ProjectType.Library;
// OR
// const projectType = ProjectType.Application;

Schematic options

There will be a generated schema.d.ts file that will contain all the options that the schematic supports. By default, we include directory, tags, and name as the options. If you need to add more, please update this file and the schema.json file.

Note: The schema.d.ts file is used for type checking inside your implementation file. It should match the properties in schema.json.

Adding more schematics

To add more schematics to your plugin, create a new folder that contains a implementation file, a schema.json file, and a schema.d.ts file. After, edit the collection.json file and add your new schematic there.

{
  "$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json",
  "name": "my-plugin",
  "version": "0.0.1",
  "schematics": {
    "myPlugin": {
      "factory": "./src/schematics/my-plugin/schematic",
      "schema": "./src/schematics/my-plugin/schema.json",
      "description": "my-plugin schematic"
    },
    // new schematic
    "added-schematic": {
      "factory": "./src/schematics/added-schematic/schematic",
      "schema": "./src/schematics/added-schematic/schema.json",
      "description": "added-schematic schematic"
    }
  }
}

To read more about schematics and how they work, you can go to the documentation at angular.io/guide/schematics-authoring

Schematic Testing

The schematic spec file will include boilerplate to help you get started with testing. This includes setting up a empty workspace, and the schematic test runner.

Full E2Es are supported (and recommended) and will run everything on the file system like a user would.

Builder

The generated builder is set up to just emit output. It's up to you to decide what you would like to actually want the builder to do. Some examples of what a builder can do are:

  • Use the .NET core compiler (or something similar)
  • Compile Stencil/Svelte/Vue components
  • Deploy an app on a CDN
  • Publish to NPM
  • and many more!

Adding more builders

Adding more builders to your plugin is exactly the same as adding more schematics. Create a new folder then add a implementation, schema.json and schema.d.ts files. Then edit the builders.json file in the root of your plugin project.

{
  "$schema": "../../node_modules/@angular-devkit/architect/src/builders-schema.json",
  "builders": {
    "build": {
      "implementation": "./src/builders/my-plugin/builder",
      "schema": "./src/builders/my-plugin/schema.json",
      "description": "my-plugin builder"
    },
    // new builder
    "newBuilder": {
      "implementation": "./src/builders/new-builder/builder",
      "schema": "./src/builders/new-builder/schema.json",
      "description": "new-builder builder"
    }
  }
}

Note: to use your new builder in any target (inside the workspace.json or angular.json), you would use the following @my-org/my-plugin:newBuilder

To read more about builders and how they work, you can go to the documentation at angular.io/guide/cli-builder

Builder testing

The builder spec file contains boilerplate to set up the CoreSchemaRegistry, TestingArchitectHost and adds the builder from a package.json.

There are some additional comments to help with these tests. To read more about testing builders, you can go to the angular.io/guide/cli-builder#testing-a-builder docs.

Full E2Es are supported (and recommended) and will run everything on the file system like a user would.

E2Es

One of the biggest benefits that the Nx Plugin package provides is support for E2E testing your plugin.

When running a E2E, we create a temporary E2E directory in the root of your workspace. This temporary directory is a blank Nx workspace, and will have your plugin's built package installed locally.

E2E Testing file

When a new plugin is generated, a test file will be created in the my-plugin-e2e app. Inside this test file, there is already tests for making sure that the builder ran, checking if directories are created with the --directory option, and checking if tags are added to nx.json.

We'll go over a few parts of a test file below:

it('should create my-plugin', async done => {
  const plugin = uniq('my-plugin');
  ensureNxProject('@my-org/my-plugin', 'dist/libs/my-plugin');
  await runNxCommandAsync(`generate @my-org/my-plugin:myPlugin ${plugin}`);

  const result = await runNxCommandAsync(`build ${plugin}`);
  expect(result.stdout).toContain('Builder ran');

  done();
});
  • The uniq function creates a random name with the prefix and a random number.
  • The ensureNxProject is the function that will create the temporary directory. It takes two arguments, the plugin package name and the dist directory of when it's built.
  • The runNxCommandAsync will execute a nx command in the E2E directory.

There are additional functions that the @nrwl/nx-plugin/testing package exports. Most of them are file utilities to manipulate and read files in the E2E directory.

Assets

Sometimes you might want to include some assets with your plugin. This might be a image or some additional binaries.

To make sure that assets are copied to the dist folder, open the workspace.json (or angular.json) file, and find the plugin's project. Inside the build property, you can add additional assets. By default, we include all .md files in the root, all non-ts files in folders, and the collection.json and builders.json files.

"build": {
  "builder": "@nrwl/node:package",
  "options": {
    // shortened...
    "assets": [
      "libs/my-plugin/*.md",
      {
        "input": "./libs/my-plugin/src",
        "glob": "**/*.!(ts)",
        "output": "./src"
      },
      {
        "input": "./libs/my-plugin",
        "glob": "collection.json",
        "output": "."
      },
      {
        "input": "./libs/my-plugin",
        "glob": "builders.json",
        "output": "."
      }
    ]
  }
}

Publishing your Nx Plugin

To publish your plugin follow these steps:

  1. Build your plugin with the command nx run my-plugin:build
  2. npm publish ./dist/libs/my-plugin and follow the prompts from npm.
  3. Thats it!

Note: currently you will have to modify the package.json version by yourself or with a tool.

After that, you can then install your plugin like any other npm package, npm i -D @my-org/my-plugin.

Nx listing

If you would like your plugin to be included with the nx list command, open up an issue on the Nrwl/nx repo and let's discuss!