./fmski

VuePress

I've started with a "website" back in the days that was just a plain HTML page but always wanted to have a blog, mainly to keep in one place things I would always forget after a while and need to Google again and, well, as an extra if some of those posts can help people out there it's always a plus!

My company is actually using Vue.js to develop our different web frontends which surprised me, why not React? Ensued a really interesting conversation mainly around the ease of use of Vue.js vs React and the different open source approach, i.e. community driven vs company driven (the story of Vue.js in video here). I was sold and decided why not kill two birds with one stone and try Vue.js while creating myself a nice little blog. I chose VuePress as most of my content is going to be static. I thought at that time it would be the right choice as this is supported by the people behind Vue.js and didn't even really consider other alternatives. Until now I've also added a talks and an about section.

In this post I want to come back to some of the hurdles I've encountered and how I managed to fix them, keeping in mind that I'm not a web developer and some of those might not even be related directly to VuePress or Vue.js. Hopefully that will help you on your journey as well.

Vue.js, VuePress, default theme, blog plugin, blog theme

My first hurdle was to understand what is going on with all those components and what do I need to build what I want.

Vue.js, a javascript framework, is powering VuePress, a static website generator. This is fine. The problem came up with the distinction between the default theme, which is what you get by default for your VuePress powered website, the @vuepress/plugin-blog which adds blog-like functionalities such as comments, classification, pagination etc... and @vuepress/theme-blog which adds some UI components for the functionalities added by the @vuepress/plugin-blog. The difference between the @vuepress/plugin-blog and @vuepress/theme-blog is explained in the documentation

You must distinguish between the official blog plugin and this theme. Both of them are maintained by VuePress. We try to implement all the common and necessary blog features in the plugin, and pay more attention to the interactive experience in the theme. So, the plugin might be reused in several blog themes, and this theme is one of them.

This sounds rather simple but there's a LOT of documentation on three different websites (vuepress, theme-blog, plugin-blog) that all look exactly the same and it's rather hard to know to whom applies what I would like to achieve or even what I'm reading. This makes things, in general, really confusing.

All of those also have different Github repositories, with most of the issues / pull requests being on the VuePress repo itself.

Fonts

In order to add non standard fonts to my website I started by creating a bunch of .styl file which is the CSS language used by Vuepress in their samples.

In theme/styles I created an index.style which includes all my others .styl files.

@require './typography.styl'
@require './code.styl'

[...]

Added my fonts in the /fonts folder and modified typography.styl to look like the following

@font-face
  font-family: 'JetBrainsMono'
  src: url('../fonts/JetBrainsMono-Regular.woff2') format('woff2')
  font-style: normal
  font-weight: normal

@font-face
  font-family: 'JetBrainsMono'
  src: url('../fonts/JetBrainsMono-Bold.woff2') format('woff2')
  font-style: bold
  font-weight: bold

I also had to create an enhanceApp.js file in theme/ to include my styles

import './styles/index.styl'

export default ({
  Vue, // the version of Vue being used in the VuePress app
  options, // the options for the root Vue instance
  router, // the router instance for the app
  siteData
}) => {

}

I'm honestly not too sure how I figured all that out as there was not much documentation regarding fonts and it's probably me just copy / pasting setup files from other blogs I would find on Github, not ideal..

I ran the server and that seemed to be good enough and working, minus some errors in the console related to the fonts but without much info on what was going on / how to fix it. This was fine until I tried to yarn build to deploy and it would flat out crash and report an error regarding fonts, again not really telling me what was wrong.

I went on another dive and more copy / pasting later I finally found out that I had to define a path for my fonts in the theme/index.js

const path = require('path')

module.exports = {
  alias: {
    fonts: path.resolve(__dirname, 'fonts'),
  },
} 

and change my typography.styl file (note the subtle use of ~)

@font-face
  font-family: 'JetBrainsMono'
  src: local('JetBrainsMono'), local('JetBrainsMono-Regular'), url('~fonts/JetBrainsMono-Regular.woff2') format('woff2')
  font-style: normal
  font-weight: normal
  font-display: auto
  
@font-face
  font-family: 'JetBrainsMono'
  src: local('JetBrainsMono'), local('JetBrainsMono-Bold'), url('~fonts/JetBrainsMono-Bold.woff2') format('woff2')
  font-style: bold
  font-weight: bold
  font-display: auto
  
@font-face
  font-family: 'JetBrainsMono'
  src: local('JetBrainsMono'), local('JetBrainsMono-Italic'), url('~fonts/JetBrainsMono-Italic.woff2') format('woff2')
  font-style: italic
  font-weight: normal
  font-display: auto

Markdown styling

Because I was going with using my own theme, I, of course didn't have any kind of styling for my blog posts, not being too sure where to start or what to do I went straight in the theme-default VuePress repo and copy pasted the styles index.styl and code.styl, tweaking them to look as I want. It also does not seem possible to apply scoped CSS to the markdown of different layouts. I might have done something wrong but the only way I managed to do it is to add an id or class to <Content/> and add the specific CSS to my index.styl which means the CSS is not scoped and polutes the global CSS file.

This other blog post helped me quite a bit on my journey.

Asset handling

Next I wanted to specify images in the frontmatter of my blog posts for SEO reasons but also to display, for instance, a header for each of them.

Turns out it's not trivial as this issue from two years ago on GitHub explains. To specify assets you need to add them to the public/ directory and reference them using an absolute path. I could already see how messy this will become and how hard it will be to maintain when I start moving things around, especially if I want in the future to have posts containing a large number of pictures...

This PR seemed to bring the approach I was thinking of and allow you to just dump images close to the *.md and it just copies automatically everything neatly to the /public folder where needed. Unfortunately it has been approved a year ago but is still not merged. I ended up using this comment to get the desired functionality. Not great but this works.

SEO

I wanted some basic SEO for my posts, this is not provided outside of the box so I used that plugin and it seems to work nicely enough if we take into account the fact that VuePress does not support assets resolution in frontmatter as seen previously.

Analytics

Next up was adding some very very basic analytics just so I have a bit of a clue what gets visited and to which volume, I don't care much about any details. There's a plugin for Google Analytics but I definitely didn't want to go with that so after a bit of looking around I found about Ackee which is open source, can be self hosted and seems to care enough about privacy, perfect! Now the problem was that I couldn't find how to add the <script/> bit. After some digging I used the approach with the bodyScripts configuration block used in this theme. See here for the actual setup.

Lazyload images

How about lazy loading images now? I don't have much imagery yet but one goal would be to have a photography section so I would need to be able to lazy load images, load specific sizes depending on the user screen size so it still loads reasonably fast and also ideally have some sort of gallery. None of this is provided out of the box which I guess is fair enough, as stated here

Resizing/optimizing images is not the primary goal of VuePress. It should be dev's responsability to take care of its assets' weight.

There's also one or two plugins to "zoom in" pictures which you can find on the pretty nice awesome-vuepress repository but nothing like a gatsby-image plugin. I tried a bit more, using grunt tasks to generate different image buckets and then using the srcset to use the correct size but it just became a huge mess, especially when you add to this the hacks regarding asset handling and I can just see that it's going to be either a lot of work or just really messy and hard to work with.

Conclusion

I highlighted the main hurdles I encountered here and how I "fixed" them but I also forgot to highlight the nice things about VuePress. I do really believe it's a nice little framework as it is but it should probably only be used to write documentation and deploy it quickly. Basic blogging work also nicely but anything more or a bit custom (try to write your own theme...) and it's quite a bit of work and effort (digging in other people's blogs to try and understand how it works is no fun).

Adding on top of that the hot reloading is quite irritating as it's never clear when it's going to work or on which type of changes it is working. It will also sometime work on *.md content and the next time will not. This means you're going to spend your time killing the server and restarting on pretty much every change not knowing if what you wrote is broken or if it's just the server not reloading properly. This seems to be an issue since at least a year and has been reported here.

I'm for now pretty happy with the status quo of my website but will probably dig into Gridsome next.


Questions, remarks about this post?
Reach me on Twitter @florianmski