Wrangling JavaScript with Vim

I’ve created a few posts on here about writing JavaScript with Vim, this is because it’s what I do all day (and night) long, I’ve refined my editor to make writing this slightly questionable language as easy as possible. I’ve now hit a point, once again, where I feel like I should share my tooling for everyone else to take advantage of. You can find everything I’m going to talk about in my dotfiles under the Vim directory if you’re curious.

Plugin management

I’ve gone through a few different systems since starting to use Vim, I’ve finally settled on one that’ll be tough to beat: vim-plug. A good plugin manager is essential to any good Vim configuration, in my opinion. It allows me to easily add, remove and update plugins as well as keep them in sync across machines. The parallel processing and optional deferred loading are excellent features.

My configuration is modularised by having bootstrap.vim load all files in my modules directory, one of these is plugins.vim which configures vim-plug and then loads the individual configuration files for each plugin from modules/plugins. This allows my actual plugin list to remain clean and concise. I recommend following a similar pattern to keep your configuration clean.

The point of this section being: Make sure you have a good plugin manager and a nice place to list your plugins as well as their configuration. It’ll help keep things clean. Feel free to copy my system exactly, in fact, I encourage it. Fork my dotfiles if you so wish.

Essential plugins

I’m going to list a fairly exhaustive list of every plugin I use that can help with JavaScript development. There’s going to be a lot here, but I’ll try to justify each one as best as I can. Adding all of them will have no impact on the performance of your editor (unless you’re on a Raspberry Pi for example) and vim-plug will fetch / update them incredibly quickly. I actually use a lot more than this, but these are some of the most relevant.

Project specific configuration

I use embear/vim-localvimrc to provide project specific functionality such as executing tests or running the build. Because this is something that isn’t universal, having a .lvimrc to hand is extremely useful. I have the following binding defined at the moment so I can just hit “<localleader>tt” (which is “|tt” right now for me) to test this file, it doesn’t matter if I’m in the source or test file, it just works.

This is relying on vim-dispatch to make the whole thing asynchronous. It actually executes in a tmux split and pulls the results into my Vim quickfix list when done.

I also have my path set to some greedy globs and suffixesadd set to contain .js. This allows me to press gf (open file under cursor) on the following require statement, and it will actually take me to the source (if it exists)!

And here’s the configuration I’m currently using for that particular bit of magic.


I use UltiSnips to manage my snippets, which is a fantastic tool. The key to snippets, however, is to not have too many. That is why I only have three at the time of writing. It’s pretty obvious what they’re for, the most used being fn. Having a few for your most common patterns is a good idea, but delete them if you find you’re not using them, keep your snippets clean.


Concealing is a neat (and relatively new) feature in Vim that allows you to mask a set of characters as a single character. It just so happens that vim-javascript has some excellent conceal configuration that’s easy to use and very effective. Here’s what I currently use, it’s pretty self explanatory.

This is all well and good, but it got me thinking, what if I could just press the @ key and have it expand to “this” but still show an @ through conceal? Essentially creating a cute little language on top of JavaScript within Vim that’s arguably easier to write and read.

Expanding and concealing

This is where my vim-syntax-expand plugin comes in. Here’s a quick demo to give you an idea of what I mean if my previous paragraph was not clear.

I can write concealed characters and see concealed characters, but it actually writes the real JavaScript to the file. It’s caused some people to be slightly confused when looking at my screen, but normal JavaScript is only a set conceallevel=0 away. And yes, it’s intelligent enough to not expand in comments or strings, so you can still type @ or # when required.

The < to “return” mapping uses a special rule that will only work if you’re at the beginning of a line, so you can still type “<=”. Here’s my full configuration, which is also featured in the repository README.md.

I’ve been using it for around and week so far and it feels great. I guess I’m just yearning for a more concise functional language. I type fn, hit “<C-j>” and I get a lambda symbol and a block to write in. Then I can return true by typing “< true”.

This is the sort of thing Vim is amazing at, removing the cruft between you and your text, so you can edit without thinking and concentrate on the problem at hand. Yes it takes practice to use efficiently, but so does every good tool.

This is Shia LaBeouf responding to your “should I give Vim a go?” thoughts.

  • dale


    for your article. it s really helpful. one question from noobie how your actual plugins within plugged forlder end up in modules/plugin folder. why you need to keep them in source control would not that will be anyway install once you start new fresh copy of vim from plugins.vim and kept in default folder of vim-plugged i.e plugged folder.

  • Pingback: Equipping Vim for JavaScript | Oliver Caldwell's blog()

  • Neil McLaughlin

    Really helpful post – thanks for writing up your thoughts.

    Looking at your current dot files it looks like you stopped using syntastic when moving to nvim (based on the fact that it was removed from neovim/.config/nvim/plugins.vim). Have I understood that right and what was your reasoning?



  • JavaMatrix

    The youtube link is dead. Thanks for the article, looking into learning JS and vim at the same time.

  • Mayur Pande

    How comes you refer to javascript as a questionable language? As I currently just stopped learning php to learn js, as people said that was a questionable language. Seems I am going around in circles!

    • There’s no a unquestionable programming language, we’re human beings and each one of us tastes so different, there will never be a perfect language to learn, all of them have good and bad features, if you like it and is useful, learn it!

      • Yup, just personal taste. I’ve been writing it for years now but I don’t like it. Personally I think it’s poorly designed and way too easy to footgun in comparison to other languages I study, but it’s just personal preference. Kind of a running theme on this blog and my twitter though.


  • Thanks for helping me get gf working in JavaScript! But why not just do:

    set path+=*

    It seems like this works just as well for me, and it doesn’t matter what project I’m in (It doesn’t have to have a src/main directory).

    • foo.sh and foo.js would then be potential candidates is all. May be a problem for some but not others, if * works for you, go for it! 🙂

  • skywind3000

    If you are using vim 8 or neovim, maybe you would like to try :

    http://github.com/skywind3000/asyncrun.vim ,

    Nice replacement to vim-dispatch with much better user experience.


    • Oh neat, I’m using neovim now (when I do use Vim) but most of the time I’m in http://spacemacs.org/

      I write a lot more lisp/FP now so it suits me pretty well.

  • Cameron M

    Hey Oliver! Thanks for setting this all up. I’m trying to run just your vim config. So, I forked your dotfiles, and then deleted everything in dotfiles except the vim folder. Then, in .vimrc I changed the first source line to point to the bootstrap.vim. But for the second line, I can’t find that .vimrc_local file anywhere, and when I run vim -u ./path/to/my/vimrcfile I get the error “E484: Can’t open file /Users/me/dotfiles/vim/.vimrc_local”. Any thoughts on how to get this working on my Mac terminal?

    • Hey there, that’s actually something I keep in my home folder. I’m sorry, I thought I made it optional so it wouldn’t throw if it didn’t exist, apparently not.

      touch ~/.vimrc_local should do the trick I think. It’s just a file where you can store machine specific tweaks since I use the same config on multiple laptops.

      • Cameron M

        Hey, thanks for the response! Before I go ahead and run that, I noticed in the newest version of your dotfiles, vim is gone and you’re using neovim instead. I’m trying to stay cutting-edge, so if I take that dotfiles folder, removed everything but neovim, Makefile, and packages.txt, and then removed all lines from packages.txt except the neovim and python ones. If I ran the Makefile, would that work?

        • Well, that’s a matter of taste. I use neovim because I kind of like where the project is going, although I spend most of my day in http://spacemacs.org/ now, which again, is just taste. It’s got good tooling for lisp and it behaves like Vim, so I’m happy with it.

          Vim 8 and neovim both offer great things and I think both are good, maybe go across what Vim 8 added and what neovim offers, decide if it’s worth the hassle of switching things.

          The makefile is mainly for my Arch Linux stuff, the only thing you actually need to run from there is the sync script (./neovim/.config/nvim/sync.sh for neovim, but basically the same for normal vim). So all you need to do is copy that directory in (or use stow to symlink it) and run sync.sh.

          If you want to run neovim you can run it alongside vim, why not try it and go back to vim if you have issues. They’re almost the same to the end user, but some newer plugins only work in one or the other since both add really neat new APIs for doing things like autocompletion without locking the program up.

          • Cameron M

            Oliver, that’s an excellent response, thank you! I think I’ll go ahead and play around with both and see how I like them. Much obliged for the instructions with the sync script so I can set that up!

          • Cameron M

            @OliverCaldwell:disqus sorry to bother again, but I’ve still been having issues. Could it be because I’m on a Mac and not Arch? I figured it’d work out since it’s all unix-based… but maybe not. I’m trying to just do regular vim first, but when I run sh /path/to/sync.sh my terminal just flashes red for a second and returns to the prompt. when I vim into a js file I still just get regular vim, no coloring etc. Any thoughts?

          • This latest version of sync.sh relies on neovim https://github.com/Olical/dotfiles/blob/master/neovim/.config/nvim/sync.sh#L11-L12

            If you want to use regular Vim you’ll have to go back a few commits (could be a lot…) to the time where it was still based on normal Vim. I think the package manager and autocompletion I use also rely on neovim features. So they’re not compatible I’m afraid.

          • Cameron M

            Oh no problem! I just went ahead and installed neovim. Ran your .sh script with sh and the path. No errors, but Is there a good way to check that everything is working correctly? I see syntax highlighting now on files…