What is @angular-devkit/schematics?
@angular-devkit/schematics is a powerful tool for creating and managing code transformations in Angular projects. It allows developers to automate tasks such as generating components, services, and other Angular constructs, as well as performing code modifications and migrations.
What are @angular-devkit/schematics's main functionalities?
Generating a Component
This feature allows you to generate a new Angular component by creating the necessary TypeScript file with a basic component structure.
const { Rule, SchematicContext, Tree } = require('@angular-devkit/schematics');
function createComponent(options) {
return (tree, _context) => {
const content = `import { Component } from '@angular/core';
@Component({
selector: 'app-${options.name}',
templateUrl: './${options.name}.component.html',
styleUrls: ['./${options.name}.component.css']
})
export class ${options.name.charAt(0).toUpperCase() + options.name.slice(1)}Component { }
`;
tree.create(`/src/app/${options.name}/${options.name}.component.ts`, content);
return tree;
};
}
module.exports = { createComponent };
Updating a File
This feature allows you to update an existing file by replacing specified text with new text.
const { Rule, SchematicContext, Tree } = require('@angular-devkit/schematics');
function updateFile(options) {
return (tree, _context) => {
const filePath = options.path;
if (tree.exists(filePath)) {
const content = tree.read(filePath).toString('utf-8');
const updatedContent = content.replace(options.oldText, options.newText);
tree.overwrite(filePath, updatedContent);
}
return tree;
};
}
module.exports = { updateFile };
Deleting a File
This feature allows you to delete a specified file from the project.
const { Rule, SchematicContext, Tree } = require('@angular-devkit/schematics');
function deleteFile(options) {
return (tree, _context) => {
const filePath = options.path;
if (tree.exists(filePath)) {
tree.delete(filePath);
}
return tree;
};
}
module.exports = { deleteFile };
Other packages similar to @angular-devkit/schematics
yeoman-generator
Yeoman Generator is a scaffolding tool that allows developers to create custom generators for various types of projects. It is more general-purpose compared to @angular-devkit/schematics, which is specifically tailored for Angular projects.
plop
Plop is a micro-generator framework that allows developers to create custom generators for code scaffolding. It is simpler and more lightweight compared to @angular-devkit/schematics, making it suitable for smaller projects or those not specifically tied to Angular.
hygen
Hygen is a fast and lightweight code generator that allows developers to create custom templates and generators. It is similar to @angular-devkit/schematics in terms of functionality but is more focused on simplicity and ease of use.
Schematics
A scaffolding library for the modern web.
Description
Schematics are generators that transform an existing filesystem. They can create files, refactor existing files, or move files around.
What distinguishes Schematics from other generators, such as Yeoman or Yarn Create, is that schematics are purely descriptive; no changes are applied to the actual filesystem until everything is ready to be committed. There is no side effect, by design, in Schematics.
Glossary
Term | Description |
---|
Schematics | A generator that executes descriptive code without side effects on an existing file system. |
Collection | A list of schematics metadata. Schematics can be referred by name inside a collection. |
Tool | The code using the Schematics library. |
Tree | A staging area for changes, containing the original file system, and a list of changes to apply to it. |
Rule | A function that applies actions to a Tree . It returns a new Tree that will contain all transformations to be applied. |
Source | A function that creates an entirely new Tree from an empty filesystem. For example, a file source could read files from disk and create a Create Action for each of those. |
Action | An atomic operation to be validated and committed to a filesystem or a Tree . Actions are created by schematics. |
Sink | The final destination of all Action s. |
Task | A Task is a way to execute an external command or script in a schematic. A Task can be used to perform actions such as installing dependencies, running tests, or building a project. A Task is created by using the SchematicContext object and can be scheduled to run before or after the schematic Tree is applied. |
Tooling
Schematics is a library, and does not work by itself. A reference CLI is available on this repository, and is published on NPM at @angular-devkit/schematics-cli. This document explains the library usage and the tooling API, but does not go into the tool implementation itself.
The tooling is responsible for the following tasks:
- Create the Schematic Engine, and pass in a Collection and Schematic loader.
- Understand and respect the Schematics metadata and dependencies between collections. Schematics can refer to dependencies, and it's the responsibility of the tool to honor those dependencies. The reference CLI uses NPM packages for its collections.
- Create the Options object. Options can be anything, but the schematics can specify a JSON Schema that should be respected. The reference CLI, for example, parses the arguments as a JSON object and validates it with the Schema specified by the collection.
- Schematics provides some JSON Schema formats for validation that tooling should add. These validate paths, html selectors and app names. Please check the reference CLI for how these can be added.
- Call the schematics with the original Tree. The tree should represent the initial state of the filesystem. The reference CLI uses the current directory for this.
- Create a Sink and commit the result of the schematics to the Sink. Many sinks are provided by the library; FileSystemSink and DryRunSink are examples.
- Output any logs propagated by the library, including debugging information.
The tooling API is composed of the following pieces:
Engine
The SchematicEngine
is responsible for loading and constructing Collection
s and Schematics
. When creating an engine, the tooling provides an EngineHost
interface that understands how to create a CollectionDescription
from a name, and how to create a SchematicDescription
.
Schematics (Generators)
Schematics are generators and part of a Collection
.
Collection
A Collection is defined by a collection.json
file (in the reference CLI). This JSON defines the following properties:
Prop Name | Type | Description |
---|
name | string | The name of the collection. |
version | string | Unused field. |
Schematic
Operators, Sources and Rules
A Source
is a generator of a Tree
; it creates an entirely new root tree from nothing. A Rule
is a transformation from one Tree
to another. A Schematic
(at the root) is a Rule
that is normally applied on the filesystem.
Operators
FileOperator
s apply changes to a single FileEntry
and return a new FileEntry
. The result follows these rules:
- If the
FileEntry
returned is null, a DeleteAction
will be added to the action list. - If the path changed, a
RenameAction
will be added to the action list. - If the content changed, an
OverwriteAction
will be added to the action list.
It is impossible to create files using a FileOperator
.
Provided Operators
The Schematics library provides multiple Operator
factories by default that cover basic use cases:
FileOperator | Description |
---|
contentTemplate<T>(options: T) | Apply a content template (see the Templating section) |
pathTemplate<T>(options: T) | Apply a path template (see the Templating section) |
Provided Sources
The Schematics library additionally provides multiple Source
factories by default:
Source | Description |
---|
empty() | Creates a source that returns an empty Tree . |
source(tree: Tree) | Creates a Source that returns the Tree passed in as argument. |
url(url: string) | Loads a list of files from the given URL and returns a Tree with the files as CreateAction applied to an empty Tree . |
apply(source: Source, rules: Rule[]) | Apply a list of Rule s to a source, and return the resulting Source . |
Provided Rules
The schematics library also provides Rule
factories by default:
Rule | Description |
---|
noop() | Returns the input Tree as is. |
chain(rules: Rule[]) | Returns a Rule that's the concatenation of other Rule s. |
forEach(op: FileOperator) | Returns a Rule that applies an operator to every file of the input Tree . |
move(root: string) | Moves all the files from the input to a subdirectory. |
merge(other: Tree) | Merge the input Tree with the other Tree . |
contentTemplate<T>(options: T) | Apply a content template (see the Template section) to the entire Tree . |
pathTemplate<T>(options: T) | Apply a path template (see the Template section) to the entire Tree . |
template<T>(options: T) | Apply both path and content templates (see the Template section) to the entire Tree . |
filter(predicate: FilePredicate<boolean>) | Returns the input Tree with files that do not pass the FilePredicate . |
Templating
As referenced above, some functions are based upon a file templating system, which consists of path and content templating.
The system operates on placeholders defined inside files or their paths as loaded in the Tree
and fills these in as defined in the following, using values passed into the Rule
which applies the templating (i.e. template<T>(options: T)
).
Path Templating
Placeholder | Description |
---|
__variable__ | Replaced with the value of variable . |
__variable@function__ | Replaced with the result of the call function(variable) . Can be chained to the left (__variable@function1@function2__ etc). |
Content Templating
Placeholder | Description |
---|
<%= expression %> | Replaced with the result of the call of the given expression. This only supports direct expressions, no structural (for/if/...) JavaScript. |
<%- expression %> | Same as above, but the value of the result will be escaped for HTML when inserted (i.e. replacing '<' with '<') |
<% inline code %> | Inserts the given code into the template structure, allowing to insert structural JavaScript. |
<%# text %> | A comment, which gets entirely dropped. |
Examples
Simple
An example of a simple Schematics which creates a "hello world" file, using an option to determine its path:
import { Tree } from '@angular-devkit/schematics';
export default function MySchematic(options: any) {
return (tree: Tree) => {
tree.create(options.path + '/hi', 'Hello world!');
return tree;
};
}
A few things from this example:
- The function receives the list of options from the tooling.
- It returns a
Rule
, which is a transformation from a Tree
to another Tree
.
Templating
A simplified example of a Schematics which creates a file containing a new Class, using an option to determine its name:
export class <%= classify(name) %> {
}
import { strings } from '@angular-devkit/core';
import {
Rule,
SchematicContext,
SchematicsException,
Tree,
apply,
branchAndMerge,
mergeWith,
template,
url,
} from '@angular-devkit/schematics';
import { Schema as ClassOptions } from './schema';
export default function (options: ClassOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
if (!options.name) {
throw new SchematicsException('Option (name) is required.');
}
const templateSource = apply(url('./files'), [
template({
...strings,
...options,
}),
]);
return branchAndMerge(mergeWith(templateSource));
};
}
Additional things from this example:
strings
provides the used dasherize
and classify
functions, among others.- The files are on-disk in the same root directory as the
index.ts
and loaded into a Tree
. - Then the
template
Rule
fills in the specified templating placeholders. For this, it only knows about the variables and functions passed to it via the options-object. - Finally, the resulting
Tree
, containing the new file, is merged with the existing files of the project which the Schematic is run on.
19.0.0 (2024-11-19)
Breaking Changes
@schematics/angular
- The app-shell schematic is no longer compatible with Webpack-based builders.
@angular-devkit/build-angular
-
The browserTarget
option has been removed from the DevServer and ExtractI18n builders. buildTarget
is to be used instead.
-
Protractor is no longer supported.
Protractor was marked end-of-life in August 2023 (see https://protractortest.org/). Projects still relying on Protractor should consider migrating to another E2E testing framework, several support solid migration paths from Protractor.
- https://angular.dev/tools/cli/end-to-end
- https://blog.angular.dev/the-state-of-end-to-end-testing-with-angular-d175f751cb9c
@angular-devkit/core
@angular/build
- The
@angular/localize/init
polyfill will no longer be added automatically to projects. To prevent runtime issues, ensure that this polyfill is manually included in the "polyfills" section of your "angular.json" file if your application relies on Angular localization features.
@angular/ssr
-
The CommonEngine
API now needs to be imported from @angular/ssr/node
.
Before
import { CommonEngine } from '@angular/ssr';
After
import { CommonEngine } from '@angular/ssr/node';
@angular-devkit/schematics-cli
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------- |
| 37693c40e | feat | add package manager option to blank schematic |
@schematics/angular
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------------------- |
| a381a3db1 | feat | add option to export component as default |
| 755f3a07f | feat | add option to setup new workspace or application as zoneless mode |
| cfca5442e | feat | integrate withEventReplay()
in provideClientHydration
for new SSR apps |
| 292a4b7c2 | feat | update app-shell and ssr schematics to adopt new Server Rendering API |
| b1504c3bc | fix | component spec with export default |
| 4b4e000dd | fix | don't show server routing prompt when using browser
builder |
| 4e2a5fe15 | fix | enable opt-in for new @angular/ssr
feature |
| fcf7443d6 | fix | explicitly set standalone:false |
| 7992218a9 | fix | remove declaration
and sourceMap
from default tsconfig |
| 9e6ab1bf2 | fix | use default import for express
|
@angular/cli
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------- |
| 201b60e1d | feat | handle string key/value pairs, e.g. --define |
| b847d4460 | fix | recommend optional application update migration during v19 update |
| f249e7e85 | perf | enable Node.js compile code cache when available |
| ecc107d83 | perf | enable Node.js compile code cache when available |
@angular-devkit/architect
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------- |
| 78f76485f | feat | merge object options from CLI |
@angular-devkit/build-angular
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------- |
| 0a4ef3026 | feat | karma-coverage w/ app builder |
| dcbdca85c | feat | karma+esbuild+watch |
| 54594b5ab | feat | support karma with esbuild |
| ea5ae68da | fix | bring back style tags in browser builder |
| 476f94f51 | fix | fix --watch regression in karma |
| 25d928b4f | fix | fix hanging terminal when browser-sync
is not installed |
| 2ec877dd0 | fix | handle basename collisions |
| ab6e19e1f | fix | handle main field |
| 43e7aae22 | fix | remove double-watch in karma |
| 1e37b5939 | fix | serve assets |
| 9d7613db9 | fix | zone.js/testing + karma + esbuild |
| e40384e63 | refactor | remove deprecated browserTarget
|
| 62877bdf2 | refactor | remove Protractor builder and schematics |
@angular-devkit/core
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------ |
| 0d8a1006d | refactor | remove deprecated fileBuffer
function in favor of stringToFileBuffer
|
@angular/build
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- |
| b6951f448 | feat | add sass
to stylePreprocessorOptions
in application builder |
| efb434136 | feat | Auto-CSP support as a part of angular.json schema |
| 816e3cb86 | feat | enable component stylesheet hot replacement by default |
| 3b00fc908 | feat | introduce outputMode
option to the application builder |
| 7d883a152 | feat | introduce ssr.experimentalPlatform
option |
| c48d6947e | feat | set development/production condition |
| f63072668 | feat | utilize ssr.entry
during prerendering to enable access to local API routes |
| bbc290133 | feat | utilize ssr.entry
in Vite dev-server when available |
| 5a7a2925b | fix | add missing redirect in SSR manifest |
| 06e5176c2 | fix | add warning when --prerendering
or --app-shell
are no-ops |
| ecaf870b5 | fix | always clear dev-server error overlay on non-error result |
| f8677f6a9 | fix | always record component style usage for HMR updates |
| 099e477a8 | fix | avoid hashing development external component stylesheets |
| 3602bbb77 | fix | avoid overwriting inline style bundling additional results |
| 71534aadc | fix | check referenced files against native file paths |
| fed31e064 | fix | correctly use dev-server hmr option to control stylesheet hot replacement |
| b86bb080e | fix | disable dev-server websocket when live reload is disabled |
| 7c50ba9e2 | fix | ensure index.csr.html
is always generated when prerendering or SSR are enabled |
| efb2232df | fix | ensure accurate content size in server asset metadata |
| 18a8584ea | fix | ensure SVG template URLs are considered templates with external stylesheets |
| 7502fee28 | fix | Exclude known --import
from execArgv when spawning workers |
| 2551df533 | fix | fully disable component style HMR in JIT mode |
| c41529cc1 | fix | handle APP_BASE_HREF
correctly in prerendered routes |
| 87a90afd4 | fix | incomplete string escaping or encoding |
| 1bb68ba68 | fix | move lmdb to optionalDependencies |
| a995c8ea6 | fix | prevent prerendering of catch-all routes |
| 1654acf0f | fix | relax constraints on external stylesheet component id |
| 0d4558ea5 | fix | set ngServerMode
during vite prebundling |
| 55d7f01b6 | fix | simplify disabling server features with --no-server
via command line |
| cf0228b82 | fix | skip wildcard routes from being listed as prerendered routes |
| af52fb49b | fix | synchronize import/export conditions between bundler and TypeScript |
| 6c618d495 | fix | update logic to support both internal and external SSR middlewares |
| bfa8fec9b | fix | use named export reqHandler
for server.ts request handling |
| c8e1521a2 | fix | workaround Vite CSS ShadowDOM hot replacement |
| d6a34034d | refactor | remove automatic addition of @angular/localize/init
polyfill and related warnings |
@angular/ssr
| Commit | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------- |
| 92209dd2e | feat | add createRequestHandler
and createNodeRequestHandler
utilities |
| 41fb2ed86 | feat | Add getHeaders
Method to AngularAppEngine
and AngularNodeAppEngine
for handling pages static headers |
| f346ee8a8 | feat | add isMainModule
function |
| d66aaa3ca | feat | add server routing configuration API |
| bca568389 | feat | dynamic route resolution using Angular router |
| 30c25bf68 | feat | export AngularAppEngine
as public API |
| 455b5700c | feat | expose writeResponseToNodeResponse
and createWebRequestFromNodeRequest
in public API |
| 9692a9054 | feat | improve handling of aborted requests in AngularServerApp
|
| 576ff604c | feat | introduce AngularNodeAppEngine
API for Node.js integration |
| 3c9697a8c | feat | introduce new hybrid rendering API |
| 4b09887a9 | feat | move CommonEngine
API to /node
entry-point |
| d43180af5 | fix | add missing peer dependency on @angular/platform-server
|
| 74b3e2d51 | fix | add validation to prevent use of provideServerRoutesConfig
in browser context |
| 2640bf7a6 | fix | correct route extraction and error handling |
| 44077f54e | fix | designate package as side-effect free |
| df4e1d360 | fix | enable serving of prerendered pages in the App Engine |
| 0793c78cf | fix | ensure wildcard RenderMode is applied when no Angular routes are defined |
| 65b6e75a5 | fix | export RESPONSE_INIT
, REQUEST
, and REQUEST_CONTEXT
tokens |
| 4ecf63a77 | fix | export PrerenderFallback |
| 50df63196 | fix | improve handling of route mismatches between Angular server routes and Angular router |
| 3cf7a5223 | fix | initialize the DI tokens with null
to avoid requiring them to be set to optional |
| 85df4011b | fix | resolve bootstrap is not a function
error |
| e9c9e4995 | fix | resolve circular dependency issue from main.server.js reference in manifest |
| 64c52521d | fix | show error when multiple routes are set with RenderMode.AppShell
|
| 280ebbda4 | fix | support for HTTP/2 request/response handling |
| fb05e7f0a | fix | use wildcard server route configuration on the '/' route when the app router is empty |
| 12ff37adb | perf | cache generated inline CSS for HTML |
| 1d70e3b46 | perf | cache resolved entry-points |
| f460b91d4 | perf | integrate ETags for prerendered pages |
| e52ae7f6f | perf | prevent potential stampede in entry-points cache |
<!-- CHANGELOG SPLIT MARKER -->
<a name="18.2.12"></a>