Learn how to build a high-octane 🚀📦 web component with Angular Elements that lazy loads images and achieves a near perfect lighthouse perf score https://angularfirebase.com/lessons/angular-elements-advanced-techniques/

Docs https://angular.io/guide/elements
Manfred Steyer's Guide https://www.softwarearchitekt.at/post/2018/07/29/angular-elements-part-ii-lazy-and-external-web-components.aspx
Nrwl Top 5 https://blog.nrwl.io/5-reasons-to-use-angular-elements-390c9a629f89
Web Components https://www.webcomponents.org/
2024-02-04T07:06:47.896Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
207215b0-1624-46db-b9ae-664e5783a411
f15d82bd2ec41acdb5a5b4482bc39cfd432c153772fb1983a8a20bb7bc9c876a
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
One of the most exciting trends happening in web development is the adoption of web components, because they allow us to build applications that don't walk us into a specific framework or programming style.
I'm going to be using Web Components in production very soon, so I wanted to share some advanced concepts that I've learned working with Angular Elements.
And I'll even show you how to achieve a near perfect Lighthouse performance score with the full power of Angular and Firebase in your JavaScript bundle.
If you're new here, like and subscribe, and congrats to Damien Wright, who's last week's t shirt winner.
But don't worry missed out, there's another one of a kind t shirt going out this week.
All you have to do is leave a comment below.
Over the last few months, I've been building a product called Fireship IO, which is just a better way for me to deliver my content to you.
This project needs to be very fast and search engine optimized, But it also needs to use Firebase for user authentication and dynamic data.
The beauty of web components is that I can pre render all of my static content and then bootstrap in custom elements when they're needed.
Throughout this journey, I've used pretty much every web component tool that's out there and I found that Angular Elements is the most productive for a larger project, but you'll also wanna check out Stencil and lit element, which I think are both very promising.
The big advantage of elements is that, a, you get the full power of Angular, and, b, your components share the same dependency injector tree, which means you can easily share data or functionality between your custom elements.
And c, the API is stable and being used in production at Google.
Today, we're going to build a custom element that can lazy load an image based on the user's scroll position in the browser.
When the image is loading, it will show this Facebook style shimmer placeholder, then replace it with the image when it's fully loaded.
Now we'll jump into some code, but if you haven't already seen my original Angular Elements video, you'll wanna check that one out which is a little more basic level.
The first thing you wanna do is go into your Angular app and then run n g add at angular elements.
This will install the dependencies and also the polyfills to ensure that your elements are compatible with all browsers.
Then you can go into the app directory and you'll wanna just go ahead and delete everything except for the app module.
You'll also notice I've generated a couple of regular components in here as well.
The first thing we'll wanna do is register our components as custom elements.
I'm assuming Angular will have a better way to do this in the future, but currently we import Injector from Angular Core and create custom element from Angular Elements.
Now if you want to use your elements within the context of an Angular app, you'll want to add them to the entry components array.
The important thing is that we go down here to the app module and add the injector to the constructor.
If you have a big project, there's probably a whole bunch of different elements to register.
So the way I like to set this up is to create an array of tuples.
So the first item is the Angular class name and then the second item is the name of the custom element.
So that's how you'll actually use it in the DOM.
So now we can loop over these elements and we can actually destructure them directly in the for loop, which I think is a really nice looking piece of JavaScript.
From there, we can call create custom element And that gives us a dry way to register a large number of components.
Now let's switch gears and see how we can create a single JavaScript bundle that we can use outside of Angular.
What you're looking at here is the build script that I wrote from my original Angular Elements video.
It just takes all of your production build files and then concatenates them into a single file in the public directory.
So this works fine, but it's kind of a hack.
I'd recommend checking out NGX build plus to extend the default behavior of the CLI, and hopefully the CLI will just support this out of the box in the future.
We'll stick with the simple approach for now, and I've added a couple of build and serve scripts to my package.
Json.
It first runs ng build prod, and then it runs the build script with node.
So now that we have our JavaScript bundled, I'm going to put it to use in just a static HTML page by adding it as a script to the head of the document.
And you can see down here I'm using this image lazy custom element, which we'll build here in a few minutes.
Now I'll go ahead and run a Lighthouse audit, And keep in mind, I'm also not lazy loading the images at this point either.
We get a 1st Contentful Paint in 2.5 seconds, and time to interactive is 4 seconds.
I've also added Firebase to my JavaScript bundle, so we have 342 kilobytes here in total that needs to be loaded before the rest of the page can render.
But the great thing about elements is that we can defer the script until after the page is rendered.
So how do we do that?
We just go into our script tag and add defer, and we're done.
If we run the audit again, we get a first paint in 600 milliseconds, which might as well just be 0.
And 3 seconds later, we have the full power of Angular and Firebase ready in the page.
So you can already get amazing performance with Elements, but it's only going to get better in the next few months here as Angular Ivy becomes production ready.
So that's pretty awesome stuff, but I wanna share a few advanced pro tips that I've throughout my experience working with elements.
The first thing I'd recommend doing is disabling Angular's automatic change detection or NG zones, which you can do here in the main TS file.
The reason for this is that I've run into some really hard to debug issues that only happen in production.
So you'll find that life is much easier when you tell the component explicitly when to rerender.
Now if we go into the component itself, you can see I've imported everything under the kitchen sink here from Angular Core.
You won't need all these things in your elements.
I just wanna show you a few different techniques at your disposal.
And also, if you don't wanna turn off zones globally, you can do it here at the component level by doing change detection strategy on push.
The next big decision is whether or not to use the shadow DOM.
So the term web components encompasses a few different features, one of which is obviously custom elements, but another one is the shadow DOM.
If you turn the shadow DOM on, it means that your CSS styles will be encapsulated in this component.
That can be a good thing if you don't want your CSS to bleed out, but it can also make your components harder to style, it's a trade off.
And the shadow DOM also supports slots, which is something that we'll look at towards the end of this video.
Now there are 2 things that I commonly inject in the constructor.
Element ref will give us a reference to the actual DOM APIs that exist on this element.
The next one is the change detection ref, which allows us to rerender this component manually instead of relying on the automatic change detection.
Because we're displaying an image, we'll have our custom element behave just like a regular image tag.
We'll give it a source attribute and an alt attribute.
Now the special thing about our custom element is that it only displays an image when it's actually visible in the viewport.
For that, we're going to emit our own custom event called is visible.
Now when it comes to your internal component state, I recommend keeping the input values as immutable.
You have the flexibility to manage the state however you want, but here's a pattern that I find especially effective.
So we'll create an object with a couple of properties on it, And we only want to rerender our component if the state changes.
Then we'll set up a method here called set state which takes a key and a value as its arguments.
Then Then we can go ahead and use the spread syntax to create a new object and set that as the new state on the component.
Then we can guarantee a rerender here by calling detect changes on the change detection ref.
This code might look familiar because it's inspired by the way React works.
Contrary to popular belief, I do not hate React.
Overall, I found this to be a very reliable way to work with elements, But there's definitely many different ways you could do this.
Let's go ahead and switch over to the HTML and put this to use.
1st, we'll set up a div.
And if the loaded state is false, then we'll go ahead and show that placeholder.
You can check out the full CSS for that animation in the source code.
Then we'll set up a figure to wrap the image itself.
And we'll only show this if it's visible based on the user's scroll position on the window.
Then we'll add an image tag inside of here, which will only be loaded over the network when this visible property flips to True.
Just because it's visible doesn't mean it's loaded yet, so we'll also hide the image until it's fully loaded.
And then we'll run an event handler once that event takes place.
And the last thing to make note of is that we're passing our input source to the actual image source here.
So, again, our custom element feels just like a regular image tag with some added benefit.
So now the challenge is determining whether or not the user has scrolled to this element.
To make that happen, we're going to need to access some native DOM APIs.
We've already set up a reference to the native element in the constructor of this component.
We can go ahead and call it here, and then we can call get bounding client rect, which will give us the actual measurements of that DOM element.
If the top of the window is less than or equal to the window inner height, then we know that that element has been scrolled to.
And we also wanna check that the element is not already visible because if it is, then there's no point in running this code.
But if it is visible for the first time, then we'll go ahead and run our set state method, which will change the state and then rerender the component.
Another thing we wanna do is emit a custom event when the element becomes visible.
I'll cover the implementation of that in just a minute.
So there are 2 different situations where we want to calculate the visibility of the element.
1st, when the component is initialized.
Because if the element is already in the viewport, then we don't want to wait for the user to scroll to load it.
Then to listen to the scroll position, we can add host listener then window colon Scroll to listen to the global window scroll event.
And when that happens, we'll go ahead and calculate the visibility of the element.
So that's how we determine when an element's visible and also rerender it when its state changes.
For the image itself, there's a built in load event which will fire when the image is fully loaded.
So when that takes place we'll go ahead and set the loaded state to true again re rendering the component.
So the end result looks like this.
We start with a placeholder.
When the image loads it's displayed and the placeholder is removed.
Again, the great thing about web components is that we can interact with them using vanilla JavaScript in the DOM.
So we could use document query selector to grab the element and append it somewhere or change its CSS styles or whatever.
By default, the internal properties and methods on the component are not available when you grab it from the DOM like this.
But it can be very useful to expose a public method that can be used by the developers working with your elements.
For example, let's set up a log method that logs out the internal state of the component.
The method that I found works best, although I'd like to see this improved in future versions of Angular Elements is to use the Input decorator.
The reason we do it this way and not just attach input to a method is that it gives us context to this or this component instance.
So we can console log this state, which would otherwise be undefined if it was a regular method.
Now another thing that's really useful on the same note is to emit a custom event that can be listened to in the browser.
So we already have an event emitter set up on this component, And we can emit through that just like we normally would in Angular, and we'll also set up a custom event in the DOM.
We'll give that a name of is visible and then we can reference our native element and dispatch the event through it.
If we go back to the browser, we can now grab this element from the DOM, attach an event listener to it, and handle it however we want using vanilla JavaScript or some other framework.
So I've set up the is visible listener, and then I'm going to console log the event when it occurs.
As soon as the image becomes visible in the viewport, it logs that custom event to the Console.
So that takes care of that.
The next thing I wanna show you is content projection using slots.
If you look at the image on the left here, you'll notice a caption underneath that has a default header and default caption.
If we revisit our static HTML, you can see that I have a couple of spans that are inside of the lazy image tags.
The spans have a slot attribute which corresponds to a certain place that they'll be displayed which we'll define inside of our custom element.
So now I'll switch over to the component HTML, and we'll go ahead and add a figure caption.
Then we can include slot tags that have a specific name that defines where this content will be displayed.
This is super useful when you have components that can be customized, but you don't want the end user to have to worry about adding the required markup to it.
And if you want the user to just be able to transclude some markup inside your component, you can simply drop in a slot tag.
That will be considered the default slot and the user can just pass in whatever HTML they want and it will be rendered here.
I'm gonna go ahead and wrap things up there.
I have a whole bunch of other ideas for Angular Elements for future videos, so make sure to like and subscribe.
And if you wanna take your development to the next level, consider becoming a pro member at angularfirebase .com.
You'll get access to my full length courses, my book, as well as a whole bunch of other resources designed to help you build and ship apps faster.
Thanks for watching, and I'll talk to you soon.

Speaker 0: One of the most exciting trends happening in web development is the adoption of web components, because they allow us to build applications that don't walk us into a specific framework or programming style. I'm going to be using Web Components in production very soon, so I wanted to share some advanced concepts that I've learned working with Angular Elements. And I'll even show you how to achieve a near perfect Lighthouse performance score with the full power of Angular and Firebase in your JavaScript bundle. If you're new here, like and subscribe, and congrats to Damien Wright, who's last week's t shirt winner. But don't worry missed out, there's another one of a kind t shirt going out this week.

All you have to do is leave a comment below. Over the last few months, I've been building a product called Fireship IO, which is just a better way for me to deliver my content to you. This project needs to be very fast and search engine optimized, But it also needs to use Firebase for user authentication and dynamic data. The beauty of web components is that I can pre render all of my static content and then bootstrap in custom elements when they're needed. Throughout this journey, I've used pretty much every web component tool that's out there and I found that Angular Elements is the most productive for a larger project, but you'll also wanna check out Stencil and lit element, which I think are both very promising.

The big advantage of elements is that, a, you get the full power of Angular, and, b, your components share the same dependency injector tree, which means you can easily share data or functionality between your custom elements. And c, the API is stable and being used in production at Google. Today, we're going to build a custom element that can lazy load an image based on the user's scroll position in the browser. When the image is loading, it will show this Facebook style shimmer placeholder, then replace it with the image when it's fully loaded. Now we'll jump into some code, but if you haven't already seen my original Angular Elements video, you'll wanna check that one out which is a little more basic level.

The first thing you wanna do is go into your Angular app and then run n g add at angular elements. This will install the dependencies and also the polyfills to ensure that your elements are compatible with all browsers. Then you can go into the app directory and you'll wanna just go ahead and delete everything except for the app module. You'll also notice I've generated a couple of regular components in here as well. The first thing we'll wanna do is register our components as custom elements.

I'm assuming Angular will have a better way to do this in the future, but currently we import Injector from Angular Core and create custom element from Angular Elements. Now if you want to use your elements within the context of an Angular app, you'll want to add them to the entry components array. The important thing is that we go down here to the app module and add the injector to the constructor. If you have a big project, there's probably a whole bunch of different elements to register. So the way I like to set this up is to create an array of tuples.

So the first item is the Angular class name and then the second item is the name of the custom element. So that's how you'll actually use it in the DOM. So now we can loop over these elements and we can actually destructure them directly in the for loop, which I think is a really nice looking piece of JavaScript. From there, we can call create custom element And that gives us a dry way to register a large number of components. Now let's switch gears and see how we can create a single JavaScript bundle that we can use outside of Angular.

What you're looking at here is the build script that I wrote from my original Angular Elements video. It just takes all of your production build files and then concatenates them into a single file in the public directory. So this works fine, but it's kind of a hack. I'd recommend checking out NGX build plus to extend the default behavior of the CLI, and hopefully the CLI will just support this out of the box in the future. We'll stick with the simple approach for now, and I've added a couple of build and serve scripts to my package.

Json. It first runs ng build prod, and then it runs the build script with node. So now that we have our JavaScript bundled, I'm going to put it to use in just a static HTML page by adding it as a script to the head of the document. And you can see down here I'm using this image lazy custom element, which we'll build here in a few minutes. Now I'll go ahead and run a Lighthouse audit, And keep in mind, I'm also not lazy loading the images at this point either.

We get a 1st Contentful Paint in 2.5 seconds, and time to interactive is 4 seconds. I've also added Firebase to my JavaScript bundle, so we have 342 kilobytes here in total that needs to be loaded before the rest of the page can render. But the great thing about elements is that we can defer the script until after the page is rendered. So how do we do that? We just go into our script tag and add defer, and we're done.

If we run the audit again, we get a first paint in 600 milliseconds, which might as well just be 0. And 3 seconds later, we have the full power of Angular and Firebase ready in the page. So you can already get amazing performance with Elements, but it's only going to get better in the next few months here as Angular Ivy becomes production ready. So that's pretty awesome stuff, but I wanna share a few advanced pro tips that I've throughout my experience working with elements. The first thing I'd recommend doing is disabling Angular's automatic change detection or NG zones, which you can do here in the main TS file.

The reason for this is that I've run into some really hard to debug issues that only happen in production. So you'll find that life is much easier when you tell the component explicitly when to rerender. Now if we go into the component itself, you can see I've imported everything under the kitchen sink here from Angular Core. You won't need all these things in your elements. I just wanna show you a few different techniques at your disposal.

And also, if you don't wanna turn off zones globally, you can do it here at the component level by doing change detection strategy on push. The next big decision is whether or not to use the shadow DOM. So the term web components encompasses a few different features, one of which is obviously custom elements, but another one is the shadow DOM. If you turn the shadow DOM on, it means that your CSS styles will be encapsulated in this component. That can be a good thing if you don't want your CSS to bleed out, but it can also make your components harder to style, it's a trade off.

And the shadow DOM also supports slots, which is something that we'll look at towards the end of this video. Now there are 2 things that I commonly inject in the constructor. Element ref will give us a reference to the actual DOM APIs that exist on this element. The next one is the change detection ref, which allows us to rerender this component manually instead of relying on the automatic change detection. Because we're displaying an image, we'll have our custom element behave just like a regular image tag.

We'll give it a source attribute and an alt attribute. Now the special thing about our custom element is that it only displays an image when it's actually visible in the viewport. For that, we're going to emit our own custom event called is visible. Now when it comes to your internal component state, I recommend keeping the input values as immutable. You have the flexibility to manage the state however you want, but here's a pattern that I find especially effective.

So we'll create an object with a couple of properties on it, And we only want to rerender our component if the state changes. Then we'll set up a method here called set state which takes a key and a value as its arguments. Then Then we can go ahead and use the spread syntax to create a new object and set that as the new state on the component. Then we can guarantee a rerender here by calling detect changes on the change detection ref. This code might look familiar because it's inspired by the way React works.

Contrary to popular belief, I do not hate React. Overall, I found this to be a very reliable way to work with elements, But there's definitely many different ways you could do this. Let's go ahead and switch over to the HTML and put this to use. 1st, we'll set up a div. And if the loaded state is false, then we'll go ahead and show that placeholder.

You can check out the full CSS for that animation in the source code. Then we'll set up a figure to wrap the image itself. And we'll only show this if it's visible based on the user's scroll position on the window. Then we'll add an image tag inside of here, which will only be loaded over the network when this visible property flips to True. Just because it's visible doesn't mean it's loaded yet, so we'll also hide the image until it's fully loaded.

And then we'll run an event handler once that event takes place. And the last thing to make note of is that we're passing our input source to the actual image source here. So, again, our custom element feels just like a regular image tag with some added benefit. So now the challenge is determining whether or not the user has scrolled to this element. To make that happen, we're going to need to access some native DOM APIs.

We've already set up a reference to the native element in the constructor of this component. We can go ahead and call it here, and then we can call get bounding client rect, which will give us the actual measurements of that DOM element. If the top of the window is less than or equal to the window inner height, then we know that that element has been scrolled to. And we also wanna check that the element is not already visible because if it is, then there's no point in running this code. But if it is visible for the first time, then we'll go ahead and run our set state method, which will change the state and then rerender the component.

Another thing we wanna do is emit a custom event when the element becomes visible. I'll cover the implementation of that in just a minute. So there are 2 different situations where we want to calculate the visibility of the element. 1st, when the component is initialized. Because if the element is already in the viewport, then we don't want to wait for the user to scroll to load it.

Then to listen to the scroll position, we can add host listener then window colon Scroll to listen to the global window scroll event. And when that happens, we'll go ahead and calculate the visibility of the element. So that's how we determine when an element's visible and also rerender it when its state changes. For the image itself, there's a built in load event which will fire when the image is fully loaded. So when that takes place we'll go ahead and set the loaded state to true again re rendering the component.

So the end result looks like this. We start with a placeholder. When the image loads it's displayed and the placeholder is removed. Again, the great thing about web components is that we can interact with them using vanilla JavaScript in the DOM. So we could use document query selector to grab the element and append it somewhere or change its CSS styles or whatever.

By default, the internal properties and methods on the component are not available when you grab it from the DOM like this. But it can be very useful to expose a public method that can be used by the developers working with your elements. For example, let's set up a log method that logs out the internal state of the component. The method that I found works best, although I'd like to see this improved in future versions of Angular Elements is to use the Input decorator. The reason we do it this way and not just attach input to a method is that it gives us context to this or this component instance.

So we can console log this state, which would otherwise be undefined if it was a regular method. Now another thing that's really useful on the same note is to emit a custom event that can be listened to in the browser. So we already have an event emitter set up on this component, And we can emit through that just like we normally would in Angular, and we'll also set up a custom event in the DOM. We'll give that a name of is visible and then we can reference our native element and dispatch the event through it. If we go back to the browser, we can now grab this element from the DOM, attach an event listener to it, and handle it however we want using vanilla JavaScript or some other framework.

So I've set up the is visible listener, and then I'm going to console log the event when it occurs. As soon as the image becomes visible in the viewport, it logs that custom event to the Console. So that takes care of that. The next thing I wanna show you is content projection using slots. If you look at the image on the left here, you'll notice a caption underneath that has a default header and default caption.

If we revisit our static HTML, you can see that I have a couple of spans that are inside of the lazy image tags. The spans have a slot attribute which corresponds to a certain place that they'll be displayed which we'll define inside of our custom element. So now I'll switch over to the component HTML, and we'll go ahead and add a figure caption. Then we can include slot tags that have a specific name that defines where this content will be displayed. This is super useful when you have components that can be customized, but you don't want the end user to have to worry about adding the required markup to it.

And if you want the user to just be able to transclude some markup inside your component, you can simply drop in a slot tag. That will be considered the default slot and the user can just pass in whatever HTML they want and it will be rendered here. I'm gonna go ahead and wrap things up there. I have a whole bunch of other ideas for Angular Elements for future videos, so make sure to like and subscribe. And if you wanna take your development to the next level, consider becoming a pro member at angularfirebase .com.

You'll get access to my full length courses, my book, as well as a whole bunch of other resources designed to help you build and ship apps faster. Thanks for watching, and I'll talk to you soon.
One of the most exciting trends happening in web development is the adoption of web components, because they allow us to build applications that don't walk us into a specific framework or programming style. I'm going to be using Web Components in production very soon, so I wanted to share some advanced concepts that I've learned working with Angular Elements.
software development
And I'll even show you how to achieve a near perfect Lighthouse performance score with the full power of Angular and Firebase in your JavaScript bundle. If you're new here, like and subscribe, and congrats to Damien Wright, who's last week's t shirt winner. But don't worry missed out, there's another one of a kind t shirt going out this week. All you have to do is leave a comment below. Over the last few months, I've been building a product called Fireship IO, which is just a better way for me to deliver my content to you. This project needs to be very fast and search engine optimized, But it also needs to use Firebase for user authentication and dynamic data. The beauty of web components is that I can pre render all of my static content and then bootstrap in custom elements when they're needed. Throughout this journey, I've used pretty much every web component tool that's out there and I found that Angular Elements is the most productive for a larger project, but you'll also wanna check out Stencil and lit element, which I think are both very promising. The big advantage of elements is that, a, you get the full power of Angular, and, b, your components share the same dependency injector tree, which means you can easily share data or functionality between your custom elements.
And c, the API is stable and being used in production at Google. Today, we're going to build a custom element that can lazy load an image based on the user's scroll position in the browser. When the image is loading, it will show this Facebook style shimmer placeholder, then replace it with the image when it's fully loaded. Now we'll jump into some code, but if you haven't already seen my original Angular Elements video, you'll wanna check that one out which is a little more basic level.
animation
google
The first thing you wanna do is go into your Angular app and then run n g add at angular elements. This will install the dependencies and also the polyfills to ensure that your elements are compatible with all browsers. Then you can go into the app directory and you'll wanna just go ahead and delete everything except for the app module. You'll also notice I've generated a couple of regular components in here as well. The first thing we'll wanna do is register our components as custom elements. I'm assuming Angular will have a better way to do this in the future, but currently we import Injector from Angular Core and create custom element from Angular Elements. Now if you want to use your elements within the context of an Angular app, you'll want to add them to the entry components array.
The important thing is that we go down here to the app module and add the injector to the constructor. If you have a big project, there's probably a whole bunch of different elements to register. So the way I like to set this up is to create an array of tuples.
programming
So the first item is the Angular class name and then the second item is the name of the custom element. So that's how you'll actually use it in the DOM. So now we can loop over these elements and we can actually destructure them directly in the for loop, which I think is a really nice looking piece of JavaScript. From there, we can call create custom element And that gives us a dry way to register a large number of components. Now let's switch gears and see how we can create a single JavaScript bundle that we can use outside of Angular. What you're looking at here is the build script that I wrote from my original Angular Elements video. It just takes all of your production build files and then concatenates them into a single file in the public directory. So this works fine, but it's kind of a hack. I'd recommend checking out NGX build plus to extend the default behavior of the CLI, and hopefully the CLI will just support this out of the box in the future. We'll stick with the simple approach for now, and I've added a couple of build and serve scripts to my package. Json. It first runs ng build prod, and then it runs the build script with node. So now that we have our JavaScript bundled, I'm going to put it to use in just a static HTML page by adding it as a script to the head of the document.
And you can see down here I'm using this image lazy custom element, which we'll build here in a few minutes. Now I'll go ahead and run a Lighthouse audit, And keep in mind, I'm also not lazy loading the images at this point either. We get a 1st Contentful Paint in 2.5 seconds, and time to interactive is 4 seconds.
animation
photography
graphic design
I've also added Firebase to my JavaScript bundle, so we have 342 kilobytes here in total that needs to be loaded before the rest of the page can render. But the great thing about elements is that we can defer the script until after the page is rendered. So how do we do that? We just go into our script tag and add defer, and we're done. If we run the audit again, we get a first paint in 600 milliseconds, which might as well just be 0. And 3 seconds later, we have the full power of Angular and Firebase ready in the page. So you can already get amazing performance with Elements, but it's only going to get better in the next few months here as Angular Ivy becomes production ready. So that's pretty awesome stuff, but I wanna share a few advanced pro tips that I've throughout my experience working with elements. The first thing I'd recommend doing is disabling Angular's automatic change detection or NG zones, which you can do here in the main TS file. The reason for this is that I've run into some really hard to debug issues that only happen in production. So you'll find that life is much easier when you tell the component explicitly when to rerender. Now if we go into the component itself, you can see I've imported everything under the kitchen sink here from Angular Core. You won't need all these things in your elements. I just wanna show you a few different techniques at your disposal. And also, if you don't wanna turn off zones globally, you can do it here at the component level by doing change detection strategy on push. The next big decision is whether or not to use the shadow DOM. So the term web components encompasses a few different features, one of which is obviously custom elements, but another one is the shadow DOM. If you turn the shadow DOM on, it means that your CSS styles will be encapsulated in this component. That can be a good thing if you don't want your CSS to bleed out, but it can also make your components harder to style, it's a trade off. And the shadow DOM also supports slots, which is something that we'll look at towards the end of this video. Now there are 2 things that I commonly inject in the constructor. Element ref will give us a reference to the actual DOM APIs that exist on this element. The next one is the change detection ref, which allows us to rerender this component manually instead of relying on the automatic change detection. Because we're displaying an image, we'll have our custom element behave just like a regular image tag. We'll give it a source attribute and an alt attribute. Now the special thing about our custom element is that it only displays an image when it's actually visible in the viewport. For that, we're going to emit our own custom event called is visible.
Now when it comes to your internal component state, I recommend keeping the input values as immutable. You have the flexibility to manage the state however you want, but here's a pattern that I find especially effective. So we'll create an object with a couple of properties on it, And we only want to rerender our component if the state changes.
systems
Then we'll set up a method here called set state which takes a key and a value as its arguments. Then Then we can go ahead and use the spread syntax to create a new object and set that as the new state on the component. Then we can guarantee a rerender here by calling detect changes on the change detection ref. This code might look familiar because it's inspired by the way React works. Contrary to popular belief, I do not hate React. Overall, I found this to be a very reliable way to work with elements, But there's definitely many different ways you could do this.
Let's go ahead and switch over to the HTML and put this to use. 1st, we'll set up a div. And if the loaded state is false, then we'll go ahead and show that placeholder. You can check out the full CSS for that animation in the source code. Then we'll set up a figure to wrap the image itself. And we'll only show this if it's visible based on the user's scroll position on the window. Then we'll add an image tag inside of here, which will only be loaded over the network when this visible property flips to True.
animation
visualization
Just because it's visible doesn't mean it's loaded yet, so we'll also hide the image until it's fully loaded. And then we'll run an event handler once that event takes place. And the last thing to make note of is that we're passing our input source to the actual image source here. So, again, our custom element feels just like a regular image tag with some added benefit. So now the challenge is determining whether or not the user has scrolled to this element. To make that happen, we're going to need to access some native DOM APIs. We've already set up a reference to the native element in the constructor of this component. We can go ahead and call it here, and then we can call get bounding client rect, which will give us the actual measurements of that DOM element. If the top of the window is less than or equal to the window inner height, then we know that that element has been scrolled to. And we also wanna check that the element is not already visible because if it is, then there's no point in running this code. But if it is visible for the first time, then we'll go ahead and run our set state method, which will change the state and then rerender the component.
Another thing we wanna do is emit a custom event when the element becomes visible. I'll cover the implementation of that in just a minute. So there are 2 different situations where we want to calculate the visibility of the element. 1st, when the component is initialized. Because if the element is already in the viewport, then we don't want to wait for the user to scroll to load it.
visualization
Then to listen to the scroll position, we can add host listener then window colon Scroll to listen to the global window scroll event. And when that happens, we'll go ahead and calculate the visibility of the element. So that's how we determine when an element's visible and also rerender it when its state changes. For the image itself, there's a built in load event which will fire when the image is fully loaded. So when that takes place we'll go ahead and set the loaded state to true again re rendering the component. So the end result looks like this. We start with a placeholder. When the image loads it's displayed and the placeholder is removed. Again, the great thing about web components is that we can interact with them using vanilla JavaScript in the DOM. So we could use document query selector to grab the element and append it somewhere or change its CSS styles or whatever. By default, the internal properties and methods on the component are not available when you grab it from the DOM like this. But it can be very useful to expose a public method that can be used by the developers working with your elements. For example, let's set up a log method that logs out the internal state of the component. The method that I found works best, although I'd like to see this improved in future versions of Angular Elements is to use the Input decorator. The reason we do it this way and not just attach input to a method is that it gives us context to this or this component instance. So we can console log this state, which would otherwise be undefined if it was a regular method. Now another thing that's really useful on the same note is to emit a custom event that can be listened to in the browser. So we already have an event emitter set up on this component, And we can emit through that just like we normally would in Angular, and we'll also set up a custom event in the DOM. We'll give that a name of is visible and then we can reference our native element and dispatch the event through it. If we go back to the browser, we can now grab this element from the DOM, attach an event listener to it, and handle it however we want using vanilla JavaScript or some other framework. So I've set up the is visible listener, and then I'm going to console log the event when it occurs. As soon as the image becomes visible in the viewport, it logs that custom event to the Console. So that takes care of that. The next thing I wanna show you is content projection using slots. If you look at the image on the left here, you'll notice a caption underneath that has a default header and default caption. If we revisit our static HTML, you can see that I have a couple of spans that are inside of the lazy image tags. The spans have a slot attribute which corresponds to a certain place that they'll be displayed which we'll define inside of our custom element.
So now I'll switch over to the component HTML, and we'll go ahead and add a figure caption. Then we can include slot tags that have a specific name that defines where this content will be displayed. This is super useful when you have components that can be customized, but you don't want the end user to have to worry about adding the required markup to it.
graphic design
And if you want the user to just be able to transclude some markup inside your component, you can simply drop in a slot tag.
That will be considered the default slot and the user can just pass in whatever HTML they want and it will be rendered here. I'm gonna go ahead and wrap things up there. I have a whole bunch of other ideas for Angular Elements for future videos, so make sure to like and subscribe. And if you wanna take your development to the next level, consider becoming a pro member at angularfirebase .com. You'll get access to my full length courses, my book, as well as a whole bunch of other resources designed to help you build and ship apps faster. Thanks for watching, and I'll talk to you soon.
software
software development
publishing
books
animation
youtube
One of the most exciting trends happening in web development is the adoption of web components, because they allow us to build applications that don't walk us into a specific framework or programming style. I'm going to be using Web Components in production very soon, so I wanted to share some advanced concepts that I've learned working with Angular Elements. And I'll even show you how to achieve a near perfect Lighthouse performance score with the full power of Angular and Firebase in your JavaScript bundle. If you're new here, like and subscribe, and congrats to Damien Wright, who's last week's t shirt winner. But don't worry missed out, there's another one of a kind t shirt going out this week. All you have to do is leave a comment below. Over the last few months, I've been building a product called Fireship IO, which is just a better way for me to deliver my content to you. This project needs to be very fast and search engine optimized, But it also needs to use Firebase for user authentication and dynamic data. The beauty of web components is that I can pre render all of my static content and then bootstrap in custom elements when they're needed. Throughout this journey, I've used pretty much every web component tool that's out there and I found that Angular Elements is the most productive for a larger project, but you'll also wanna check out Stencil and lit element, which I think are both very promising. The big advantage of elements is that, a, you get the full power of Angular, and, b, your components share the same dependency injector tree, which means you can easily share data or functionality between your custom elements. And c, the API is stable and being used in production at Google. Today, we're going to build a custom element that can lazy load an image based on the user's scroll position in the browser. When the image is loading, it will show this Facebook style shimmer placeholder, then replace it with the image when it's fully loaded. Now we'll jump into some code, but if you haven't already seen my original Angular Elements video, you'll wanna check that one out which is a little more basic level. The first thing you wanna do is go into your Angular app and then run n g add at angular elements. This will install the dependencies and also the polyfills to ensure that your elements are compatible with all browsers. Then you can go into the app directory and you'll wanna just go ahead and delete everything except for the app module. You'll also notice I've generated a couple of regular components in here as well. The first thing we'll wanna do is register our components as custom elements. I'm assuming Angular will have a better way to do this in the future, but currently we import Injector from Angular Core and create custom element from Angular Elements. Now if you want to use your elements within the context of an Angular app, you'll want to add them to the entry components array. The important thing is that we go down here to the app module and add the injector to the constructor. If you have a big project, there's probably a whole bunch of different elements to register. So the way I like to set this up is to create an array of tuples. So the first item is the Angular class name and then the second item is the name of the custom element. So that's how you'll actually use it in the DOM. So now we can loop over these elements and we can actually destructure them directly in the for loop, which I think is a really nice looking piece of JavaScript. From there, we can call create custom element And that gives us a dry way to register a large number of components. Now let's switch gears and see how we can create a single JavaScript bundle that we can use outside of Angular. What you're looking at here is the build script that I wrote from my original Angular Elements video. It just takes all of your production build files and then concatenates them into a single file in the public directory. So this works fine, but it's kind of a hack. I'd recommend checking out NGX build plus to extend the default behavior of the CLI, and hopefully the CLI will just support this out of the box in the future. We'll stick with the simple approach for now, and I've added a couple of build and serve scripts to my package. Json. It first runs ng build prod, and then it runs the build script with node. So now that we have our JavaScript bundled, I'm going to put it to use in just a static HTML page by adding it as a script to the head of the document. And you can see down here I'm using this image lazy custom element, which we'll build here in a few minutes. Now I'll go ahead and run a Lighthouse audit, And keep in mind, I'm also not lazy loading the images at this point either. We get a 1st Contentful Paint in 2.5 seconds, and time to interactive is 4 seconds. I've also added Firebase to my JavaScript bundle, so we have 342 kilobytes here in total that needs to be loaded before the rest of the page can render. But the great thing about elements is that we can defer the script until after the page is rendered. So how do we do that? We just go into our script tag and add defer, and we're done. If we run the audit again, we get a first paint in 600 milliseconds, which might as well just be 0. And 3 seconds later, we have the full power of Angular and Firebase ready in the page. So you can already get amazing performance with Elements, but it's only going to get better in the next few months here as Angular Ivy becomes production ready. So that's pretty awesome stuff, but I wanna share a few advanced pro tips that I've throughout my experience working with elements. The first thing I'd recommend doing is disabling Angular's automatic change detection or NG zones, which you can do here in the main TS file. The reason for this is that I've run into some really hard to debug issues that only happen in production. So you'll find that life is much easier when you tell the component explicitly when to rerender. Now if we go into the component itself, you can see I've imported everything under the kitchen sink here from Angular Core. You won't need all these things in your elements. I just wanna show you a few different techniques at your disposal. And also, if you don't wanna turn off zones globally, you can do it here at the component level by doing change detection strategy on push. The next big decision is whether or not to use the shadow DOM. So the term web components encompasses a few different features, one of which is obviously custom elements, but another one is the shadow DOM. If you turn the shadow DOM on, it means that your CSS styles will be encapsulated in this component. That can be a good thing if you don't want your CSS to bleed out, but it can also make your components harder to style, it's a trade off. And the shadow DOM also supports slots, which is something that we'll look at towards the end of this video. Now there are 2 things that I commonly inject in the constructor. Element ref will give us a reference to the actual DOM APIs that exist on this element. The next one is the change detection ref, which allows us to rerender this component manually instead of relying on the automatic change detection. Because we're displaying an image, we'll have our custom element behave just like a regular image tag. We'll give it a source attribute and an alt attribute. Now the special thing about our custom element is that it only displays an image when it's actually visible in the viewport. For that, we're going to emit our own custom event called is visible. Now when it comes to your internal component state, I recommend keeping the input values as immutable. You have the flexibility to manage the state however you want, but here's a pattern that I find especially effective. So we'll create an object with a couple of properties on it, And we only want to rerender our component if the state changes. Then we'll set up a method here called set state which takes a key and a value as its arguments. Then Then we can go ahead and use the spread syntax to create a new object and set that as the new state on the component. Then we can guarantee a rerender here by calling detect changes on the change detection ref. This code might look familiar because it's inspired by the way React works. Contrary to popular belief, I do not hate React. Overall, I found this to be a very reliable way to work with elements, But there's definitely many different ways you could do this. Let's go ahead and switch over to the HTML and put this to use. 1st, we'll set up a div. And if the loaded state is false, then we'll go ahead and show that placeholder. You can check out the full CSS for that animation in the source code. Then we'll set up a figure to wrap the image itself. And we'll only show this if it's visible based on the user's scroll position on the window. Then we'll add an image tag inside of here, which will only be loaded over the network when this visible property flips to True. Just because it's visible doesn't mean it's loaded yet, so we'll also hide the image until it's fully loaded. And then we'll run an event handler once that event takes place. And the last thing to make note of is that we're passing our input source to the actual image source here. So, again, our custom element feels just like a regular image tag with some added benefit. So now the challenge is determining whether or not the user has scrolled to this element. To make that happen, we're going to need to access some native DOM APIs. We've already set up a reference to the native element in the constructor of this component. We can go ahead and call it here, and then we can call get bounding client rect, which will give us the actual measurements of that DOM element. If the top of the window is less than or equal to the window inner height, then we know that that element has been scrolled to. And we also wanna check that the element is not already visible because if it is, then there's no point in running this code. But if it is visible for the first time, then we'll go ahead and run our set state method, which will change the state and then rerender the component. Another thing we wanna do is emit a custom event when the element becomes visible. I'll cover the implementation of that in just a minute. So there are 2 different situations where we want to calculate the visibility of the element. 1st, when the component is initialized. Because if the element is already in the viewport, then we don't want to wait for the user to scroll to load it. Then to listen to the scroll position, we can add host listener then window colon Scroll to listen to the global window scroll event. And when that happens, we'll go ahead and calculate the visibility of the element. So that's how we determine when an element's visible and also rerender it when its state changes. For the image itself, there's a built in load event which will fire when the image is fully loaded. So when that takes place we'll go ahead and set the loaded state to true again re rendering the component. So the end result looks like this. We start with a placeholder. When the image loads it's displayed and the placeholder is removed. Again, the great thing about web components is that we can interact with them using vanilla JavaScript in the DOM. So we could use document query selector to grab the element and append it somewhere or change its CSS styles or whatever. By default, the internal properties and methods on the component are not available when you grab it from the DOM like this. But it can be very useful to expose a public method that can be used by the developers working with your elements. For example, let's set up a log method that logs out the internal state of the component. The method that I found works best, although I'd like to see this improved in future versions of Angular Elements is to use the Input decorator. The reason we do it this way and not just attach input to a method is that it gives us context to this or this component instance. So we can console log this state, which would otherwise be undefined if it was a regular method. Now another thing that's really useful on the same note is to emit a custom event that can be listened to in the browser. So we already have an event emitter set up on this component, And we can emit through that just like we normally would in Angular, and we'll also set up a custom event in the DOM. We'll give that a name of is visible and then we can reference our native element and dispatch the event through it. If we go back to the browser, we can now grab this element from the DOM, attach an event listener to it, and handle it however we want using vanilla JavaScript or some other framework. So I've set up the is visible listener, and then I'm going to console log the event when it occurs. As soon as the image becomes visible in the viewport, it logs that custom event to the Console. So that takes care of that. The next thing I wanna show you is content projection using slots. If you look at the image on the left here, you'll notice a caption underneath that has a default header and default caption. If we revisit our static HTML, you can see that I have a couple of spans that are inside of the lazy image tags. The spans have a slot attribute which corresponds to a certain place that they'll be displayed which we'll define inside of our custom element. So now I'll switch over to the component HTML, and we'll go ahead and add a figure caption. Then we can include slot tags that have a specific name that defines where this content will be displayed. This is super useful when you have components that can be customized, but you don't want the end user to have to worry about adding the required markup to it. And if you want the user to just be able to transclude some markup inside your component, you can simply drop in a slot tag. That will be considered the default slot and the user can just pass in whatever HTML they want and it will be rendered here. I'm gonna go ahead and wrap things up there. I have a whole bunch of other ideas for Angular Elements for future videos, so make sure to like and subscribe. And if you wanna take your development to the next level, consider becoming a pro member at angularfirebase .com. You'll get access to my full length courses, my book, as well as a whole bunch of other resources designed to help you build and ship apps faster. Thanks for watching, and I'll talk to you soon.
One
one
of
of
the
the
most
most
exciting
exciting
trends
trends
happening
happening
in
in
web
web
development
development
is
is
the
the
adoption
adoption
of
of
web
web
components,
components
because
because
they
they
allow
allow
us
us
to
to
build
build
applications
applications
that
that
don't
don't
walk
walk
us
us
into
into
a
a
specific
specific
framework
framework
or
or
programming
programming
style.
style
I'm
i'm
going
going
to
to
be
be
using
using
Web
web
Components
components
in
in
production
production
very
very
soon,
soon
so
so
I
i
wanted
wanted
to
to
share
share
some
some
advanced
advanced
concepts
concepts
that
that
I've
i've
learned
learned
working
working
with
with
Angular
angular
Elements.
elements
And
and
I'll
i'll
even
even
show
show
you
you
how
how
to
to
achieve
achieve
a
a
near
near
perfect
perfect
Lighthouse
lighthouse
performance
performance
score
score
with
with
the
the
full
full
power
power
of
of
Angular
angular
and
and
Firebase
firebase
in
in
your
your
JavaScript
javascript
bundle.
bundle
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe,
subscribe
and
and
congrats
congrats
to
to
Damien
damien
Wright,
wright
who's
who's
last
last
week's
week's
t
t
shirt
shirt
winner.
winner
But
but
don't
don't
worry
worry
missed
missed
out,
out
there's
there's
another
another
one
one
of
of
a
a
kind
kind
t
t
shirt
shirt
going
going
out
out
this
this
week.
week
All
all
you
you
have
have
to
to
do
do
is
is
leave
leave
a
a
comment
comment
below.
below
Over
over
the
the
last
last
few
few
months,
months
I've
i've
been
been
building
building
a
a
product
product
called
called
Fireship
fireship
IO,
io
which
which
is
is
just
just
a
a
better
better
way
way
for
for
me
me
to
to
deliver
deliver
my
my
content
content
to
to
you.
you
This
this
project
project
needs
needs
to
to
be
be
very
very
fast
fast
and
and
search
search
engine
engine
optimized,
optimized
But
but
it
it
also
also
needs
needs
to
to
use
use
Firebase
firebase
for
for
user
user
authentication
authentication
and
and
dynamic
dynamic
data.
data
The
the
beauty
beauty
of
of
web
web
components
components
is
is
that
that
I
i
can
can
pre
pre
render
render
all
all
of
of
my
my
static
static
content
content
and
and
then
then
bootstrap
bootstrap
in
in
custom
custom
elements
elements
when
when
they're
they're
needed.
needed
Throughout
throughout
this
this
journey,
journey
I've
i've
used
used
pretty
pretty
much
much
every
every
web
web
component
component
tool
tool
that's
that's
out
out
there
there
and
and
I
i
found
found
that
that
Angular
angular
Elements
elements
is
is
the
the
most
most
productive
productive
for
for
a
a
larger
larger
project,
project
but
but
you'll
you'll
also
also
wanna
wanna
check
check
out
out
Stencil
stencil
and
and
lit
lit
element,
element
which
which
I
i
think
think
are
are
both
both
very
very
promising.
promising
The
the
big
big
advantage
advantage
of
of
elements
elements
is
is
that,
that
a,
a
you
you
get
get
the
the
full
full
power
power
of
of
Angular,
angular
and,
and
b,
b
your
your
components
components
share
share
the
the
same
same
dependency
dependency
injector
injector
tree,
tree
which
which
means
means
you
you
can
can
easily
easily
share
share
data
data
or
or
functionality
functionality
between
between
your
your
custom
custom
elements.
elements
And
and
c,
c
the
the
API
api
is
is
stable
stable
and
and
being
being
used
used
in
in
production
production
at
at
Google.
google
Today,
today
we're
we're
going
going
to
to
build
build
a
a
custom
custom
element
element
that
that
can
can
lazy
lazy
load
load
an
an
image
image
based
based
on
on
the
the
user's
user's
scroll
scroll
position
position
in
in
the
the
browser.
browser
When
when
the
the
image
image
is
is
loading,
loading
it
it
will
will
show
show
this
this
Facebook
facebook
style
style
shimmer
shimmer
placeholder,
placeholder
then
then
replace
replace
it
it
with
with
the
the
image
image
when
when
it's
it's
fully
fully
loaded.
loaded
Now
now
we'll
we'll
jump
jump
into
into
some
some
code,
code
but
but
if
if
you
you
haven't
haven't
already
already
seen
seen
my
my
original
original
Angular
angular
Elements
elements
video,
video
you'll
you'll
wanna
wanna
check
check
that
that
one
one
out
out
which
which
is
is
a
a
little
little
more
more
basic
basic
level.
level
The
the
first
first
thing
thing
you
you
wanna
wanna
do
do
is
is
go
go
into
into
your
your
Angular
angular
app
app
and
and
then
then
run
run
n
n
g
g
add
add
at
at
angular
angular
elements.
elements
This
this
will
will
install
install
the
the
dependencies
dependencies
and
and
also
also
the
the
polyfills
polyfills
to
to
ensure
ensure
that
that
your
your
elements
elements
are
are
compatible
compatible
with
with
all
all
browsers.
browsers
Then
then
you
you
can
can
go
go
into
into
the
the
app
app
directory
directory
and
and
you'll
you'll
wanna
wanna
just
just
go
go
ahead
ahead
and
and
delete
delete
everything
everything
except
except
for
for
the
the
app
app
module.
module
You'll
you'll
also
also
notice
notice
I've
i've
generated
generated
a
a
couple
couple
of
of
regular
regular
components
components
in
in
here
here
as
as
well.
well
The
the
first
first
thing
thing
we'll
we'll
wanna
wanna
do
do
is
is
register
register
our
our
components
components
as
as
custom
custom
elements.
elements
I'm
i'm
assuming
assuming
Angular
angular
will
will
have
have
a
a
better
better
way
way
to
to
do
do
this
this
in
in
the
the
future,
future
but
but
currently
currently
we
we
import
import
Injector
injector
from
from
Angular
angular
Core
core
and
and
create
create
custom
custom
element
element
from
from
Angular
angular
Elements.
elements
Now
now
if
if
you
you
want
want
to
to
use
use
your
your
elements
elements
within
within
the
the
context
context
of
of
an
an
Angular
angular
app,
app
you'll
you'll
want
want
to
to
add
add
them
them
to
to
the
the
entry
entry
components
components
array.
array
The
the
important
important
thing
thing
is
is
that
that
we
we
go
go
down
down
here
here
to
to
the
the
app
app
module
module
and
and
add
add
the
the
injector
injector
to
to
the
the
constructor.
constructor
If
if
you
you
have
have
a
a
big
big
project,
project
there's
there's
probably
probably
a
a
whole
whole
bunch
bunch
of
of
different
different
elements
elements
to
to
register.
register
So
so
the
the
way
way
I
i
like
like
to
to
set
set
this
this
up
up
is
is
to
to
create
create
an
an
array
array
of
of
tuples.
tuples
So
so
the
the
first
first
item
item
is
is
the
the
Angular
angular
class
class
name
name
and
and
then
then
the
the
second
second
item
item
is
is
the
the
name
name
of
of
the
the
custom
custom
element.
element
So
so
that's
that's
how
how
you'll
you'll
actually
actually
use
use
it
it
in
in
the
the
DOM.
dom
So
so
now
now
we
we
can
can
loop
loop
over
over
these
these
elements
elements
and
and
we
we
can
can
actually
actually
destructure
destructure
them
them
directly
directly
in
in
the
the
for
for
loop,
loop
which
which
I
i
think
think
is
is
a
a
really
really
nice
nice
looking
looking
piece
piece
of
of
JavaScript.
javascript
From
from
there,
there
we
we
can
can
call
call
create
create
custom
custom
element
element
And
and
that
that
gives
gives
us
us
a
a
dry
dry
way
way
to
to
register
register
a
a
large
large
number
number
of
of
components.
components
Now
now
let's
let's
switch
switch
gears
gears
and
and
see
see
how
how
we
we
can
can
create
create
a
a
single
single
JavaScript
javascript
bundle
bundle
that
that
we
we
can
can
use
use
outside
outside
of
of
Angular.
angular
What
what
you're
you're
looking
looking
at
at
here
here
is
is
the
the
build
build
script
script
that
that
I
i
wrote
wrote
from
from
my
my
original
original
Angular
angular
Elements
elements
video.
video
It
it
just
just
takes
takes
all
all
of
of
your
your
production
production
build
build
files
files
and
and
then
then
concatenates
concatenates
them
them
into
into
a
a
single
single
file
file
in
in
the
the
public
public
directory.
directory
So
so
this
this
works
works
fine,
fine
but
but
it's
it's
kind
kind
of
of
a
a
hack.
hack
I'd
i'd
recommend
recommend
checking
checking
out
out
NGX
ngx
build
build
plus
plus
to
to
extend
extend
the
the
default
default
behavior
behavior
of
of
the
the
CLI,
cli
and
and
hopefully
hopefully
the
the
CLI
cli
will
will
just
just
support
support
this
this
out
out
of
of
the
the
box
box
in
in
the
the
future.
future
We'll
we'll
stick
stick
with
with
the
the
simple
simple
approach
approach
for
for
now,
now
and
and
I've
i've
added
added
a
a
couple
couple
of
of
build
build
and
and
serve
serve
scripts
scripts
to
to
my
my
package.
package
Json.
json
It
it
first
first
runs
runs
ng
ng
build
build
prod,
prod
and
and
then
then
it
it
runs
runs
the
the
build
build
script
script
with
with
node.
node
So
so
now
now
that
that
we
we
have
have
our
our
JavaScript
javascript
bundled,
bundled
I'm
i'm
going
going
to
to
put
put
it
it
to
to
use
use
in
in
just
just
a
a
static
static
HTML
html
page
page
by
by
adding
adding
it
it
as
as
a
a
script
script
to
to
the
the
head
head
of
of
the
the
document.
document
And
and
you
you
can
can
see
see
down
down
here
here
I'm
i'm
using
using
this
this
image
image
lazy
lazy
custom
custom
element,
element
which
which
we'll
we'll
build
build
here
here
in
in
a
a
few
few
minutes.
minutes
Now
now
I'll
i'll
go
go
ahead
ahead
and
and
run
run
a
a
Lighthouse
lighthouse
audit,
audit
And
and
keep
keep
in
in
mind,
mind
I'm
i'm
also
also
not
not
lazy
lazy
loading
loading
the
the
images
images
at
at
this
this
point
point
either.
either
We
we
get
get
a
a
1st
1st
Contentful
contentful
Paint
paint
in
in
2.5
2.5
seconds,
seconds
and
and
time
time
to
to
interactive
interactive
is
is
4
4
seconds.
seconds
I've
i've
also
also
added
added
Firebase
firebase
to
to
my
my
JavaScript
javascript
bundle,
bundle
so
so
we
we
have
have
342
342
kilobytes
kilobytes
here
here
in
in
total
total
that
that
needs
needs
to
to
be
be
loaded
loaded
before
before
the
the
rest
rest
of
of
the
the
page
page
can
can
render.
render
But
but
the
the
great
great
thing
thing
about
about
elements
elements
is
is
that
that
we
we
can
can
defer
defer
the
the
script
script
until
until
after
after
the
the
page
page
is
is
rendered.
rendered
So
so
how
how
do
do
we
we
do
do
that?
that
We
we
just
just
go
go
into
into
our
our
script
script
tag
tag
and
and
add
add
defer,
defer
and
and
we're
we're
done.
done
If
if
we
we
run
run
the
the
audit
audit
again,
again
we
we
get
get
a
a
first
first
paint
paint
in
in
600
600
milliseconds,
milliseconds
which
which
might
might
as
as
well
well
just
just
be
be
0.
0
And
and
3
3
seconds
seconds
later,
later
we
we
have
have
the
the
full
full
power
power
of
of
Angular
angular
and
and
Firebase
firebase
ready
ready
in
in
the
the
page.
page
So
so
you
you
can
can
already
already
get
get
amazing
amazing
performance
performance
with
with
Elements,
elements
but
but
it's
it's
only
only
going
going
to
to
get
get
better
better
in
in
the
the
next
next
few
few
months
months
here
here
as
as
Angular
angular
Ivy
ivy
becomes
becomes
production
production
ready.
ready
So
so
that's
that's
pretty
pretty
awesome
awesome
stuff,
stuff
but
but
I
i
wanna
wanna
share
share
a
a
few
few
advanced
advanced
pro
pro
tips
tips
that
that
I've
i've
throughout
throughout
my
my
experience
experience
working
working
with
with
elements.
elements
The
the
first
first
thing
thing
I'd
i'd
recommend
recommend
doing
doing
is
is
disabling
disabling
Angular's
angular's
automatic
automatic
change
change
detection
detection
or
or
NG
ng
zones,
zones
which
which
you
you
can
can
do
do
here
here
in
in
the
the
main
main
TS
ts
file.
file
The
the
reason
reason
for
for
this
this
is
is
that
that
I've
i've
run
run
into
into
some
some
really
really
hard
hard
to
to
debug
debug
issues
issues
that
that
only
only
happen
happen
in
in
production.
production
So
so
you'll
you'll
find
find
that
that
life
life
is
is
much
much
easier
easier
when
when
you
you
tell
tell
the
the
component
component
explicitly
explicitly
when
when
to
to
rerender.
rerender
Now
now
if
if
we
we
go
go
into
into
the
the
component
component
itself,
itself
you
you
can
can
see
see
I've
i've
imported
imported
everything
everything
under
under
the
the
kitchen
kitchen
sink
sink
here
here
from
from
Angular
angular
Core.
core
You
you
won't
won't
need
need
all
all
these
these
things
things
in
in
your
your
elements.
elements
I
i
just
just
wanna
wanna
show
show
you
you
a
a
few
few
different
different
techniques
techniques
at
at
your
your
disposal.
disposal
And
and
also,
also
if
if
you
you
don't
don't
wanna
wanna
turn
turn
off
off
zones
zones
globally,
globally
you
you
can
can
do
do
it
it
here
here
at
at
the
the
component
component
level
level
by
by
doing
doing
change
change
detection
detection
strategy
strategy
on
on
push.
push
The
the
next
next
big
big
decision
decision
is
is
whether
whether
or
or
not
not
to
to
use
use
the
the
shadow
shadow
DOM.
dom
So
so
the
the
term
term
web
web
components
components
encompasses
encompasses
a
a
few
few
different
different
features,
features
one
one
of
of
which
which
is
is
obviously
obviously
custom
custom
elements,
elements
but
but
another
another
one
one
is
is
the
the
shadow
shadow
DOM.
dom
If
if
you
you
turn
turn
the
the
shadow
shadow
DOM
dom
on,
on
it
it
means
means
that
that
your
your
CSS
css
styles
styles
will
will
be
be
encapsulated
encapsulated
in
in
this
this
component.
component
That
that
can
can
be
be
a
a
good
good
thing
thing
if
if
you
you
don't
don't
want
want
your
your
CSS
css
to
to
bleed
bleed
out,
out
but
but
it
it
can
can
also
also
make
make
your
your
components
components
harder
harder
to
to
style,
style
it's
it's
a
a
trade
trade
off.
off
And
and
the
the
shadow
shadow
DOM
dom
also
also
supports
supports
slots,
slots
which
which
is
is
something
something
that
that
we'll
we'll
look
look
at
at
towards
towards
the
the
end
end
of
of
this
this
video.
video
Now
now
there
there
are
are
2
2
things
things
that
that
I
i
commonly
commonly
inject
inject
in
in
the
the
constructor.
constructor
Element
element
ref
ref
will
will
give
give
us
us
a
a
reference
reference
to
to
the
the
actual
actual
DOM
dom
APIs
apis
that
that
exist
exist
on
on
this
this
element.
element
The
the
next
next
one
one
is
is
the
the
change
change
detection
detection
ref,
ref
which
which
allows
allows
us
us
to
to
rerender
rerender
this
this
component
component
manually
manually
instead
instead
of
of
relying
relying
on
on
the
the
automatic
automatic
change
change
detection.
detection
Because
because
we're
we're
displaying
displaying
an
an
image,
image
we'll
we'll
have
have
our
our
custom
custom
element
element
behave
behave
just
just
like
like
a
a
regular
regular
image
image
tag.
tag
We'll
we'll
give
give
it
it
a
a
source
source
attribute
attribute
and
and
an
an
alt
alt
attribute.
attribute
Now
now
the
the
special
special
thing
thing
about
about
our
our
custom
custom
element
element
is
is
that
that
it
it
only
only
displays
displays
an
an
image
image
when
when
it's
it's
actually
actually
visible
visible
in
in
the
the
viewport.
viewport
For
for
that,
that
we're
we're
going
going
to
to
emit
emit
our
our
own
own
custom
custom
event
event
called
called
is
is
visible.
visible
Now
now
when
when
it
it
comes
comes
to
to
your
your
internal
internal
component
component
state,
state
I
i
recommend
recommend
keeping
keeping
the
the
input
input
values
values
as
as
immutable.
immutable
You
you
have
have
the
the
flexibility
flexibility
to
to
manage
manage
the
the
state
state
however
however
you
you
want,
want
but
but
here's
here's
a
a
pattern
pattern
that
that
I
i
find
find
especially
especially
effective.
effective
So
so
we'll
we'll
create
create
an
an
object
object
with
with
a
a
couple
couple
of
of
properties
properties
on
on
it,
it
And
and
we
we
only
only
want
want
to
to
rerender
rerender
our
our
component
component
if
if
the
the
state
state
changes.
changes
Then
then
we'll
we'll
set
set
up
up
a
a
method
method
here
here
called
called
set
set
state
state
which
which
takes
takes
a
a
key
key
and
and
a
a
value
value
as
as
its
its
arguments.
arguments
Then
then
Then
then
we
we
can
can
go
go
ahead
ahead
and
and
use
use
the
the
spread
spread
syntax
syntax
to
to
create
create
a
a
new
new
object
object
and
and
set
set
that
that
as
as
the
the
new
new
state
state
on
on
the
the
component.
component
Then
then
we
we
can
can
guarantee
guarantee
a
a
rerender
rerender
here
here
by
by
calling
calling
detect
detect
changes
changes
on
on
the
the
change
change
detection
detection
ref.
ref
This
this
code
code
might
might
look
look
familiar
familiar
because
because
it's
it's
inspired
inspired
by
by
the
the
way
way
React
react
works.
works
Contrary
contrary
to
to
popular
popular
belief,
belief
I
i
do
do
not
not
hate
hate
React.
react
Overall,
overall
I
i
found
found
this
this
to
to
be
be
a
a
very
very
reliable
reliable
way
way
to
to
work
work
with
with
elements,
elements
But
but
there's
there's
definitely
definitely
many
many
different
different
ways
ways
you
you
could
could
do
do
this.
this
Let's
let's
go
go
ahead
ahead
and
and
switch
switch
over
over
to
to
the
the
HTML
html
and
and
put
put
this
this
to
to
use.
use
1st,
1st
we'll
we'll
set
set
up
up
a
a
div.
div
And
and
if
if
the
the
loaded
loaded
state
state
is
is
false,
false
then
then
we'll
we'll
go
go
ahead
ahead
and
and
show
show
that
that
placeholder.
placeholder
You
you
can
can
check
check
out
out
the
the
full
full
CSS
css
for
for
that
that
animation
animation
in
in
the
the
source
source
code.
code
Then
then
we'll
we'll
set
set
up
up
a
a
figure
figure
to
to
wrap
wrap
the
the
image
image
itself.
itself
And
and
we'll
we'll
only
only
show
show
this
this
if
if
it's
it's
visible
visible
based
based
on
on
the
the
user's
user's
scroll
scroll
position
position
on
on
the
the
window.
window
Then
then
we'll
we'll
add
add
an
an
image
image
tag
tag
inside
inside
of
of
here,
here
which
which
will
will
only
only
be
be
loaded
loaded
over
over
the
the
network
network
when
when
this
this
visible
visible
property
property
flips
flips
to
to
True.
true
Just
just
because
because
it's
it's
visible
visible
doesn't
doesn't
mean
mean
it's
it's
loaded
loaded
yet,
yet
so
so
we'll
we'll
also
also
hide
hide
the
the
image
image
until
until
it's
it's
fully
fully
loaded.
loaded
And
and
then
then
we'll
we'll
run
run
an
an
event
event
handler
handler
once
once
that
that
event
event
takes
takes
place.
place
And
and
the
the
last
last
thing
thing
to
to
make
make
note
note
of
of
is
is
that
that
we're
we're
passing
passing
our
our
input
input
source
source
to
to
the
the
actual
actual
image
image
source
source
here.
here
So,
so
again,
again
our
our
custom
custom
element
element
feels
feels
just
just
like
like
a
a
regular
regular
image
image
tag
tag
with
with
some
some
added
added
benefit.
benefit
So
so
now
now
the
the
challenge
challenge
is
is
determining
determining
whether
whether
or
or
not
not
the
the
user
user
has
has
scrolled
scrolled
to
to
this
this
element.
element
To
to
make
make
that
that
happen,
happen
we're
we're
going
going
to
to
need
need
to
to
access
access
some
some
native
native
DOM
dom
APIs.
apis
We've
we've
already
already
set
set
up
up
a
a
reference
reference
to
to
the
the
native
native
element
element
in
in
the
the
constructor
constructor
of
of
this
this
component.
component
We
we
can
can
go
go
ahead
ahead
and
and
call
call
it
it
here,
here
and
and
then
then
we
we
can
can
call
call
get
get
bounding
bounding
client
client
rect,
rect
which
which
will
will
give
give
us
us
the
the
actual
actual
measurements
measurements
of
of
that
that
DOM
dom
element.
element
If
if
the
the
top
top
of
of
the
the
window
window
is
is
less
less
than
than
or
or
equal
equal
to
to
the
the
window
window
inner
inner
height,
height
then
then
we
we
know
know
that
that
that
that
element
element
has
has
been
been
scrolled
scrolled
to.
to
And
and
we
we
also
also
wanna
wanna
check
check
that
that
the
the
element
element
is
is
not
not
already
already
visible
visible
because
because
if
if
it
it
is,
is
then
then
there's
there's
no
no
point
point
in
in
running
running
this
this
code.
code
But
but
if
if
it
it
is
is
visible
visible
for
for
the
the
first
first
time,
time
then
then
we'll
we'll
go
go
ahead
ahead
and
and
run
run
our
our
set
set
state
state
method,
method
which
which
will
will
change
change
the
the
state
state
and
and
then
then
rerender
rerender
the
the
component.
component
Another
another
thing
thing
we
we
wanna
wanna
do
do
is
is
emit
emit
a
a
custom
custom
event
event
when
when
the
the
element
element
becomes
becomes
visible.
visible
I'll
i'll
cover
cover
the
the
implementation
implementation
of
of
that
that
in
in
just
just
a
a
minute.
minute
So
so
there
there
are
are
2
2
different
different
situations
situations
where
where
we
we
want
want
to
to
calculate
calculate
the
the
visibility
visibility
of
of
the
the
element.
element
1st,
1st
when
when
the
the
component
component
is
is
initialized.
initialized
Because
because
if
if
the
the
element
element
is
is
already
already
in
in
the
the
viewport,
viewport
then
then
we
we
don't
don't
want
want
to
to
wait
wait
for
for
the
the
user
user
to
to
scroll
scroll
to
to
load
load
it.
it
Then
then
to
to
listen
listen
to
to
the
the
scroll
scroll
position,
position
we
we
can
can
add
add
host
host
listener
listener
then
then
window
window
colon
colon
Scroll
scroll
to
to
listen
listen
to
to
the
the
global
global
window
window
scroll
scroll
event.
event
And
and
when
when
that
that
happens,
happens
we'll
we'll
go
go
ahead
ahead
and
and
calculate
calculate
the
the
visibility
visibility
of
of
the
the
element.
element
So
so
that's
that's
how
how
we
we
determine
determine
when
when
an
an
element's
element's
visible
visible
and
and
also
also
rerender
rerender
it
it
when
when
its
its
state
state
changes.
changes
For
for
the
the
image
image
itself,
itself
there's
there's
a
a
built
built
in
in
load
load
event
event
which
which
will
will
fire
fire
when
when
the
the
image
image
is
is
fully
fully
loaded.
loaded
So
so
when
when
that
that
takes
takes
place
place
we'll
we'll
go
go
ahead
ahead
and
and
set
set
the
the
loaded
loaded
state
state
to
to
true
true
again
again
re
re
rendering
rendering
the
the
component.
component
So
so
the
the
end
end
result
result
looks
looks
like
like
this.
this
We
we
start
start
with
with
a
a
placeholder.
placeholder
When
when
the
the
image
image
loads
loads
it's
it's
displayed
displayed
and
and
the
the
placeholder
placeholder
is
is
removed.
removed
Again,
again
the
the
great
great
thing
thing
about
about
web
web
components
components
is
is
that
that
we
we
can
can
interact
interact
with
with
them
them
using
using
vanilla
vanilla
JavaScript
javascript
in
in
the
the
DOM.
dom
So
so
we
we
could
could
use
use
document
document
query
query
selector
selector
to
to
grab
grab
the
the
element
element
and
and
append
append
it
it
somewhere
somewhere
or
or
change
change
its
its
CSS
css
styles
styles
or
or
whatever.
whatever
By
by
default,
default
the
the
internal
internal
properties
properties
and
and
methods
methods
on
on
the
the
component
component
are
are
not
not
available
available
when
when
you
you
grab
grab
it
it
from
from
the
the
DOM
dom
like
like
this.
this
But
but
it
it
can
can
be
be
very
very
useful
useful
to
to
expose
expose
a
a
public
public
method
method
that
that
can
can
be
be
used
used
by
by
the
the
developers
developers
working
working
with
with
your
your
elements.
elements
For
for
example,
example
let's
let's
set
set
up
up
a
a
log
log
method
method
that
that
logs
logs
out
out
the
the
internal
internal
state
state
of
of
the
the
component.
component
The
the
method
method
that
that
I
i
found
found
works
works
best,
best
although
although
I'd
i'd
like
like
to
to
see
see
this
this
improved
improved
in
in
future
future
versions
versions
of
of
Angular
angular
Elements
elements
is
is
to
to
use
use
the
the
Input
input
decorator.
decorator
The
the
reason
reason
we
we
do
do
it
it
this
this
way
way
and
and
not
not
just
just
attach
attach
input
input
to
to
a
a
method
method
is
is
that
that
it
it
gives
gives
us
us
context
context
to
to
this
this
or
or
this
this
component
component
instance.
instance
So
so
we
we
can
can
console
console
log
log
this
this
state,
state
which
which
would
would
otherwise
otherwise
be
be
undefined
undefined
if
if
it
it
was
was
a
a
regular
regular
method.
method
Now
now
another
another
thing
thing
that's
that's
really
really
useful
useful
on
on
the
the
same
same
note
note
is
is
to
to
emit
emit
a
a
custom
custom
event
event
that
that
can
can
be
be
listened
listened
to
to
in
in
the
the
browser.
browser
So
so
we
we
already
already
have
have
an
an
event
event
emitter
emitter
set
set
up
up
on
on
this
this
component,
component
And
and
we
we
can
can
emit
emit
through
through
that
that
just
just
like
like
we
we
normally
normally
would
would
in
in
Angular,
angular
and
and
we'll
we'll
also
also
set
set
up
up
a
a
custom
custom
event
event
in
in
the
the
DOM.
dom
We'll
we'll
give
give
that
that
a
a
name
name
of
of
is
is
visible
visible
and
and
then
then
we
we
can
can
reference
reference
our
our
native
native
element
element
and
and
dispatch
dispatch
the
the
event
event
through
through
it.
it
If
if
we
we
go
go
back
back
to
to
the
the
browser,
browser
we
we
can
can
now
now
grab
grab
this
this
element
element
from
from
the
the
DOM,
dom
attach
attach
an
an
event
event
listener
listener
to
to
it,
it
and
and
handle
handle
it
it
however
however
we
we
want
want
using
using
vanilla
vanilla
JavaScript
javascript
or
or
some
some
other
other
framework.
framework
So
so
I've
i've
set
set
up
up
the
the
is
is
visible
visible
listener,
listener
and
and
then
then
I'm
i'm
going
going
to
to
console
console
log
log
the
the
event
event
when
when
it
it
occurs.
occurs
As
as
soon
soon
as
as
the
the
image
image
becomes
becomes
visible
visible
in
in
the
the
viewport,
viewport
it
it
logs
logs
that
that
custom
custom
event
event
to
to
the
the
Console.
console
So
so
that
that
takes
takes
care
care
of
of
that.
that
The
the
next
next
thing
thing
I
i
wanna
wanna
show
show
you
you
is
is
content
content
projection
projection
using
using
slots.
slots
If
if
you
you
look
look
at
at
the
the
image
image
on
on
the
the
left
left
here,
here
you'll
you'll
notice
notice
a
a
caption
caption
underneath
underneath
that
that
has
has
a
a
default
default
header
header
and
and
default
default
caption.
caption
If
if
we
we
revisit
revisit
our
our
static
static
HTML,
html
you
you
can
can
see
see
that
that
I
i
have
have
a
a
couple
couple
of
of
spans
spans
that
that
are
are
inside
inside
of
of
the
the
lazy
lazy
image
image
tags.
tags
The
the
spans
spans
have
have
a
a
slot
slot
attribute
attribute
which
which
corresponds
corresponds
to
to
a
a
certain
certain
place
place
that
that
they'll
they'll
be
be
displayed
displayed
which
which
we'll
we'll
define
define
inside
inside
of
of
our
our
custom
custom
element.
element
So
so
now
now
I'll
i'll
switch
switch
over
over
to
to
the
the
component
component
HTML,
html
and
and
we'll
we'll
go
go
ahead
ahead
and
and
add
add
a
a
figure
figure
caption.
caption
Then
then
we
we
can
can
include
include
slot
slot
tags
tags
that
that
have
have
a
a
specific
specific
name
name
that
that
defines
defines
where
where
this
this
content
content
will
will
be
be
displayed.
displayed
This
this
is
is
super
super
useful
useful
when
when
you
you
have
have
components
components
that
that
can
can
be
be
customized,
customized
but
but
you
you
don't
don't
want
want
the
the
end
end
user
user
to
to
have
have
to
to
worry
worry
about
about
adding
adding
the
the
required
required
markup
markup
to
to
it.
it
And
and
if
if
you
you
want
want
the
the
user
user
to
to
just
just
be
be
able
able
to
to
transclude
transclude
some
some
markup
markup
inside
inside
your
your
component,
component
you
you
can
can
simply
simply
drop
drop
in
in
a
a
slot
slot
tag.
tag
That
that
will
will
be
be
considered
considered
the
the
default
default
slot
slot
and
and
the
the
user
user
can
can
just
just
pass
pass
in
in
whatever
whatever
HTML
html
they
they
want
want
and
and
it
it
will
will
be
be
rendered
rendered
here.
here
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
I
i
have
have
a
a
whole
whole
bunch
bunch
of
of
other
other
ideas
ideas
for
for
Angular
angular
Elements
elements
for
for
future
future
videos,
videos
so
so
make
make
sure
sure
to
to
like
like
and
and
subscribe.
subscribe
And
and
if
if
you
you
wanna
wanna
take
take
your
your
development
development
to
to
the
the
next
next
level,
level
consider
consider
becoming
becoming
a
a
pro
pro
member
member
at
at
angularfirebase
angularfirebase
.com.
com
You'll
you'll
get
get
access
access
to
to
my
my
full
full
length
length
courses,
courses
my
my
book,
book
as
as
well
well
as
as
a
a
whole
whole
bunch
bunch
of
of
other
other
resources
resources
designed
designed
to
to
help
help
you
you
build
build
and
and
ship
ship
apps
apps
faster.
faster
Thanks
thanks
for
for
watching,
watching
and
and
I'll
i'll
talk
talk
to
to
you
you
soon.
soon
success
The adoption of web components and the use of Angular allow for building applications that don't use specific framework or programming style. Recrafting a fast, search engine optimized project is recommended, and creating a custom element and registering components as custom elements is recommended. Visibility of element visibility is discussed, and the process of creating a custom image tag and setting up a method for the set state function is discussed. Visibility of element visibility is addressed, and content projection using slots and default tags is introduced. A link is provided for a full course on Angular on the Sprint website.
Advanced Angular Elements
One of the most exciting trends happening in web development is the adoption of web components, because they allow us to build applications that don't walk us into a specific framework or programming style. I'm going to be using Web Components in production very soon, so I wanted to share some advanced concepts that I've learned working with Angular Elements. And I'll even show you how to achieve a near perfect Lighthouse performance score with the full power of Angular and Firebase in your JavaScript bundle. If you're new here, like and subscribe, and congrats to Damien Wright, who's last week's t shirt winner. But don't worry missed out, there's another one of a kind t shirt going out this week. All you have to do is leave a comment below. Over the last few months, I've been building a product called Fireship IO, which is just a better way for me to deliver my content to you. This project needs to be very fast and search engine optimized, But it also needs to use Firebase for user authentication and dynamic data. The beauty of web components is that I can pre render all of my static content and then bootstrap in custom elements when they're needed. Throughout this journey, I've used pretty much every web component tool that's out there and I found that Angular Elements is the most productive for a larger project, but you'll also wanna check out Stencil and lit element, which I think are both very promising. The big advantage of elements is that, a, you get the full power of Angular, and, b, your components share the same dependency injector tree, which means you can easily share data or functionality between your custom elements. And c, the API is stable and being used in production at Google. Today, we're going to build a custom element that can lazy load an image based on the user's scroll position in the browser. When the image is loading, it will show this Facebook style shimmer placeholder, then replace it with the image when it's fully loaded. Now we'll jump into some code, but if you haven't already seen my original Angular Elements video, you'll wanna check that one out which is a little more basic level. The first thing you wanna do is go into your Angular app and then run n g add at angular elements. This will install the dependencies and also the polyfills to ensure that your elements are compatible with all browsers. Then you can go into the app directory and you'll wanna just go ahead and delete everything except for the app module. You'll also notice I've generated a couple of regular components in here as well. The first thing we'll wanna do is register our components as custom elements. I'm assuming Angular will have a better way to do this in the future, but currently we import Injector from Angular Core and create custom element from Angular Elements. Now if you want to use your elements within the context of an Angular app, you'll want to add them to the entry components array. The important thing is that we go down here to the app module and add the injector to the constructor. If you have a big project, there's probably a whole bunch of different elements to register. So the way I like to set this up is to create an array of tuples. So the first item is the Angular class name and then the second item is the name of the custom element. So that's how you'll actually use it in the DOM. So now we can loop over these elements and we can actually destructure them directly in the for loop, which I think is a really nice looking piece of JavaScript. From there, we can call create custom element And that gives us a dry way to register a large number of components. Now let's switch gears and see how we can create a single JavaScript bundle that we can use outside of Angular. What you're looking at here is the build script that I wrote from my original Angular Elements video. It just takes all of your production build files and then concatenates them into a single file in the public directory. So this works fine, but it's kind of a hack. I'd recommend checking out NGX build plus to extend the default behavior of the CLI, and hopefully the CLI will just support this out of the box in the future. We'll stick with the simple approach for now, and I've added a couple of build and serve scripts to my package. Json. It first runs ng build prod, and then it runs the build script with node. So now that we have our JavaScript bundled, I'm going to put it to use in just a static HTML page by adding it as a script to the head of the document. And you can see down here I'm using this image lazy custom element, which we'll build here in a few minutes. Now I'll go ahead and run a Lighthouse audit, And keep in mind, I'm also not lazy loading the images at this point either. We get a 1st Contentful Paint in 2.5 seconds, and time to interactive is 4 seconds. I've also added Firebase to my JavaScript bundle, so we have 342 kilobytes here in total that needs to be loaded before the rest of the page can render. But the great thing about elements is that we can defer the script until after the page is rendered. So how do we do that? We just go into our script tag and add defer, and we're done. If we run the audit again, we get a first paint in 600 milliseconds, which might as well just be 0. And 3 seconds later, we have the full power of Angular and Firebase ready in the page. So you can already get amazing performance with Elements, but it's only going to get better in the next few months here as Angular Ivy becomes production ready. So that's pretty awesome stuff, but I wanna share a few advanced pro tips that I've throughout my experience working with elements. The first thing I'd recommend doing is disabling Angular's automatic change detection or NG zones, which you can do here in the main TS file. The reason for this is that I've run into some really hard to debug issues that only happen in production. So you'll find that life is much easier when you tell the component explicitly when to rerender. Now if we go into the component itself, you can see I've imported everything under the kitchen sink here from Angular Core. You won't need all these things in your elements. I just wanna show you a few different techniques at your disposal. And also, if you don't wanna turn off zones globally, you can do it here at the component level by doing change detection strategy on push. The next big decision is whether or not to use the shadow DOM. So the term web components encompasses a few different features, one of which is obviously custom elements, but another one is the shadow DOM. If you turn the shadow DOM on, it means that your CSS styles will be encapsulated in this component. That can be a good thing if you don't want your CSS to bleed out, but it can also make your components harder to style, it's a trade off. And the shadow DOM also supports slots, which is something that we'll look at towards the end of this video. Now there are 2 things that I commonly inject in the constructor. Element ref will give us a reference to the actual DOM APIs that exist on this element. The next one is the change detection ref, which allows us to rerender this component manually instead of relying on the automatic change detection. Because we're displaying an image, we'll have our custom element behave just like a regular image tag. We'll give it a source attribute and an alt attribute. Now the special thing about our custom element is that it only displays an image when it's actually visible in the viewport. For that, we're going to emit our own custom event called is visible. Now when it comes to your internal component state, I recommend keeping the input values as immutable. You have the flexibility to manage the state however you want, but here's a pattern that I find especially effective. So we'll create an object with a couple of properties on it, And we only want to rerender our component if the state changes. Then we'll set up a method here called set state which takes a key and a value as its arguments. Then Then we can go ahead and use the spread syntax to create a new object and set that as the new state on the component. Then we can guarantee a rerender here by calling detect changes on the change detection ref. This code might look familiar because it's inspired by the way React works. Contrary to popular belief, I do not hate React. Overall, I found this to be a very reliable way to work with elements, But there's definitely many different ways you could do this. Let's go ahead and switch over to the HTML and put this to use. 1st, we'll set up a div. And if the loaded state is false, then we'll go ahead and show that placeholder. You can check out the full CSS for that animation in the source code. Then we'll set up a figure to wrap the image itself. And we'll only show this if it's visible based on the user's scroll position on the window. Then we'll add an image tag inside of here, which will only be loaded over the network when this visible property flips to True. Just because it's visible doesn't mean it's loaded yet, so we'll also hide the image until it's fully loaded. And then we'll run an event handler once that event takes place. And the last thing to make note of is that we're passing our input source to the actual image source here. So, again, our custom element feels just like a regular image tag with some added benefit. So now the challenge is determining whether or not the user has scrolled to this element. To make that happen, we're going to need to access some native DOM APIs. We've already set up a reference to the native element in the constructor of this component. We can go ahead and call it here, and then we can call get bounding client rect, which will give us the actual measurements of that DOM element. If the top of the window is less than or equal to the window inner height, then we know that that element has been scrolled to. And we also wanna check that the element is not already visible because if it is, then there's no point in running this code. But if it is visible for the first time, then we'll go ahead and run our set state method, which will change the state and then rerender the component. Another thing we wanna do is emit a custom event when the element becomes visible. I'll cover the implementation of that in just a minute. So there are 2 different situations where we want to calculate the visibility of the element. 1st, when the component is initialized. Because if the element is already in the viewport, then we don't want to wait for the user to scroll to load it. Then to listen to the scroll position, we can add host listener then window colon Scroll to listen to the global window scroll event. And when that happens, we'll go ahead and calculate the visibility of the element. So that's how we determine when an element's visible and also rerender it when its state changes. For the image itself, there's a built in load event which will fire when the image is fully loaded. So when that takes place we'll go ahead and set the loaded state to true again re rendering the component. So the end result looks like this. We start with a placeholder. When the image loads it's displayed and the placeholder is removed. Again, the great thing about web components is that we can interact with them using vanilla JavaScript in the DOM. So we could use document query selector to grab the element and append it somewhere or change its CSS styles or whatever. By default, the internal properties and methods on the component are not available when you grab it from the DOM like this. But it can be very useful to expose a public method that can be used by the developers working with your elements. For example, let's set up a log method that logs out the internal state of the component. The method that I found works best, although I'd like to see this improved in future versions of Angular Elements is to use the Input decorator. The reason we do it this way and not just attach input to a method is that it gives us context to this or this component instance. So we can console log this state, which would otherwise be undefined if it was a regular method. Now another thing that's really useful on the same note is to emit a custom event that can be listened to in the browser. So we already have an event emitter set up on this component, And we can emit through that just like we normally would in Angular, and we'll also set up a custom event in the DOM. We'll give that a name of is visible and then we can reference our native element and dispatch the event through it. If we go back to the browser, we can now grab this element from the DOM, attach an event listener to it, and handle it however we want using vanilla JavaScript or some other framework. So I've set up the is visible listener, and then I'm going to console log the event when it occurs. As soon as the image becomes visible in the viewport, it logs that custom event to the Console. So that takes care of that. The next thing I wanna show you is content projection using slots. If you look at the image on the left here, you'll notice a caption underneath that has a default header and default caption. If we revisit our static HTML, you can see that I have a couple of spans that are inside of the lazy image tags. The spans have a slot attribute which corresponds to a certain place that they'll be displayed which we'll define inside of our custom element. So now I'll switch over to the component HTML, and we'll go ahead and add a figure caption. Then we can include slot tags that have a specific name that defines where this content will be displayed. This is super useful when you have components that can be customized, but you don't want the end user to have to worry about adding the required markup to it. And if you want the user to just be able to transclude some markup inside your component, you can simply drop in a slot tag. That will be considered the default slot and the user can just pass in whatever HTML they want and it will be rendered here. I'm gonna go ahead and wrap things up there. I have a whole bunch of other ideas for Angular Elements for future videos, so make sure to like and subscribe. And if you wanna take your development to the next level, consider becoming a pro member at angularfirebase .com. You'll get access to my full length courses, my book, as well as a whole bunch of other resources designed to help you build and ship apps faster. Thanks for watching, and I'll talk to you soon.
The adoption of web components and the use of Angular allow for building applications that don't use specific framework or programming style. Recrafting a fast, search engine optimized project is recommended, and creating a custom element and registering components as custom elements is recommended. Visibility of element visibility is discussed, and the process of creating a custom image tag and setting up a method for the set state function is discussed. Visibility of element visibility is addressed, and content projection using slots and default tags is introduced. A link is provided for a full course on Angular on the Sprint website.