NeoVim Setup for PHP and NodeJS Development

NeoVim Setup for PHP and NodeJS Development

How I sped up my development with NeoVim for WordPress, React, SvelteKit, and more

ยท

7 min read

Hi everyone! ๐Ÿ‘‹

It's been a while since my last post, and today I want to show you how I sped up my development in the last weeks.

Until recently, I've been a big fan of Visual Studio Code and it was my primary editor for the last years. Over time, I learned more and more key bindings, started to really use the command palette and started to not do everything with the mouse - and guess what, it felt a lot faster than doing everything with the mouse.

Now, I still love VS Code, can really recommend it and I use it for example in the browser on GitHub. But since I tried Vim, I'm now using this as my primary editor.

Please note, I'm by far no (Neo)Vim expert and still learning it. In this article, I want to share my story about how I got into (Neo)Vim and what my setup looks like.

Why Vim?

When I first heard about Vim, I was like "why in the world would you use Vim when there is VS Code and all the other modern IDE's?". The only thing I knew about Vim at this time was how to exit Vim. But after a deeper look at Vim and some great input from a co-worker, I decided to at least try it for some time.

Here are the main reasons:

  • ๐Ÿš€ Speed. I was really impressed by how fast you can be with Vim - even when you're still learning it.
  • ๐ŸŒ I can use it on the server. That's awesome, because I always used a FTP client when I needed to edit files on the server. Now, I can work with files on the server just as I do with files on my computer - directly from the terminal.
  • โŒจ๏ธ I didn't really know any terminal-based text editor before.

How I learned Vim

Quick answer: Learning by doing :)

I started to use only Vim for a few days, which forced me to learn Vim commands and key bindings. No VS Code or any other text editor - only Vim. At the beginning, I was really slow and constantly looking up how to do basic stuff.

But every day I got faster, learned new commands and improved my workflow. And until now, I didn't go back to VS Code.

That's my config for Vim:

set encoding=UTF-8
" Set encoding

set number
" Show line numbers by default

syntax on
" Enable syntax highlighting by default

filetype plugin indent on
" show existing tab with 4 spaces width
set tabstop=4
" when indenting with '>', use 4 spaces width
set shiftwidth=4
" On pressing tab, insert 4 spaces
set expandtab

" Tab / Shift Tab to switch between tabs (:tabe <file>)
nnoremap <Tab> :tabnext<CR>
nnoremap <S-Tab> :tabprevious<CR>

NeoVim

After using Vim for a few weeks, I now moved to NeoVim. I really like Vim now, but there are some VS Code features I'd love to have in Vim. That's why I decided to use NeoVim.

That's how I wanted my NeoVim setup to look like:

  • Not too different to my normal Vim setup so I can still work with the default Vim editor if I can't use NeoVim (e.g. on servers)
  • Main use case:
    • PHP (+ WordPress)
    • React / NextJS
    • Svelte / SvelteKit

You see, a pretty simple setup. So now let's actually set it up:

Installation & Setup

1. Install NeoVim

Follow the instructions on the NeoVim installation page or use the following command:

macOS (with brew): brew install neovim

Windows (with winget): winget install NeoVim.NeoVim

2. Install VimPlug

To manage the plugins / extensions, I decided to use VimPlug as the plugin manager. Read the installation guide here or use the following command:

macOS / Linux:

sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
       https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'

Windows (PowerShell):

iwr -useb https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim |`
    ni "$(@($env:XDG_DATA_HOME, $env:LOCALAPPDATA)[$null -eq $env:XDG_DATA_HOME])/nvim-data/site/autoload/plug.vim" -Force

3. NeoVim Config

Create the NeoVim config file ~/.config/nvim/init.vim and paste the following:

set encoding=UTF-8
set number
syntax on

" set tab to 4 spaces
filetype plugin indent on
set tabstop=4
set shiftwidth=4
set expandtab

" Tab / Shift Tab to navigate between tabs
nnoremap <Tab> :tabnext<CR>
nnoremap <S-Tab> :tabprevious<CR>

" CoC settings
set nobackup
set nowritebackup
set cmdheight=2
set updatetime=300
set shortmess+=c
if has("nvim-0.5.0") || has("patch-8.1.1564")
  set signcolumn=number
else
  set signcolumn=yes
endif
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ CheckBackspace() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
function! CheckBackspace() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction
if has('nvim')
  inoremap <silent><expr> <c-space> coc#refresh()
else
  inoremap <silent><expr> <c-@> coc#refresh()
endif
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
nnoremap <silent> K :call ShowDocumentation()<CR>
function! ShowDocumentation()
  if CocAction('hasProvider', 'hover')
    call CocActionAsync('doHover')
  else
    call feedkeys('K', 'in')
  endif
endfunction
autocmd CursorHold * silent call CocActionAsync('highlight')

" VimPlug plugin manager
call plug#begin()
Plug 'https://github.com/vim-airline/vim-airline'
Plug 'https://github.com/tpope/vim-commentary'
Plug 'https://github.com/ap/vim-css-color'
Plug 'https://github.com/rafi/awesome-vim-colorschemes'
Plug 'https://github.com/neoclide/coc.nvim'
Plug 'othree/html5.vim'
Plug 'pangloss/vim-javascript'
Plug 'evanleck/vim-svelte', {'branch': 'main'}
call plug#end()

" set the colorsheme
" list: https://github.com/rafi/awesome-vim-colorschemes
colorscheme minimalist

At the top, you can see some settings like the tab with, encoding and I also want syntax highlighting and line numbers enabled by default.

Next is a big config block for the CoC extension. I can't really explain what all this is doing, I got this from the CoC installation & setup guide. Basically, it enables the autocompletion window and creates some hotkeys like K to show the documentation.

Below that, you can find the VimPlug section. Here are all the plugins registered:

  • vim-airline: status/tabline showing things like the current git branch and vim mode.
  • vim-commentary: Comment stuff out, gcc to comment out lines
  • vim-css-color: Highlight color names
  • awesome-vim-colorschemes: A big collection of color schemes, I'm using minimalist (set with colorscheme <name>)
  • coc.nvim: Language Server Support, completion, ...
  • html5.vim: Syntax & indentation for HTML5 and SVG (required for vim-svelte)
  • vim-javascript: Syntax & indentation for JavaScript (required for vim-svelte)
  • vim-svelte: Syntax & indentation for Svelte

4. Install Plugins

Because we changed the NeoVim config, restart NeoVim first. There may be some errors because the plugins aren't installed yet. Use VimPlug to install the plugins specified in the config file:

:PlugInstall

5. Set Up CoC Extension

Once the plugins are installed, close NeoVim and navigate to the folder of the CoC extension:

macOS / Linux: ~/.local/share/nvim/plugged/coc.nvim/

Windows: ~/vimfiles/plugged/coc.nvim/

Now, install the dependencies and build the source code:

npm ci && npm run build

6. Extensions for the CoC Extension

You can now start NeoVim again and there shouldn't be any errors. To complete the setup, let's install some extensions for CoC, like a JS/TS language server and intelephense for PHP:

:CocInstall coc-tsserver coc-json coc-svelte @yaegassy/coc-intelephense

7. Optional: WordPress

I'm working with WordPress themes and plugins, but with the current setup every WordPress function is marked as error because the intelephense extension doesn't know I'm inside a WordPress theme with all the WordPress functions available. We can change that by opening the CoC config (:CocConfig) and adding "wordpress" to the list of intelephense.stubs. If you type "intelephense.stubs", you can use the autocompletion by CoC to create the whole list and then only append "wordpress" to the end of the list.

Full list:

{
    "intelephense.stubs": [
        "apache",
        "bcmath",
        "bz2",
        "calendar",
        "com_dotnet",
        "Core",
        "ctype",
        "curl",
        "date",
        "dba",
        "dom",
        "enchant",
        "exif",
        "FFI",
        "fileinfo",
        "filter",
        "fpm",
        "ftp",
        "gd",
        "gettext",
        "gmp",
        "hash",
        "iconv",
        "imap",
        "intl",
        "json",
        "ldap",
        "libxml",
        "mbstring",
        "meta",
        "mysqli",
        "oci8",
        "odbc",
        "openssl",
        "pcntl",
        "pcre",
        "PDO",
        "pdo_ibm",
        "pdo_mysql",
        "pdo_pgsql",
        "pdo_sqlite",
        "pgsql",
        "Phar",
        "posix",
        "pspell",
        "readline",
        "Reflection",
        "session",
        "shmop",
        "SimpleXML",
        "snmp",
        "soap",
        "sockets",
        "sodium",
        "SPL",
        "sqlite3",
        "standard",
        "superglobals",
        "sysvmsg",
        "sysvsem",
        "sysvshm",
        "tidy",
        "tokenizer",
        "xml",
        "xmlreader",
        "xmlrpc",
        "xmlwriter",
        "xsl",
        "Zend OPcache",
        "zip",
        "zlib",
        "wordpress"
    ]
}

And that's my current NeoVim setup. Maybe this will help some of you who want to get started with NeoVim.

What's your favorite editor or IDE? Are you using Vim / NeoVim too? Let me know in the comments!

Thank you for reading, happy coding and have a great day! ๐Ÿ˜Š๐Ÿš€

Did you find this article valuable?

Support Linus Benkner by becoming a sponsor. Any amount is appreciated!

ย