I recently completed a pretty fun little website[1] for the U.S. freight rail industry using Hugo, Vue.js, Nuxt, Vuetify, Chart.js and Netlify. It is open source on GitHub[2].
It will soon replace an aging version of the site[3] that was built with Sitecore CMS, .NET, and SQL Server.
At first I considered using Hugo to generate the HTML for the site from git-backed JSON/YAML/TOML files. But the quantity and complexity of the Golang templates was clearly going to be tedious, inflexible, and tough to maintain.
So I settled on using Hugo to generate a read-only REST API instead[4], based on a nice blog post I had read[5][6].
This freed me to use any front-end framework I wished, and I chose Vue, Vuetify, and Axios for their simplicity and productivity on this solo-developer project.
In the end I was quite happy with this combination. Hugo was incredibly fast and productive for ranging over and manipulating all of the JSON/YAML/TOML data files to produce the final read-only REST API JSON... after the initial learning curve with Golang templates.
And the front-end really just boiled down to some key Lodash transformations of the JSON into the various shapes of data that were needed for tabular reports and Chart.js graphs.
Pretty sure you have conflated the abilities of the half dozen frontend frameworks you added (for simplicity) with the the backend you replaced. ".Net" (not actually a specific backend) and an rdbms are not in any significant way a friction against a REST api.
Mean while the only noticable difference between the sites is the front end.
My comment above was intended to add some value and perspective on using Hugo in a real world business/industry/paying customer website scenario... something beyond a personal blog.
So RE: the main discussion here about Jekyll and Hugo and static site generators (SSGs), I think that if you take a moment to consider the difference between the SSG/JAMstack approach vs. the traditional "build the response on every request" back-end approach (and I'm not picking on .NET and SQL Server there, I've developed many sites using them myself) you'll see that there are some huge differences[1].
I think the most important difference is that with SSGs and JAMstack, your back-end code only runs at build time, on free build server infrastructure. There is no runtime back-end code, and therefore you can operate these JAMstack sites, at scale, at zero or near-zero operating cost. In the case of my customer, I estimate I saved them $100K over the life of this new site. Of course, your use-case must align with this sort of architecture. Not every site can or should be totally re-generated when content is changed.
And importantly for my customer, they did not have to sacrifice a nice, user-friendly content-management experience. I happen to be using Netlify CMS, but others like Contentful and Forestry are nice options too[2].
We’ve mostly lost track of our ability to talk about things of technical interest on the front end. It’s common to see framework soup (though OP explained themselves well in their response). I have to put headphones on when junior engineers talk JavaScript tech, it makes me too angry/amused and they probably should be talking about it anyway since it will help their careers if they pick the right ones.
Sadly a similar thing has happened to programming languages, we use languages just for their libraries. The language itself must be treated as an empty vessel for the ML/Numeric/Web/Physics whatever it is you need. Or programmers you need to hire. This bothers me but is the purpose of our industry, to minimize construction time through reuse.
You shouldn't rely on third-party fonts (some people like me block those) for your graphical design. This is how that page looks in my Chrome: https://i.imgur.com/y03EQBc.png (using uBlock Origin with Fanboy's Anti-thirdparty Fonts blocking list: https://www.fanboy.co.nz/fanboy-antifonts.txt). At least host those fonts yourself.
I understand that you and some others may block 3rd party fonts, but the percentage of people that do this has to be tiny, no? I’d venture it’s around the amount that block all JavaScript.
Sure you should have your sites work without JavaScript and probably host all your fonts. I personally do that usually, but from a building standpoint, I’m assuming 3rd party fonts or forcing JavaScript for a normal site is going to be fine for more than 95% of your users.
It's not really a question of how many people are savvy enough to protect themselves from 3rd-party data collection.
I don't know how you feel about the GDPR (or the data brokerage industry, in general), but if web developers want to minimize government regulations we should probably architect our sites so as to minimize 3rd-party data collection of PII in the first place (which is enabled by including 3rd-party fonts).
I'm a big fan of serving content APIs as static assets like you are doing here. Especially good for content which changes infrequently (a few times a day rather than many times a minute).
Static site generators typically make it simple to publish a structured data view like a JSON or XML feed of content alongside content pages as HTML (such a bonus!), but it is interesting to see that you've separated the API generation entirely as a Hugo build. (presumably for compile speed?)
I work at Netlify and am something of a JAMstack enthusiast. I'd love to learn more about the experience of designing and building this. If you'd be interested in doing more of a write up, or just sharing any of the learnings from along the way, I'd love to chat.
Good question! Sorry to be kind of cryptic there in the interest of brevity.
Lodash is sort of a query language for data in JavaScript. The name is a play on Underscore, the name of a rival implementation. So Lodash is literally a "lowered dash character"... i.e., an underscore.
Anyway, here's an example in the code for the website I mentioned above[1].
In this example, Lodash is wrapping a JavaScript array of objects named "rows", filtering out just the "keys" in the objects, further filtering down to only the ones that are numeric, and then mapping those to an array of strings that are properly-formatted dates.
The original array came from Hugo-generated JSON exposed as a read-only REST API[2]
We switched the Let's Encrypt website from Jekyll to Hugo. We did it primarily for i18n support (Jekyll does not support translation), but it would have been worth it just to avoid Jekyll's ruby dependency nightmare. Hugo is a single static binary, so simple.
I built the actix.rs website with hugo and while I generally like it it has some bizarre things that make development harder than necessary. Sometimes it randomly refuses to build pages that worked before, until you realize it has something to do with it now picking up other templates. But no error message.
And that you can't shell out to helper scripts makes it very restricted in so many aspects. I wanted to extract source examples from other code and preprocess it and the only way I could make it work was some really ugly go template code and that didn't even let me implement everything I want since they are so restrictive :(
I really wish one could shell out to an executable to fill the gaps.
Thank you! The LE site is terrific (as is LE itself). Because it is open-source, I essentially cloned it for a professional association. https://casinoanalytics.org
Credit to LE is on the FAQ page. Thanks again.
And it is full of implicit stuff, cryptic templates, and the whole thing is pretty unintuitive. You also cant write plugins for it. Jekyll has i18n support I dont know what you are talking about.
I don't see myself moving from Jekyll for a long time.
And it's mainly because of Jekyll-Assets. It's just too useful for not only bundling assets but effortlessly md5 tagging everything for caching on the nginx side of things.
Hugo and others have nothing like this, and rolling your own set up isn't feasible for that because for it to be done right, it needs to be supported at the generator / plugin level so your template helpers know how to deal with looking things up from the untagged file name.
My site has about 170 blog posts and dozens of other pages and Jekyll's incremental reloader refreshes in a little over 2 seconds. That's about 1 second longer than I'd like to see a blog post get live reloaded in development, but it's good enough.
An asset pipeline (and templatized at that) is being added to Hugo as we speak. Just Sass support to begin with but more later. Once that’s added the reasons to use Jekyll, which is essentially abandonware, will shrink to zero.
md5 tagging at the Hugo level has been talked about since 2014 and it's still no where on the horizon. If SASS support still isn't out yet, who knows how long "later" is.
> Once that’s added the reasons to use Jekyll, which is essentially abandonware, will shrink to zero.
They are working hard on Jekyll 4.x and huge sites like Docker's documentation[0] use Jekyll. I'd still feel comfortable using it today.
It really comes down to preference IMO. Jekyll is more than adequate to use for a blog or large site. If you like liquid's template engine and enjoy having the ability to write plugins in Ruby then it's a good match.
> md5 tagging at the Hugo level has been talked about since 2014 and it's still no where on the horizon. If SASS support still isn't out yet, who knows how long "later" is.
As someone who follows Hugo development closely, I wouldn't be surprised if both md5 tagging (fingerprinting) and sass support is out in the next week :)
If you have a CDN or Varnish, they can provide eTags, and you don't need an md5 in the URL, except to save the browser from doing a GET request and getting a 304 Not Modified. A few Not Modified requests served by a fast server is worth the tradeoff of not having to deal with an asset pipeline, or worse, overly aggressive caching, which is common in asset pipeline environments where the cache settings designed for md5 tagged assets inevitably get applied to non-tagged assets.
That would cause issues when deploying new versions. Even if the CDN or Varnish serves an updated etag, the browsers could potentially keep using an older version from its cache. Not what you want when you just fixed important bugs. This has happened to me, even without aggressive caching.
I suspect that even if you told the browser to revalidate on each request, you would end up in situations where the browser ignores it or is overruled by a corporate proxy.
With a md5 in the URL, the browser would be forced to make a new request.
I've seen that happen, but I've seen people reset their browser caches because of misconfigured aggressive caching much more often.
IMO max-age=0, must-revalidate is a much better choice for the average website/blog owner.
For complex apps, setting up the asset pipeline can be worth the tradeoff. But Hugo is hardly a lower tier static site generator for not supporting this.
You can't shoot yourself in the foot with the md5 tagging approach. It completely solves cache invalidation in a simple way. That's why it's so popular.
When the content of your file changes you get a completely new file which has no cache headers associated to it. Then nginx caches the file forever, and when you make a change, a new file is created and the process repeats but if you don't make a change, then the same file is served from the user's local cache.
I'm curious about this too considering GitHub uses it for GitHub pages, I would assume they have a vested interest in maintaining Jekyll even if they had to fork it to improve upon it.
Having few assets is better than having a fancy asset pipeline. https://www.gatsbyjs.org/ supports code splitting and since it uses JavaScript, CSS generation libraries like styled-components, Glamourous, and JSS are available. That means only outputting the CSS and JS that are needed for the page. This is great for blogs where someone might only read one article. The Hugo community is working toward minimal assets too.
> Having few assets is better than having a fancy asset pipeline.
It's not about a fancy asset pipeline.
It's taking app.css and turning it into app.a5fec617.css so that you can configure your web server to cache it forever. It's important to do this for CSS, JS and all of your images and other assets. Each blog post of mine has a cover image and with 170 blog posts, that's 170 blog images that need to be md5 tagged.
The asset pipeline (transforming SASS into CSS and minifying everything) is just a nice convenience.
It's also nice to be able to just write {% asset foo.jpg %} and end up with <img src="images/foo.34fbc1e9.jpg" width="256" height="256" alt="foo" /> in the HTML. Never having to manually set a height/width or alt tag (unless I want to manually override it) saves a lot of time.
Without md5 tagging but with a reasonably configured web server, the browser gets an eTag in the response headers to the first request to load that cover image, and sends it in the headers to the second request and gets a 304 Not Modified response with an empty body. The size of the cover image is completely moot when comparing a proper Hugo config vs a proper asset pipeline config.
The main advantage of a hash is that browsers will download the new version of your CSS/JS on the next page view, while still caching it «forever»
If the url stays the same, you never know what version your visitors will get. You might publish a new version, but the user would not see it due to browser caches or proxies.
Caching something forever just doesn't impress me at all, it did when I first heard about the rails pipeline, but what matters to me more is that it's cached through a proxy or CDN, and that eTags prevent large files containing the exact same bytes from being sent repeatedly to the same client.
It impresses me as a user though since ETag still incurs a round trip while "forever" expiration doesn't. There's a night and day difference between ETags and no HTTP request at all.
You are likely complacent because you're always on a good connection, since you keep arguing in these comments (even farther down) as if conditional GET requests obsolete other forms of caching.
The real benefit of ETags is that they generalize over all content dynamically, but they come at the cost of incurring more requests than expiration caching. I don't see how you could keep arguing here unless you didn't understand that trade-off.
Another thing to remember: browsers don't fire up unlimited requests, usually you have 6-8 pipes to get your assets through. Even simple if-modified-since will still take space in them, while "eternal caching" will leave them free, i.e. no request will be made.
> rolling your own set up isn't feasible for that because for it to be done right
I do cache-busting > hugo > minification using a simple bash wrapper script. Though, in the coming week, Hugo might natively start supporting the cache busting and minification.
I like the speed and flexibility of Hugo. It doesn't force you into the blog format like Jekyll does. Jekyll has collections but collections don't have all the features of posts. I keep coming back to Jekyll because of the relative link support that works across VS Code, Github, and Jekyll. Hugo added support then removed it.
I'm in the process of creating a new blog and site (I have python, vue, nuxt background) which maybe will have more non technical authors and dynamic content in the future and after many iterations (looking deeply at Hugo, Lektor, Forestry and even Wordpress [headless]) I will probably go to a
open source headless CMS Strapi https://strapi.io and Nuxt.js frontend.
If anybody knows a python and flask based headless CMS let me know!
Not Flask, but still Python: Wagtail - https://github.com/wagtail/wagtail - is a popular headless CMS option. Michael Harrison from rice.edu / Openstax gave a great talk about this at last week's Wagtail Space:
big thanks. Actually I worked for Openstax (Connexions) in the past but I think I did not met Michael Harrison at my time :)) I will definitely give it a testrun!
I have an interesting Jekyll performance story. I was trying to build a website [1] that was going to be the new destination for git information. The site is a static site and I figured that since Jekyll was integrated into GitHub, it would be simple. My script downloaded all of the git documentation from the linux kernel website, did some parsing of the HTML files adding front matter, and then tried to generate the site.
My Jekyll(Ruby) script was running over a day and never finished. Hugo(Go) ran in about 5 minutes. Granted there are over 10,000 pages being generated by Jekyll but it was so painfully slow, I couldn't possibly have a daily CI system that generated the site.
I'm still fixing some https issues with GitHub static site hosting, but it should be working soon.
Speaking as a newbie (python and R mostly) who just wants the blogging software to blog, I use Jekyll because it’s the default choice. Yes there are python options but I don’t want to program the software - my programming energy is already spoken for.
I don’t care about the speed differential.
However if Hugo is actually easier somehow, well that would be tempting.
It is significantly easier to setup because (in typical Go style) only requires you to download and install a single fat binary. You do not need to do what you're otherwise doing with the likes of Jekyll which involve a significant Ruby environment alongside to function.
I've been using it for over two years, and this is the thing I like most about it.
as someone with relatively rudimentary skills who tried and failed two or three times to get jekyll working on a throwaway vps, hugo is indeed very, very easy.
I really like Hugo and use it for one of my websites. It is refreshing to get such a fast website.
Where I find Hugo lacking though is I have found it very difficult to theme. Hugo has a very particular way of doing things with sections, sub-sections, leaf nodes and branch nodes, and a very particular folder structure where having an index.md file does one thing, but an _index.md file means something totally different. This would be fine if the docs were extensive and explained this clearly but they are very light in this area and most knowledge seems to be burried in individual disqus posts and other people's heads. I am sure it makes sense to people already familiar to Hugo, but trying to grok it all as a new-comer has been difficult.
As a result working out how to do even trivial things such as listings of pages in grandchild-directories, or even just having a list of child pages with other textual content has been a terrible struggle for me. Existing themes are invariably horrendously out of date, so trying to learn from those is also difficult. To this day on my site, if you go to specific directory paths there is literally a blank page because for the life of me I cannot work out how to make Hugo display just a simple list of posts in grandchild directories. It is infuriating! Perhaps it is my fault for wanting a semantic directory structure (e.g. domain.com/subject1/subject2/actualContentInHere/ and the pages for subject1/ and subject2/ are literally blank).
TL;Dr - good but if you want to do more than CSS tweaks on an existing theme then you're in for a challenge.
I second this. I built my own template from scratch and even though my layout structure is quite simple it consumed a lot of time to find out how where to put files in order to make things happen. I agree that better documentation would have helped, but it would be also great if Hugo was more (explicitly) configurable instead of purely relying on conventions.
(Once setup though, I continue to enjoy Hugo – it’s fast and mostly stays out of one’s way.)
Few months ago, I migrated to Hugo after several years on Jekyll, and I'm so glad I did. While Hugo does have many flaws, I love it for its simplicity, which is also the reason why I chose static website generation over Wordpress or CMS.
I still like Jekyll and I might use it for blogs that has more complex requirements for building the site. However, my blog is simple and I just wanted to generate my site quickly (and boy is it quick). Also using the template was very easy, and I was able to migrate my Jekyll theme to Hugo without too much trouble.
We’re running our blog on Jekyll. Is there any good reason to migrate to Hugo? In the article I’ve found this comment:
Hugo’s key differentiators: 1. Ease of install 2. Speed (critical for large sites) 3. Integrated live-reload while editing in near realtime 4. Multilingual capabilities 5. Flexible 6. Very strong community 7. Very good & comprehensive documentation (but not perfect…yet)
Other than 3., all other points are valid for Jekyll as well. So why move, other than for the sake of just migrating (which can be fun too...)?
Hugo is a fantastic tool and I would choose it again. However there is a little annoying bug for years: If you let Hugo create a table of contents it adds an unnecessary level of nesting, if the highest level of content headings is h2. This is pretty common if you use h1 for the page title (that shouldn't be repeated in the table of contents).
But besides that Hugo is a feature rich, fast and easy to install tool.
I don't know if this is the same issue, but there is a workaround in https://github.com/gohugoio/hugo/issues/1778. The TOC had been driving me crazy, and I had just learned to live with it for now, but I think the workaround can address some of the issue.
I've used pretty much every product out there for static site generation, and I gave up.
So I created [0] Statik.
I dont mind manually building out the mardown/razor/etc. In the end, I get exactly what I want, with no overhead or heavy abstractions weghing me down.
I believe there's a python static webpage generator that's been around for a while that already makes use of that name: https://github.com/thanethomson/statik
I'm surprised nobody mentioned Hakyll [1] here - a great Jekyll alternative that's fast(ish) and supports hot-reloading. You do have to like / tolerate Haskell though (this polarises opinion pretty fast...)
I agree to most of your points. I too recently moved from jekyll to Hugo and I know I did not make a bad choice. It is awesome and making me to write more. Hosted on github pages.
https://www.rammy.in
To be more precise, we support any static site generator, as we will serve any static content that you make available. So you can even use GitLab pages to e.g. display and easily share test output, documentation, or anything else.
If you use reactjs based frameworks, you get the same amount of upfront effort as Hugo. It's not harder. However build times are slower.
But as your website complexity increases, you can leverage the reactjs ecosystem (both people and libraries).
In Hugo, you get locked to their templating system. Which is nice...but very non standard and relatively non-Googleable.
I ended up with a hybrid approach where Hugo and Golang templates are only for building the data (TOML files) into the required JSON for a read-only REST API. The remainder of the solution is all JavaScript (in my case Vue and Nuxt instead of React and Next).
I came very close to switching to Gatsby early on, and I am very curious to know how my project[1] would have gone with Gatsby instead of Hugo.
I get the impression that for the data manipulation (avoiding complex Golang templates that generate HTML) and for build speed, Hugo takes it. Certainly if you are working in React the simplicity of a single framework is the way to go, as you did.
I also kind of felt a little more weird about mixing Gatsby and React with my preferred front-end framework, Vue, than I did about having to combine Golang template logic in one layer (API) with JavaScript in another layer (App).
> Since you are going to spend a huge amount of time writing js code for the front-end anyways...
My general goal in using an SSG is to have a static site. HTML and CSS. Maybe some images, of course. But I typically don’t reach for an SSG if I’m building something that requires a huge amount of time writing JS code. The goal is to have zero JS and zero backend. I know others may not care to create the smallest, fastest pages they can, but if I need a bunch of JS, that strikes me as the opposite of a static site.
I think you are reading too much into what "JS based" means. You will end up writing the exact same amount of mark-up in Gatsby or Hugo - except that one is in JS (ES6) versus Golang based templates.
The amount of JavaScript is not "huger" and Hugo does not make it zero markup. The only difference is that you get to leverage the react ecosystem which is far far bigger ... And it is easier for a dev (who probably already knows React) to pickup Gatsby versus Hugo.
You are in the exact same webpack, js, npm ecosystem as a vanilla react site.
If you have a fundamental distaste for js..that is a whole different matter altogether.
Yeah, everything you’re saying just invokes my fundamental distaste for the JS ecosystem. Hugo is fantastic for its utter lack of any sort of environment requirements. Requiring webpack, npm, React, and any dependencies else at all is a complete turnoff. Hugo’s Go-based templating isn’t difficult to pick up (I use it and extend it and I’ve never actually read any of the docs outside of one place I wanted to check on loop-based variables). Of course, I’ve been using various templating languages for over a decade, so I can pretty much see some examples and relatively immediately intuit how it works with little effort. For me, having to invoke npm is a non-starter for SSG work. I reach for an SSG because I don’t want any JS at all—or a very minor, controlled amount of it. To be fair, I feel the same toward just about any other SSG—if a person must setup an environment to use the tool, the SSG is doing it wrong.
I went this way too. If your site has a dynamic/interactive frontend, Gatsby makes it super easy to build a static-but-interactive site. Another huge plus with Gatsby is that it uses React's server-side-rendering to ensure that the site is still seo-friendly.
If you have more than a few snippets of JS on your site, Hugo comes up way short. It's great for simple things though.
Aaaaaand this is why I don't jump on the latest frameworks anymore... I can almost hold my breath long enough for a framework to go out of style.
The first time I read about Jekyll was here, and now already something better has come along, my brain just gave me that tiny little mental high-five on my decision to no longer live on the bleeding edge
I thought I would also end up just being one of those (I had a sort of setting-up the blog using Hugo post too). But lately my blogging on many other topics that I'm really passionate about has picked up.
Writing in Org mode has really reduced the writing block for me. I'm so glad I switched from Octopress to Hugo about maybe 2 years back.
No, I got into developing an Emacs package that exports Org mode to Hugo-friendly Markdown - ox-hugo. Here's the package homepage created using Emacs/Org mode + ox-hugo + Hugo: https://ox-hugo.scripter.co/.
I found the existing static site generators confusing and wrote my own, which ended up being equally confusing for everyone except me. Whatever works, I guess. https://github.com/sidmani/anodize
I still use bleeding edge PHP with articles written in XML originally implemented in 2001, it works no need to change, only occasional template or PHP related improvements.
I see these articles come up quite often yet it makes no sense to switch to hugo. I also tried it because I was fed up with Ruby (not Jekyll). It turns out that the tedium of implicit hell and cryptic templates which comes with hugo makes it much worse than the occasional bumps with upgrading Jekyll. Hugo is like choosing Scala (which is a baroque abomination of implicit stuff) over Kotlin (which is a pragmatic language). I think the problem here is bias. When you are fed up with something you tend to see everything else through rose colored glasses. See hugo for what it is: a tedious, cryptic unintuitive and dumb static site engine.
It will soon replace an aging version of the site[3] that was built with Sitecore CMS, .NET, and SQL Server.
At first I considered using Hugo to generate the HTML for the site from git-backed JSON/YAML/TOML files. But the quantity and complexity of the Golang templates was clearly going to be tedious, inflexible, and tough to maintain.
So I settled on using Hugo to generate a read-only REST API instead[4], based on a nice blog post I had read[5][6].
This freed me to use any front-end framework I wished, and I chose Vue, Vuetify, and Axios for their simplicity and productivity on this solo-developer project.
In the end I was quite happy with this combination. Hugo was incredibly fast and productive for ranging over and manipulating all of the JSON/YAML/TOML data files to produce the final read-only REST API JSON... after the initial learning curve with Golang templates.
And the front-end really just boiled down to some key Lodash transformations of the JSON into the various shapes of data that were needed for tabular reports and Chart.js graphs.
[1] https://app.rrpm.run/ [2] https://github.com/railroadpm/site [3] http://www.railroadpm.org/ [4] https://api.rrpm.run/reports/bnsf/all [5] https://discourse.gohugo.io/t/build-a-json-api-with-hugos-cu... [6] https://forestry.io/blog/build-a-json-api-with-hugo/