Nx community plugins are a powerful new technology by Nrwl that allows you to customize the functionality of Nx. If you have not yet watched Nrwl's official Nx Plugin guide then I highly recommend starting there.
You may be familiar with the ng add
command from the Angular CLI. This allows you to easily add a dependency and add any necessary files or configurations with a single command. @angular/material
is a great example of a library that utilizes this technology. Not only will ng add @angular/material
update your package.json
with the latest version of the library, but it will add the configurations you need and prompt you for additional customization. Since Nx relies heavily on Angular schematics, this functionality is fully supported in Nx Plugins.
Angular CLI vs Nx CLI
When using an Nx workspace, you have the choice of using the Angular CLI or the Nx CLI. While the commands for both CLI's are very similar, there are some minor differences, and one of them is with the ng add
command.
First of all, the Nx CLI does not automatically add the dependency to your package.json
, so the user must do that themselves. Second, the command is slightly different and executes an init
schematic. Under the hood, ng add
schematics are named init
with an ng-add
alias to support the Angular CLI.
Angular CLI:
ng add @nxtend/ionic-react
Nx CLI:
// npm
npm install --dev --exact @nxtend/ionic-react
// yarn
yarn install --dev --exact @nxtend/ionic-react
nx g @nxtend/ionic-react:init
Implementation
First, you'll want to edit collection.json
and add a new schematic named init
with an alias of ng-add
:
"schematics": {
"init": {
"factory": "./src/schematics/init/schematic",
"schema": "./src/schematics/init/schema.json",
"description": "Initialize the @nxtend/ionic-react plugin",
"aliases": ["ng-add"],
"hidden": true
}
}
Similar to other schematics, you can add flags and user prompts within the schema.json
file defined above using the properties
object:
"properties": {
"unitTestRunner": {
"type": "string",
"enum": ["karma", "jest", "none"],
"description": "Test runner to use for unit tests",
"default": "jest",
"x-prompt": {
"message": "Which Unit Test Runner would you like to use for the application?",
"type": "list",
"items": [
{
"value": "jest",
"label": "Jest [ https://jestjs.io ]"
},
{
"value": "karma",
"label": "Karma [ https://karma-runner.github.io ]"
}
]
}
},
"skipInstall": {
"type": "boolean",
"description": "Skip installing after adding @nrwl/workspace",
"default": false
}
}
I recommend viewing the Authorizing Schematics guide by Angular for more information on schematic prompts.
Finally, we can actually implement our schematic with the schematic.ts
file. Some of the more common actions taken in an init
schematic are adding dependencies and setting the schematic as the default collection. If you want to learn about adding dependencies in an Nx Plugin then check out my previous blog post.
Nx provides a function to add your schematic as the default collection if one does not currently exist. This can be easily demonstrated with the @nrwl/angular
or @nrwl/react
Nx Plugins. Essentially, if the init
schematic for either of these plugins is executed and there is currently no default collection specified in the users workspace.json
then that plugin will be set. This allows the user to execute commands without specifying that specific plugin.
// With @nrwl/react set as default collection
nx generate app myApp
// With @nrwl/react not set as default collection
nx generate @nrwl/react:app myApp
First, import setDefaultCollection
:
import { setDefaultCollection } from '@nrwl/workspace/src/utils/rules/workspace';
Next, execute this function with your plugin name as the function parameter within your default functions chain:
export default function(): Rule {
return chain([
setDefaultCollection('@nxtend/ionic-react')
]);
}
Testing
Testing your init
schematic is similar to testing any other schematic
. Here is a simple example taken from my @nxtend/ionic-react
plugin:
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import { readJsonInTree } from '@nrwl/workspace';
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
import { join } from 'path';
describe('init', () => {
let appTree: Tree;
const testRunner = new SchematicTestRunner(
'@nxtend/ionic-react',
join(__dirname, '../../../collection.json')
);
beforeEach(() => {
appTree = createEmptyWorkspace(Tree.empty());
});
it('should set default collection', async () => {
const result = await testRunner
.runSchematicAsync('init', {}, appTree)
.toPromise();
const workspaceJson = readJsonInTree(result, 'workspace.json');
expect(workspaceJson.cli.defaultCollection).toEqual('@nxtend/ionic-react');
});
});
Conclusion
Adding init
schematics, also known as ng add
schematics, are trivial thanks to the work done by the Nrwl team. As a bonus, consider executing your newly made init
schematic within your application
or other schematic. This ensures that your initilization process is executed whether the user initiated it or not.
References
Nx
Nx Plugin Guide
Building an Nx Plugin to Add Dependencies to a Project
Authoring Schematics by Angular
@nxtend/ionic-react GitHub
Top comments (0)