Mais conteúdo relacionado Semelhante a JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers (20) JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers6. @maciejtreder
Do Not Reinvent the Wheel
• Angular CLI
• Angular Webpack starter (https://github.com/preboot/angular-webpack)
• Angular Universal starter (https://github.com/angular/universal-starter)
10. @maciejtreder
Schematics
• Set of instructions (rules) consumed by the Angular CLI to manipulate the
file-system and perform NodeJS tasks
• Extensible - possible to combine multiple internal and external rules
• Atomic - “commit approach”/“all or nothing”
ng add/update/init/something
12. @maciejtreder
package.json
{
"author": "Maciej Treder <contact@maciejtreder.com>",
"name": "@ng-toolkit/universal",
"main": "dist/index.js",
"version": "1.1.50",
"description": "Adds Angular Universal support for any Angular CLI project",
"repository": {
"type": "git",
"url": "git+https://github.com/maciejtreder/ng-toolkit.git"
},
"license": "MIT",
"schematics": "./collection.json",
"peerDependencies": {
},
"dependencies": {
},
"devDependencies": {
},
"publishConfig": {
"access": "public"
"schematics": "./collection.json",
14. @maciejtreder
schema.json{
"$schema": "http://json-schema.org/schema",
"id": "ng-toolkit universal",
"title": "Angular Application Options Schema",
"type": "object",
"properties": {
"directory": {
"description": "App root catalog",
"type": "string",
"default": "."
},
"http": {
"description": "Determines if you want to install TransferHttpCacheModule",
"type": "boolean",
"default": true
}
},
"required": []
ng add @ng-toolkit/universal —http false
17. @maciejtreder
Rule
• Set of instructions for the Angular CLI
• (tree: Tree, context: SchematicContext) => Tree | Observable<Tree> |
Rule | void
let rule: Rule = (tree: Tree) => {
tree.create('hello', 'world');
return tree;
}
krk-mps4m:angular-oslo mtreder$ ls
hello
krk-mps4m:angular-oslo mtreder$ cat hello
world
CLI
19. @maciejtreder
Tree | Observable<Tree> | Rule |
void
export function performAdditionalAction(originalRule: Rule): Rule {
return (tree: Tree, context: SchematicContext) => {
originalRule.apply(tree, context)
.pipe(map(
(tree: Tree) => console.log(tree.exists('hello'))
)
);
}
}
20. @maciejtreder
export function applyAndLog(rule: Rule): Rule {
bugsnag.register('0b326fddc255310e516875c9874fed91');
return (tree: Tree, context: SchematicContext) => {
return (<Observable<Tree>> rule(tree, context))
.pipe(catchError((error: any) => {
let subject: Subject<Tree> = new Subject();
bugsnag.notify(error, (bugsnagError, response) => {
if (!bugsnagError && response === 'OK') {
console.log(`Stacktrace sent to tracking system.`);
}
subject.next(Tree.empty());
subject.complete();
});
return subject;
}));
}
}
22. @maciejtreder
ng update
{
"ng-update": {
"requirements": { "my-lib": "^5" },
"migrations": "./migrations/migration-collection.json"
}
} {
"schematics": {
"migration-01": { "version": "6", "factory": "./update-6" },
"migration-02": { "version": "6.2", "factory": "./update-6_2" },
"migration-03": { "version": "6.3", "factory": "./update-6_3" }
}
}
Updates one or multiple packages, its peer dependencies and the peer dependencies th
23. @maciejtreder
ng [what?] —collection
export default function(options: Schema): Rule {
const rule: Rule = chain([
externalSchematic('@schematics/angular', 'ng-new', options),
// other rules
]);
return rule;
}
Shadows default rules/schematics collection
• ng new —collection @ng-toolkit/init
• ng generate service —collection myCollection
24. @maciejtreder
Working with source-code
import * as ts from 'typescript';
export default function(options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
const filePath = `${options.directory}/sourceFile.ts`;
const recorder = tree.beginUpdate(filePath);
let fileContent = getFileContent(tree, filePath);
let sourceFile: ts.SourceFile = ts.createSourceFile('temp.ts', fileContent, ts.ScriptTarget.Latest);
sourceFile.forEachChild(node => {
if (ts.isClassDeclaration(node)) {
node.members.forEach(node => {
if (ts.isConstructorDeclaration(node)) {
if (node.body) {
recorder.insertRight(node.body.pos + 1, 'console.log('constructor!');')
}
}
});
}
});
tree.commitUpdate(recorder);
const recorder = tree.beginUpdate(filePath);
let sourceFile: ts.SourceFile = ts.createSourceFile(
import * as ts from 'typescript';
recorder.insertRight(node.body.pos + 1, 'console.log('constructor!');')
tree.commitUpdate(recorder);
27. @maciejtreder
Why should I use typescript?
Task:
change all ‘window’ occurences to ‘this.window’
Source code:export MyClass {
private message = 'Do not open window!';
console.log(window
.URL);
}
28. @maciejtreder
SchematicContext
export default function(options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
context.addTask(new NodePackageInstallTask(options.directory));
return tree;
}
}
• NodePackageInstallTask
• NodePackageLinkTask
• RepositoryInitializerTask
• RunSchematicTask
• TslintFixTask
29. @maciejtreder
Testing
const collectionPath = path.join(__dirname, './collection.json');
describe('Universal', () => {
let appTree: UnitTestTree;
const schematicRunner = new SchematicTestRunner('@ng-toolkit/universal', collectionPath);
const appOptions: any = { name: 'foo', version: '7.0.0'};
beforeEach((done) => {
appTree = new UnitTestTree(Tree.empty());
schematicRunner.runExternalSchematicAsync(
'@schematics/angular',
'ng-new',
appOptions,
appTree
).subscribe(tree => {
appTree = tree
done();
});
});
30. @maciejtreder
Testing
const defaultOptions: any = {
project: 'foo',
disableBugsnag: true,
directory: '/foo'
};
it('Should add server build', (done) => {
schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).subscribe(tree => {
const cliConfig = JSON.parse(getFileContent(tree, `${defaultOptions.directory}/angular.json`));
expect(cliConfig.projects.foo.architect.server).toBeDefined(`Can't find server build`);
done();
});
})
31. @maciejtreder
e2e
npm install -g verdaccio
verdaccio --config scripts/default.yaml >> verdacio_output &
npm set registry=http://localhost:4873/
echo "//localhost:4873/:_authToken="fooBar"" >> ~/.npmrc
32. @maciejtreder
e2e
npm install -g verdaccio
verdaccio --config scripts/default.yaml >> verdacio_output &
npm set registry=http://localhost:4873/
cp ~/.npmrc ~/.npmrc_original
echo "//localhost:4873/:_authToken="fooBar"" >> ~/.npmrc
35. @maciejtreder
No more boring readme!
Change long instructions to simple parameters
ng add @ng-toolkit/universal
• installs @ng-toolkit/universal package
• creates server configuration in angular.json
• adds NgtUniversalModule to your default app module
• adds TransferHttpCacheModule
• replaces all ocurences of window object with window wrapper
37. @maciejtreder
Customize your codebase!
• install @xyz/forms
• add OurFormsModule to your app
• customize your code in 32123 files
• udpate @xyz/forms
• customize your code again!
• ng add @xyz/forms
• ng update @xyz/forms
VS
Notas do Editor kreska od npm do angular + info,ze będzie coś robic zmienić tytuł dopisać CLI do obrazka zmienić nazwę zmiennej errorów wewn. dodać slajd
window -> this.window
private someVar = „do not ocen the widnow”; sprawdzić interfejs potrzebny do napisania własnego taska verdaccio na dol cd testApp