The Web Bare Necessities

Today I had yet another conversation on Web Development and Frameworks, with someone that is not even into Web Development but is trying to catch up through common feeds such Hacker News or similar channels.

The funny part of nowadays Web Development is that people believe you need a Framework to create something Web related, or you are out.

Once again, Frameworks are a very good option when they solve your problem, but these might also be the reason you have a problem in the first place.

As example, in this recent post of mine, the task was simple, but developers decided regardless to use a Framework in order to compare performance, and without even considering a Web standards code-base competitor.

Accordingly, this one is my take on questions such: “how do I usually do Web Development?

The Web is already a Framework

Concepts like Separation of Concerns, Decoupling, Model View Controller, and many other words you might have heard about Web Development, are actually available by default.

For instance, this is the most basic, fully cross platform, View we could have on the web:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Most basic View</title>
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1.0,minimum-scale=1.0"
    >
  </head>
  <body></body>
</html>

Such view could be enriched through some Style Sheet, improving the visualization of the page we are going to deliver.

And such style could be included either via link

<head>
  <!-- ... previous <head> content, plus ... -->
  <link rel="styleSheet" href="css/main.css">
</head>

or even inline, as some performance related technique might suggest these days

<head>
  <!-- ... previous <head> content, plus ... -->
  <style>
  /* an inline style example */
  html {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
  }

  *, *:before, *:after {
    box-sizing: inherit;
  }
  </style>
</head>

We could already put manually some model related data, writing some text directly on the body tag, truth is that we probably would like to deliver some modern fancy page and not just a static one.

Fair enough, and here it comes as standard!

A modern DOM in a bounce of bytes

If you have been using jQuery for the last 5+ years you probably didn’t notice that this library influenced, and surely in a good way, few modern Web standards.

My 2.4KB CDN based DOM4 polyfill, as example, is capable of normalizing so many new standard features it would be lame to use a library in order to obtain what native can do already, and most of the time even faster.

Add the most basic and unobtrusive $ dollar based utility you can think of, and you might realize things can be already very simple to do, without adding superfluous, but precious, bytes to download for our delivered page.

$('body').on('click', function (e) {
  console.log('the user clicked somewhere');
});

So far, with a total amount of 3.6KB minified and gzipped from a CDN, which means these will be irrelevant once used in different sites from the very same CDN, we can do already amazing things like adding, removing, or dispatching a listener with ease!

// can we pass events around?
// CustomEvent is there to help!
$('body').dispatch('click');
// simplified through the $ utility

Giving for granted we can extend the API with anything we need, what else are we missing?

Adding Graceful Enhancement

The most important goal of the Web is backward compatibility, and this is also a double bladed sword ‘cause sometimes it’s just not easy, or possible at all, to polyfill older browsers.

However, whenever it’s very cheap and simple, or widely adopted as solution, it’s always convenient to have handy snippets capable of fixing most known issues on the modern Web.

For instance, while Internet Explorer removed conditional HTML comments from its parser, good old IE9 and lower will understand them, giving us the ability to fix most common APIs like HTML5 Timers, by default capable of accepting extra arguments at declaration time, plus most of the entire DOM Level 3 specification for IE8 only.

<head>
  <!-- before any other script on the page -->
  <!--[if lte IE 9]>
  <script>(function(f){window.setTimeout=f(window.setTimeout);window.setInterval=f(window.setInterval)})(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c.apply(this,a)},t)}});</script>
  <![endif]-->
  <!--[if IE 8]><script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script><![endif]-->

The purpose of these conditional comments is pretty simple:

// what's cool about extra arguments?
function logIt(i) {
  console.log(i);
}

// for instance, you don't need
// a closure per each iteration
for (var i = 0; i < 5; i++) {
  setTimeout(logIt, i * 1000, i);
}

You would rarely find books talking about timers as standard, which is the reason even big names creating JavaScript engines might have hard time implementing them the right way at their first attempt.

I guess sometimes one really needs to read just standard specifications, instead of trusting blindly some opinionated blog post or book, what do you think?

Bringing in ES5

I have been working on Mobile Web for long time, and the amount of inconsistencies between not so modern browsers has been both a nightmare and a revelation.

What I have learned in my experience is that most of the modern JavaScript features you’d like to have today, are available by default in every browser or engine that introduced Function.prototype.bind natively.

No kidding, the most basic feature detection test you can make, in order to have a 99% fully capable ES5 modern environment, is to check for this method in the native prototype:

<script>
Function.bind||(function(s){document.write([
  '<script src="'+s+'es5-shim.min.js" defer><',
  '<script src="'+s+'es5-sham.min.js" defer><',''
].join('/script>'))}(
  '//cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.7/'
));
</script>

Above little piece of code in your header, will ensure only older browsers will bring in most needed ES5 methods polyfills in your page.

Just be sure this script is added early enough in your stack, and please feel free to remove defer from those scripts, but definitively don’t use async instead, since it’s full of surprises.

Only one missing bit!

Web standards introduced a while ago the DOMContentLoaded event type, an event that made old style Web pages instantly responsive and reactive because scripts were executed before the user could even see the page!

That feature got lost recently when they introduced the script async attribute, something that could be parsed and interpreted at any time in a page life cycle, even after the DOM content has been loaded, making the listener DOMContentLoaded completely unreliable.

In few words, for one non-blocking script achievement unlocked, a commonly used entry point to initialize components and page logic has been lost!

So this is the way we could solve the issue:

<script>
!function(r,e,a,d,y){
  function $(f){d?f():r.push(f)}e.ready=$;e.addEventListener(a,
  y=function(){d=!e.removeEventListener(a,y,d);while(y=r.shift())y()},d
)}([],document,'DOMContentLoaded',!1);</script>

Used as inline script on top of the page, eventually after conditional old IE comments, we can be definitively sure whatever we pass to document.ready(fn) will be executed ASAP.

It’s some sort of hidden, but well known dependency, we could simply trust on our project or Website, and without compromising required bandwidth at all.

Moreover, if you are familiar with jQuery, think document.ready(fn) as its equivalent. Many developers have been writing plugins and logic starting from $(document).ready(fn), you just need to drop the wrapper and use above snippet inline to have exact same feature ;-)

Normalized CSS

In order to be sure that all elements will consistently render as expected, we might want to add as very first style the following one:

<head>
  <!-- before any other style -->
  <link
    rel="styleSheet"
    href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css"
  >
</head>

The normalize.css library is battle-tested and also used in famous frameworks such bootstrap.

As Summary

What I didn’t mention at the beginning, is that I would have described this Website layout.

All mentioned techniques, polyfills, and practices in this post are exactly what you are surfing now indeed:

And all of above points in a tiny Web site, probably one of the smallest you can surf on these days.

Accordingly, are you still sure you need “that Framework“ to deliver your next project?

Please feel free to leave some comment in the Disqus area, and thank you for reading!

Andrea Giammarchi

Fullstack Web Developer, Senior Software Engineer, Team Leader, Architect, Node.js, JavaScript, HTML5, IoT, Trainer, Publisher, Technical Editor