My vim setup to speed up JavaScript coding for my Electron and React Native apps
Tags: vim, electron, reactnative, javascript
Published: 2020-10-21 08:17:29

{% youtube UZBjt04y4Oo %}

Hi, it's [Takuya](https://twitter.com/inkdrop_app).

I'm developing a Markdown note-taking app called [Inkdrop](https://www.inkdrop.app/).
It runs smoothly on both desktop and mobile - macOS, Windows, Linux, iOS and Android.
That's because my app is built with Electron for desktop, and React Native for mobile.
So, I write them basically in JavaScript.

[![Inkdrop](https://dev-to-uploads.s3.amazonaws.com/i/cypdv4j6n6ybgni2xhep.jpg)](https://www.inkdrop.app/)

In this article, I'd like to share my JavaScript coding workflow using vim.
I don't use any IDE like VSCode but I prefer doing things on terminal.
I use Neovim and tmux.
I've written about [my basic workflow on terminal here](https://blog.inkdrop.info/my-dev-workflow-using-tmux-vim-video-e30e78a9acce).
I'll explain more about my vim setup.
My dotfiles are published on [GitHub here](https://github.com/craftzdog/dotfiles-public).

## Plugins

Here are the plugins that I use:

* [dein.nvim](https://github.com/Shougo/dein.vim) for managing plugins
* [coc.nvim](https://github.com/neoclide/coc.nvim) for autocompletion, imports and type definitions
* [defx.nvim](https://github.com/Shougo/defx.nvim) for exploring files
* [denite.nvim](https://github.com/Shougo/denite.nvim) for searching files
* [jiangmiao/auto-pairs](https://github.com/jiangmiao/auto-pairs) for inserting brackets, parens, quotes in pair

## dein.nvim - Plugin management

To install/update plugins, I'm using [dein.nvim](https://github.com/Shougo/dein.vim).
You can define plugins that you want to use in [dein.toml file](https://github.com/craftzdog/dotfiles-public/blob/master/.vim/rc/dein.toml):

```toml
[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
repo = 'Shougo/defx.nvim'
depends = ['defx-git', 'defx-icons']
hook_add = """
source ~/.config/nvim/plugins/defx.rc.vim
"""

[[plugins]]
repo = 'Shougo/denite.nvim'
hook_add = """
source ~/.config/nvim/plugins/denite.rc.vim
"""

[[plugins]]
repo = 'jiangmiao/auto-pairs'

[[plugins]]
repo = "neoclide/coc.nvim"
merge = 0
rev = "release"
hook_add = """
source ~/.config/nvim/plugins/coc.rc.vim
"""
```

Here is another toml file named [dein_lazy.toml](https://github.com/craftzdog/dotfiles-public/blob/master/.vim/rc/dein_lazy.toml):

```toml
[[plugins]]
repo = 'elzr/vim-json'
on_ft = ['json']

[[plugins]]
repo = 'yuezk/vim-js'
on_ft = ['javascript', 'javascript.jsx']

[[plugins]]
repo = 'maxmellon/vim-jsx-pretty'
on_ft = ['javascript', 'javascript.jsx']
```

This file has plugins that are loaded on demand based on file type.
For example, `vim-json` plugin is loaded only when you opened a json file.
By doing like that, vim can avoid loading unnecessary plugins.
So, you can keep vim launching quick and running fast.
In this file, I wrote plugins for file types that I often use.

## coc.nvim - Intellisense

[coc.nvim](https://github.com/neoclide/coc.nvim) is **C**onquer **o**f **C**ompletion.
It is the plugin that provides intellisense on your vim environment.
For example, it provides auto-completion, auto import, type definitions, things like IDEs usually support, which is neat.

Let's say you have a TypeScript something like this:

```typescript
type Note = {
  _id: string,
  body: string,
  title: string,
  createdAt: number,
  updatedAt: number,
  tags: [string]
}

const note: Note = {
  _id: 'hige',
  body: '# hello',
  title: 'example note',
  createdAt: 'moji'
}
console.log('note:', note)
```

So now, createdAt should be number.
But if you mistakenly set a string to the property, then it tells you that it's incorrect:

![TypeScript error](https://dev-to-uploads.s3.amazonaws.com/i/91v6rgrq2p5mjezujkvt.png)
It tells you should number, not string.
coc.nvim does like this for you.

It also provides auto-completion like this:

![auto completion](https://dev-to-uploads.s3.amazonaws.com/i/9n0d2gmc8kba67if6zyi.png)
As you can see, it helps you by showing tooltips with the type definition.

It also works great for functions.
You have another ts file named 'hoge' which has Book and a function named `getThingsDone`.
Then, you want to write `getThingsDone`, then, you type `getThin` and you got it.

![type definition](https://dev-to-uploads.s3.amazonaws.com/i/wfqki7cnulwsrnx0hjqx.png)

It also shows you the definition and description like this.
Then you say Okay, let's insert it.
Then, it inserts an import statement automatically.

```typescript
import {getThingsDone} from './hoge'  // imported automatically

getThingsDone(hoge)
```

This is pretty neat. useful.

When you want to see the type definition, I configured <kbd>shift-K</kbd> key to show the definition.
When you typed <kbd>shift-K</kbd>, it shows you the definition on a tooltip.
So, even if you don't remember the type, it quickly tells you what type is under the cursor.

![tooltip](https://dev-to-uploads.s3.amazonaws.com/i/fwhlipqcjexg7dscqjak.png)

On top of that, when you don't get it from the tooltip, and you want to see the detail,
press <kbd>gd</kbd>, which means 'go to definition'.
Then, you can jump to the location of the type definition.
Type <kbd>ctrl-o</kbd> to go back.
If the type definition is in the same file, it just brings your cursor to the definition like so.

So, coc.nvim provides such coding assistances.
It's very powerful and useful. I recommend this.

In this example, I demonstrated with TypeScript but I am basically writing FlowJS for my product.
But coc.nvim also works great with FlowJS.
Let's say, here is the note module of Inkdrop.
As you can see, it works....not as great as TypeScript but it works fine, like GoToDefinition, 
auto-completion...hmmm...not so good.

![FlowJS](https://dev-to-uploads.s3.amazonaws.com/i/fcocwsv9mf7qvtp6b0da.png)

But anyway, it's useful.
To be honest, I want to switch from FlowJS to TypeScript as soon as possible.
But my codebase is huge and it's hard.
So, I reluctantly stay on FlowJS at the moment.

Here is the config for coc.nvim.
The point is extensions here (`.config/nvim/plugins/coc.rc.vim`).
I installed 4 extensions.

```vim
" Extensions
let g:coc_global_extensions = [
  \ 'coc-json',
  \ 'coc-tsserver',
  \ 'coc-prettier',
  \ 'coc-eslint',
  \ ]
```

If you use TypeScript, install `coc-tsserver` extension.
And I use a helper extension for json files, prettier, and eslint.

You got another config file. It is `coc-settings.json`:

```json
{
  "coc.preferences.formatOnSaveFiletypes": ["json", "css", "markdown"],
  "eslint.autoFixOnSave": true,
  "eslint.autoFix": true,
  "tsserver.enableJavascript": false,
  "languageserver": {
    "flow": {
      "command": "flow",
      "args": ["lsp"],
      "filetypes": ["javascript", "javascriptreact"],
      "initializationOptions": {},
      "requireRootPattern": true,
      "settings": {},
      "rootPatterns": [".flowconfig"]
    }
  },
  ...
}
```

If you use flowjs, you have to configure languageserver like this.
Flow can speak languageserver protocol. So, you can use it.
If you use both TypeScript and FlowJS, you have to set `"tsserver.enableJavascript": false`, so that you can disable TypeScript when editing js file.

That's it.

## defx.nvim - Filer

I open a filer every time I need because I don't like keep showing a file tree on left side of the window.

![filer](https://dev-to-uploads.s3.amazonaws.com/i/5kksbp9xoww7k2ha0jr2.png)

Then, open a file by choosing from it.
The filer I use is [defx.nvim](https://github.com/Shougo/defx.nvim).
I assign it with <kbd>sf</kbd> key.

The config file looks like this.

```vim
nnoremap <silent>sf :<C-u>Defx -listed -resume
      \ -columns=indent:mark:icon:icons:filename:git:size
      \ -buffer-name=tab`tabpagenr()`
      \ `expand('%:p:h')` -search=`expand('%:p')`<CR>
nnoremap <silent>fi :<C-u>Defx -new `expand('%:p:h')` -search=`expand('%:p')`<CR>
```

I guess these are copied from readme.
And you can open a file tree like this,
you can explore directory and find a component, things like that.. using vim-like keystrokes.

If you changed a file, it shows '**M**' label as you can see here, so it tells you this has been modified.
It is well-built as a filer. I love it.

![Modifier label](https://dev-to-uploads.s3.amazonaws.com/i/voivn2uzreq0bv5vtax7.png)

Of course, you can manage files in the filer.

* Create new file: <kbd>shift-N</kbd>
* Delete file: <kbd>D</kbd>
* Rename file: <kbd>R</kbd>

## Fonts

![Nerd Fonts](https://github.com/ryanoasis/nerd-fonts/raw/master/images/sankey-glyphs-combined-diagram.svg)

As you may see some icons like JavaScript, folders in my terminal,
That's because I'm using the font called [Nerd Fonts](https://github.com/ryanoasis/nerd-fonts).
This font comes with a bunch of icons, as you can see, Font Awesome, Devicons, Weather Icons, Seti UI, and on, and on.
So you can get those icons to display on your terminal.

## denite.nvim - Search

To search files in a project, I use [denite.nvim](https://github.com/Shougo/denite.nvim).
This plugin itself doesn't provide the search feature but I configure it to do it.
The config is [here](https://github.com/craftzdog/dotfiles-public/blob/master/.config/nvim/plugins/denite.rc.vim).

For example, I have a bunch of files in my Inkdrop project.
To search files, press `;f`, then the search window pop up.

![file search](https://dev-to-uploads.s3.amazonaws.com/i/uko6f8b7eomacn89krud.png)

When you input keyword like 'editor', it quickly searches files that match the keyword with the filename.
Then you can quickly open it.

If you want to grep file contents with patterns, press `;r`.
If you input a keyword like 'Notebook', it finds files with locations that appear the keyword.

![Grep files](https://dev-to-uploads.s3.amazonaws.com/i/xi2kk0b9n87p45st4042.png)

On top of that, you can filter them with keyword by typing, like `import`, then you can see only items with keywords.
So, if you've got many files in your project, you can always quickly find files and locations.

Well, it'd be hard to tell how I configured denite.nvim in detail though...
Here is the keymaps for grep and search:

```vim
nnoremap <silent> ;r :<C-u>Dgrep<CR>
nnoremap <silent> ;f :<C-u>Denite file/rec<CR>
```

This `Dgrep` command is defined here:

```vim
" Ag command on grep source
call denite#custom#var('grep', 'command', ['ag'])
call denite#custom#var('grep', 'default_opts', ['-i', '--vimgrep'])
call denite#custom#var('grep', 'recursive_opts', [])
call denite#custom#var('grep', 'pattern_opt', [])
call denite#custom#var('grep', 'separator', ['--'])
call denite#custom#var('grep', 'final_opts', [])
" grep
command! -nargs=? Dgrep call s:Dgrep(<f-args>)
function s:Dgrep(...)
  if a:0 > 0
    execute(':Denite -buffer-name=grep-buffer-denite grep -path='.a:1)
  else
    let l:path = expand('%:p:h')
    if has_key(defx#get_candidate(), 'action__path')
      let l:path = fnamemodify(defx#get_candidate()['action__path'], ':p:h')
    endif
    execute(':Denite -buffer-name=grep-buffer-denite -no-empty '.join(s:denite_option_array, ' ').' grep -path='.l:path)
  endif
endfunction
```

What it actually does is to run an external program called [ag](https://github.com/ggreer/the_silver_searcher).
It is a code searching tool that focuses on speed.
Then, the command adds parameters based on context in order to search files.
It's pretty neat.

## auto-pairs

Then, speaking of the small thing, I prefer to use [auto-pairs](https://github.com/jiangmiao/auto-pairs) plugin.
This plugin is, as its name suggests, it helps insert brackets in pair automatically.
If you type open bracket, it automatically closes the bracket.
It also works with double quotes. Even if you removed characters, it erases the pair of quotes.
It works fine with single quotes, square bracket, curly bracket, and normal bracket as well.
It improves my typing speed.

* * *

That's pretty much it!
I hope it's helpful for your terminal workflow.

- Follow me on [Twitter](https://twitter.com/inkdrop_app) & [Instagram](https://instagram.com/craftzdog)
- [Inkdrop - Markdown note-taking app](https://www.inkdrop.app/)

[![Subscribe Newsletter](https://cdn-images-1.medium.com/max/2372/1*-J5tp1_lulY9QknoLEv6zA.png)](http://eepurl.com/dNgJo6)

[![My YouTube channel](https://cdn-images-1.medium.com/max/3000/1*r-daItizHpAU-fQZk3ISag.png)](https://www.youtube.com/c/devaslife)