Tutorials on Javascript Micro Library

Learn about Javascript Micro Library from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

Build Your Own JavaScript Micro-Library Using Web Components: Part 4 of 4

In this capstone tutorial, we're going to actually use the micro-library in app code so you can see how the micro-library makes things easier for developers in real world development. In the previous steps of this 4-part tutorial, this is what we accomplished: In this final tutorial, we will now refactor an example component to use the @Component decorator and the attachShadow function from our micro-library. We're refactoring a file, packages/component/src/card/Card.ts , which contains the CardComponent class. This is a regular Web Components custom element. To get it to use our micro-library, we first import Component and attachShadow from our micro-library. Next, we add the Component decorator to CardComponent . We remove the line at the bottom of the file that registers the component, noting the tag name in-card . Remove customElements.define('in-card', CardComponent); . The above code is now automated by our micro-library. We set the selector property to the ElementMeta passed into Component to in-card , the same string originally used to register the component. Next, we move the content of the style tag in the constructor to the new style property on ElementMeta . We do the same for the template of CardComponent . We migrate the HTML to the new template property until the ElementMeta is filled in. Next, we remove everything in the constructor and replace it with a call to our micro-library's attachShadow function, passing in this to the first argument. This automates Shadow DOM setup. To make sure everything is working properly, this is where we start up the development server and observe the changes in the browser. Nothing should have changed about the user interface. Everything should appear the same. Our CardComponent has now been successfully refactored to use the micro-library's utilities, eliminating boilerplate and making the actual component code easier to reason about. That completes this 4-part tutorial series on building a micro-library for developing with Web Components. Our micro-library supports autonomous and form-associated custom elements. It enables developers to automate custom element setup as well as Shadow DOM setup, so they can focus on the unique functionality of their components. In the long run, these efficiencies add up to a lot of saved time and cognitive effort. If you want to dive more into ways to build long-lived web apps that use Web Components and avoid lock-in into specific JavaScript frameworks, check out Fullstack Web Components: Complete Guide to Building UI Libraries with Web Components.

Thumbnail Image of Tutorial Build Your Own JavaScript Micro-Library Using Web Components: Part 4 of 4

Build Your Own JavaScript Micro-Library Using Web Components: Part 3 of 4

Here is Part 3/4 of our tutorial series on building a JavaScript micro-library for creating your apps with Web Components. As I pointed out in previous lessons, the micro-library eases the path to development with Web Components, automating a lot of the work so developers can build their apps faster. Here's what we covered so far: Now in this tutorial, Part 3, we will automate another piece of functionality for classes that use our decorator. In this case, we'll automatically attach a Shadow DOM to those classes so that the user of the library does not have to manually create a Shadow DOM for their custom elements. Now that we have ElementMeta stored on the prototype of any class using the Component decorator, our next step is to write a reusable function that'll be used in the constructor of the same class to instantiate the Shadow DOM. By abstracting this logic to a reusable function , we'll reduce several lines of code in each component implementation down to one line. Basically, we want to take something like this... ...and reduce it to one line. The first argument of attachShadow is the instance of the class which, in the constructor , you can reference as this . The second argument is the Object that configures the call to element.attachShadow . You can read more about element.attachShadow on MDN . To start development of this new function , make a new directory named template in packages/common/src and create a new file in that directory named index.ts . Create another file in the directory, named shadow.ts . In packages/common/src/template/shadow.ts , create a new function named attachShadow and export it. Declare two arguments for attachShadow : context and options . Make options optional with ? and type define context as any , and options as ShadowRootInit , a type definition exported from lib.dom.d.ts . Follow up in packages/common/src/template/index.ts and ensure attachShadow is exported for the main index.ts . Finally, in packages/common/index.ts , export the attachShadow function. Jumping back to packages/common/src/template/shadow.ts , fill in the algorithm for attachShadow . Make a const named shadowRoot , type defined as ShadowRoot , equal to context.attachShadow . On the next line, make a const named template , equal to document.createElement('template') . This line creates a new HTML template. Set the content of the HTML template using the ElementMeta stored on the prototype of whatever class will use this attachShadow function. Pass in context.elementMeta.style to a style tag and context.elementMeta.template afterward. Finally, append a clone of the HTML template to the ShadowRoot . When you are finished, the attachShadow function should look like this: With Component and attachShadow now supporting autonomous and form-associated custom elements, you can now use the new decorator pattern in actual components. Build the @in/common package again so files inside the @in/ui package can pick up the latest changes. We're almost done building this Web Components micro-library, though there's a lot more features you could add. In the final lesson in building our micro-library, we'll refactor some example components to use the micro-library so you can see how end developers actually use the library. For more about building UI Libraries using Web Components, check out our latest book Fullstack Web Components: Complete Guide to Building UI Libraries with Web Components.

Thumbnail Image of Tutorial Build Your Own JavaScript Micro-Library Using Web Components: Part 3 of 4

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

Build Your Own JavaScript Micro-Library Using Web Components: Part 2 of 4

As we covered in the previous tutorial , a micro-library helps developers implement common features more quickly than using the web APIs directly. Now in this tutorial, we will code our class decorator that allows our classes to instantly gain new features without writing the code for them every time. The class decorator eliminates boilerplate and allows users of the micro-library to focus on higher-level concepts while delegating common class setups to the micro-library. Implementing a class decorator is going to significantly improve the developer experience, allowing developers to code Web Components faster. We'll enhance the class-based implementation which custom elements rely on by cleaning up each constructor . Specifically, we move the declaration of an HTML template and CSS to a new function that decorates the class . This, combined with abstracting template and style generation to a reusable function , will have the positive effect of reducing the boilerplate for each component. Here's an example of what a typical component will look like when it uses the decorator in our micro-library. This ButtonComponent will now look something like the following. We'll use a mono-repo structure for this project. So, create a packages/common directory with one source file: index.ts . To keep this package organized, we should figure out a way to divide the code into logical chunks. Making a directory for all decorators seems prudent, then organizing the decorators by function. To start developing the component decorator, create a new directory in packages/common/src/decorator , then make a new file at packages/common/src/decorator/index.ts , and another file at packages/common/src/decorator/component.ts . Any file named index.ts manages exports for several files in the same directory. Other files in a directory contain library code. Open packages/common/src/decorator/component.ts in your IDE to begin. First, let's define the interface used by the component decorator. This keeps the first argument of the decorator function type safe. Declare a new interface named ElementMeta and ensure it is exported with the export keyword. There are three properties on this interface : selector , style , and template . All three properties are optional, denoted by the ? prior to : . TypeScript class decorators are factory functions, that is, they return a function that constructs an Object . The Object we're concerned with is the class definition of the component using this decorator. Based on the values of properties on the ElementMeta , we'll modify the prototype of the class so we can use those properties to register the component with the CustomElementRegistry and instantiate an HTML template with Shadow DOM. The basic structure of the function is as follows: Let's put a fail-safe mechanism in for users who haven't specified an ElementMeta in the first argument of Component . The above conditional checks if meta is undefined and when truthy, displays a console error for developers in Dev Tools, then aborts the rest of the algorithm that depends on ElementMeta . We have two objectives for the class decorator: register the component using the selector property, then add metadata on the class definition to later append an HTML template to Shadow DOM using the style and template properties on the ElementMeta . Let's start with registering the component via the decorator function. In the factory function, reference the selector and pass it and the class definition, here named target , to customElements.define . This allows the end-user to omit a call to customElements.define in their implementation. The user has the option to ignore selector entirely in the ElementMeta , so be sure to wrap the call to define in a conditional. Class decorators are a place where you can modify the prototype of a class , so that's exactly what we're going to do. We're going to store the ElementMeta passed through the Component function arguments on the prototype of the class , so we can later access the template and style in the constructor of the component class . Set a new property called elementMeta on the prototype to the meta that was passed into the Component function . To avoid the style and template properties from ever being undefined , here is a good place for some conditionals that set each of these properties to an empty string in case it is undefined . When you are finished with the Component decorator, the function should look like this: Development of the Component decorator is finished, but you still need to provide the decorator and the interface for use outside the @in/common package . To finalize development of the decorator, add the proper exports to packages/common/src/decorator/index.ts and packages/common/index.ts . In packages/common/src/decorator/index.ts add the following exports. Export the same from packages/common/index.ts . index.ts is the entry point of the @in/common package. When the @in/common package is built, other packages in the monorepo will be able to reference anything exported from the index.ts . Check the build successfully runs, which means your TypeScript is valid. If you get an error like zsh: command not found: lerna make sure lerna is installed globally and try the build command again. If you see lerna success output in the Terminal, you are ready to proceed. Otherwise, check your TypeScript is correct. Now that we have ElementMeta stored on the prototype of any class using the Component decorator, we can write a reusable function that could be used in the constructor of the same class to instantiate Shadow DOM. Later, we'll work with Shadow DOM and abstract its setup into the functionality of our micro-library, leaving library users with one less detail to worry about. For more about Web Components, check out our latest book Fullstack Web Components: Complete Guide to Building UI Libraries with Web Components

Thumbnail Image of Tutorial Build Your Own JavaScript Micro-Library Using Web Components: Part 2 of 4

Build Your Own JavaScript Micro-Library Using Web Components: Part 1

If you've ever wondered how libraries like React , Preact , or Svelte work under the hood, this is a great exploration of what you need to know. Using Web Components means that your own micro-library, which we build in this series, will work easily with any JavaScript codebase. This achieves greater levels of code reuse. Let's dive in. When building with Web Components, you will rely heavily on the set of specifications that make up Web Components: The main benefits Web Components bring to the table: reuse, interoperable, accessible, having a long lifespan, are due to their reliance on browser specifications. Had we adopted a library or framework, we might have lost some or all of these characteristics in the user interfaces built with it. UI components coded with some libraries aren't interoperable with other JavaScript libraries or frameworks, which puts a hard limit on reuse. Even though we gain these benefits from Web Components, we have lost any benefit JavaScript libraries have to offer. Frameworks and libraries like React, Vue, Angular, and Svelte provide an abstraction around browser specifications. React, for example, famously opted for a purely functional approach, giving engineers "hooks" to manage side effects in user interfaces. JavaScript libraries and frameworks provide architectural patterns that make life easier on the part of the web developer, offering features not available with browser specifications alone, like data binding and state management. What if we could retain the benefits of Web Components while also gaining the architectural design of a JavaScript framework? Indeed, there are many such Web Component libraries already. Now you get to build your own. In this 4-part tutorial series , we'll demystify the inner workings of Web Components libraries as you get to develop your own. Using TypeScript decorators, we'll develop a new interface that simplifies development but doesn't compromise on performance. The micro-library we'll code optimizes to less than 1Kb of minified JavaScript. Among its features is that it allows the components we develop to transform from something like this: ...to instead use a TypeScript decorator named Component , like this: Decorators are denoted by the @ symbol, followed by the name of the decorator function , in this case, Component . In the above example, the Component function is called with a single argument: an Object where the developer can declare the tag name, CSS style, and HTML template. These are the advantages of using class decorators to handle templates and styling: In addition to making a class decorator that allows you declare a tag name, styling, and template with a cleaner interface than before, you'll also code a method decorator that simplifies binding event listeners to custom elements. Instead of typing this.addEventListener('click', this.onClick) , what if you could decorate the onClick method and still provide the same functionality? It could look something like this: If all of this seems foreign, don't fret. Coding decorators is much like coding any JavaScript function . Providing these framework-like features to custom elements may be easier than you think. Think of a micro-library as a collection of prewritten code used for common development tasks that has a small footprint. Micro-libraries may have similar functionality as much larger libraries but with way less code that optimizes down to a few Kb or maybe even less than 1 Kb. That's why they are "micro". Micro-libraries have existed for a while. Famously, Preact is a ~3 Kb alternative to the ~45 Kb React. Micro-libraries exist, in part, to provide a more performant alternative to popular JavaScript libraries. In the context of custom elements, micro-libraries are an interesting solution because we can gain the functionality of a JavaScript library with little expense with regards to performance. In Parts 2-4 of this micro-library tutorial series, I'll show you how to identify reusable parts of Web Components code and abstract logic away from each component implementation in a functional manner. You'll code a class decorator that handles declaration of a component selector, styling and template. You'll learn how to use method decorators to attach event listeners to DOM elements. You'll have a basic Web Components micro-library you can expand upon and use in actual apps. For a deep dive into Web Components, check out our latest book -  Fullstack Web Components: Complete Guide to Building UI Libraries with Web Components . It covers how to build robust UI libraries and entire applications using Web Components. 

Thumbnail Image of Tutorial Build Your Own JavaScript Micro-Library Using Web Components: Part 1