Debug/print Hugo's composed virtual filesystem

Hi,

I’m trying to deal with a complex module hierarchy and am not understanding when/why I’m encountering certain errors. There are frankly a handful that don’t make sense to me, even with my (evolved?) understanding of how Hugo resolves source file trees before generating site content.

I’m not very familiar with golang, but is there a way to show the final source tree/virtual filesystem in a kind of debug mode so I can have a better sense of why my mounts aren’t configured correctly?

1 Like

There are some nice CLI commands that (when NOT running the server) show some details:

hugo config mounts
hugo mod graph

If you achieve any further enlightenment outside of this thread and the discourse please let us know :slight_smile:

Hi @davidsneighbour,

The hugo config mounts command seems promising, but it immediately fails to render the inherited mounts from an imported module. For example, I have a very simple config.toml:

baseURL = "/"
defaultContentLanguage = "spaceforce"
defaultContentLanguageInSubdir = true
disableKinds = ["RSS", "taxonomyTerm"]
enableMissingTranslationPlaceholders = true

[taxonomies]
    tag = "tags"
    category = "categories"
    topic = "topics"

[module]
  
  [[module.imports]]
    ignoreConfig = false
    ignoreImports = false
    path = "path/to/some/module.git"

The imported module has a very complex config.toml, which imports/mounts several other modules, but all I see in the output of the command is:

Snarkbot:space-force starves$ hugo config mounts
{
   "path": "path/to/current/module.git",
   "dir": "the/current/directory",
   "mounts": [
      {
         "source": "package.json",
         "target": "assets/_jsconfig/package.json"
      },
      {
         "source": "content",
         "target": "content"
      },
      {
         "source": "data",
         "target": "data"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "i18n",
         "target": "i18n"
      },
      {
         "source": "archetypes",
         "target": "archetypes"
      },
      {
         "source": "assets",
         "target": "assets"
      },
      {
         "source": "static",
         "target": "static"
      }
   ]
}
{
   "path": "path/to/some/module.git",
   "dir": "/var/folders/3m/20yr1zw962q8_ccfch9bklhc0000gq/T/hugo_cache/modules/filecache/modules/pkg/mod/path/to/some/module.git@v1.1.0/",
   "mounts": [
      {
         "source": "assets",
         "target": "assets"
      },
      {
         "source": "content",
         "target": "content"
      },
      {
         "source": "i18n",
         "target": "i18n"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "static",
         "target": "static"
      },
      {
         "source": "package.json",
         "target": "assets/_jsconfig/package.json"
      }
   ]
}

Well, I actually just tested it on my own complex Hugo app and it showed me much more. This means your modules config might be broken. Post a sample repo to test and we’ll see.

The output you posted looks like no “real” mounts are configured in those config.toml files, just the standard mounts.

Maybe you misunderstand mounts too, I tend to mount more verbose, like for a bootstrap 5 module:


[[module.mounts]]
source = "assets"
target = "assets"

[[module.mounts]]
source = "assets/scss/bootstrap/_vendor"
target = "assets/scss/bootstrap/vendor"

[[module.imports]]
path = "github.com/twbs/bootstrap"

[[module.imports.mounts]]
source = "scss"
target = "assets/scss/bootstrap"

[[module.imports.mounts]]
source = "js"
target = "assets/bootstrap"

[[module.imports.mounts]]
source = "js/index.esm.js"
target = "assets/bootstrap/index.js"

[[module.imports]]
path = "github.com/dnb-hugo/libraries/popper.js"

It’s important what’s inside of this modules config.toml.

Thanks for the help so far…I’m not confident I have ANY of this set up correctly, so I’ll take all the tips I can.

My expectation/understanding is that the final hugo config mounts would show at least all of the configured mounts from the imported module as well as any locally configured mounts.

The imported module’s config.toml (shown below) actually describes an entire site that builds over 350 pages. What it generates for me is exactly correct for the site it defines. Now, I’m trying to make a slight customization to that site by using it as a module in my customized site.

baseURL = "/"
defaultContentLanguage = "arcus"
defaultContentLanguageInSubdir = true
disableKinds = ["RSS", "taxonomyTerm"]
enableMissingTranslationPlaceholders = true

[taxonomies]
    tag = "tags"
    category = "categories"
    topic = "topics"

[module]
  [[module.imports]]
    path = "my/base/module"

  [[module.imports.mounts]]
    source = "src/scss"
    target = "assets/scss/box-office"

  [[module.imports.mounts]]
    source = "src/modules"
    target = "assets/js/modules"

  [[module.imports.mounts]]
    source = "src/index.app.jsx"
    target = "assets/js/index.app.jsx"

  [[module.imports.mounts]]
    source = "site/layouts/_default"
    target = "layouts/_default"

  [[module.imports.mounts]]
    source = "site/layouts/partials"
    target = "layouts/partials"

  [[module.imports.mounts]]
    source = "site/layouts/shortcodes"
    target = "layouts/shortcodes"
  
  [[module.imports.mounts]]
    source = "site/content"
    target = "content"

  [[module.imports.mounts]]
    source = "site/static"
    target = "static"
  
  [[module.imports.mounts]]
    source = "site/layouts/about"
    target = "layouts/about"
  
  [[module.imports.mounts]]
    source = "site/layouts/features"
    target = "layouts/features"
  
  [[module.imports.mounts]]
    source = "site/layouts/getting-started"
    target = "layouts/getting-started"
  
  [[module.imports.mounts]]
    source = "site/layouts/iframe"
    target = "layouts/iframe"
  
  [[module.imports.mounts]]
    source = "site/layouts/library/section.lang1.html"
    target = "layouts/library/section.html"
  
  [[module.imports.mounts]]
    source = "site/layouts/news"
    target = "layouts/news"

  [[module.imports.mounts]]
    source = "site/data/prices"
    target = "data/prices"

  [[module.imports.mounts]]
    source = "site/layouts/pricing/section.site2.html"
    target = "layouts/pricing/section.html"
  
  [[module.imports.mounts]]
    source = "site/layouts/speedtest"
    target = "layouts/speedtest"
  
  [[module.imports.mounts]]
    source = "site/layouts/solutions"
    target = "layouts/solutions"
  
  [[module.imports.mounts]]
    source = "site/layouts/status"
    target = "layouts/status"
  
  [[module.imports.mounts]]
    source = "site/layouts/support/section.site2.html"
    target = "layouts/support/section.html"
  
  [[module.imports.mounts]]
    source = "site/layouts/topics"
    target = "layouts/topics"
  
  [[module.imports.mounts]]
    source = "site/layouts/terms-of-service/section.site2.html"
    target = "layouts/terms-of-service/section.html"

  [[module.imports.mounts]]
    source = "site/layouts/index.site1.html"
    target = "layouts/index.html"
  
  [[module.imports.mounts]]
    source = "site/layouts/404.html"
    target = "layouts/404.html"
  
  [[module.imports.mounts]]
    source = "site/layouts/unsupported.html"
    target = "layouts/unsupported.html"

  [[module.imports.mounts]]
    source = "src/scss"
    target = "assets/scss/box-office"

  [[module.mounts]]
    source = "node_modules/font-awesome/fonts"
    target = "static/fonts/font-awesome"

  [[module.mounts]]
    source = "static"
    target = "static"
  
  [[module.imports]]
    path = "path/to/my/change-log.git"
  
  [[module.imports.mounts]]
    source = "content"
    target = "content"

  [[module.imports.mounts]]
    source = "layouts"
    target = "layouts/change-log"
  
  [[module.imports]]
    path = "path/to/my/knowledge-base.git"
  
  [[module.imports.mounts]]
    source = "content"
    target = "content/kb"
  
  [[module.imports.mounts]]
    source = "layouts"
    target = "layouts/kb"

  [[module.mounts]]
    source = "content"
    target = "content"
1 Like

Just a side note: “modules” might not be “modules”. Are you sure the imported module has a go.mod? If not, then it’s not a mdule, even if you call it like a module.

Regarding the imported snippet - I am not sure about it, but maybe the [module] is not required? It’s a very verbose module-import-mount setup. Put a testable sample repo up so we can play around with it.

Yes, there is a go.mod at every level.

I will try to cobble together a test repo - I’m not able to share our actual repos, which, of course, would make this all a lot easier.

He is right. hugo config mounts prints what Hugo is using.

Okay, @bep and @davidsneighbour - what am I missing here?

I’ve created 3 hugo modules, GitHub - shauntarves/hugo-module-1, GitHub - shauntarves/hugo-module-2, and GitHub - shauntarves/hugo-module-3

hugo-module-2 requires hugo-module-1 and hugo-module-3 requires hugo-module-2. When I run hugo config mounts within hugo-module-3, all I see is:

{
   "path": "github.com/shauntarves/hugo-module-3",
   "dir": "modules/hugo-module-3",
   "mounts": [
      {
         "source": "content",
         "target": "content"
      },
      {
         "source": "data",
         "target": "data"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "i18n",
         "target": "i18n"
      },
      {
         "source": "archetypes",
         "target": "archetypes"
      },
      {
         "source": "assets",
         "target": "assets"
      },
      {
         "source": "static",
         "target": "static"
      }
   ]
}
{
   "path": "github.com/shauntarves/hugo-module-2",
   "dir": "/var/folders/3m/20yr1zw962q8_ccfch9bklhc0000gq/T/hugo_cache/modules/filecache/modules/pkg/mod/github.com/shauntarves/hugo-module-2@v1.0.0/",
   "mounts": [
      {
         "source": "content",
         "target": "content"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "static",
         "target": "static"
      }
   ]
}

and when I try to build the site, none of the content or layouts from hugo-module-1 are available and the building fails.

If I’m completely misinterpreting what should be happening here with transitive dependencies and such, please let me know. I’m only going off of my assumptions based on the fact that ignoreConfig and ignoreImports lead me to believe that the module’s own config and imports should be brought along.

The config directory is only supported by the main project (which is something I/we should fix …, but I guess I was lazy at the time I implemented it).

Run hugo mod tidy and hugo mod get -u ./... in all three modules and tag them again with the latest version number (from deepest to lowest module). It might be that module 1 is missing something. Check the release page for module 1 and remove the release 1.0.0 (without v), I had some issues with tags too and found it always better to have vMAJOR.MINOR.PATCH as tag/release name.

So what does that mean exactly? Do modules NOT bring along their configs when used? Will I basically have to replicate the config from module-2 and module-1 in the config for module-3?

If that’s the case, then what does the ignoreConfig parameter do?

The actual tag on all of the modules is of the vMAJOR.MINOR.PATCH format. The title of the release doesn’t have the v but that’s completely irrelevant to any git/go construct.

I did as you suggested, ran hugo mod tidy && hugo mod get -u ./... in each module starting from 3 down to 1. There was no change in behavior.

It means you cannot use a directory structure for configuration within a module, but you can use a directory structure for configuration in the main project. Within a module, just place a single configuration file at the root.

In my case the “release” without v in the name actually blocked all v-tags because somehow github returned it as latest release instead of the newer v#.#.# release.

However, you should move your module2’s config directory to a config.toml/yaml/json file as @jmooring noted. It’s not parsed by hugo in a subdirectory. I opened a proposal on Github for that feature.

@bep @davidsneighbour

Thank you for the clarification. I was not noticing you kept saying config directory (as opposed to config file). I will make these changes and hope for better behavior.

Best,
Shaun

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