Assumed knowledge: some prior experience with the terminal and ssh keys. This project builds upon a previous barebones boilerplate code project.
Before diving into building a web app, it’s best to get an idea of how the code will be structured. That is, formulate a design (or plan, architecture) for how to write the code in a way that it can scale without becoming incomprehensible. The best way to do this is to have an understanding of how we think about code, or how we mentally model the solution to the problem (application) we are trying to solve (build). The patterns used in this boilerplate are what I use to write code for prototyping things quickly, as it matches the way I model the flow and connections between different parts of the codebase. You might develop your own system, and have your own way of modelling things mentally.
Firstly, clone the repository, and checkout the code-design branch.
git clone email@example.com:drohen/js-canvas-boilerplate.git
git checkout code-design
Ensure dependencies are installed, run:
Ensure the code runs in development mode:
There are now 2 new dependencies added to this project:
There are now 3 global types available to this project, defined in
Observer: a generic observable interface describing an object with 3 methods:
next: a method that receives some data based on the generic type, called based on some logic followed by the observable that calls it
complete: a method that is called when next will no longer be called by the observable
error: a method that is called when an error occurs within the observable, likely resulting in no further calls to occur
MountFn: a generic function type definition, describing a function that receives an instance of some type that extends an HTMLElement (here it will be used with custom elements)
ClickObservable: a interface defining a readonly property that is an observable, as it has a single method
subscribethat receives an
Observeras the parameter.
The HTML file now includes 2 new template elements (defined by their unique id values), along with their contents:
The CSS file contains styles for these two components. As this file is imported into the shadow DOM of the custom elements, the child elements of the components are “namespaced” by using the host css pseudo-class.
The application requires some kind of entrypoint. Per common programming convention, the core class of this project is called “Main.” Although, as this class isn’t automatically instantiated, it’s provided a static method that does the instantiation, and this is called immediately after the class definition. This has been added to the previously empty
As mention, one of the patterns that will be used in this project is a simplified version of the “observer.” Alongside the
src/index.ts file created earlier, there’s now another file named
src/subscriberHandler.ts. This file provides an “abstraction” for making a class or property “observable” by a “subscriber” object. The subscriber object can optionally provide next, complete, or error methods, per the type interface definition.
The example code in
src/index.ts at this stage shows a property called
uiLoader as providing a
subscribe method, where parent Main class instance becomes a subscriber, waiting for new DOM components to be emitted. There’s also a call to next, within the
update method. Although the component isn’t being used explicitly as a subscriber, it can still be passed the data it’s expecting to receive via this method.
A relatively new addition to the web browser API is Web Components, which brings us custom elements. Also alongside the
src/index.ts file is a
UI directory, which contains many UI related files.
There are 2 helper classes, used for building and defining the UI:
uiLoaderimports the custom element class objects, causing them to be defined within the custom element registry, so they can be successfully mounted to the DOM. It also takes care of emitting the instances of the components when they’re mounted, via an observable. There’s an example in this stage that attaches the custom elements to the DOM within the
uiComponentis a base class inherited by the custom element class objects. It helps to emit the instance when mounted, attach the main stylesheet to the element’s shadow DOM, and exposes a callback for when the instance is mounted.
There are 2 custom element class objects, corresponding to the template elements defined in
uiBlockrefers to the custom element with the id
ui-blockand is also an observer, whose
nextmethod is referenced in the
src/index.tsupdate loop. This
nextmethod demonstrates how the DOM component can be manipulated programatically, while not needing a direct reference to any external context.
uiButtonsimilarly refers to a custom element,
ui-button, and provides an observable interface via the
onDefinedmethod, called via the base
UIComponentclass, adds an event listener to the button contain within the shadow DOM. On click, the button will call the subscriber’s
Before next steps
By following the pattern outlined, you can rapidly build a web app with a manageable code structure. Other posts in this blog will build upon the design.
To view this code on the Internet, as demonstrated in the earlier post (if you have set up Github pages with your repository):
Build the code with
npm run build.
Push to the main branch to update the UI.
It should now show an interactive button that loads a number counter to the view.