Building a JavaScript documentation website


I think code documentation works best when it lives side by side with the code it is documenting rather than being written in a separate document. When it's separate, it becomes easy for documentation to become stale. Out of sight, out of mind!

However, documentation can be easier to read if it's nicely formatted rather than reading straight from the code editor. With this in mind, I started looking at JSDoc for documenting my JavaScript code. You simply write the documentation with your source code and then run a command to generate a static website build with nicely formatted documentation. Best of both worlds!

In this article I'll show you how I setup and wrote documentation with JSDoc and how I deployed the output to Netlify.

Folder structure

At the root of my repo I created a new folder at docs/jsdoc and changed into that directory in the console. Then I ran yarn init and followed the console steps to create a new package.json file. Then I ran yarn add jsdoc docdash --dev to install the required packages.

Keeping all of the documentation configuration in a subdirectory prevents polluting the main code base with additional configuration and keeps the node modules separate. Netlify supports deploying sites from within subdirectories so everything required to build a documentation site can be neatly organised in its own folder. I can also easily add other folders under docs for additional documentation sites, say for my view components as an example.

Configuration

Next I created a simple README.md file which will automatically get pulled into the generated index.html file by JSDoc during the build.

Then I had to configure a script to run the JSDoc build in package.json:

"scripts": {
  "build_jsdoc": "rm -rf build && jsdoc -c jsdoc.json -d build",
  "dev_jsdoc": "rm -rf dist && jsdoc -c jsdoc.json -d dist"
}

I also ensured that dist was added to my .gitignore file. The build_jsdoc script is used to generate the production version of the documentation but sometimes I want to test things out without messing up the production version so I also added the dev_jsdoc command for this purpose. In summary, this first removes all files in the build folder, gets the configuration for JSDoc from jsdoc.json and outputs the build in either the build or dist folders.

So clearly I needed a jsdoc.json file to write my JSDoc configuration:

{
  "docdash": {
    "static": true,
    "sort": true,
    "search": true,
    "collapse": true,
    "typedefs": true,
    "removeQuotes": "none",
    "scripts": [],
    "menu":{
      "Github repo": {
        "href":"https://github.com/knoxjeffrey/personal_website",
        "target":"_blank",
        "class":"menu-item",
        "id":"repository"
      }
    }
  },
  "opts": {
    "access": "all",
    "readme": "README.md",
    "recurse": true,
    "template": "node_modules/docdash"
  },
  "plugins": [
  ],
  "templates": {
    "default": {
      "includeDate": false,
      "useLongnameInNav": true
    }
  },
  "source": {
    "include": ["../../source/assets/javascripts"],
    "includePattern": ".+.js?$"
  }
}

You no doubt have already noticed Docdash which I added to give a clean, responsive documentation template theme for JSDoc 3. You can read more about the configuration options on their GitHub repo.

Under source you can add as many folders as you need which directs JSDoc where to navigate to in order to find your documentation and you can include a regex pattern for the file extensions.

One configuration change I ensured I made was to set includeDate to false. If you set it as true then the current date and time of when the documentation was built is added to every page. However this would mean your build output will change every time you run yarn build_jsdoc even when there are no documentation changes and therefore you will end up with unnecessary builds in Netlify. This became even more important when I automated the build process with a GitHub action which I will go into in my next blog post.

Just a little bit more configuration left! I have a netlify.toml file at the root of my repo but I need another one to sit with my docs:

[build]
  # Directory that contains the deploy-ready HTML files and assets generated by
  # the build. This is relative to the base directory if one has been set, or the
  # root directory if a base has not been set.
  publish = "build/"

[context.production.processing]
  skip_processing = false

[context.production.processing.css]
  bundle = true
  minify = true

[context.production.processing.js]
  bundle = true
  minify = true

[context.production.processing.html]
  pretty_urls = false

[context.production.processing.images]
  compress = false

You have to make sure the base directory is set from within the Netlify UI when you get to the point of setting that up otherwise Netlify will build from the root and also read the netlify.toml in the root. One other thing to note from my config is that pretty_urls should be set as false otherwise the sub navigation within the documentation site will not work correctly.

Documenting JavaScript

There's quite a lot to take in when reading through the various tags in the JSDoc site so make sure you spend some time reading through it all. Below is an example of the documentation for one of my Stimulus controllers to initialise Commento:

import { Controller } from "stimulus"

/**
* @class CommentsController
* @classdesc Stimulus controller to initialise Commento to allow users to view and make comments.
* @extends Controller
*/
export default class extends Controller {
  /**
  * @property {Function} load - targets the button to load comments
  * @property {Function} commento - targets the div to initialise Commento
  * @memberof CommentsController
  * @static
  */
  static targets = [ "load", "commento" ]

  /** 
  * Triggered by a click event.
  * Hides the button for loading comments.
  * Adds top margin to the Commneto block and initialises Commento
  * 
  * @instance
  * @memberof CommentsController
  * @returns {void} N/A
  * */
  load() {
    this.loadTarget.style.display = "none"
    this.commentoTarget.classList.add("margin-top--xxl")
    window.commento.main()
  }
}

You can read through more examples in my repo.

When you have your documentation written, run yarn build_jsdoc from the command line to build your documentation static website. You can now commit these changes to production.

Netlify

I logged into my Netlify account and setup a new site which linked to my repo. As mentioned above, I ensured I set my base directory as docs/jsdoc which means during the deploy Netlify knows what directory to switch to. Netlify will only run a full build if there are changes in the docs/jsdoc directory, otherwise it will start and then cancel the build.

That's it, my documentation site is built and you can view the final output here. Now, this works okay but it means you have to remember to manually rebuild the documentation every time you make changes. I can do better than that and in my next blog post I will show you how to use a GitHub action to automate the process.