Hook — 05 : 40 a.m., Barranquilla ↔ São Paulo hand-off
Sunrise painted the Caribbean while I reviewed Diego’s pull-request from Brazil. He’d hand-coded a feature module, forgotten to add it to the workspace, and our CI in Panama croaked. “Why not scaffold with an Angular generator?” I asked between sips of café tinto. Minutes later we ran a custom schematic, wired a builder to bundle translations, and green ticks replaced red Xs—all before the humidity hit. Today’s post distills that cross-continent refactor: you’ll learn how Angular 18’s CLI super-powers—generators, builders, and workspaces—transform boilerplate into one-line commands, whether you’re coding from Mexican rooftops or Colombian coworks.
Why Master the CLI Now?
Challenge | Pre-CLI Pain | Angular 18 CLI Fix |
---|---|---|
Manual file scaffolding | Typos, missing metadata | Generators create typed boilerplate with lint & tests |
Custom build steps (i18n, Tailwind) | Bash scripts in package.json | Builders integrate tasks into ng build pipeline |
Multi-app monorepos | Yarn workspaces + custom tsconfig | Named workspaces manage libs/apps in one angular.json |
Slow dev loops | Full rebuild on file change | Built-in HMR & differential loading |
Onboarding juniors remotely | “Where do I put this file?” | CLI enforces structure; schematics document intent |
Concept Check—Generators vs. Builders vs. Workspaces
- Generator (schematic): CLI command that writes files + updates JSON.
- Builder: Node function that extends the ESBuild-based pipeline (test, lint, deploy).
- Workspace: The repo boundary managed by
angular.json
, now supports named scopes for sub-apps in Angular 18.
Think of it like coffee prep across Latin America: generator is the recipe, builder the espresso machine, workspace the kitchen layout.
Step-by-Step Walkthroughs
1 — Creating a Feature With the New Generator API
Angular 18 ships @schematics/angular@18
with JSON presets—no more long flags.
bashCopyEditng g feature products --preset=crud --standalone
Generated:
bashCopyEdit▾ src/app/products/
▸ products.routes.ts
▸ products.component.ts
▸ products.component.html
▸ products.service.ts
▸ products.model.ts
▸ products.spec.ts
Highlights
--preset=crud
wires a service with basicgetAll()
,create()
, etc.--standalone
auto-imports the route into rootapp.config.ts
.- Unit tests scaffolded with Jest.
Pitfall #1
Running inside wrong project. Fix: prepend ng g feature ... --project=admin-portal
.
2 — Building a Custom Builder for Tailwind Purge
bashCopyEditng g @schematics/angular:builder tailwind-purge
Creates builders.json
:
jsonCopyEdit{
"builders": {
"tailwind": {
"implementation": "./tailwind-builder.js",
"schema": "./tailwind-schema.json",
"description": "Purges unused Tailwind classes"
}
}
}
Implement tailwind-builder.js
:
tsCopyEditimport { createBuilder } from '@angular-devkit/architect';
import { execSync } from 'node:child_process';
export default createBuilder(({ projectRoot }, context) => {
try {
execSync('npx tailwindcss -i src/styles.css -o dist/styles.css --minify', {
stdio: 'inherit',
});
context.logger.info('Tailwind purge complete');
return { success: true };
} catch {
return { success: false };
}
});
Register in angular.json
:
jsonCopyEdit"architect": {
"build": {
"builder": "@myorg/tailwind:tailwind",
"options": { "projectRoot": "apps/store" }
}
}
Now ng build store
purges CSS automatically—no extra npm script.
Pitfall #2
Missing permissions on Windows WSL. Fix: use npx cross-env
or shell-independent Node APIs.
3 — Organizing a Multi-App Workspace
Angular 18 introduces named workspaces inside one repo.
bashCopyEditng new fintech --create-application=false
cd fintech
ng g application web-app
ng g application admin-api --backend
angular.json
snippet:
jsonCopyEdit{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 2,
"workspaces": {
"web-app": { "root": "apps/web-app", "type": "frontend" },
"admin-api": { "root": "apps/admin-api", "type": "backend" }
}
}
- HMR and lint configs inherited; each app can override builder targets.
- Shared UI library lives under
libs/ui
.
CLI Commands Cheat-Sheet
CLI | What it does |
---|---|
ng g feature <name> | Scaffold CRUD standalone module |
ng g builder <name> | Create custom builder skeleton |
ng add @angular/ssr | Add SSR + incremental hydration |
ng run <proj>:tailwind | Execute custom builder |
ng dep-graph | Visualize library/feature dependencies |
Remote-Work Insight 🏝️
Last quarter in Costa Rica I had 200 ms latency to our Git server. Using Angular 18’s caching builder (
--cache
flag) cut rebuilds from 30 s to 7 s, saving my prepaid data and my patience. Tip: mount.angular/cache
on a RAM disk in low-IO environments (e.g., old MacBooks in beach hostels).
Common Pitfalls & Fixes
Error | Cause | Fix |
---|---|---|
Cannot find builder | Wrong package path | Check builders.json name matches angular.json |
Schematic input does not validate | Missing flag for required schema prop | Run ng g feature users --dry-run to preview |
Circular lib import in workspace | Shared util imports back | Run ng lint --fix --circularDeps |
Performance & Accessibility Checkpoints
- Build Time—
ng build --stats-json
should show < 2 MB initial bundle; custom builders shouldn’t add polyfill bloat. - Lighthouse—verify incremental hydration routes hit < 1 s FCP on Fast 3G.
- Monorepo Size—
du -sh libs
weekly; remove unused libraries viang analytics prune
. - Accessible Templates—generators include ARIA labels; keep them when refactoring.
Diagram Idea
SVG: “CLI Flow” → Generator (write files) → Workspace config → Builder pipeline → Dist output (browser).
Wrap-Up
Angular 18’s CLI turns repetitive scaffolding into one-liners, plugs custom workflows straight into the build graph, and wrangles multi-app repos without tears. Generators handle boilerplate, builders extend the pipeline, and named workspaces scale your codebase from Dominican fintech POCs to Brazilian enterprise portals. Adopt them early, script your team’s patterns, and you’ll spend more time shipping features—and less time hunting missing imports across time zones.