Step-by-step guide to creating new generators.
@nx/plugin installed: pnpm add -D @nx/plugin1
2
3
4
5
6
# Using Just (recommended)
just generator-new payment-service --type=service
# Or direct Nx command
pnpm exec nx g @nx/plugin:generator payment-service \
--project=generators
Edit generators/payment-service/schema.json:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"$schema": "http://json-schema.org/schema",
"id": "PaymentServiceGenerator",
"title": "Payment Service Generator",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the service",
"$default": { "$source": "argv", "index": 0 }
},
"includeTests": {
"type": "boolean",
"description": "Include test files",
"default": true
},
"database": {
"type": "string",
"enum": ["postgres", "mongodb", "none"],
"default": "postgres"
}
},
"required": ["name"]
}
Edit generators/payment-service/schema.d.ts:
1
2
3
4
5
export interface PaymentServiceGeneratorSchema {
name: string;
includeTests?: boolean;
database?: 'postgres' | 'mongodb' | 'none';
}
Edit generators/payment-service/generator.ts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import {
Tree,
formatFiles,
generateFiles,
names,
joinPathFragments,
} from '@nx/devkit';
import { PaymentServiceGeneratorSchema } from './schema';
export default async function paymentServiceGenerator(
tree: Tree,
options: PaymentServiceGeneratorSchema
) {
const projectRoot = joinPathFragments('apps', options.name);
const templateOptions = {
...options,
...names(options.name),
tmpl: '',
};
generateFiles(
tree,
joinPathFragments(__dirname, './files'),
projectRoot,
templateOptions
);
await formatFiles(tree);
return () => {
console.log(`✅ Generated payment service: ${options.name}`);
};
}
1
2
3
4
5
6
7
generators/payment-service/files/
├── src/
│ ├── index.ts__tmpl__
│ └── __fileName__.service.ts__tmpl__
├── __tests__/
│ └── __fileName__.service.spec.ts__tmpl__
└── package.json__tmpl__
Example template __fileName__.service.ts__tmpl__:
1
2
3
4
5
6
7
8
9
export class <%= className %>Service {
constructor() {
console.log('<%= name %> service initialized');
}
async processPayment(amount: number): Promise<void> {
// TODO: Implement payment processing
}
}
Edit generators/generators.json:
1
2
3
4
5
6
7
8
9
{
"generators": {
"payment-service": {
"factory": "./src/generators/payment-service/generator",
"schema": "./src/generators/payment-service/schema.json",
"description": "Creates a new payment service"
}
}
}
1
2
3
4
5
# Dry run first
pnpm exec nx g ./generators:payment-service my-payments --dry-run
# Execute
pnpm exec nx g ./generators:payment-service my-payments
1
2
3
4
5
6
7
8
9
10
11
12
13
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import generator from './generator';
describe('payment-service generator', () => {
it('should create service files', async () => {
const tree = createTreeWithEmptyWorkspace();
await generator(tree, { name: 'test-payment' });
expect(tree.exists('apps/test-payment/src/index.ts')).toBeTruthy();
expect(tree.exists('apps/test-payment/src/test-payment.service.ts')).toBeTruthy();
});
});