Automatic Dynamic Sidebars in Vuepress

How can you get automatic sidebars to be generated in Vuepress depending on the page?

The Situation

Vuepress is simple.

That’s both a great and not-so-great positive at the same time in the same line.

Using Vuepress is simple enough. Introducing navigation through a sidebar and a navbar is simple too. Specifically for the sidebar - you just add some code in /docs/.vuepress/config.js.

module.exports = {
  //...
  themeConfig: {
    sidebar: [
      { title: "Home", children: [""] },
      {
        title: "Misc",
        children: ["more"]
      }
    ]
  }
  //...
};

This will create a sidebar with links under Home and Misc. The title of links will be the title of the page or the first header element within the markdown files that the links link to.

From the previously highlighted example -

vuepress-site-navbar-sidebar

The H2 headers will be links grouped below the file links.

But, what if you-

  1. want to Create different sidebars for different pages. Site to behave like a bunch of different guides. When you go to specific pages (which are represented as folders in Vuepress root folder) , the navigation changes to point to different markdown files in the folder
  2. want to continue having H2 behaviour be Vuepress default - show the links within the specific markdown files
  3. don’t want to write all the file links by hand and want the system to automatically “see” the content to be linked

For example -

vuepress-dynamic-sidebar-appearance

We need Admin, Developer and other folders need to have their own sidebars with navigation links.

This sidebar behaviour is slightly different from Vuepress default, which seemingly assumes that all of the content is one big happy family - links just point to the different markdown files in the document root and to the H2 elements when the parent links are expanded.

Solutions

Vuepress is after all powered by Vue - so customisation is not really a complex problem.

However, I did not find this as straight forward as something like Gridsome - you just create a component for navigation like any sane developer and the system will exactly do what it has to - render the navbar.

Vuepress’s navbar is driven by config (and if applicable, plugins) - so this seemed not so elegant(!?) at first. But as always - all you need are docs and some time to take care of any problem.

Here are the solutions that I tried. The final solution that worked for me is at the end because I am heartless and believe in making people scroll.

Solution 1. Use vuepress-plugin-auto-sidebar plugin

The plugin vuepress-plugin-auto-sidebar seemed to do exactly what I wanted.

To install a plugin in Vuepress, all you have to do is -

  1. Install the package using npm/yarn
  2. Use the plugin in config

So, then..

npm install --save vuepress-plugin-auto-sidebar

Include plugin in /docs/.vuepress/config.js-

module.exports = {
  // ...
  plugins: {

"vuepress-plugin-auto-sidebar": {
      titleMap: {
        "salesforce-for-students": "Salesforce for Students",
        "pd1-guide": "Platform Developer I Certification Guide",
        "admin-guide": "Admin Certification Guide",
        "why-learn-salesforce": "Why Learn Salesforce?",
        misc: "Miscellany"
      }
    },
// ...
}

This will provide custom titles for the different folders and automatically pick up the files within the folder to create distinct, dynamic navigation bars.

In the ideal world, this should have been it and I should not have been sitting around to create a blog post about all the circus. But hey - ideal world is not exciting.

  1. Getting started was bit of a bother. The documentation is in Chinese and there are not examples abound. As always, Google to the rescue - translated text made sense
  2. Next off - I could not quite figure out how autoNext and autoPrev worked. My sort order for files was messed up in the folders, and this was the only way I could control the order of appearance for navlinks.
  3. There were random failures that I could not quite debug - you could never say when sidebars generation failed (silently) and for the life of me - I could not figure out why. With dozens of files in different folders, I was in a spot. I was sick of cut/pasting content just to see when the content caused the program to fail
  4. If you have a directory and README in the directory, the README does not show in the nav. This is expected and as per Vuepress, but I could never say when the README did not appear as a separate link. It appeared in some cases and disappeared elsewhere

Solution 2: Use vuepress-bar

vuepress-bar was another solution that seemed promising.

Install..

npm i --save vuepress-bar

Use the package in /docs/.vuepress/config.js -

const getConfig = require("vuepress-bar");

module.exports = {
  themeConfig: {
    ...getConfig(`${__dirName}/..`)
  }
};

Although this worked more reliably, I could not figure out how to generate distinct sidebars for indidvidual content folders. All links appeared under one title - not ideal for my case.

vuepress-bar-sidebar

If you just want a dynamic sidebar (and/or a navbar) - you should use this library.

Solution 3: Go custom

My final solution - just do everything. All it took was a couple of lines of code.

Do changes in /docs/.vuepress/config.js -

const fs = require("fs");
const path = require("path");

module.exports = {
  //...
  themeConfig: {
    sidebar: {
      "/why-learn-salesforce/": getSideBar(
        "why-learn-salesforce",
        "Why Salesforce?"
      ),
      "/admin-guide/": getSideBar("admin-guide", "Admin Certification Guide"),
      "/pd1-guide/": getSideBar("pd1-guide", "PD1 Certification Guide"),
      "/salesforce-for-students/": getSideBar(
        "salesforce-for-students",
        "Salesforce for Students"
      )
    }
  }
  //...
};

function getSideBar(folder, title) {
  const extension = [".md"];

  const files = fs
    .readdirSync(path.join(`${__dirname}/../${folder}`))
    .filter(
      item =>
        item.toLowerCase() != "readme.md" &&
        fs.statSync(path.join(`${__dirname}/../${folder}`, item)).isFile() &&
        extension.includes(path.extname(item))
    );

  return [{ title: title, children: ["", ...files] }];
}

And voila -

vuepress-sidebar-auto-generate-function

  1. We have a distinct sidebar for each folder - first level links are the files within the folder
  2. Links to README and other files are consistent
comments powered by Disqus