Santosh Yadav
Google Developer Expert for Angular GitHub Start and Nx Champion, Open source contributor for Angular and NgRx, creator ng deploy for Netlify, NestJSAddons core team.
Santosh Yadav
GDE for Angular, GitHub Star, Auth0 Ambassador
Writer AngularInDepth, Software Consultant
twitter.com/SantoshYadavDev
github.com/SantoshYadavDev
https://www.linkedin.com/in/yadavsantosh/
santoshyadav.dev
Automate file creation/modification
Automate creating application/libraries
Automate Installation
npm install -g @angular-devkit/schematics-cli
schematics blank --name=ng-add
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function ngAdd(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
_context.addTask(new NodePackageInstallTask());
//add a new file
tree.create('index.ts',`console.log('Schematics is amazing')`);
//read a file
const fileData= tree.read('index.ts') || '';
_context.logger.info(fileData?.toString());
//overwrite a file
tree.overwrite('index.ts',`console.log('schematics is great')`)
_context.logger.info(fileData?.toString());
//delete a file
tree.delete('index.ts');
return tree;
};
}
generate
import { Tree } from "@angular-devkit/schematics/src/tree/interface";
import { Rule, apply, url, applyTemplates, chain, branchAndMerge, mergeWith, SchematicContext } from "@angular-devkit/schematics";
import { strings } from "@angular-devkit/core";
export function generate(_options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
const template = apply(url('./files'), [
applyTemplates({
...strings,
..._options
})
])
return chain([
branchAndMerge(mergeWith(template))
])(tree, context);
}
}
generate/index.ts
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"ng-add": {
"description": "A blank schematic.",
"factory": "./ng-add/index#ngAdd"
},
"generate": {
"description": "Generate schematic.",
"factory": "./generate/index#generate"
}
}
}
collection.json
{
"properties": {
"name": {
"type": "string",
"minLength": 1,
"default": "world",
"x-prompt": "What is your name?"
},
"useColor": {
"type": "boolean",
"x-prompt": "Would you like the response in color?"
}
}
}
schema.json
"schematics": "./src/collection.json",
package.json
// will not make any changes as debug is always false
schematcs .:ng-add
// will make actual changes
schematics .:ng-add --debug false
// test generate schematics
schematics .:generate --name test --debug false
Test Schematics
https://angular.io/guide/schematics
https://medium.com/@tomastrajan/total-guide-to-custom-angular-schematics-5c50cf90cdb4
https://indepth.dev/posts/1323/angular-schematics-from-0-to-publishing-your-own-library-i
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
}
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
}
Overriding Webpack Configuration.
Building and Publishing Angular Libraries.
Using Other Tools for Test like Jest or cypress.io.
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "bulma-app:build"
},
"configurations": {
"production": {
"browserTarget": "bulma-app:build:production"
}
}
}
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "bulma-app:build"
},
"configurations": {
"production": {
"browserTarget": "bulma-app:build:production"
}
}
}
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/bulma-app",
"index": "projects/bulma-app/src/index.html",
"main": "projects/bulma-app/src/main.ts",
"polyfills": "projects/bulma-app/src/polyfills.ts",
"tsConfig": "projects/bulma-app/tsconfig.app.json",
"aot": false,
"assets": [
],
"styles": [
],
"scripts": [
]
},
"configurations": {
"production": {
}
}
}
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/bulma-app",
"index": "projects/bulma-app/src/index.html",
"main": "projects/bulma-app/src/main.ts",
"polyfills": "projects/bulma-app/src/polyfills.ts",
"tsConfig": "projects/bulma-app/tsconfig.app.json",
"aot": false,
"assets": [
],
"styles": [
],
"scripts": [
]
},
"configurations": {
"production": {
}
}
}
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/ngx-bulma/tsconfig.lib.json",
"project": "projects/ngx-bulma/ng-package.json"
}
}
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/ngx-bulma/tsconfig.lib.json",
"project": "projects/ngx-bulma/ng-package.json"
}
}
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/bulma-app/src/test.ts",
"polyfills": "projects/bulma-app/src/polyfills.ts",
"tsConfig": "projects/bulma-app/tsconfig.spec.json",
"karmaConfig": "projects/bulma-app/karma.conf.js",
"assets": [
"projects/bulma-app/src/favicon.ico",
"projects/bulma-app/src/assets"
],
"styles": [
"projects/bulma-app/src/styles.css"
],
"scripts": [
]
}
}
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/bulma-app/src/test.ts",
"polyfills": "projects/bulma-app/src/polyfills.ts",
"tsConfig": "projects/bulma-app/tsconfig.spec.json",
"karmaConfig": "projects/bulma-app/karma.conf.js",
"assets": [
"projects/bulma-app/src/favicon.ico",
"projects/bulma-app/src/assets"
],
"styles": [
"projects/bulma-app/src/styles.css"
],
"scripts": [
]
}
}
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/bulma-app/e2e/protractor.conf.js",
"devServerTarget": "bulma-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "bulma-app:serve:production"
}
}
}
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/bulma-app/e2e/protractor.conf.js",
"devServerTarget": "bulma-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "bulma-app:serve:production"
}
}
}
import { BuilderContext, BuilderOutput, createBuilder } from
'@angular-devkit/architect';
import { json } from '@angular-devkit/core';
import { schema as BuilderOptions } from './schema';
export default createBuilder<json.JsonObject
& BuilderOptions>(execute);
async function execute(options: BuilderOptions,
context: BuilderContext)
: Promise<BuilderOutput> {
// custom logic to process
}
index.ts
import { BuilderContext, BuilderOutput, createBuilder } from
'@angular-devkit/architect';
import { json } from '@angular-devkit/core';
import { schema as BuilderOptions } from './schema';
export default createBuilder<json.JsonObject
& BuilderOptions>(execute);
async function execute(options: BuilderOptions,
context: BuilderContext)
: Promise<BuilderOutput> {
// custom logic to process
}
index.ts
const build = await context.scheduleTarget({
target: 'build',
project: context.target?.project || '',
configuration: 'production'
});
const schduleBuild = await context.scheduleBuilder('@angular-devkit/build-angular:browser', {
main: 'src/main.ts',
polyfills: "src/polyfills.ts",
});
index.ts
context.reportStatus('running');
// "error",
// "running",
// "stopped",
// "waiting"
context.reportRunning();
index.ts
{
"$schema": "@angular-devkit/architect/src/builders-schema.json",
"builders": {
"custom_builder_name": {
"implementation": "./deploy",
"schema": "./deploy/schema.json",
"description": "Runs any command line in the operating system."
}
}
}
builders.json
{
"$schema": "@angular-devkit/architect/src/builders-schema.json",
"builders": {
"custom_builder_name": {
"implementation": "./deploy",
"schema": "./deploy/schema.json",
"description": "Runs any command line in the operating system."
}
}
}
builders.json
{
"name": "@netlify-builder/deploy",
"version": "2.0.3",
"description": "A Netlify builder schematics for deployment",
"main": "index.js",
"builders": "./builders.json"
}
package.json
{
"name": "@netlify-builder/deploy",
"version": "2.0.3",
"description": "A Netlify builder schematics for deployment",
"main": "index.js",
"builders": "./builders.json"
}
package.json
"custom_builder_name": {
"builder": "package:custom_builder_name",
"options": {
// provide options
}
}
ngx-build-plus
@angular/fire:deploy
@angular-builders/jest
@azure/ng-deploy
Builders By Community
References
Thanks for writing about schematics and Builders
twitter.com/SantoshYadavDev
github.com/santoshyadav198613
https://www.linkedin.com/in/yadavsantosh/
santoshyadav.dev
Thank you
By Santosh Yadav
Google Developer Expert for Angular GitHub Start and Nx Champion, Open source contributor for Angular and NgRx, creator ng deploy for Netlify, NestJSAddons core team.