How can I build a JS asset separately for each piece of content?

I have a JS file in my asset dir for rendering a map visualisation, and all of my content files have a list of location lat-long pairs defined in the frontmatter.

In my template footer, I have the following:

{{ $mapJS := resources.Get "js/render-map.js" | js.Build ( dict "params" ( dict "locations" .Params.locations ) ) }}                                                          
<script src="{{ $mapJS.RelPermalink }}"></script>

…but this only renders one file and put it in my public dir’s js/ folder. What I want is for it to run for each content file and put the output in that piece of content’s page resource js/ dir (i.e., /blog/posts/<post-slug>/js/render-map.js). Is this possible? Or is there some other approach I’m supposed to take to create per-content files from a single asset?

I did have the JS inline, but now I’m trying to tidy up my theme and separate different types of files, add asset processing, etc. I have hundreds of content files that all feature this map, so copying the JS file as a page resource for each would be very wasteful.

I tried adding resources.Copy ( printf "%s/%s" $.File.Dir "js/render-meta-map.js" ) inbetween the js.Build and fingerprint functions, but this just output the file to my public dir. Plus, there doesn’t seem to be any way of disabling the caching of the pipe chain and running the asset processing more than once, so I’m pretty sure I’m barking up the wrong tree here. Is inline JS in the Go template really the only way of achieving what I need?

One approach is to pass the front matter values in an HTML data attribute. For example…

markdown

+++
title = 'Post 1'
date = 2021-01-01T00:00:00-00:00
[[locations]]
name = 'a'
latitude =  42
longitude = 67
[[locations]]
name = 'b'
latitude = 67
longitude = 42
++++

single.html

<div id="locations" data-locations="{{ .Params.locations | jsonify }}"></div>

baseof.html

{{ with resources.Get "js/main.js" | js.Build }}
  <script src="{{ .RelPermalink }}"></script>
{{ end }}

assets/js/main.js

document.addEventListener('DOMContentLoaded', function() {
  const el = document.getElementById('locations');
  if (el) {
    const locations = JSON.parse(el.dataset.locations);
    console.log(locations);
    // etc.
  }
});
1 Like