Templates

Create static assets on a per-template basis, rather than universal files

A common way of providing Javascript and CSS for a website is to create a single Javascript file and a single CSS file, which are both used on every page of the site. With Static, however, the goal is to create many Javascript and CSS files, each being specific to a particular page template.

For example, assume a simple website with 4 unique pages (each with their own design template):

  • Home
  • About
  • Services
  • Contact

Traditionally, a developer might create a single Javascript file (typically named something like scripts.js) and a single CSS file (typically named something like styles.css). Each of these files would contain all the logic or styles for all 4 pages. The argument for this approach is twofold: it is generally easier for a developer to manage the compilation of a single file, and it also allows web browsers to cache a single file and attempt to increase performance across pages.

The downside(s) of the single file approach

While some real conveniences are afforded with the single file approach, there are also downsides.

  • Each page is forced to download Javascript and CSS that it can’t use. In the case of highly interactive or graphical sites, this can have a serious impact on performance.
  • The compilation speed for each asset decreases (gets slower), as even development on pages with simple styles or logic requires the compilation of the logic and styles for every page.
  • Javascript files tend to turn into “junk drawers”, wherein developers attempt to run expensive logic on every page, even when it only applies to one.
  • It becomes easier to create conflicting logic and styles between pages, which opens the door for unreliable experiences.

The Solution: Templates

Static’s solution to the single-file approach is to make it easy to create a set of assets (Javascript and CSS) for each specific page template. As a result, each page will only download and load the logic and styles that it requires, increasing performance and improving the resiliency of the code.

The concept, within Static, is called “Templates”, and it means thinking about the logic and styles required for each designed page template from the ground up, and then compiling the logic and styles into files that are only meant to be loaded by the page template they relate to.

For example, assuming the same 4 page website described above, the Template approach would require 8 separate files (two for each page), rather than one Javascript and one CSS file for the entire site:

  • /static/dist/js/home.js
  • /static/dist/css/home.css
  • /static/dist/js/about.js
  • /static/dist/css/about.css
  • /static/dist/js/services.js
  • /static/dist/css/services.css
  • /static/dist/js/contact.js
  • /static/dist/css/contact.css

With Static, the above isn’t as scary or tedious to maintain as it my sound.

First, the CLI makes it easy to generate the source files for both the Javascript and CSS resources for a specific page template by using the CLI’s template create command:

# Create a series of static resources for multiple page templates
$ static template create --name home,about,services,contact
Static SUCCESS: ./src/js/home.js was created!
Static SUCCESS: ./src/css/home.scss was created!
Static SUCCESS: ./src/js/about.js was created!
Static SUCCESS: ./src/css/about.scss was created!
Static SUCCESS: ./src/js/services.js was created!
Static SUCCESS: ./src/css/services.scss was created!
Static SUCCESS: ./src/js/contact.js was created!
Static SUCCESS: ./src/css/contact.scss was created!

Next, the CLI will automatically compiled the logic and styles for each page template into separate files with the compile command:

# Compile all static assets and watch for changes
$ static -w
Static SUCCESS: ./dist/js/home.js was compiled!
Static SUCCESS: ./dist/css/home.css was compiled!
Static SUCCESS: ./dist/js/about.js was compiled!
Static SUCCESS: ./dist/css/about.css was compiled!
Static SUCCESS: ./dist/js/services.js was compiled!
Static SUCCESS: ./dist/css/services.css was compiled!
Static SUCCESS: ./dist/js/contact.js was compiled!
Static SUCCESS: ./dist/css/contact.css was compiled!
Static INFO: Watching files...

What about reusable / global logic or styles?

A well-known best practice for development is to attempt to reduce code redundancy by separating common functionality or styles into reusable modules. With the single file approach, this is very easy because all logic or styles are already accessible to every page (as all pages share the same files).

With Static, this is still easy, through the use of a “global” import.

Global functionality within Javascript
Many websites have Javascript functionality that truly applies to each page on the site. Static’s approach to this kind of global functionality is to code it into a global module found at src/js/lib/global.js, and then import the module on any page that needs to share it.

For example, if a website had a top navigation on each page, and the top navigation required Javascript to manage a specific interaction, this logic would first be added to the global module found at src/js/lib/global.js:

/**
 * Global Functionality
 * The logic in this is intended to ONLY contain any functionality
 * that is required on every page load.
 *
 * NOTE: Please do not include any page-specific logic here.
 **/

import Logger from "../lib/logger";

export default function () {
  const NAME = 'Global';
  Logger.info(`${NAME} > loading`);

  // Vars
  // ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  const topNav = document.getElementById('global-top-nav');

  // Logic
  // ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

  /**
   * init --- Initialization block
   */
  function init() {
    Logger.info(`${NAME} > init`);

    // Add TOP NAV logic here
    topNav.addEventListener('click', (e) => {
        // Do something on click
    });
  }

  // Do not edit below this line...
  // ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  Logger.info(`${NAME} > loaded`);

  init();
}

After the global logic is added to the global module, the developer would then make sure to import and initialize the global module within each template-specific Javascript file (this included as part of a default Javascript template file):

/**
 * Home template
 * This file contains logic specific to a template.
 * It is intended to ONLY be loaded on templates that require
 * this specific functionality.
 **/

import Global from './lib/global';
import Logger from './lib/logger';

// Vars
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

const NAME = 'Home';

// Logic
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

// Bootstrap global functionality
Global();

// Do not edit below this line...
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Logger.info(`${NAME} > loaded`);