Lume 2.4.0 - Maruja Mallo

7 min read

Ola πŸ‘‹!

This new version of Lume is dedicated to Maruja Mallo, an extraordinary surrealist painter born in Galicia in 1902 who gained international fame. Learn more about Maruja.

New plugin: check_urls

Broken links are one of the biggest issues on the Web. A recent study detected that 27.6% of the top 10 million sites are dead. And for those sites that are still alive, they are likely to change the URLs at some point, after a redesign or content updates, causing a lot of broken links.

The new plugin check_urls will help you to keep your links healthy, by checking all links in your website (not only to HTML pages but also files like images, JavaScript or CSS). This plugin already existed for some time as experimental plugin thanks to iacore, but it was moved to the main Lume repo and was improved with additional features.

The basic way to use it is like any other plugin. No big surprises here!

import lume from "lume/mod.ts";
import checkUrls from "lume/plugins/check_urls.ts";

const site = lume();
site.use(checkUrls());

export default site;

The default configuration will check all your internal links and warns you when a broken link is found. This plugin is compatible with redirects: when a link to a non-existing page is found, but it redirects to an existing page, the url is valid.

Strict mode

There's a mode for a more strict detection:

site.use(checkUrls({
  strict: true,
}));

In the strict mode the redirects are not allowed, all links must go to the final page. This also affects to the trailing slashes: for example /about-me is invalid but /about-me/ is valid.

External URLs

By default, the plugin only checks internal links. But you can configure it to check links to external domains:

site.use(checkUrls({
  external: true,
}));

Warning

This option can make the build slower, specially if you have many external links, so probably it's a good idea to enable it only occasionally.

Learn more about this plugin in the documentation page.

New plugin: icons

Nowadays, most websites are using icons to a greater or lesser extent. The icons plugin allows to use some of the most popular SVG icon libraries. The installation can't be easier:

import lume from "lume/mod.ts";
import icons from "lume/plugins/icons.ts";

const site = lume();
site.use(icons());

export default site;

To import an icon, just use the icon filter which returns the path of the icon's svg file.

<img src="{{ "acorn" |> icon("phosphor") }}">

Lume will download the "acorn" icon from the popular Phosphor library into /icons/phosphor/acorn.svg (the output folder is configurable) and return the path.

Some icons have different variations that you can configure with the name:variation syntax:

<img src="{{ "acorn:duotone" |> icon("phosphor") }}">

Alternatively, you can set the variation in the second argument of the filter:

<img src="{{ "acorn" |> icon("phosphor", "duotone") }}">

You can use inline plugin to inline the SVG code in the HTML.

<img src="{{ "acorn" |> icon("phosphor") }}" inline>

The icon plugin supports the following icon collections and it's easily extensible with more.

Learn more about this plugin in the documentation page.

New plugin google_fonts

Another common asset used to build sites is webfonts. Google Fonts is a fantastic resource for open source fonts, but loading the fonts from the Google Fonts CDN is not the best option, not only for privacy and GDPR compliance, but also for performance.

The google_fonts plugin downloads the optimized font files from Google fonts automatically into the /fonts directory (configurable) and generates the /fonts.css file (also configurable) with the @font-face declarations.

To use it, just register the plugin passing the sharing URL of your font selection. For example, let's say we want to use Playfair Display:

import lume from "lume/mod.ts";
import googleFonts from "lume/plugins/google_fonts.ts";

const site = lume();

site.use(googleFonts({
  fonts:
    "https://fonts.google.com/share?selection.family=Playfair+Display:ital,wght@0,400..900;1,400..900",
}));

export default site;

It's possible to rename the fonts, useful if you want to change a font without changing the code:

site.use(googleFonts({
  fonts: {
    display: "https://fonts.google.com/share?selection.family=Playfair+Display:ital,wght@0,400..900;1,400..900",
    text: "https://fonts.google.com/share?selection.family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900"
}));

In the example above, the Playfair Display font is renamed to "display" and Roboto to "text", so this allows the use of the fonts in the CSS code with these names:

h1 {
  font-family: display;
}
body {
  font-family: text;
}

Go to the documentation page to learn more about the Google Fonts plugin!

New plugins brotli and gzip

Thanks to Into the V0id for adding these two plugins to Lume. They are useful for compressing text-based files (like HTML, JavaScript, SVG, or CSS files) using the Gzip and Brotli algorithms and output files with the same name but with .gz or .br extensions. For example, in addition to the /index.html page, the plugins generate also /index.html.gz (for Gzip) and /index.html.br (for Brotli).

I think it's not necessary to show how to activate the plugin, but just to demonstrate how predictable and "boring" Lume is:

import lume from "lume/mod.ts";
import brotli from "lume/plugins/brotli.ts";

const site = lume();

site.use(brotli());

export default site;

New precompress middleware

brotli and gzip plugins can be combined with the new precompress middleware if you're using Lume server to serve your static files (for example in Deno Deploy). This middleware checks the Accept-Encoding header and if the browser accepts br or gzip values, it will serve the precompressed file.

import Server from "lume/core/server.ts";
import precompress from "lume/middlewares/precompress.ts";

const server = new Server();

server.use(precompress());

server.start();

Learn more about these plugins in the brotli and gzip documentation pages.

modify_urls supports CSS files

The modify_urls plugin now can search and modify urls in CSS files. This is not important only for this plugin but also for other plugins that use modify_urls under the hood, like base_path and relative_urls.

Example with base_path

base_path is one of Lume's most useful plugins because it adds a prefix to all absolute URLs of your site. This is important if your site is hosted in a subdirectory.

For example, let's say you want to host your blog in the location https://my-site.com/blog/ and you have this HTML code:

<a href="/posts/hello-world/">Hello world</a>

The plugin automatically fixes the URL to add the /blog/ prefix:

<a href="/blog/posts/hello-world/">Hello world</a>

Until now, the plugin only transformed URLs in HTML pages. If your site has this CSS code:

.background {
  background-image: url("/img/bg.png");
}

The background image will fail because the /blog/ prefix is missing. As of Lume 2.4.0, this plugin can transform also CSS files. This option is disabled by default, it requires to configure it in the _config.ts file:

site.use(basePath({
  extensions: [".html", ".css"],
}));

Now not only HTML pages but also CSS files will be processed:

.background {
  background-image: url("/blog/img/bg.png");
}

Important

Keep in mind that Lume only processes files that are loaded. To transform CSS files they must be loaded before. If you're using any styling plugin like postcss, lightningcss, or sass, you don't need to do anything else. But if you are copying the css files with site.copy([".css"]) or site.copy("/styles") they won't be processed. To fix it, you have to use site.loadAssets([".css"]).

Fallbacks for metas and feed plugins

Some plugins like metas and feed allow to define aliases to other variables. For example, if we want to use the variable title inside metas.title:

title: Page title
metas:
  title: =title

As of Lume 1.4, it's possible to define fallbacks to other variables or provide a default variable:

metas:
  title: =title || =header.title || Default title

In this example, the title used in metas is the title variable. If it's not defined, the header.title variable is used. And if it's doesn't exist, the string "Default title" will be used.

Support for author in feed plugin

In addition to fallbacks, the feed plugin has added support for the author name and author URL variables:

site.use(feed({
  output: ["/posts.rss", "/posts.json"],
  query: "type=post",
  info: {
    title: "=site.title",
    description: "=site.description",
    authorName: "=site.author.name",
    authorUrl: "=site.author.url",
  },
  items: {
    title: "=title",
    description: "=excerpt",
    authorName: "=author.name",
    authorUrl: "=author.url",
  },
}));

Other changes

  • Several improvements to esbuild plugin by Into the V0id.
  • Added the new variable fediverse to the metas plugin, to generate the <meta name="fediverse:creator" content="..."> tag added to Mastodon.
  • Fixed some bugs related to Windows support and CJK characters.
  • New option placeholder in the unocss plugin to insert the generated code in a specific place.
  • New option placeholder in the components configuration to insert the generated CSS and JavaScript code in a specific place.
  • Updated all dependencies to their latest version.

And more changes. See the CHANGELOG file for more details.

Happy Luming!