Day 28 — Advanced CLI: Custom Schematics & Builders
📘 Day 28 — Advanced CLI: Custom Schematics & Builders
Zero to Hero — Hands-on Angular Tutorial
Today you will learn:
- ✔️ What are Schematics? (
ng generate ...) - ✔️ Installing the Schematics CLI
- ✔️ Creating a Custom Schematic (e.g., “Company Standard Component”)
- ✔️ What are Builders? (
ng build ...) - ✔️ Creating a Builder (e.g., “Deploy to AWS”)
You use ng generate component every day. Today, you will learn how to write your own ng generate my-company-component. 🛠️
🟦 1. What are Schematics?
Schematics are code generators. They take a “Tree” (your file system), apply transformations (create/modify files), and return a new “Tree”.
Why build your own?
- Enforce naming conventions.
- Auto-generate Service + Store + Component files in one command.
- Update 50 files automatically during a migration.
🟩 2. Creating a Schematic
Step 1: Install Tools
npm install -g @angular-devkit/schematics-cli
Step 2: Create Project
schematics blank my-schematic
cd my-schematic
Step 3: Define the Logic
Edit src/my-schematic/index.ts:
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
export function mySchematic(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
// 1. Create a file
tree.create('hello-world.txt', 'Hello from your Custom Schematic!');
// 2. Log message
_context.logger.info('🎉 Created hello-world.txt');
return tree;
};
}
Step 4: Build & Run
npm run build
schematics .:my-schematic
It should generate hello-world.txt in your current folder!
🟧 3. Using Templates (EJS)
Creating files string-by-string is hard. We use Templates.
Create Template File: src/my-schematic/files/__name@dasherize__.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-<%= dasherize(name) %>',
template: `<h1><%= classify(name) %> Works!</h1>`
})
export class <%= classify(name) %>Component {}
<%= name %>: Variable replacement.__name@dasherize__: Dynamic filename (e.g.,my-component.component.ts).
Update index.ts to use TemplateSource:
import { url, apply, template, mergeWith } from '@angular-devkit/schematics';
import { strings } from '@angular-devkit/core';
export function myComponent(options: any): Rule {
return () => {
const source = apply(url('./files'), [
template({
...options,
...strings // helper functions like dasherize, classify
})
]);
return mergeWith(source);
};
}
Now schematics .:my-component --name=UserProfile creates a real Angular component!
🟥 4. What are Builders?
Builders control the process (ng build, ng test, ng deploy).
They don’t generate code; they run tasks.
Example:
ng builduses@angular-devkit/build-angular:browserng testuses@angular-devkit/build-angular:karma
Why build a Custom Builder?
- “I want
ng deployto upload to my FTP server.” - “I want
ng buildto also compress images.”
🟫 5. Creating a Custom Builder
Step 1: Create File builder.ts
import { createBuilder, BuilderContext, BuilderOutput } from '@angular-devkit/architect';
export default createBuilder(commandBuilder);
async function commandBuilder(
options: any,
context: BuilderContext,
): Promise<BuilderOutput> {
context.reportStatus(`Executing custom command...`);
context.logger.info(`✨ Running custom build for: ${options.name}`);
// Simulate work
await new Promise(resolve => setTimeout(resolve, 1000));
context.logger.info('✅ Done!');
return { success: true };
}
Step 2: usage in angular.json
"my-custom-command": {
"builder": "./my-builder:command",
"options": {
"name": "Production"
}
}
Running ng run my-app:my-custom-command will now trigger your script.
🎉 End of Day 28 — What You Learned
Today you became a Toolmaker:
- ✔️ Schematics: How to generate code programmatically.
- ✔️ Templating: Using EJS to create dynamic files.
- ✔️ Builders: How to hook into the
ngcommand system.
Automation is the key to scaling huge teams. 🚀
🧪 Day 28 Challenge
“The Service Generator”
- Create a schematic named
fast-service. - It should accept a
--nameargument. - It should create
[name].service.ts. - The service template should automatically include:
providedIn: 'root'- A dummy
getItems()method that returns an Observable. - Imported
HttpClientautomatically.
- Test it by generating
user.service.ts.
Want the solution? Say: “Show the Day 28 challenge solution”