Hi,
in my project, different pages require different pieces of JavaScript code depending on e.g. which short codes are used. I was looking for a way to
- Only include the JavaScript code which is actually required for a page
- Only use a single HTTP request per page for JavaScript
To solve this, I developed a little technique which I wanted to share - maybe somebody can reuse (or improve on) it.
The general idea is that all layouts can ‘register’ a script for inclusion - the baseof.html
template then takes care of generating a single resource.
The central pieces are two partial layouts:
-
layouts/partial/resources/register_script.html
: this partial can be called to register a script. It’s just an abstraction over the scratch pad and contains just{{ .scratch.Add "scripts" .resource }}
-
layouts/partial/resources/combine.html
: this partial is invoked bybaseof.html
and takes care of combining all registered resources. It concatenates all resources (alas, ‘resource.Combine’ wouldn’t work here) and then generates a unique file name based on the MD5 hash of the generated script:{{ $code_fragments := slice }} {{ range (.page.Scratch.Get .set) }} {{ $code_fragments = $code_fragments | append .Content }} {{ end }} {{ $code_fragments = delimit $code_fragments "" }} {{ $resource_path := printf .outPath (md5 $code_fragments) }} {{ $resource := $code_fragments | resources.FromString $resource_path }} {{ return $resource }}
With this at hand, my partial layouts can now use e.g.
{{ partial "resource/register_script" (dict "scratch" .scratch "resource" (resources.Get "js/collapsible-tree.js")) }}
to register a resource for inclusion (here: js/collapsible-tree.js
, for pages which happen to use a tree control)
The baseof.html
layout then uses
{{ .Scratch.Set "scripts" slice -}}
at the very top (to setup the ‘scripts’ slice which register_script
depends on) plus
{{ $resource := partial "resource/combine" (dict "page" . "set" "scripts" "outPath" "js/script-%s.js") }}
{{ $script := $resource | minify | fingerprint }}
<script type="text/javascript" src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
at thee bottom of <body>
to get the combined script, minimize it, fingerprint it.