[TIP]: Generate Pages from Remote - Is it possible to generate a JSON file, dynamically, at build time? -

As an example, I’d like a file to be available at the top level of my site, “/site.json” with, say, the following content…

{
  "last-build": "20211218T163000Z"
}

In this example, the timestamp would be generated at build time, not hard coded :slight_smile:

1 Like

Yep, thought that would be the area, but not having much luck understanding the concepts on that page. I guess it’s separating the whole Hugo processing and generation flow from the concepts on that page which are confusing me. home, page, section, taxonomy, term, all seem to be distracting my understanding for, what I’m thinking, is a simpler requirement. Must be just me. Can’t seem to find an example anywhere though.

config.toml

enableGitInfo = true

[outputs]
home = ['HTML', 'RSS', 'JSON']

layouts/_default/home.json

{{ jsonify (dict "last-build" .Site.LastChange) }}

This will generate public/index.json with something like:

{"last-build":"2020-06-26T07:50:52-04:00"}

Format the date as needed.

1 Like

You asked for “last build” not “last change”. So…

{{ jsonify (dict "last-build" (now.Format "20060102T150405Z")) }}
1 Like

For simpler use cases, you can also do this: Creating a resource from template | Hugo

3 Likes

Nice. It’s easy to forget about this capability.

layouts/_default/baseof.html

{{ if .IsHome }}
  {{ $j := jsonify (dict "last-build" (now.Format "20060102T150405Z")) }}
  {{ $noop := (resources.FromString "/site.json" $j).Permalink }}
{{ end }}

Notes:

  • Wrapped in .IsHome to limit the number of times we do it.
  • The resource isn’t published until it is accessed via .Permalink or .RelPermalink, so we do that and assign the result to something ($noop or whatever).
4 Likes

Very slick. Thank you soooo much :sunglasses:

It would be nice if we could write:

{{ resources.FromString "/site.json" $j | resources.Publish }}

The implementation could just invoke .RelPermalink …

2 Likes

Pseudo pages from data using the same approach:

git clone --single-branch -b hugo-forum-topic-36112 https://github.com/jmooring/hugo-testing hugo-forum-topic-36112
cd hugo-forum-topic-36112
hugo server

I don’t know why that hadn’t occurred to me before.

3 Likes

Can Hugo write to the real top level of a project (not the site top level)? Have wondered how to do dynamic edits to a top-level vercel.json file for Content Security Policy purposes (e.g., to use the new resources.GetRemote to grab remote files and generate hashes).

@jmooring’s example above is project level (as in, it’s site/language agnostic).

2 Likes

This is so cool! It deserves to be the solution of the topic.

Also I am pinning this topic for a couple of days, people need to know this technique

Awesome!

2 Likes

Thanks to @jmooring and @bep I’ve implemented what I needed to. My final solution annexed the ‘generate at build time’ elements.

This example shows the additional files that my current solution refactored to:

assets/build
├── site.json
└── manifest.json

layouts/partials
└── buildTimeResources.html

An example for the contents of buildTimeResources.html would be something like:

{{/* Build-time generated content */}}
{{/* Generated once, by way of '.IsHome' wrapper */}}
{{- if .IsHome -}}

    {{/* Example (using simple string) */}}
    {{/* {{ $j := jsonify (dict "last-build" (now.Format "20060102T150405Z")) }}
    {{ $noop := (resources.FromString "/site.json" $j).Permalink }} */}}

    {{/* Example (using template asset file) */}}
    {{- $j := resources.Get "build/site.json" | minify -}}
    {{- $noop := ($j | resources.ExecuteAsTemplate "/site.json" .).RelPermalink -}}

    {{- $j := resources.Get "build/manifest.json" | minify -}}
    {{- $noop := ($j | resources.ExecuteAsTemplate "/favicon/manifest.json" .).RelPermalink -}}

{{- end -}}

The content of the templates simply include whatever you require, along with any go template code. So, for my simple site.json example mentioned previously, something like:

{
  "build": "{{ (now.Format `20060102T150405Z`) }}",
  "version": "{{ hugo.Version }}",
  "environment": "{{ hugo.Environment }}",
  "commit": "{{ hugo.CommitHash }}"
}

The whole thing is currently kicked off by simply referencing that partial at the bottom (could be anywhere) of layouts/partials/_default/baseof.html

<!DOCTYPE html>
. . .
</html>
{{- partial "buildTimeResources" . -}}

There have been ideas for better syntax for the ability to create the actual files (their creation being a by-product of RelPermalink at present). Something like @bep’s pipe to resources.Publish would be great. It might also be better to be able to kick the whole process off as part of the build (as a 1st class citizen of the build process) rather than jury-rig a hook by way of the baseof.html. However, it works, helped my understanding of the Hugo build process, and I’m very happy with the help and eventual solution. Thanks guys :grin:

4 Likes

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.