Global variables? Pass a scratch map to blocks?

Hi,
I am using Hugo to parse a large, complex JSON file and then generate many pages using different values from throughout the JSON.
Originally the site was set up to Unmarshal it many times whenever needed but now I am exploring optimizing this.
I am able to create a scratch map in the baseof.html file and pass it to partials such as header and sidebar, but this does not seem to work for a block such as main.
Is it possible to pass a dict to a block ?
Any other ideas for a better approach?
Thank you!

In your baseof template, when rendering the home page, retrieve the data then store it on the page.

{{ if .IsHome }}
  {{ $u :="https://www.example.com/tests/data/books.json" }}
  {{ with resources.GetRemote $u }}
    {{ with .Err }}
      {{ errorf "%s" }}
    {{ else }}
      {{ $.Store.Set "books" (unmarshal .) }}
    {{ end }}
  {{ else }}
    {{ errorf "Unable to get remote data at %s" $u }}
  {{ end }}
{{ end }}

The above is executed once, or once per language on a multilingual site.

The .Page.Store method is like .Page.Scratch, but the data survives rebuilds when running hugo server. In this case you can use either, but I’ve gotten into the habit of using the newer (.Store) method instead.

To access the data from a downstream template (e.g., layouts/_default/single.html) do:

{{ site.Home.Store.Get "books" }}

Fascinating, thank you so much. This looks really promising.

I tried this out; it almost works, but some of the content pages are built before the home page and therefore do not receive the values.

Is there a way to force hugo to build a certain page before all others?

Ah yes, concurrency, sorry about that.

baseof.html

{{ with $h := site.Home }}
  {{ if not ($h.Store.Get "books") }}
    {{ $u :="https://www.example.com/tests/data/books.json" }}
    {{ with resources.GetRemote $u }}
      {{ with .Err }}
        {{ errorf "%s" }}
      {{ else }}
        {{ $h.Store.Set "books" (unmarshal .) }}
      {{ end }}
    {{ else }}
      {{ errorf "Unable to get remote data at %s" $u }}
    {{ end }}
  {{ end }}
{{ end }}

So, we do the above on every page, but skip if we find the Store value on the home page. Due to concurrency and Hugo’s speed, the code above will be executed more than once. But once the Store has been written, subsequent pages won’t try again.

Testing a 1000 page site, the code above was executed between 2 and 8 times (tested it about 10 times). This is similar to what happens when you use partialCached, and is expected.

So why not just use partialCached?

layouts/partials/get-data.html

{{ $d := "" }}
{{ $u :="https://www.example.com/tests/data/books.json" }}
{{ with resources.GetRemote $u }}
  {{ with .Err }}
    {{ errorf "%s" }}
  {{ else }}
    {{ $d = unmarshal . }}
  {{ end }}
{{ else }}
  {{ errorf "Unable to get remote data at %s" $u }}
{{ end }}
{{ return $d }}

Then call it from anywhere with:

{{ partialCached "get-data.html" . }}

On a 1000 page site, calling it once per page, the partial was only executed once.[1]

     cumulative       average       maximum      cache  percent  cached  total  
       duration      duration      duration  potential   cached   count  count  template
     ----------      --------      --------  ---------  -------  ------  -----  --------
   754.432445ms     754.432µs   13.769389ms          0        0       0   1000  _default/single.html
     57.06049ms   14.265122ms   32.166341ms          0        0       0      4  _internal/_default/rss.xml
     22.55036ms    22.55036ms    22.55036ms          0        0       0      1  _internal/_default/sitemap.xml
     17.47322ms      17.473µs    2.190263ms        100      100     999   1000  partials/get-data.html
    15.368735ms    5.122911ms   14.915814ms          0        0       0      3  _default/list.html
    14.094115ms   14.094115ms   14.094115ms          0        0       0      1  _default/home.html

  1. Requires v0.111.0. ↩︎

1 Like