Slide 1

Slide 1 text

Hacking the Angular Compiler with our own Syntax! by Dominic Elm and Kwinten Pisman

Slide 2

Slide 2 text

Do you still understand the code you wrote 6 months ago ? @elmd_ @KwintenP

Slide 3

Slide 3 text

…or the code your co-workers wrote 6 months ago ? @elmd_ @KwintenP

Slide 4

Slide 4 text

… or someone else’s code ? @elmd_ @KwintenP

Slide 5

Slide 5 text

@elmd_ @KwintenP

Slide 6

Slide 6 text

Code should express intent! @elmd_ @KwintenP

Slide 7

Slide 7 text

@elmd_ @KwintenP

Slide 8

Slide 8 text

@elmd_ @KwintenP

Slide 9

Slide 9 text

What did you do last night? @elmd_ @KwintenP

Slide 10

Slide 10 text

What did you do last night? @elmd_ @KwintenP

Slide 11

Slide 11 text

- . / ❤ @elmd_ @KwintenP

Slide 12

Slide 12 text

@elmd_ @KwintenP
Data found!#
{{ item }}#
Custom Styles#

Slide 13

Slide 13 text

@elmd_ @KwintenP
Data found!#
{{ item }}#
Custom Styles#

Slide 14

Slide 14 text

@elmd_ @KwintenP
Data found!#
{{ item }}#
Custom Styles#

Slide 15

Slide 15 text

@elmd_ Dominic Elm @KwintenP Kwinten Pisman thoughtram https://thoughtram.io StackBlitz https://stackblitz.com strongbrew https://strongbrew.io StackBlitz https://stackblitz.com Google Developer Expert https://bit.ly/2nAqRrZ Google Developer Expert https://bit.ly/2nAqRrZ

Slide 16

Slide 16 text

Angular Checklist @elmd_ @KwintenP

Slide 17

Slide 17 text

Angular Profiler DevTools @elmd_ @KwintenP

Slide 18

Slide 18 text

@elmd_ @KwintenP

Slide 19

Slide 19 text

js js JS @elmd_ @KwintenP ???

Slide 20

Slide 20 text

js js JS @elmd_ @KwintenP Compiler

Slide 21

Slide 21 text

A compiler is a computer program that translates computer code written in one programming language into another language. @elmd_ @KwintenP ”

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Declarative vs Imperative @elmd_ @KwintenP

Slide 24

Slide 24 text

Tasks of the Angular Compiler @elmd_ @KwintenP

Slide 25

Slide 25 text

Tasks of the Angular Compiler Type checking of our templates @elmd_ @KwintenP

Slide 26

Slide 26 text

Tasks of the Angular Compiler Type checking of our templates @elmd_ @KwintenP Find errors in the structure of our application

Slide 27

Slide 27 text

Tasks of the Angular Compiler Type checking of our templates @elmd_ @KwintenP Find errors in the structure of our application Transform decorators into static properties

Slide 28

Slide 28 text

Tasks of the Angular Compiler Type checking of our templates @elmd_ @KwintenP Find errors in the structure of our application Transform decorators into static properties Transpile TypeScript into JavaScript

Slide 29

Slide 29 text

Tasks of the Angular Compiler Type checking of our templates @elmd_ @KwintenP Find errors in the structure of our application Transform decorators into static properties Transpile TypeScript into JavaScript Generate template instructions

Slide 30

Slide 30 text

How do we build an Angular application? @elmd_ @KwintenP

Slide 31

Slide 31 text

@elmd_ @KwintenP Angular CLI

Slide 32

Slide 32 text

@elmd_ @KwintenP Webpack

Slide 33

Slide 33 text

@elmd_ @KwintenP Webpack *.bundle.js *.bundle.js main.bundle.js App

Slide 34

Slide 34 text

@elmd_ @KwintenP Webpack *.bundle.js *.bundle.js main.bundle.js main.ts AppModule AppComponent

Slide 35

Slide 35 text

@elmd_ @KwintenP webpack.config.js Webpack

Slide 36

Slide 36 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin AngularCompilerPlugin

Slide 37

Slide 37 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code AngularCompilerPlugin

Slide 38

Slide 38 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code AngularCompilerPlugin

Slide 39

Slide 39 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin

Slide 40

Slide 40 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code Resolve Dependencies, Bundle Bundle AngularCompilerPlugin

Slide 41

Slide 41 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost

Slide 42

Slide 42 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost ngProgram AOT ts.Program JIT

Slide 43

Slide 43 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Analysis AOT ngProgram AOT ts.Program JIT

Slide 44

Slide 44 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT

Slide 45

Slide 45 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Type Checking Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT

Slide 46

Slide 46 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Type Checking Emit Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT Transformer

Slide 47

Slide 47 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Type Checking Emit Angular Code Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT Transformer

Slide 48

Slide 48 text

Cool. But what’s next? @elmd_ @KwintenP

Slide 49

Slide 49 text

@elmd_ @KwintenP Loader .html

Slide 50

Slide 50 text

@elmd_ @KwintenP Loader .html
Angular rocks! #

Slide 51

Slide 51 text

@elmd_ @KwintenP
Angular rocks! #
Loader .html
Angular rocks! #

Slide 52

Slide 52 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code Resolve Dependencies, Bundle Bundle AngularCompilerPlugin

Slide 53

Slide 53 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Angular Code Resolve Dependencies, Bundle Bundle AngularCompilerPlugin HTML Loader Custom Loader

Slide 54

Slide 54 text

How?!? @elmd_ @KwintenP

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

@elmd_ @KwintenP $

Slide 58

Slide 58 text

@elmd_ @KwintenP $ ng add ngx-build-plus $

Slide 59

Slide 59 text

@elmd_ @KwintenP $ ng add ngx-build-plus touch extra-webpack-config.js $ $

Slide 60

Slide 60 text

module.exports = { module: { rules: [ { test: /\.html$/, use: [ { loader: path.resolve('path/to/custom/html/loader') }, { loader: 'raw-loader' #// import file as a string } ] } ] } }; @elmd_ @KwintenP

Slide 61

Slide 61 text

module.exports = { module: { rules: [ { test: /\.html$/, use: [ { loader: path.resolve('path/to/custom/html/loader') }, { loader: 'raw-loader' #// import file as a string } ] } ] } }; @elmd_ @KwintenP

Slide 62

Slide 62 text

@elmd_ @KwintenP $ ng add ngx-build-plus touch extra-webpack-config.js $ $

Slide 63

Slide 63 text

@elmd_ @KwintenP $ ng add ngx-build-plus touch extra-webpack-config.js $ touch ng-emoji-plugin.js $ $

Slide 64

Slide 64 text

export default { pre() { #// before build }, post() { #// after build }, config(config: webpack.Configuration) { #// after webpack config was built by the CLI } }; @elmd_ @KwintenP

Slide 65

Slide 65 text

export default { pre() { #// before build }, post() { #// after build }, config(config: webpack.Configuration) { #// after webpack config was built by the CLI } }; @elmd_ @KwintenP

Slide 66

Slide 66 text

export default { pre() { #// before build }, post() { #// after build }, config(config: webpack.Configuration) { const acp = findAngularCompilerPlugin(config) as AngularCompilerPlugin; if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); @elmd_ @KwintenP

Slide 67

Slide 67 text

export default { pre() { #// before build }, post() { #// after build }, config(config: webpack.Configuration) { const acp = findAngularCompilerPlugin(config) as AngularCompilerPlugin; if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); @elmd_ @KwintenP

Slide 68

Slide 68 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 69

Slide 69 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 70

Slide 70 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 71

Slide 71 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 72

Slide 72 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 73

Slide 73 text

@elmd_ @KwintenP $ ng serve

Slide 74

Slide 74 text

https://bit.ly/2n1Wb32 @elmd_ @KwintenP ng-emojis

Slide 75

Slide 75 text

But wait, inline templates @elmd_ @KwintenP

Slide 76

Slide 76 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Type Checking Emit Angular Code Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT Transformer

Slide 77

Slide 77 text

@elmd_ @KwintenP webpack.config.js Webpack Loader Loader Loader ngc Plugin Plugin AngularCompilerPlugin Generated Angular Code Resolve Dependencies, Bundle AngularCompilerPlugin WebpackCompilerHost ts.CompilerHost Type Checking Emit Angular Code Resolve AOT Analysis AOT ngProgram AOT ts.Program JIT Transformer Transformer Custom TS Transformer

Slide 78

Slide 78 text

TypeScript Transformers @elmd_ @KwintenP

Slide 79

Slide 79 text

AST @elmd_ @KwintenP

Slide 80

Slide 80 text

AST @elmd_ @KwintenP

Slide 81

Slide 81 text

AST @elmd_ @KwintenP

Slide 82

Slide 82 text

AST @elmd_ @KwintenP

Slide 83

Slide 83 text

AST ( )=> @elmd_ @KwintenP

Slide 84

Slide 84 text

export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { #// change sourceFile (AST) }; } @elmd_ @KwintenP

Slide 85

Slide 85 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; }

Slide 86

Slide 86 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; } function findInlineTemplate(sourceFile: ts.SourceFile) { return tsquery(sourceFile, INLINE_TEMPLATE_QUERY); }

Slide 87

Slide 87 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; }

Slide 88

Slide 88 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; } function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { #// ast walker function return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); }

Slide 89

Slide 89 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; } function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { #// ast walker function return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); }

Slide 90

Slide 90 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; } function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { #// ast walker function return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); }

Slide 91

Slide 91 text

@elmd_ @KwintenP export function transformer(context: ts.TransformationContext) { return (sourceFile: ts.SourceFile) #=> { const template = findInlineTemplate(sourceFile); return updateInlineTemplate(template, sourceFile, context); }; } function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { #// ast walker function return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); }

Slide 92

Slide 92 text

@elmd_ @KwintenP function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { #// ast walker function return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); }

Slide 93

Slide 93 text

function updateInlineTemplate( nodes: Array, sourceFile: ts.SourceFile, context: ts.TransformationContext) { const visitor: ts.Visitor = (node: ts.Node) #=> { if (nodes.includes(node)) { const prop = node as ts.PropertyAssignment; const currentTpl = prop.initializer.getFullText(); const inlineTpl = ts.createNoSubstitutionTemplateLiteral( updateDirectives(currentTpl, true) ); return ts.updatePropertyAssignment(prop, prop.name, inlineTpl); } return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(sourceFile, visitor); @elmd_ @KwintenP

Slide 94

Slide 94 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 95

Slide 95 text

if (!acp) { throw new Error('AngularCompilerPlugin not found'); } const options: AngularCompilerPluginOptions = { ##...acp.options, directTemplateLoading: false #// ##<-- IMPORTANT }; config.plugins = removeCompilerPlugin(config.plugins, acp); const newCompilerPlugin = new AngularCompilerPlugin(options); acp._transformers = [inlineTplTransformer, ##...acp._transformers]; config.plugins.push(newCompilerPlugin); return config; } }; @elmd_ @KwintenP

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

Reactive Programming! @elmd_ @KwintenP

Slide 99

Slide 99 text

Click Me @Component({...}) export class AppComponent implements OnInit { clicks$ = new Subject(); ngOnInit() { // we can either manually subscribe // or use the async pipe this.clicks$.subscribe(console.log); } }

Slide 100

Slide 100 text

Click Me @Component({...}) export class AppComponent implements OnInit { @ObservableEvent() clicks$: Observable; ngOnInit() { // we can either manually subscribe // or use the async pipe this.clicks$.subscribe(console.log); } }

Slide 101

Slide 101 text

CAN WE HAZ IT? PLZZZ

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

Key Takeaways @elmd_ @KwintenP

Slide 105

Slide 105 text

Key Takeaways @elmd_ @KwintenP What the Angular Compiler does and how it works

Slide 106

Slide 106 text

Key Takeaways @elmd_ @KwintenP TypeScript Transformers What the Angular Compiler does and how it works

Slide 107

Slide 107 text

Key Takeaways @elmd_ @KwintenP TypeScript Transformers ngx-template-streams What the Angular Compiler does and how it works

Slide 108

Slide 108 text

Key Takeaways @elmd_ @KwintenP TypeScript Transformers ngx-template-streams Experiment yourself! What the Angular Compiler does and how it works

Slide 109

Slide 109 text

BUT most importantly, you can learn so much while at the same time having FUN! @elmd_ @KwintenP

Slide 110

Slide 110 text

Thank You revo.js! @elmd_ @KwintenP