lazy.nvimを使った起動時間チューニング入門! ~起動速度10倍を目指して~
1. はじめに
この記事では、lazy.nvimを使ったVim起動の高速化について解説します。
移行した後のdotfilesはこちらです
最近、vim-plugからlazy.nvimへ移行し、全てをLuaで書き直すことでVimの起動速度が向上したのと
とても可愛い起動画面を作ることができました。
どのくらい早くなったの
整理していくうちに追加したいプラグインが増えたり、新しいプラグインに移行したので、完全な比較ではありませんが、
控えめにみても300ms程度かかっていたものが20msで起動できるように改善できました。
(比較には下記ツールを用いています。)
詳細のプラグインなどは最後の結果の方に記載しようと思います。
before
- vim-plug を用いたnvim (遅延ロードなし)
- 総プラグイン数50
計測結果
$ vim-startuptime -vimpath nvim > before.log
Measured: 10 times
Total Average: 356.781100 msec
Total Max: 526.554000 msec
Total Min: 209.534000 msec
after
- lazy.nvim を用いて遅延ロードをしたnvim
- 総プラグイン数56
計測結果
$ vim-startuptime -vimpath nvim > after.log
Measured: 10 times
Total Average: 18.506800 msec
Total Max: 20.024000 msec
Total Min: 18.092000 msec
以前の300msでも気にならなかったものが、15倍も改善されていると、かなり嬉しくなりました。
次の章からは、lazy.nvimの特徴や高速化の実現方法について順を追って説明していきます。
2. lazy.nvim への移行
移行のきっかけ
Vimの設定を全てLuaで統一したく、そのタイミングでパッケージマネージャも一緒に見直そうと考え、lazy.nvimへの移行を決定しました。
vim-plugと比較してみて
vim-plugとlazy.nvimを比較してみると、以下の点が良いなと感じました。
pluginの依存関係が1ファイルで一目超然
参考までに、以下のようなfern (ファイルツリー) を構築するまでの設定例で説明してみます。
以下はfernをインストールしているluaスクリプトです。
最初にメインとなるプラグインを記載し、( 'lambdalisue/fern.vim'
) 2行目からはプラグインの依存関係となるものをを記載しています。
return {
'lambdalisue/fern.vim',
keys = {
{ "<C-n>", ":Fern . -reveal=% -drawer -toggle -width=40<CR>", desc = "toggle fern" },
},
dependencies = {
{ 'lambdalisue/nerdfont.vim', },
{
'lambdalisue/fern-renderer-nerdfont.vim',
config = function()
vim.g['fern#renderer'] = "nerdfont"
end
},
},
}
自分のfernはファイルアイコンやディレクトリアイコンを表示するために、nerdfontを利用しており、
そのためのプラグインを2つ導入しています。
依存する/されるプラグイン側の設定も一緒に記載することができるため、
かなり書きやすいなと感じています。
vim起動時の自動インストール
設定ファイルいじると、自動でlazyが立ち上がり、プラグインのインストールが始まります!
とても便利 && UIがカッコ良いです。
パフォーマンスが計測できるUIがついており、
実は自分はここで計測してみて起動時間のチューニングをしてみたくなりました。
遅延ロードの設定が柔軟
私は、vimのhelpを日本語でみるために、vimdoc-jaのプラグインを入れています。
もちろん常時必要なプラグインではないので、特定のキーが押された瞬間に遅延ロードするように設定をしました。
return {
'vim-jp/vimdoc-ja',
lazy = true,
keys = {
{ "h", mode = "c", },
},
}
上記の設定で、コマンドモードで h
を押した瞬間にvimdoc-jaがロードされ、日本語vimdocを閲覧することができます。
ちょっとわかりにくいですが、lazyの画面でnotLoadedだったvimdoc-japanが、:h
を押した瞬間にロードされています。
こちらは一例ですが、他の遅延ロードのパターンもいろいろ用意されています。
3. lazy.nvim を使ったVim起動の高速化のいろいろ
おすすめの設定として、defaultでlazy = trueを入れると良いです。
こちらの設定を入れると、基本的にプラグインはロードされなくなり、
後に述べる遅延ロード設定でのイベント発火でしかプラグインがロードされなくなります。
遅延ロード設定の紹介と実例
- event
- keys
- cmd
- ft
と4つの種類で遅延ロード設定を行うことができるため、
そちらを紹介していきます。 (組み合わせることも可能です)
1. event
このオプションは、特定のNeovimイベントが発生したときにプラグインを読み込むように設定できます。
goolord/alpha-nvim での設定
起動時にalpha-nvimというプラグインで起動画面をカスタマイズしているの、
VimEnter
というイベントでロードするようにしています。
{
'goolord/alpha-nvim',
event = "VimEnter",
}
hrsh7th/nvim-cmp での設定
lspの補完にnvim-cmpを使っており、
こちらは入力されだしてからの補完という流れでしか使わないため、
InsertEnter
というイベントでロードするようにしています。
{
'hrsh7th/nvim-cmp',
event = "InsertEnter",
}
2. keys
このオプションは、指定されたキーが押されたときにプラグインを読み込むように設定します。
vim-jp/vimdoc-ja での設定
先ほど紹介したvimdoc-jpですね。
コマンドラインモードでの入力は mode
を使うことで記載することが出来ます。
{
'vim-jp/vimdoc-ja',
lazy = true,
keys = {
{ "h", mode = "c", },
},
}
lambdalisue/fern.vim での設定
fernでも設定しています。(ファイルツリーです)
自分は Control + n
で開く設定しているので、
そちらのコマンドが入力されてから遅延ロードするように設定しました。
{
'lambdalisue/fern.vim',
keys = {
{ "<C-n>", ":Fern . -reveal=% -drawer -toggle -width=40<CR>", desc = "toggle fern" },
},
}
3. cmd
このオプションは、指定されたコマンドが実行されたときにプラグインを読み込むように設定します。
williamboman/mason.nvim
お馴染みのmasonですね。
自分としては、Lspやlinter, formatterを管理する際にコマンドラインでの入力をしているので
cmdとして入力されうるものを定義しています。
return {
'williamboman/mason.nvim',
cmd = {
"Mason",
"MasonInstall",
"MasonUninstall",
"MasonUninstallAll",
"MasonLog",
"MasonUpdate",
},
}
folke/which-key.nvim
WhichKeyです。
たまに使いたくなった時に、コマンドいれて見れるようにしてます。
{
'folke/which-key.nvim',
lazy = true,
cmd = {
"WhichKey",
},
opts = {},
}
4. ft
このオプションは、特定のファイルタイプが開かれたときにプラグインを読み込むように設定します。
特定の言語のみ使うプラグインなんかは設定しやすいですね。
kat0h/bufpreview.vim
markdownのpreviewで用いているものをft
にてmarkdown
を指定しています。
{
'kat0h/bufpreview.vim',
build = 'deno task prepare',
ft = {
"markdown",
},
dependencies = {
'vim-denops/denops.vim'
}
}
以上4つの遅延ロードする設定の紹介でした。
もちろん組み合わせての設定もできるため、複数のロードタイミングがある場合は、どちらも設定しておくと良いです。
4. まとめ
どのくらい早くなったの(再掲)
before
- vim-plug を用いたnvim (遅延ロードなし)
- 総プラグイン数50
before plugins (50個)
call plug#begin('~/.vim/plugged')
Plug 'vim-jp/vimdoc-ja'
Plug 'mattn/vim-goimports'
Plug 'tyru/open-browser.vim'
Plug 'mechatroner/rainbow_csv'
" fern
Plug 'lambdalisue/fern.vim'
Plug 'lambdalisue/fern-git-status.vim'
Plug 'hashivim/vim-terraform'
" react
Plug 'pangloss/vim-javascript'
Plug 'leafgarland/typescript-vim'
Plug 'peitalin/vim-jsx-typescript'
Plug 'maxmellon/vim-jsx-pretty'
" UML
Plug 'weirongxu/plantuml-previewer.vim'
Plug 'aklt/plantuml-syntax'
Plug 'kannokanno/previm'
" Rust
Plug 'rust-lang/rust.vim'
Plug 'mattn/webapi-vim'
" git
Plug 'airblade/vim-gitgutter'
Plug 'tpope/vim-fugitive'
Plug 'tpope/vim-rhubarb'
Plug 'hashivim/vim-terraform'
Plug '/Users/s09104/ghq/github.com/yuucu/vimq.vim'
Plug 'MTDL9/vim-log-highlighting'
Plug 'tyru/open-browser-github.vim'
Plug 'simeji/winresizer'
Plug 'kdheepak/lazygit.nvim'
Plug 'udalov/kotlin-vim'
Plug 'neovim/nvim-lspconfig'
Plug 'williamboman/mason.nvim'
Plug 'williamboman/mason-lspconfig.nvim'
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/vim-vsnip'
Plug 'j-hui/fidget.nvim'
Plug 'jjo/vim-cue'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
Plug 'github/copilot.vim'
Plug 'kosayoda/nvim-lightbulb'
Plug 'antoinemadec/FixCursorHold.nvim'
Plug 'folke/trouble.nvim'
Plug 'folke/lsp-colors.nvim'
Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-telescope/telescope.nvim', { 'tag': '0.1.1' }
Plug 'nvim-telescope/telescope-frecency.nvim'
Plug 'kkharji/sqlite.lua'
Plug 'sebdah/vim-delve'
Plug 'nvim-tree/nvim-web-devicons'
" memo
Plug 'glidenote/memolist.vim'
" go install github.com/mattn/memo@latest
Plug 'delphinus/telescope-memo.nvim'
" theme
Plug 'sainnhe/sonokai'
Plug 'nordtheme/vim'
Plug 'cocopon/iceberg.vim'
Plug 'AlexvZyl/nordic.nvim'
Plug 'junegunn/seoul256.vim'
Plug 'raphamorim/lucario'
Plug 'preservim/vim-colors-pencil'
call plug#end()
計測結果
$ vim-startuptime -vimpath nvim > before.log
Measured: 10 times
Total Average: 356.781100 msec
Total Max: 526.554000 msec
Total Min: 209.534000 msec
after
- lazy.nvim を用いて遅延ロードをしたnvim
- 総プラグイン数56
after plugins (56個)
● LuaSnip
● alpha-nvim
● ayu-vim
● bufferline.nvim
● cmp-buffer
● cmp-nvim-lsp
● cmp-path
● cmp_luasnip
● copilot.lua
● copilot.vim
● friendly-snippets
● gitsigns.nvim
● lazy.nvim
● lsp-format.nvim
● lspkind.nvim
● lspsaga.nvim
● lualine.nvim
● mason-lspconfig.nvim
● mason.nvim
● mini.indentscope
● mini.splitjoin
● modes.nvim
● neodev.nvim
● noice.nvim
● nui.nvim
● null-ls.nvim
● nvim-cmp
● nvim-lspconfig
● nvim-treesitter
● nvim-treesitter-textobjects
● nvim-web-devicons
● plenary.nvim
● sqlite.lua
● telescope-frecency.nvim
● telescope-fzf-native.nvim
● telescope.nvim
● todo-comments.nvim
● trouble.nvim
● vim-fugitive
● vim-rhubarb
● vim-sleuth
○ bufpreview.vim
○ catppuccin
○ denops.vim
○ fern-renderer-nerdfont.vim
○ fern.vim
○ glyph-palette.vim
○ kanagawa.nvim
○ neotest
○ neotest-go
○ nerdfont.vim
○ nvim-dap
○ onedark.nvim
○ vimdoc-ja
○ which-key.nvim
○ copilot-cmp
計測結果
$ vim-startuptime -vimpath nvim > after.log
Measured: 10 times
Total Average: 18.506800 msec
Total Max: 20.024000 msec
Total Min: 18.092000 msec
おわりに
この記事では、lazy.nvimを使ったVim起動の高速化について解説しました。
適切な遅延ロードの設定を行うことで、20ms という速度でvimを起動することが可能になりました。
ぜひvimの起動時間にお困りの際は、遅延ロードの設定を見直してみてください!
ここまで読んでいただきありがとうございました。
参考
- 移行後のdotfiles
- lazy.nvim
Discussion