Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers

22 views

Published on

Say hello to the Angular CLI from new perspective. Get to know what schematics are and how you can use them for your purpose. Make use of ng add, ng update, ng new command and much more. Learn how to create read update and delete files automatically in your project, and how to execute npm tasks such as installing dependencies.

Published in: Education
  • Be the first to comment

  • Be the first to like this

JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers

  1. 1. @maciejtreder
  2. 2. @maciejtreder Angular Schematics Develop for developers
  3. 3. @maciejtreder @maciejtreder • Kraków, Poland • Senior Software Development Engineer in Test Akamai Technologies • Angular passionate • Open source contributor (founder of @ng-toolkit project) • Articles author
  4. 4. @maciejtreder • Cambridge, Massachusetts • Content Delivery Network • Over 240 00 servers deployed in more then 120 countries • Serves 15%-30% of the Internet traffic
  5. 5. @maciejtreder Innovation Begins With an Idea • SEO friendly • Works offline • Cheap environment - Angular Universal - PWA - Serverless
  6. 6. @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)
  7. 7. @maciejtreder Yet Another Boilerplate… • Progressive Web App • Server-Side Rendering • Hosted on AWS Lambda • Uploaded to GitHub • ~30 clones weekly angular-universal-serverless-pwa
  8. 8. @maciejtreder The Gray Eminence Is GIT designed for hosting dev tools? @esosanderelias
  9. 9. @maciejtreder Schematics
  10. 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
  11. 11. @maciejtreder ng add @ng-toolkit/universal
  12. 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",
  13. 13. @maciejtreder collection.json { "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", "schematics": { "ng-add": { "factory": "./schematics", "description": "Update an application with server side rendering (Angular Universal)", "schema": "./schema.json" } } } "factory": "./schematics", "schema": "./schema.json"
  14. 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
  15. 15. @maciejtreder schematics.ts export default function index(options: any): Rule { if (options.http) { //true or nothing was passed (default value) } else { //false was passed } }
  16. 16. @maciejtreder Tree • Object which represents file system • Supports CRUD operations and more: • exists() • getDir() • visit() • etc
  17. 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
  18. 18. @maciejtreder tree Chaining export default function index(options: any): Rule { return chain([ rule1, rule2, rule3 ]) } rule1 rule2 rule3
  19. 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. 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; })); } }
  21. 21. @maciejtreder
  22. 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. 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. 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);
  25. 25. @maciejtreder is… • isImportDeclaration • isVariableDeclaration • isClassDeclaration • isMethodDeclaration • isStringLiteral • isIfStatement
  26. 26. @maciejtreder tree. tree.create('path', 'content'); tree.exists('path') tree.overwrite('path', 'new file content'); tree.getDir(`${options.directory}/src/environments`).visit( (path: Path) => { if (path.endsWith('.ts')) { addEntryToEnvironment(tree, path, 'line to be inserted'); } }); const recorder = tree.beginUpdate(‘filePath’); tree.commitUpdate(recorder);
  27. 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. 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. 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. 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. 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. 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
  33. 33. @maciejtreder e2e cd dist npm publish --registry http://localhost:4873 cd ng new testApp ng add @ng-toolkit/universal npm set registry=https://registry.npmjs.org/
  34. 34. @maciejtreder Use cases
  35. 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
  36. 36. @maciejtreder Corporate mess! Anna HYZ Corporation Front-end team Bob
  37. 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
  38. 38. @maciejtreder

×