I wrote this website using the GatsbyJS framework back in 2019. Before that I’d been using some simple Sphinx-like templating system to generate simple pages but moved to Gatsby as I’d gotten more into both React and web development. Everything was going great, until last year when Gatsby was acquired by Netlify. Since then, the project has seemingly entirely stagnated. Basically, I no longer have any faith that the Gatsby project is still being maintained so I’m moving away from it as the underlying tech stack for my site.

I took a look at NextJS, but honestly a few aspects of the framework put me off a bit. I really don’t like the direction it’s taking to become significantly more client/server coupled, I like simple static sites that can be hosted anywhere without vendor lock-in. After asking for opinions in a few chats I heard a few recommendations for Vike, the framework formerly known as vite-plugin-ssr. From my understanding it’s basically a fairly thin framework over the top of Vite that provides a proper SSR/SSG environment.

Vike vs Gatsby

Vike does less for you

Coming from Gatsby, Vike was a bit of a major change. As much as I disliked the ways that Gatsby forced you to do things, I did appreciate how much it provided for very little user effort either via built-in functionality or its large number of plugins. Vike on the other hand is a smaller framework, built on top of a smaller build tool. It has less built in, and there are significantly fewer plugins for both the framework and the build tool that it’s powered by.

Once I started to actually port the site over, I started to realise just how many things Gatsby did for me. I ended up writing a custom rollup plugin that output a sitemap using the sitemap package, as well as another plugin to output RSS feeds using the feed package. Arguably these were fairly simple to write, and provided significantly more flexibility than the Gatsby options. I ended up being able to actually call my sitemap sitemap.xml like I’d originally wanted before Gatsby forced it to be sitemap-index.xml, and I got free Atom feed generation on top of RSS. While these were fairly simple, other aspects such as image optimisations and data sourcing were a bit less simple to implement.

Vike is significantly more flexible

I touched on this briefly in the last section, but there were so many places where my website’s design was built around certain hacks to make Gatsby happy. So many complex workarounds to make static queries a less rigid system, or weird hacks to allow both Gatsby optimised images and GIFs to exist within the same component. For everything I had to do myself with Vike, I found myself able to significantly simplify some existing code. I imagine this would be even better for a site written with Vike in mind, rather than one that was mashed until it fit through a Vike-shaped hole.

Vike is faster

This is more useful for anyone trying to chase perfect 100s in Google’s Pagespeed Insights, but Vike is very very fast. It’s significantly leaner on the client, as well as way faster to build. My site used to take around 7 minutes to build on CI, which is pretty concerning for its size. It now takes just under two minutes, most of this time being spent optimising images. The build time feels even faster, given swapping from Gatsby to Vike took the yarn install time from over 5 minutes to around 15 seconds. If you hate having 17 million transitive dependencies, 30% of which have active security alerts, that’s another massive perk of Vike over Gatsby.

In terms of the frontend though, Vike is significantly leaner. There’s less frontend code, and it’s harder to accidentally bloat your site. This is probably pretty marginal for most use cases though to be fair, and systems such as image optimisation are going to matter significantly more than the small savings here. I’m someone who does like to chase those Pagespeed Insight scores though, so it was a consideration for me and in my opinion worth noting.

The image of an elephant in the room

Image optimisation. Honestly if I were to do this again, I would probably use some web service to handle this rather than setting up code to precompile this at build time. Gatsby makes this easy, but significantly complicates your code and balloons out your build times if you enable it. It also impacts a few Pagespeed Insight metrics due to its placeholder system (which honestly, why does this system even recommend formats without progressive loading support, it just encourages placeholder systems). My experience doing this in Vike on the other hand, was significantly more complicated than I expected it to be.

I initially felt like it was pretty simple, I’d built a solution using vite-imagetools’s “as=picture” system… Until I realised my solution only worked for dynamic image imports in dev mode, and didn’t copy the optimised assets to the output folder when running a production build. I eventually found that if I used Vite’s import.meta.glob to do an eager import of all images, then did a map lookup on that output, I could access the correct copied paths in both dev and build mode. This is honestly beyond absolutely awful. Because they’re eagerly imported, every single image is optimised to all the different sizes I use, whether I import it or not. I’m really hoping I did something wrong here, because this feels way worse than it should be. For any images that I knew ahead of time this was simple, as I just imported it normally. It was only the images that were dynamic, such as the headers of blog posts as they are defined in each blog posts’s markdown frontmatter.

In general, I do feel that Vite’s plugin community is a bit lacking in this regard. SSG feels niche enough within Vite that most plugins have trouble supporting it.

Markdown rendering

Markdown rendering was actually something I found significantly simpler than I expected to. You can basically tie together your favourite combination of remark/rehype plugins with unified, and then it just spits out data. Emulating Gatsby’s frontmatter was also extremely easy using the gray-matter package. If anything, I feel more confident in this output than I did with Gatsby’s, and I got to customise it further than Gatsby had allowed me to. The markdown-related packages that Gatsby used were also horrifically outdated, so it feels nice to be able to use modern versions of everything. Gatsby also oddly opted to not use Rehype and instead use a bunch of low level packages to convert the ASTs, of which I’m honestly not sure why. The only part that became problematic was when I tried to optimise the images within blog posts, which led to me writing a custom unified plugin that did the import.meta.glob hack mentioned above.

Conclusion

Honestly despite the above-mentioned pitfalls this project went much smoother than expected. I’m extremely happy with the new site setup, and barring a few bits things I could probably clean up from the migration, it feels significantly cleaner than it used to be. I love being able to use modern packages and ES features, such as the fact that the site is both written in and output as ESM. I do hope the Vike/Vite ecosystem expands more in the future to make some of these aspects more plug and play, but for now it’s still very usable. I would strongly recommend this as a migration path if you’re willing to get your hands dirty and write a lot of it yourself. In general though, a vast majority of the site just worked. Most of the code was entirely untouched, it’s all React after all. Gatsby served my site well, and I’m sad to see the framework die, but Vike does very much feel like stepping into the future when it comes to the JS ecosystem.

About the Author

Maddy Miller

Hi, I'm Maddy Miller, a Senior Software Engineer at Clipchamp at Microsoft. In my spare time I love writing articles, and I also develop the Minecraft mods WorldEdit, WorldGuard, and CraftBook. My opinions are my own and do not represent those of my employer in any capacity.