If you like my work, please consider supporting its development.

This release of Midnight, I’ve focused on making generated sites faster and more secure, as well as fixing a couple bugs and extending a feature or two.

Server Configurations

A large part of the work in this release revolves around Midnight’s ability to create server configuration files. These files are generated based on options in the site’s configuration file.

Midnight is currently able to generate configurations for Nginx and Netlify. Support for Apache/httpd and .htaccess files will come later, as I have not worked with them before and it will take some time to write a good template for those.

Faster Loading

A lot of time was spent on optimizing page load times. This is in part because search engines like Google will penalize sites that load too slowly in their search results. Also because there were some issues with visitors seeing a “Flash of Unstyled Content” (FOUC) when visiting a site using Midnight.

(A)synchronous CSS

As it turns out, sites built with Midnight load faster when CSS files are loaded synchronously, rather than asynchronously. For the non-browser-developers out there, when web browsers load a page, they typically parse the HTML sequentially and stop at every reference to a script or style file, wait for it to download, parse, and continue. Google and others recommend loading only the most important resources this way, and tell the browser to load everything else after the page has loaded.

I had done my best to implement this recommendation, yet in tests I did comparing page speed with things loading asynchronously versus everything loading synchronously, I found that pages loaded faster with everything synchronous - on HTTP/1.1 and HTTP/2.

It’s possible that I implemented it incorrectly, so in future releases I will be looking at doing a better way of loading files asynchronously by default.

Midnight still has the ability to load CSS asynchronously, so plugin developers may make use of that feature still. I recommend doing some tests to see if asynchronous loading actually gives speed benefits, though.

HTTP/2 Server Push

The last version of Midnight included support for bundling CSS into one file for HTTP/1.1 or keeping them separate for HTTP/2. This release builds on top of that by generating entries in the server configuration files to indicate which files should be pushed and, if possible, only push them on the first visit to the site.

Adding pushed files to the server configurations means site administrators don’t have to update server configurations every time a change is made to the site, when Hugo uses a different hash in the file’s name. Just copy the file to the right spot, and you’re done.

Currently only Nginx supports pushing only on first connection, as it sets a cookie in the client’s browser and pushes if the cookie is not found. Netlify does not currently have the ability to do this and, based on my email correspondence with Netlify support, will probably not be supported by Netlify in the future.

I intend on using the cookie - or another - method with Apache Httpd and Caddy in the future, as those servers gain support in Midnight. I am not very familiar with either of them, so I’m not sure if it is possible, but I will try.

Automatic JPEG Quality

To help with page loading speeds, Midnight “resizes” all JPEG image assets to their original size, which triggers Hugo’s image quality conversion. By default, Hugo converts JPEGs to use 75100 quality, which provides the best compression on average, without noticeably affecting the image.

To change the default compression amount, modify the image processing settings for Hugo to the desired default.

Caching Files

The JavaScript file loaded from Iubenda for the cookie banner by default just added a <script> tag to the page for the actual JavaScript file. Midnight now references that file directly, which allows the file to be cached by the browser.

Better Security

In this release, Midnight includes some default security improvements.

Content Security Policy

As part of the generated server configurations, Midnight generates a Content Security Policy for a site, depending on which options and plugins are installed. The generated policy:

  • Prevents scripts from connecting to random domains (using a whitelist).
  • Allows fonts only from Font Awesome and the generated site.
  • Disallows iframes from random domains - by default, only the generated site, Iubenda (if enabled), and Google (if Recaptcha is enabled on Netlify forms).
  • Images are only allowed from the generated site and https URLs.
  • Scripts are only allowed from the generated site, Iubenda (if enabled), and Google (if Recaptcha is enabled on Netlify forms).
  • Styles are only allowed from the generated site, Font Awesome, and Iubenda, if enabled.

All of the above rules also include any sources configured for plugins, to help ensure that they load correctly. If you have authored your own plugin for Midnight, check the CSP documentation for plugins for how to ensure your plugin loads correctly.

This security policy will especially help on sites with comments enabled, so that malicious commenters can’t load harmful scripts on a page, even if they somehow trick the commenting system into embedding the script on the page.

The one caveat to that is when pages require 'unsafe-inline', since attackers could inline the script into their comment instead of linking to an external file. Iubenda requires 'unsafe-inline' to be enabled when using the policy buttons, as the script modifies the <body> to include an onload attribute. I have contacted Iubenda about modifying the script to use addEventListener instead, which will allow me to remove the 'unsafe-inline' rule completely.

I have also removed all other inlined JavaScript from the HTML templates and placed the code inside JavaScript assets that are referenced as templates, so site-specific information can be loaded inside them. This means that Midnight itself no longer includes inlined JavaScript on the page.

Iubenda’s cookie consent banner, by default, registers the consent cookie to the path /. For sites with a BaseURL including a subdirectory path, that consent path is now set to that of the BaseURL. So if a site is under https://example.com/my-site, the consent cookie is registered to /my-site.

This prevents other sites under https://example.com from accessing or modifying the consent cookie, which is unlikely but could potentially happen.

Recognizing Multiple Authors

A user on GitLab noticed that, though BluestNight (now Midnight) supported multiple authors, it did not indicate who wrote the articles on list pages. The issue tracker on GitLab has been closed and replaced with a link to the tracker on Gitea, where the issue was recreated.

The feature has since been added and is automatically enabled if Midnight detects more than one author configured on the site.

A Step Toward Multilingual

GitLab user ttaeschn created a merge request on the old BluestNight theme to add a German translation. Due to the move to Gitea and the rename to Midnight, I manually merged the new translation into Midnight.

Thanks to ttaeschn for the work in creating that translation! If there are any users of Midnight who want to help with translating the theme, create an issue on Gitea with the new translation and I’ll get it merged.

Improvements to Iubenda

Midnight’s Iubenda integration now supports Iubenda’s cookie policy, which can be generated alongside the privacy policy.

Due to some confusion between Iubenda’s cookie products, namely that the cookie policy and cookie consent banner are not the same, a breaking change has been made in Iubenda’s integration. The option params.iubenda.pro.enable_cookie_policy has been renamed to params.iubenda.pro.enable_cookie_banner, as that’s what it actually does. An option params.iubenda.enable_cookie_policy has been added (noticed the lack of pro in that configuration) that enables a cookie policy button in the site footer.

Other Changes/Bug Fixes

  • Fixed some BluestNight -> Midnight renaming things I missed on last release.
  • Added some spacing to areas that needed it.
  • Moved nebula-form shortcode’s confirmation box to above the submit button to fix some visitors not seeing it because it went below the fold.
  • Fixed broken links on the 404 page when using relative by forcing root-relative on that page.
  • Removed some other references to the events feature that was removed.
  • Replaced some uses of Scratch with variable reassignment.
  • Updated README.
  • Fixed form styles.
  • Fixed the _paq is not defined error getting logged to console.