Building a Web Components Framework with Webpack, in Just a Few Hundred Lines of Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to a two-part series where we'll show you how powerful web components and webrtc have become with some help from webpack everything that you now see is running as a web component with the help of webrtc i'm even able to connect to other physical devices and to other browser tabs [Music] and all of this is made with super modern javascript and i'm going to teach you everything about it in this two-part series welcome to the first part where the focus is on web components not webrtc that part i'm going to cover in the next video so subscribe if that sounds interesting to you i have also written a blog post at cisco further discussing some elements in this video link in the description below we can't make this application directly using only web components as we're missing some crucial features from modern frameworks like routing and state management that's why we're going to make our own small framework on top of web components with the help of webpack this will help smooth out some of the shortcomings of web components and a quick side note creating a framework is actually not as hard as you think the core elements are surprisingly easy to make and a lot of the work on major frameworks goes towards edge cases documentation optimization and actually getting people to use it i'm doing neither today so this will go a lot faster so let's get started the entire project is available on github link in the description below and you can try out the demo i just showed you online if you want to right now but before i dive into the code i just want to remind everyone what the web component is in case someone is new to this or have forgotten it web components consist of three elements the first one is custom elements or the javascript part the second is html templates the html part and the last one is shadow dom or the css part they are universal and everlasting this is now part of the javascript standard which means that web components we make today should work in 20 years and they can be used in every single framework and you write them with super modern javascript it's amazing to work with here you can see a example of a web component in just one file we start at the top by declaring some general html that's not part of the component then we are using our component the way you know that this is a web component is with the dash in the name as no built-in html elements have a dash in their name we're using it before it's declared and that's allowed next up we're creating the template this is some reusable html that's going to be the body or the content of our component but this is a template and that means it will not be rendered in the html document until it's being used by a component here we're declaring some styling that affects everything but this will be view encapsulated which means that the shadow dome will prevent the styling from affecting anything outside the components so only the inside part should be styled then we're declaring the actual components by creating a new javascript class yes that's allowed now by extending html element this is sort of the base element for all custom elements and we have to call its own constructor as well the next thing we do is setting up the shadow dom by creating it and sending it to open this just means that it's accessible by javascript then we find our template and get its content and clone it into our own shadow that means that this html becomes this component's u and the last part is just going against a global object custom elements and saying that this tag is now associated with this class so to summarize each time the browser finds our element it then looks up that name in the registering here and check which class is associated with that element and creates a new instance of it which then in turn creates its own shadow dom and copies the content of this template into its component and then the component is created and renders now we're finally ready to view some code and the project the structure is going to look really similar to angular and it's a really good reason for that angular has based their structure on how web components are structured so i sort of have to use the same structure as i'm well using web components but in general i have components services modules routing a build system and super modern javascript let's look at some code here we have the project structure at the top we have the dist folder which contains the output of the build from webpack then in a package file we're defining some scripts that are just well serving and building the system and then a series of dependencies these are just dependencies for webpack there are no runtime dependencies for our application listed here all of the important elements are now in the src folder where we are declaring all of the components assets services and setting up the actual application in index.js here i'm importing all of the components setting up firebase i'm going to come back to that and defining all of our custom elements based on what we are importing and i'm also declaring some directives i'm going to show you what that is later we can look at a simple component like the about page which has three files the css file all the styling the html file well all html and the javascript file containing the declaration of the component and all its logic structure declaring them as separate files is really useful for me but you can have it all in one file if you want then we have the index.html file where we're importing some of the global fonts declaring the global styling and using the most top level component our router and i just want to mention that this is a guide on web components and not css i'm using modern css here with imports and css variables but i'm not going to show any more css than this but let me know in the comment below if you want a video on the css part here and here you can see the actual application running you can go to for example the about page and see that the route changes and use the browser button to go back and when i create a new room the other tab will automatically join as well using something i'm going to show you in the next video and then when i click it connects and i can see myself in this video chats i can also have a conversation with myself over the chat system and all of this is using webrtc for communication for both the video and the chat web components have some crucial limitations and this is the reason i'm using webpack on top to help solve some of these problems the first one is html import this is the problem where you have to declare all of your templates in one file as html has currently no way of importing one html file from another so if you have 50 html elements then you have to declare all of them in one file that's not really sustainable the next limitation is dead html this is the problem where the template have no reference to the class as it can be used in several different elements so you can't write on click and this dot some function within the class that's unfortunately not possible next up we have css shadow piercing this is when you actually want some global style to affect every single component like for example from a design system and lastly we have browser support and as long as you're not using internet explorer at all then you should be fine but now some good news all of the problems listed here are solvable by using webpack and i'm going to teach you it in just a few minutes webpack is all about merging all of your project files into one file it does this by crawling all of your javascript files and combining them into one file and it also includes html and css files most of the time and it also offers live reload that's when you change some code it's going to compile it again and reload the browser for you automatically and hot reload where it only replaces the small part you actually changed webpack can do a lot of other stuff like compiling typescript and sas but i'm not going to use that here and here you can see web back in action it's combining all of the project files into one and opening the browser to a new tab with the results and here we have the scary webpack config file this is where we're defining how that pack should function in this sort of giant javascript config object it's going to be really simple after i've shown it to you and it all starts with the entry point or where should it start crawling finding files to combine this starts in the index.js file and here it takes this file and everything that's imported so it goes to the about page for example it's this file and everything it's that's imported from there and so on and combines all of them into one file and outputs it as something.bundle.js which in the this folder is something.bundle.js then we're targeting the web then we're setting up the source map you might not know what source maps are but it's actually really simple because this is going to be combined into javascript and minified so it's going to look like this and it's really hard to read and if you get some error message in the console then you're going to be like something crashed at d what is d source map says that this random variable corresponds to some actual variable in your source code so it's just a way for the browser to help you get better error messages next up we're defining the dev server or we're just saying how it should function like it should work from the dist folder the on top here this folder and some general things like public path it should open when you're opening it for the first time we're not using hot module reload right now and it should live reload when you change something and we should enable the history fallback api that's used for our own routing system i'm going to come back to that then we have something called modules or loaders what is that the reason we need loaders because webpack does not understand stage 3 javascript or lower ok what is that javascript changes all the time new things are added and that's done via stages where stage 1 is the first and stage 4 is fully implemented and standardized the thing is webpack refuses to understand or implement anything that's not stage 4 and web components are still just stage 3 so you're going to use something called a loader to help webpack understand that and which loader are we going to use well we're going to use the big one we're going to use babel and i'm going to teach you babel as well here today bubble is all about converting new javascript to all javascript so that you can use modern javascript before it's fully supported in all browsers or in this case in webpack but it makes code slower because one line of modern javascript is converted to potentially a hundred lines of older less efficient javascripts but it allows us to use modern features before they are fully ready and that's why babel is so popular and we can actually look at all the stage proposals or things that javascript hasn't landed fully yet but babel allows us to use right now and here you will have a master list of everything that's on its way to becoming a standard part of javascript and there's a lot of cool new features on its way in the future back in the config file we're saying that every time we're hitting something like a javascript file or module.javascript excluding the null modules we're using babel or saying that babel should process the file before it's handed off to webpack the babble config is really simple it just says use the default setting stage 4 and add in support for classes and for private methods the two things that webpack can't understand yet and then we also have a loader for html and css i'm going to show you later why this is important but it's just taking the html file and css files and giving us the raw content as a string then at the end there we have some plugins that add some extra functionality to webpack the first one is clean webpack plugin it just clears the disk folder between compiles i just removed it for now as i want to view the files then we have the html template plugin because our index file does not have a reference to the main bundle so it will not load if you just open this but this copies the file over and if i extend it you can see that the bundle file is linked here so it's going to be loaded at runtime next up we have the copy plugin which just copies all of our assets because i have some asset files that i just want to be copied directly like an image of my cute dog and some css files and this is copied over directly to the dist folder and at the end there i'm just telling bampac to optimize even more if i'm running in production mode and that is webpack in a nutshell you should now be able to understand this file there are some ways we can extend it by adding typescript and sas but i'm not going to cover it in this video and webpack with all the optimalization i've added makes the entire application less than 20 kilobytes that's nothing and firebase is the only dependency and it's loaded from a cdn at runtime you might not realize how small 20 kilobytes actually is like if you open the bundle file and now it's minified as you can see but if you decompress it with prettier you can see that it's only 504 lines of total code i care you can see some of the variable names being reduced but not all of them like some of them are still their full name because they can't be reduced due to the javascript standard so here we have the entire website plus the framework in just 500 lines of code that's really amazing one of the reasons this application is so small is because all of the dependencies for web components are shipped with the browser like when you're using react view and angular then you have to ship that library alongside your application but web components are part of javascript so it's shipped with the browser but now we're ready to create the framework i just have to say up front that i have taken some shortcuts here to make it easier to understand but all of the core elements are here and we're starting with creating components a good place to start is with the about page this is a really simple page just a title image and a back button that takes you back to the main page here we have the definition for about page we're defining the class with the constructor where we're setting up the actual shadow and the function that allows us to go back to the main page and at the top we're importing the html and css for this component from those two files and it's done with the help of the raw loader that allows us to load them as strings now we can look at how the component is actually being created or the view for it because we have the setup shadow function that takes in the html which is some simple elements and the css and we want both of them to be applied to the components view or template and that is done in the setup shadow function this is a really simple function we're just starting out by creating the shadow root then creating an in memory template not getting one from the index.html and setting the inner html for that component to the global styles plus the css and then appending the html as well then we're getting the template content and cloning that into our own shadow dom but there's one thing missing here like if we open the about page we can see that we are doing this.back on the on click handler and i said that that wasn't possible because the html file had no reference to the javascript file well we can do a little hack that will solve this for us because at the time you're creating the actual shadow root then we have both the reference to the html element and the component what we can do is save the reference to the component in the window object this is a global object that's always available and then replace all instances of this dot with window dot component name or the reference to the component if we open the about page in the browser again and inspect the button we can see that the reference is now set to window.component3.back and that actually means that we can go in the console here and get the reference and execute the function ourself manually like that so now we have fully functional components that are easy to write as we can reference elements in the component with this dot and it's the same way i'm doing it in different components like the home component as well setting up the shadow and being able to do this this.something this way of structuring elements is really similar to angular if you have ever used that the final step is to define those components because this is not being used at the moment until we import it in the index file as you see here and define it against the custom elements global registry and i'm also defining something called a directive here what is that directives are a new feature with web components where you can extend the existing element to add some extra functionality but then you're not having your own view or css anymore you're reusing the one from the actual component you're extending in this case the input element if we open the text input we can see that we're not setting up any shadow root here we're just appending some logic to the input element as you can see here we're extending the input element we have a connected callback that's called automatically by the browser when the component is created and one when it's destroyed or removed from the dom and this just adds some extra functionality where we're validating or adding some form validation just adding a red border around the element if there's no value inside it and here we can see the actual input element where we are form validating so it's red with no input and when you add something it's not red anymore and this directive as i call it is applied by using the is syntax so we're saying input is text input and that means the javascript class is now associated with this component and we can add some extra functionality really neat feature but it's still really new with web components the next thing we need is services this is where we put our shared logic and application states these are single tone classes meaning that there's just one instance of them in the entire application so all components talk to the same instance and that means we can add some state to it so what i want is that all of those variables here refer to the same instant even if i'm knewing of new versions of it and this is actually kind of easy in javascript because you can do some magic with static and the constructor because in the constructor you're able to return another instance of a class and it will switch to that one automatically meaning that the first time this is created the instance is saved as this and the next time it's just switching to that instance and that means all of those variables are referring to the same instance meaning you can mute it up in all of your components and all of them are referring to the same instance we can see this in practice by console logging the random number and seeing that the number is the same for all instances even if it's newed up separately and i can now use this technique in my project to get singleton services in an easy manner the first time the reference is saved and from there on it's just returning that initial reference and then i can use this really easily in any component by just newing up to service even multiple times and it will always refer to the same instance and a quick side note this is how modern javascript classes look you can define them with a class keyword and add static properties and private properties with a hash symbol it might look a bit weird at first but it's a lot easier than typing out private each time so i'm actually starting to love it a more advanced version of the service system i just created is what angular has with its dependency injection system here we are just asking the framework for instance and it's giving it to us for us and we're not newing it up ourselves anymore i'm going to go deeper into services in the next video where i'm focusing on firebase and webrtc or the video part but this is everything i'm going to show about services in this video and then we have the final element routing we're making sure that when the user clicks on a url that the correct page is being displayed it has traditionally been the responsibility of the back-end to give users a new page when the url changes but this has now started to move to the front-end with single-page applications this is moving the responsibility for rendering the correct page from the backend to the front end or more specifically javascript we can implement single page application routing in our application by just changing it so that each time they used to change a page that would usually go to the backend now goes to the index.html file and that's why we're setting the history api fallback to true in the webpack config file we intercept this in the front end with the history object this is a global javascript object which allows us to interact with the browser's history api and save some state on each route saying which component it's associated with we can then listen for the window.eventlistener popstate which triggers each time the browser navigates back and forth and we can then retrieve the state from that event and use it to render the correct component though one missing element is rendering the correct page when the page is opened for the first time or the user refreshes with f5 and that's all about reconstructing that page based on the given url time this is the page router component is responsible for rendering out the correct page and it's less than 64 lines of code and the html file is empty as it renders the correct component on the fly and it's also the most top level component as you can see here that means it has responsibility for the entire page and which component is being rendered based on the route it does this in the connected callback which is called when this component is created here it starts by getting the current page from the url as i said you have to reconstruct the first one on the initial render and this is just going through the pages which is a list of all the pages available in the application the given route which component is associated with it and the title and finding which one is matched based on the window.path name here you can see that the location path name for the about page is slash about which corresponds to the same as i've used in the path here or the part after the local host and the port and now we are ready to render the correct page because we have saved the current page in the object which is more or less this object and then we call the render correct page function here we start by finding the previous element if there is any and removing it the previous page element or the previous page being displayed then we're creating the new page based on the component name which is this one this is how we create in-memory components and then we sign it id so we can remove it next time the page changes we add the event listener so that the component itself can tell us when it want the page to change an example of how this is done is here where you're creating a custom element saying that we want this page to change the home and dispatching it the next step is adding it to the shadow root or to the component's body so the component will be rendered and displayed and the last step is updating the title for the document to the correct one but how can we go to new page the current page can output events called change page and send along which page it wants it to change to this is an object that's the same as this one or any of the ones below so it sends along which page it wants it to change to and that is positive function that saves it to an internal variable and then saving it to the page history api which has three properties the first one is the current page object this is the state object which we can use later to reconstruct the current page when the user navigates back later and then we can save the page title and the url associated with that route which is more or less the window.location.org plus the current path this one and then we just render the new correct page based on this information so this function is rerun to render the new one and then also tear down the last one the last element is intercepting when the user clicks the back button in the browser and then rendering the correct page based on that we're setting up an event listener in the connected callback or the on init function we're going against the window at the event listener pop state this is called each time the user navigates back and forth in the navigation history for the browser and you're just checking if the state is set or this object is set and if so change the current page to this one and render it and if not we're just setting it to the default one really simple and that's it that's how you do front-end routing in less than 70 lines of code it's surprisingly easy when you try it that was all of the major features for the framework but are some missing features the first missing element is typescript this is something i considered adding but i'm going to do it as a separate video sometime in the future this would add type safety on top of what i already have which would make the framework even better and it's super easy to add with webpack as you just said that it should compile the typescript files to javascript before it's handed off to babel the next missing element is a rendering loop this is a feature of modern frameworks where it's re-rendering the components html when something in the component changes a key benefit of a rendering loop is the ability to define a variable in the class and have it automatically be rendered in the html with a syntax similar to this this would also give us the ability to change the variable and have it automatically be updated in the components html when it changes since we don't have a rendering loop you're also missing out on two-way data binding two-way data binding is a really useful feature in modern frameworks that allows you to not just update from the component to the html but also the other way around and then back and these missing features and some more means that this is not a complete framework but the key elements are present okay so it's pretty obvious that you shouldn't use my framework in your project but if you like web components and want a good framework then i highly suggest looking at polymer this is a framework library by google that will make it a lot easier to work with and create good web components but this means we are finished thank you for listening to this video and i really hope you learned something new and exciting about modern frameworks or at least something cool about web components the next video is going to cover webrtc and the video part subscribe if that sounds interesting and you can also play with the online demo if you want and the code for entire project is available on github links in the description below so what do you think are you going to start using web components from now on let's meet in the comments below
Info
Channel: Curious Programming
Views: 4,983
Rating: undefined out of 5
Keywords:
Id: AGs7hk0DWP0
Channel Id: undefined
Length: 30min 37sec (1837 seconds)
Published: Thu Jan 28 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.