Introducing VS Code Theme Builder

Posted on Wednesday, December 30, 2020

This is a post announcing a new package I've been working on intermittently throughout 2020 and I'm thrilled that it's finally ready for everyone to use. I have been using it locally in one of my own themes to work out the kinks. Here's a link to the package, and you can read on to learn more about it. The GitHub repo has a more in-depth walkthrough on how to set it up in your project if you prefer that.

So what is it?

Fair question. Authoring a VS Code theme can be pretty tedious. The JSON theme file gets very large, and if you need to tweak a color or find all the places where a color is used, it can be REALLY difficult. I wanted to make it easier, and I thought that one thing that would help is if I could use variables in the JSON file. So since JSON doesn't support variables, I decided to implement it using a familiar handlebars syntax for replacing variables in strings. The idea is that you can stringify the JSON file, replace the variables with their values, then turn it back into JSON. It looks something like this when you write your theme:

2    "name": "{{ name }}",
3    "type": "light",
4    "colors": {
5        "activityBar.background": "{{ colors.lightGray }}",
6        "activityBar.border": "{{ colors.gray }}",
7        "activityBar.activeBackground": "{{ colors.lightGray }}",
8        "activityBar.activeBorder": "{{ }}",
9        "activityBar.foreground": "{{ }}"
10    }

Then you create a config file (the library looks for theme.config.js) in your project that looks something like this:

1// theme.config.js
3module.exports = {
4    name: 'Early Riser',
5    inputFile: 'theme.json',
6    outputFileName: 'early-riser-color-theme.json',
7    outputDir: 'themes',
8    colors: {
9        blue: '#0261dc',
10        lightGray: '#e7ebef',
11        gray: '#f7fafc'
12    }

Once you install the dependency using Yarn or npm, the build-theme binary becomes available to us. By default, it will look for a file called theme.config.js in the root of our project, but we can specify a different file if we choose. We do that by passing a second parameter to our build script. The build script will take the input file defined in our config (in this example, theme.json), parse it, replace the variables with the values defined in our config, then output the new JSON file in the location specified in the config. In this example, it would create a new file (or overwite an existing one) at ./themes/early-riser-color-theme.json.

I do it like this in my theme:

2    "scripts": {
3        "build": "build-theme",
4        "publish": "npm run build && vsce publish"
5    }

If you wanted to use a different file or put the config file elsewhere in your project, you would tell the build-theme script by passing a second parameter:

2    "scripts": {
3        "build": "build-theme ./config/theme.config.js",
4        "publish": "npm run build && vsce publish"
5    }

If you think this might be helpful for you, there's a lot more detailed information on GitHub. If you'd like to see an example of it out in the wild, my Electron Highlighter and Early Riser themes use this library.