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