Migrating Bootstrap docs to Hugo

Hello to everyone.

I decided to switch the Bootstrap docs site (https://getbootstrap.com/) to Hugo. I know this isn’t going to be an easy process, but I believe the pros justify the time I’ll spend. :slight_smile:

Here is what I have so far: https://github.com/twbs/bootstrap/tree/v4-dev-xmr-hugo

Many things are currently broken; I can’t use the highlight shortcode in index.html, I’ll need to write shortcodes to replace the Jekyll plugins we use, fix aliases and probably more. But that is for after I manage to set up the structure properly.

Now, with our current structure, I’m facing an issue with some of the static files. Specifically the dist/ folder which we need in the publishdir but I can’t move it into the static folder because many things will break since people link to the dist files from all over the web.

How could I overcome this issue without plugging in gulp or something similar?

Thanks in advance for any help!


That statement does not make sense to me. Why is this a conflict?

Because people link to the dist files in the repo from all over the web; moving the dist folder into static so that Hugo copies it, will break things…

I get that, but why would the URLs be different?

Ah, OK, people link directly to the dist folder on GitHub … I assume you could set staticDir to “…/dist”; which would probably solve one problem and create another. If you create a theme you will get two static dirs…

I guess there isn’t a config option to include static folder, right?

I haven’t tried the themes approach so far because I never had the need to, so I’ll need to read about it.

Thanks for the help so far!

Again, I’m having a hard time understanding what you write. The static folder is included by default, so I’m sure you must mean something completely different.

Did you check the source tree I pasted above?

We have a dist folder we need to be in publishdir but I can’t move it into the static dir.


Hugo only supports a single staticDir config option. Stipulating that you can’t/won’t move the dist folder, I see two options:

  1. Update your deployment workflow to copy the dist folder into the publishDir path.

  2. Add a Hugo feature to allow the insertion of multiple static dirs into the site output.

The second option isn’t really an option for me since I don’t have any Go knowledge.

So, I’ll try to hook up Gulp and see how it goes.

I already miss the ability to use shortcodes and highlighting in html, although it’s just for the home page so I can probably work around it by using partials.

Anyway, thanks for the reply.

You can have HTML content files with shortcodes, but that is probably not what you want in this case. Note that there is a highlight template func that can be called from partials.

And about the “multiple static” dirs; if you can describe your needs in a GitHub issue, “someone” might help you get what you want. If you need it, then probably others will also benefit from the same.

This is what I get so far with my branch I linked above (https://github.com/twbs/bootstrap/tree/v4-dev-xmr-hugo):

C:\Users\xmr\Desktop\bootstrap>npm run docs-compile

> bootstrap@4.0.0-beta.2 docs-compile C:\Users\xmr\Desktop\bootstrap
> cd docs/ && hugo --config config.yml

ERROR 2017/10/23 18:37:36 Failed to add template "index.html" in path "C:\\Users\\xmr\\Desktop\\bootstrap\\docs\\layouts\\index.html": template: index.html:31: unexpected "<" in command
ERROR 2017/10/23 18:37:36 Failed to add template "partials/docs-navbar.html" in path "C:\\Users\\xmr\\Desktop\\bootstrap\\docs\\layouts\\partials\\docs-navbar.html": template: partials/docs-navbar.html:3: unexpected "<" in command
ERROR 2017/10/23 18:37:36 Failed to add template "partials/docs-sidebar.html" in path "C:\\Users\\xmr\\Desktop\\bootstrap\\docs\\layouts\\partials\\docs-sidebar.html": template: partials/docs-sidebar.html:4: unexpected "<" in command
ERROR 2017/10/23 18:37:36 index.html : template: index.html:31: unexpected "<" in command
ERROR 2017/10/23 18:37:36 partials/docs-navbar.html : template: partials/docs-navbar.html:3: unexpected "<" in command
ERROR 2017/10/23 18:37:36 partials/docs-sidebar.html : template: partials/docs-sidebar.html:4: unexpected "<" in command
Started building sites ...
ERROR 2017/10/23 18:37:37 Error while rendering "page": template: _default/docs.html:13:7: executing "_default/docs.html" at <partial "docs-navbar...>: error calling partial: template: "partials/docs-navbar.html" is an incomplete or empty template
npm ERR! errno 4294967295
npm ERR! bootstrap@4.0.0-beta.2 docs-compile: `cd docs/ && hugo --config config.yml`
npm ERR! Exit status 4294967295
npm ERR!
npm ERR! Failed at the bootstrap@4.0.0-beta.2 docs-compile script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\xmr\AppData\Roaming\npm-cache\_logs\2017-10-23T15_37_37_269Z-debug.log

docs-sidebar.html isn’t converted yet, but the above errors come from using a shortcode in html. For example:

{{< svg src="import.svg" width="32" height="32" class="text-primary mb-2" >}}

Note that I might be doing something obviously wrong, so I’d try to have a look later after I take a break.

As for the extra static files include, I will make a new GitHub issue, thanks.

To use shortcode in HTML it must live below /content. All files below /layouts are templates (i.e. Go templates if the suffix is HTML). But I’m guessing you would not want to go that route.

As @bep already mentioned it’s not possible to call short codes within a a template.

The usage of the highlight short code below

{{< highlight sh >}}
npm install bootstrap@{{ .Site.Params.current_version }}
{{< /highlight >}}

can be translated to

{{ highlight "npm install bootstrap@{{ .Site.Params.current_version }}" "sh" }}

But I would guess that will not be substituted with the actual value. We can circumvent this as follows:

{{ highlight (printf "npm install bootstrap@%s" .Site.Params.current_version) "sh" }}

But this approach isn’t sufficient if the code examples are longer and contain more template variables, e.g. as in the following example:

{{< highlight html >}}
<script src="{{ .Site.Params.cdn.jquery }}" integrity="{{ .Site.Params.cdn.jquery_hash }}" crossorigin="anonymous"></script>
<script src="{{ .Site.Params.cdn.popper }}" integrity="{{ .Site.Params.cdn.popper_hash }}" crossorigin="anonymous"></script>
<script src="{{ .Site.Params.cdn.js }}" integrity="{{ .Site.Params.cdn.js_hash }}" crossorigin="anonymous"></script>
{{< /highlight >}}

You need to concatenate the multiline with printf. It looks a little ugly, but it works. If you split it into multiple assignments it doesn’t look too bad.

But in general, you will be more effective if you take this discussion in the PR. Showing a working solution is simpler than talking about it. Just mention @bep if you need me to look at it.

Thanks for everyone’s replies!

I don’t like cross-posting so here’s the gist: https://github.com/twbs/bootstrap/issues/24475#issuecomment-338940795

@bep: sorry for reviving an old topic but the time is right, now :slight_smile:

So, I’ve made https://github.com/twbs/bootstrap/pull/28014

I have a TODO in the PR description, but here’s a few other things I was wondering.

  1. is it possible to make variables into strings work? The use case is this {{ highlight "gem install bootstrap -v {{ .Site.Params.current_ruby_version }}" "sh" "" }}
  2. is it possible to specify a second static dir but output it to the specified place in the publishDir? Use case, we have the dist folder which current we manually copy it into the static/foo/dist folder
  3. I noticed that if a data file’s name has - then Hugo cannot process it. Not sure if you can do something about it since I see it’s a limitation of Go https://github.com/gohugoio/hugo/issues/1474. That being said, is it possible to work around this? Like using it in a range: {{ range $i, $release := .Site.Data.docs-versions }}
  4. I also had to change our versions data file to explicitly use strings because otherwise 4.0 was being shows as 4. Every other version showed up fine though. Not sure if it’s a bug or a limitation.

Now the only thing I haven’t a solution yet, without creating multiple shortcodes is how to loop through a data file within a generic shortcode. Example of what we did before:

{% capture example %}
<div class="alert alert-success" role="alert">
  <h4 class="alert-heading">Well done!</h4>
  <p>Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.</p>
  <p class="mb-0">Whenever you need to, be sure to use margin utilities to keep things nice and tidy.</p>
{% endcapture %}
{% include example.html content=example %}

This is our content folder, so I’d need to create shortcodes for each case like the above, right?

Thanks in advance for any help, looking forward to finishing this branch :slight_smile:

  1. Everything is possible, but it is not on my current task list. I’m sure others will chime in with a good workaround.

  2. Not to my knowledge.


{{ (index .Site.Data "docs-versions") }}
  1. Depends on the data format used (they differ in their number handling), but for versions I think you can avoid a lot of head aches by storing them as strings.

The last question I don’t understand

The above can be written as:

{{ highlight (printf "gem install bootstrap -v %s" .Site.Params.current_ruby_version) "sh" "" }}

Thanks, for the replies!

I will try the above workaround about the hyphen in the data filename.

About highlight, that would work but how about his case? I can’t use a shortcode here, as far as I can tell

    {{ highlight `
    <script src="{{ .Site.Params.cdn.jquery }}" integrity="{{ .Site.Params.cdn.jquery_hash }}" crossorigin="anonymous"></script>
    <script src="{{ .Site.Params.cdn.popper }}" integrity="{{ .Site.Params.cdn.popper_hash }}" crossorigin="anonymous"></script>
    <script src="{{ .Site.Params.cdn.js }}" integrity="{{ .Site.Params.cdn.js_hash }}" crossorigin="anonymous"></script>
    ` "html" "" }}

BTW there are a few issues I’m hitting.

  1. this isn’t rendered as HTML, see the preview (scroll down a bit, after the example)
  2. I’m seeing random p tags when raw HTML is used in content. For example in https://deploy-preview-28014--twbs-bootstrap4.netlify.com/docs/4.2/getting-started/introduction/#js around the details tag