NGConf 2019 - Not Every App is a SPA
Tags: angular, conference, webdev, javascript
Published: 2019-07-01 12:10:08

---
title: NGConf 2019 - Not Every App is a SPA
published: true
description: NGConf 2019 talk by Rob Wormald
tags: angular, conference, webdev, javascript
cover_image: https://juristr.com/blog/assets/imgs/ngconf2019/ngconf-post-cover.png
---

## Disclaimer
This is my personal summary of the sessions from ngconf. While I summarize the things with my own words, the material used such as images, graphs, source code examples are not my own. Most of them are from the Youtube videos or slide of the respective speakers of the various sessions.

## Other sessions?

This article is cross-posted from [my blog](https://juristr.com/blog). If you wanna read the original one, also covering other sessions, head over to [the original article &raquo;](https://juristr.com/blog/2019/05/Angular-8-and-the-Future-NGConf-2019-Roundup/?utm_source=devto&utm_medium=crosspost). 

[Follow me on twitter](https://twitter.com/juristr).

## Not Every App is a SPA

_Rob Wormald_

Rob targets the graph mentioned by Igor about the current field Angular apps are being adopted.

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-graph-angular-adoption.png">

Going forward the team's goal is to target the two missing edges in this graph.

### Small-medium Apps, Demos, Edu Apps

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-graph-small-apps.png">

To target this left side of the graph, where small to medium apps reside, the answer is definitely Angular Elements.

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-angular-elements.png">

If this sounds new to you, [check out my related article](https://juristr.com/blog/2019/04/intro-to-angular-elements/).

Mixed environments are also a good example where Angular Elements fits in nicely:

- Lots of different frameworks
- Not everyone can start from greenfield
- Google has this problem too (Angular, AngularJS, Dart, GWT, Polymer,...)
- Mini-apps running on 3rd party sites
- NgUpgrade

In the context of Angular Elements, the registration process for bundling a single component as an Angular Element is currently (< Angular v7) still quite verbose:

```typescript
@NgModule({
  imports: [BrowserModule, CommonModule],
  declarations: [HelloWorld],
  entryComponents: [HelloWorld]
})
class HelloWorldModule {}
```

And then it needs to be registered as an Angular Element:

```typescript
platformBrowser()
  .bootstrapModule(HelloWorldModule)
  .then(({injector}) => {
    const HelloWorldElement = createCustomElement(HelloWorld, {injector});
    customElements.define('hello-world', HelloWorldElement);
  });
```

How is that going to change with Ivy?

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-elements-with-ivy.png">

The simplest way of rendering a component in Ivy is the following:

```typescript
import { Component, Input, Output, renderComponent } from '@angular/core';

@Component({
  selector: 'hello-world',
  template: `...`
})
class HelloWorld {
  @Input() name: string;
  @Output() nameChange = new EventEmitter();
  changeName = () => this.nameChange.emit(this.name);
}

renderComponent(HelloWorld);
```

So how can we make this an Angular Element in Ivy? Rob shows on stage how that will look like.

```typescript
import { renderComponent } from '@angular/core';
import { HelloWorld } from './hello-world.component';

// manually define the host rather than let Angular look for it
// then pass it as a 2nd argument to the renderComponent
const host = document.querySelector('hello-world');

renderComponent(HelloWorld, { host });

// create a custom element using the native browser API
class HelloWorldElement extends HTMLElement {}
```

This is the first step. Next, we can create a Custom Element using the native browser API and invoke the `renderComponent` from there.

```typescript
import { renderComponent } from '@angular/core';
import { HelloWorld } from './hello-world.component';

// create a custom element using the native browser API
class HelloWorldElement extends HTMLElement {
  component: HelloWorld;
  constructor()  {
    super();
    // associate "this" as the host element
    this.component = renderComponent(HelloWorld, { host: this })
  }
}
```

Note how we pass `this` (which is the Custom Element instance as the host to the render function). We can also add properties which we simply wrap.

```typescript
import { renderComponent, detectChanges } from '@angular/core';
import { HelloWorld } from './hello-world.component';

// create a custom element using the native browser API
class HelloWorldElement extends HTMLElement {
  component: HelloWorld;
  constructor()  {
    super();
    // associate "this" as the host element
    this.component = renderComponent(HelloWorld, { host: this })
  }

  set name(value) {
    this.component.name = value;
    detectChangs(this.component);
  }
  get name() {
    return this.component.name;
  }
}
```

`detectChanges` can just be imported from Angular. It's just a function :muscle: (no DI necessarily needed to inject the `ChangeDetectorRef` etc..)! 

To have attributes, we just continue using the native browser APIs.

```typescript
import { renderComponent, detectChanges } from '@angular/core';
import { HelloWorld } from './hello-world.component';

// create a custom element using the native browser API
class HelloWorldElement extends HTMLElement {
  static observedAttributes = ['name'];
  component: HelloWorld;
  constructor()  {
    super();
    // associate "this" as the host element
    this.component = renderComponent(HelloWorld, { host: this })
  }

  attributeChangedCallback(attr, oldValue, newValue) {
    this.name = newValue;
  }

  set name(value) {...}
  get name() {...}
}
```

Now this just to show how easy it is to build it by yourself with Ivy. You don't have to do this every time. Most likely this will look like this with Ivy:

```typescript
import { withNgComponent } from '@angular/elements';
import { HelloWorld } from './hello-world.component';

// create a Custom Element that wraps the Angular Component
const HelloWorldElement = withNgComponent(HelloWorld);

// register it
customElements.define('hello-world', HelloWorldElement);
```

No platforms, no modules :tada: :tada: You can of course still use the Injector if you want:

```typescript
...
// create a Custom Element that wraps the Angular Component
const HelloWorldElement = withNgComponent(HelloWorld, {injector});
...
```

In many cases you already have an Angular Component that you want to turn into an Element. **But what if you don't want to have an Angular Component, but just an Angular Element?** :thinking: Basically you just want the benefit the Angular templating system gives you. The "problem" right now is that we have the `NgModule` which tells the compiler which dependencies are needed and helps it optimize the final outcome. Technically Ivy doesn't need a `NgModule`, but still, we need to have a way to tell the component what other directives/components live in its template. One **proposal** (<< this is an EARLY PROPOSAL the team wants feedback on) is to allow to register the dependencies directly in the `@Component` tag, very much like you already can with `providers` and what was already there in `Angular RC4` (yes I remember :sweat_smile:). Something like this:

```typescript
@Component({
  selector: 'hello-world',
  template: `...`,
  providers: [SomeService],
  deps: [SomeDirective, SomePipe]
})
class HelloWorld {}
```

This is definitely more verbose, but also more direct and "simpler" if you want. To achieve the final goal of just having an Ng Element (without an Angular Component) could look something like this (based on what we've discussed before):

```typescript
import { NgElement, withElement } from '@angular/elements';
...
@NgElement({
  selector: 'hello-world',
  template: `...`,
  providers: [SomeService],
  deps: [SomeDirective, SomePipe]
})
class HelloWorld extends withNgElement {}
```

This gives you **an Angular Element without an Angular Component**. Something that might make sense in some scenarios, like when building a design system.

### Scaling Up - or What is project "Angular Photon"?

To the other side of the chart: scaling up.

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-graph-angular-scaleup.png">

In this context (during the keynote - see further up), the name **Angular Photon" came up. Imporant:

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-photon.png">

It's a research project for experimenting and "deciding how to build the right tools for the next gen of Angular Developers". It's a project in collaboration with

- Google Shopping Express (build with Angular)
- Wiz

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-collaboration.png">

<img src="https://juristr.com/blog/assets/imgs/ngconf2019/rob-what-wanted.png">

Loading components as they are needed is a big part. As a sneak peek this is what it might look like

```typescript
import { withLazyNgComponent } from '@angular/elements';

// create a Custom Element that wraps the Angular Component
const HelloWorldElement = withLazyNgComponent(() => import('./hellow-world.component'));

// register it
customElements.define('hello-world', HelloWorldElement);
```

Note the `withLazyNgComponent` that fetches the necessary scripts only when really needed.