My vim setup to speed up JavaScript coding for my Electron and React Native apps

Takuya Matsuyama - Oct 21 '20 - - Dev Community

Hi, it's Takuya.

I'm developing a Markdown note-taking app called Inkdrop.
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

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.
I'll explain more about my vim setup.
My dotfiles are published on GitHub here.

Plugins

Here are the plugins that I use:

dein.nvim - Plugin management

To install/update plugins, I'm using dein.nvim.
You can define plugins that you want to use in dein.toml file:

[[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
"""
Enter fullscreen mode Exit fullscreen mode

Here is another toml file named dein_lazy.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']
Enter fullscreen mode Exit fullscreen mode

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 is Conquer of Completion.
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:

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)
Enter fullscreen mode Exit fullscreen mode

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
It tells you should number, not string.
coc.nvim does like this for you.

It also provides auto-completion like this:

auto completion
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

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.

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

getThingsDone(hoge)
Enter fullscreen mode Exit fullscreen mode

This is pretty neat. useful.

When you want to see the type definition, I configured shift-K key to show the definition.
When you typed shift-K, 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

On top of that, when you don't get it from the tooltip, and you want to see the detail,
press gd, which means 'go to definition'.
Then, you can jump to the location of the type definition.
Type ctrl-o 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

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.

" Extensions
let g:coc_global_extensions = [
  \ 'coc-json',
  \ 'coc-tsserver',
  \ 'coc-prettier',
  \ 'coc-eslint',
  \ ]
Enter fullscreen mode Exit fullscreen mode

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:

{
  "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"]
    }
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

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

Then, open a file by choosing from it.
The filer I use is defx.nvim.
I assign it with sf key.

The config file looks like this.

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>
Enter fullscreen mode Exit fullscreen mode

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

Of course, you can manage files in the filer.

  • Create new file: shift-N
  • Delete file: D
  • Rename file: R

Fonts

Nerd Fonts

As you may see some icons like JavaScript, folders in my terminal,
That's because I'm using the font called 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.
This plugin itself doesn't provide the search feature but I configure it to do it.
The config is here.

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

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

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:

nnoremap <silent> ;r :<C-u>Dgrep<CR>
nnoremap <silent> ;f :<C-u>Denite file/rec<CR>
Enter fullscreen mode Exit fullscreen mode

This Dgrep command is defined here:

" 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
Enter fullscreen mode Exit fullscreen mode

What it actually does is to run an external program called ag.
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 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.

Subscribe Newsletter

My YouTube channel

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .