The future of Lume

by Óscar Otero

9 min read

As you may know, Deno is sunsetting after being acquired by Cloudflare. This is not a big surprise if we look at the company's activity in the latest months. For some time now, I suspected that Deno wouldn't last long, and I began preparing Lume for whatever might happen. I created the FAQ page explaining what to do if Deno disappears and started making changes in the architecture to make Lume easier to port to other runtimes.

What I didn't expect is the abandonment of the runtime (it will be maintained for just one year). I always assumed that once the company shut down, the software would be maintained by the community or an open source organization. There are indeed some movements in the community to fork the project, and now it even looks like Bartek (Deno's co-creator) is working on getting Deno into a foundation, but there is no certainty about anything.

I can't wait a year to know the future of Deno; I want a stable, boring, and reliable foundation, that's why I decided to port Lume to Node and release it as Lume 4.

TL/DR

Take a look to the migration guide in the Lume documentation and learn how to use the automatic migration tool.

The losses

HTTP imports are probably the most missed feature. This allowed you to import Lume using a single URL that just works, no matter if the URL is to a stable release, a development version using the commit hash, or a local version using the file:// protocol. Unfortunately, Node doesn't support that, so I published Lume on NPM.

Another Deno feature that I will miss is the ability to download only the imported modules. This is not possible with NPM packages, because the entire package and dependencies need to be downloaded before running, even files that you don't need. In order to avoid installing a single package with all plugins and hundreds of megabytes of dependencies, I had to split Lume into several packages.

The new Lume repository is a monorepo. Compared with HTTP imports, this introduces way more complexity and makes it difficult to test development versions with real websites. At least I'm using PNPM to manage all the stuff, which is proving very useful.

Since Lume is not a single package anymore, it doesn't make sense to continue creating big releases dedicated to certain notable Galician figures 😢. Until now, every new version of Lume introduced new plugins or features contained in the same release. Now these changes are spread across a whole bunch of packages (+70 so far), each one with its own independent release pace.

The wins

The first benefit is stability and peace of mind. Node is not a VC company or a startup that needs to play the Silicon Valley game. This change ensures the long-term survival of Lume, which is the most important thing, after all.

Another good side effect is the simplification of some plugins. The way in which Deno resolves dependencies is more complicated than Node, with three systems that behave differently: HTTP, JSR, and NPM. Some plugins, like esbuild, required a lot more code to make all three dependency resolution systems work identically. Now these plugins are simplified, since we only need to support the node_modules folder.

An unexpected benefit of having a node_modules folder with all dependencies downloaded is that it's easier to scan and copy their assets (for instance, CSS files with the themes for Prism or Highlight.js).

The NPM org

Lume is available on NPM under the @lumeland organization. The main package is @lumeland/lume and every plugin has the format name @lumeland/plugin-[name].

Official themes are published on NPM with the format name @lumeland/theme-[name]. For example, the Simple Blog theme is @lumeland/theme-simple-blog.

There's also a create-lume package that allows you to set up a new Lume site in seconds with the command npm create lume. Or install a theme with npm create lume -- --theme=@lumeland/theme-simple-blog.

All dependencies are hosted on NPM. I removed the JSR dependencies to avoid problems with some package managers not supporting it by default. Even Deno's std library was ported to NPM so it can be installed without any special configuration.

The minimum Node version is Node 24 LTS. Thanks to its native support for TypeScript, you don't need to change much of your existing Deno project, you only need to replace deno.json with package.json and change the _config.ts file with the new specifiers:

// Lume 3 (Deno): `deno task serve`
import lume from "lume/mod.ts";
import basePath from "lume/plugins/base_path.ts";

const site = lume();

site.use(basePath());

export default site;
// Lume 4 (Node): `npm run serve`
import lume from "@lumeland/lume";
import basePath from "@lumeland/plugin-base-path";

const site = lume();

site.use(basePath());

export default site;

Not ported plugins

With this new major version, all existing plugins have been migrated to Node, except the following:

  • attributes: It was one of the first Lume plugins, created before Vento existed to mitigate the cumbersome task of generating HTML attributes in Nunjucks using variables. The plugin is too specific, and if anyone needs something like this, it's easy to create a filter in the _config.ts file or install one of the many options available on NPM.
  • fff: A plugin to use fff to transform the frontmatter. Since the package hasn't been updated in two years and the plugin usage is low, I decided not to port it.
  • relations: I created this plugin for a specific project, and I thought it could be useful for other people. It's too complex and hard to configure correctly, and I don't think many people are using it.
  • decap-cms: Lume already has a CMS integrated, so maybe DecapCMS is not so useful. I got some warnings because some of its dependencies are deprecated, so I decided not to port it for now (but it could be added in the future if it's still useful).

Lume CMS

The CMS has been ported to NPM too. The GitHub adapter is not included because it will be moved into a different package (@lumeland/cms-github) to avoid downloading its dependencies when they are not needed.

In Lume 4 the CMS is not detected automatically if the _cms.ts file exists. This was a nice convenience in the Deno version, thanks to HTTP imports that allow loading packages on demand. In the Node version, the CMS must be installed like any other plugin and requires two dependencies: @lumeland/cms which is the CMS, and @lumeland/plugin-cms which is the plugin to integrate with Lume:

// _cms.ts
import createCms from "@lumeland/cms";

const cms = createCms();

// Configure the CMS here

export default cms;
// _config.ts
import lume from "@lumeland/lume";
import lumeCms from "@lumeland/plugin-cms";
import cms from "./_cms.ts";

const site = lume();

site.use(lumeCms({ cms }));

export default site;

Other changes

With this migration, there are some other changes to consider:

  • Node doesn't support the Web Cache API. On Deno, Lume used it to cache all remote files. Now these requests are cached in the _cache folder. I think this is even better because now all caches are stored in a single place.
  • The Pagefind plugin has changed to use the new UI, based on Web components.
  • The option watcher.includes was removed, since Node doesn't allow setting different paths in the same watcher.
  • site.remoteFile() was removed. Use site.remote().
  • The option includes was removed from Lume options and all plugins, so it's no longer possible to set a different _includes folder. My idea, in the future, is to make it work like _components and allow to override files in nested folders.

Take a look to the migration guide for more details about the changes.

Conclusion

Lume has changed so you don't have to change. The same spirit and philosophy, but in a different runtime. And in this case, it's a runtime maintained by a community and governed by a foundation, which offers more tranquility and peace.

That said, I want to thank the Deno team for creating such a great runtime. I did not agree with some of their decisions and the overall direction, but I admit that Node wouldn't have become so good without the inspiration from and competition with Deno. And Lume definitely wouldn't have been born without Deno.

There are some emerging initiatives to fork Deno, or create new runtimes inspired by it. Lume is now easier to port to other runtimes, so once the Node version is stabilized, I'd be happy to experiment with them, as long as they are projects created by the community (not another VC-backed company, please).

And finally, I will leave you with a music video from the Galician Rock Band Dakidarría for the song "Lume". The chorus says "Lume, máis Lume, moito máis Lume" (Lume, more Lume, much more Lume), which is the perfect song to illustrate the present and future of this static site generator.

Thanks for reading, and keep luming!