My frontend UI framework
1679702400


I want a way to be able to rapidly prototype ideas without having to redo frontend UI each time


I also do not want to spend any thought time on learning someone else’s frontend framework. Frameworks most certainly make you more productive, but they become counterproductive if you don’t know them. This is because you have to stop writing important business logic and start figuring out how the framework works, and I don’t want to do this


My decision was to create my own, reusable frontend UI that included a design, implementation, and strategy for how it should be used—basically, everything I’d need on the frontend to rapidly prototype ideas


This project has been working out really well, and I’ve been putting it together as I go along. I can call it a framework because it has everything I need


The concept I’m adopting here is consistent across both the frontend and the backend because I exclusively deploy backend APIs into FaaS without any framework either and have been doing so for a while now


Base concepts

The SPA can be initially rendered from a static file store with no requirement for server processing


I’ve followed the mobile-first principles, so the UI looks really great on mobile, as well as being responsive when the size of the viewport dynamically changes. The navigation menu is in the top left of the UI, which seems to be the prevalent place for menus



The navigation bar is at the top of the UI (it’s in the document flow and not fixed to the viewport) and contains the app logo, app name, and navigation menu. The business details are located at the bottom of web page



Directory structure

.
./css/
./js/
./js/libraries/
./js/modules/
./index.js
./images/
./index.html


I try to keep things as neat as possible, but nothing really enforces this directory structure—other than the obvious fact that changes made here need to be consistent


Most web servers have a default that will look for index.html in the document root and I’ve had no need to change this


The main controller is index.js and it will set the initial preparation of the app


JavaScript

The star of the show is JavaScript. This should be obvious seeing it’s the de facto programming language on the web frontend and that I have a few years experience developing applications with it


Both ES5 and ES6 are supported and modern JavaScript concepts (async/await, for…of etc) will be transpiled during the build process


Require.js

Require.js is an AMD module loader that understands the relationship modules have with one another and it automatically handles the asynchronous loading of these modules


Each module needs to invoke define() with the first parameter being an indexed array of modules it depends on and the second parameter being a call-back function that needs to specify parameters, in the same position as the elements in the indexed array, that will represent the dependency module as an object


Here is an example of defining a module named Fruits


Fruits.js

define(['fruits/apples', 'fruits/bananas'], function(apples, bananas) {
  return new function() {

  // do something with apples and bananas and set useful methods for the outside controller
  this.eatAnApple = function() {
  };

  this.eatABanana = function() {
  };

}})


The controller can make use of the Fruits module by requiring it


Controller.js

require(['modules/fruits'], function(fruits) {
  fruits.eatAnApple();
})


Adding Require.js to my frontend UI was very important right from the beginning. It encourages a logical way of laying out the JavaScript, and it was very quick to learn


Modules

These are the modules that will probably never have to change and are available across all the apps that make use of my UI framework


Navigation

The important concept that I’ve built into this module is the mapping between the menu buttons and elements with the data-page attribute. These are the elements that contain the relevant content


This module returns an object (instantiated from a constructor function) where I can include all the public methods that are specific to the app in this area. Within this constructor is the instantiation of another constructor function that handles the setting of the event listeners on all the menu buttons


Utilities

This module is where I perform miscellaneous tasks. Examples of miscellaneous tasks are: enabling Google Analytics, instantiating the Facebook JavaScript SDK, determining if the device is mobile, etc


CSS

I’ve written selectors that will style the navigation bar, the menu and a whole bunch of utility/helper classes that are not dependent on the structure of the HTML in any way


The stylesheet is global and the cascade is used as it should so there is no issue with undesired styling or fighting with specificity (no inline-styling)


The box model layout strategy has always worked for me and it’s the layout strategy I’m most familiar with. I’ve defined utility classes that deal with display, vertical alignment, margin and all of these utility classes enable me to rapidly implement the layout strategy


I don’t use any mainline CSS framework like Tailwind CSS or Bootstrap. This makes sense seeing as what I’ve created here is pretty much like my own Tailwind and Bootstrap (and I don’t have a reason to use theirs)


HTML

I have a parent/container element where I set a fixed height to 600px. This is usually enough vertical space to invoke a scrollbar in the browser and this will increase as more content is added


The elements that are mapped to menu buttons are children of this parent/container element and this is the most important aspect of the HTML


Assets

For the images, I get them professional created by a graphic designer. There are millions of websites that support freelancers. The average price I pay for an app logo is around ~USD $10. Flaticon has also come in very handy for app logos as well. I usually play around with favicon.cc for the favicon


I do the obvious stuff like compressing the images and using scalable vector graphics over any other format if possible. I’ve never had any issues with TinyPNG or OS X Preview for performing the compression


Testing

The testing process I follow is simple: manual functional and visual testing in all the major browsers (Chrome, Firefox, Safari)


Build process

This is the part where I put on my crash helmet and grab my balls


Babel.js

Adding Babel.js to my UI framework was very important. I want to be able to write modern ES6 but still have backwards compatibility and particularly backwards compatibility with subsequent steps in my build process. Babel.js handles all of this for me by transpiling the modern features to an equivalent in a previous version


cat "$JS_BUILT" | babel -f babel_errors.txt -o "$JS_BABEL"


javascript-obfuscator

This is a Node package that enables me to obfuscate my JavaScript pretty well (at-least I haven't found an easy way to reverse it)


javascript-obfuscator $JS_PROD --output $JS_PROD --compact true --self-defending true --dead-code-injection true


npm run build (bash ./build.sh)

I’ve described the entire build process in a shell script that travels with the repository (build.sh)


To do