The idea of deferred load is we priotize to instantly load plugin that we need on startup. And load plugin that we don't need later. So yeah it's like what zinit
does with their turbo mode. In Neovim, we can achive this with vim.defer_fn
In case you don't know, dep
is a neovim plugin manager. The reason I choose it instead of packer
is its ability to load plugins in consistent order.
Since you already got the gist of what will we do, let's jump to the code.
I will dump all of the code in init.lua
to make it simpler.
-- Install dep if it's not exist
local dep_bootstrap = function()
local path = vim.fn.stdpath('data') .. '/site/pack/deps/opt/dep'
if vim.fn.empty(vim.fn.glob(path)) > 0 then
vim.fn.system {
'git', 'clone', '--depth=1', 'https://github.com/chiyadev/dep', path
}
end
vim.cmd 'packadd dep'
end
local dep_load = function(plugins)
dep_bootstrap()
require 'dep'(plugins)
end
dep_load {
{
'NTBBloodbath/doom-one.nvim',
function()
vim.cmd 'colorscheme doom-one'
end
}
}
We will load doom-one
colorscheme instantly on startup
local dep_load = function(plugins)
dep_bootstrap()
require 'dep'(plugins)
end
-- Run dep_load `wait_time`ms later after we call it
local dep_defer_load = function(plugins, wait_time)
wait_time = wait_time or 0
vim.defer_fn(function()
dep_load(plugins)
end, wait_time)
end
dep_load {
{
'NTBBloodbath/doom-one.nvim',
function()
vim.cmd 'colorscheme doom-one'
end
}
}
dep_defer_load({
{
'lewis6991/gitsigns.nvim',
function()
require 'gitsigns'.setup()
end,
requires = 'nvim-lua/plenary.nvim',
}
}, 700)
That means dep
will load gitsigns
700ms or 0.7s later after doom-one
loaded
Okay that's basically how we do deferred load…
Let's look back at the code above. It implies:
🧑💻: "Hey Dep, please load `doom-one` on startup for me. Oh and 0.7s later also load `gitsigns`"
📦: "Ok"
*On startup*
📦: *Load `doom-one`*
*0.7s later*
📦: *Load `gitsigns`*
📦: *Remove `doom-one`*
🧑💻: "Wait.. wait.. Why did you remove `doom-one`?"
📦: "Well you told me to load `gitsigns` and since you don't need `doom-one`, I removed it for you"
See what's wrong there? Dep
has a nice feature that will auto-remove plugin that we don't initialize. It is logical since if we don't want to use a certain plugin we will not initialize it in require 'dep(<plugins_table>)'.
If we don't use a certain plugin but still want to keep it, dep
has disabled
field for it. The point is we still need to initialize it.
So the code above should be:
dep_load {
{
'NTBBloodbath/doom-one.nvim',
function()
vim.cmd 'colorscheme doom-one'
end
}
}
dep_defer_load({
{
'NTBBloodbath/doom-one.nvim',
function()
vim.cmd 'colorscheme doom-one'
end
},
{
'lewis6991/gitsigns.nvim',
function()
require 'gitsigns'.setup()
end,
requires = 'nvim-lua/plenary.nvim',
}
}, 700)
But it will be a hassle if we should manually re-initialize every plugin that has been initialized before. Therefore, we are going to make function that automate the re-initialization. The gist is after we initialize plugin/s, we can save it to a table for future use, let's call it future_plugins
. Next if we're going to load another plugin/s, we will append list of plugin/s that we want to load to future_plugins
. Now future_plugins
contain our current plugins and can be used on the future. And so we load current future_plugins
. Zamn that's how we do re-initialization.
Next off let's write the actual code:
-- Create global table
_G.Dep_future_plugins = {}
-- Append 2nd table to 1st table
local tbl_append = function(tbl_1, tbl_2)
local result = {unpack(tbl_1)}
table.move(tbl_2, 1, #tbl_2, #result + 1, result)
return result
end
local dep_load = function(plugins)
_G.Dep_future_plugins = tbl_append(_G.Dep_future_plugins, plugins)
dep_bootstrap()
require 'dep'(_G.Dep_future_plugins)
end
Here you go, now here is the demo (If it looks laggy it is because of the video recorder. It didn't even show me pressing :q
):
Look at first doom-one
loaded first and 0.7s later doom-one
and gitsigns
loaded