lewis6991 / pckr.nvim

Spiritual successor of https://github.com/wbthomason/packer.nvim
MIT License
243 stars 13 forks source link

lazy load dependencies of condition loading plugin #22

Closed epheien closed 1 month ago

epheien commented 2 months ago

Describe the feature

    {
      'nvim-tree/nvim-tree.lua',
      requires = {'nvim-tree/nvim-web-devicons'},
      cond = {cmd('NvimTreeOpen'), cmd('NvimTreeToggle')},
      config = function() require('config/nvim-tree') end,
    };

For example, in the above configuration, nvim-tree is conditionally loaded, but its dependency becomes unconditionally loaded.

It is best to load the dependencies of nvim-tree before loading it, rather than loading these dependencies at nvim startup.

lewis6991 commented 1 month ago

nvim-tree doesn't have a plugin/ directory, so lazy loading it is pointless.

What you want is to lazy load the configuration, not the plugin itself.

epheien commented 1 month ago

nvim-tree doesn't have a plugin/ directory, so lazy loading it is pointless.

What you want is to lazy load the configuration, not the plugin itself.

But nvim-web-devicons has plugin/nvim-web-devicons.vim.

If nvim-web-devicons cannot follow nvim-tree to implement lazy loading, it will slow down the startup speed of nvim

What I am saying is that, in general, when a plugin is lazy loaded, its dependencies must also be lazy loaded with it.

lewis6991 commented 1 month ago

But nvim-web-devicons has plugin/nvim-web-devicons.vim.

Which does very very little: https://github.com/nvim-tree/nvim-web-devicons/blob/master/plugin%2Fnvim-web-devicons.vim

Lazy loading is often done incorrectly and should always be implemented by plugins directly, not by users of package managers.

epheien commented 1 month ago

In practical use, it is impossible to require every plugin to fully implement lazy loading, especially for some old-fashioned Vimscript plugins.

For example:

    {
      'nvim-telescope/telescope.nvim',
      tag = '0.1.8',
      requires = {'nvim-lua/plenary.nvim', 'debugloop/telescope-undo.nvim', 'nvim-tree/nvim-web-devicons'},
      cond = {cmd('Telescope')},
      config = function() require('config/telescope') end,
    };

...

  table.insert(plugins, {
    "rcarriga/nvim-dap-ui",
    requires = {"mfussenegger/nvim-dap", "nvim-neotest/nvim-nio"},
    cond = cmd('DapuiToggle'),
    config = function()
      require('dapui').setup()
      vim.api.nvim_create_user_command('DapuiToggle', function() require('dapui').toggle() end, {})
    end,
  })

  table.insert(plugins, {
    'mfussenegger/nvim-dap',
    cond = cmd('DapToggleBreakpoint'),
    config = function()
      vim.api.nvim_create_user_command('DapHover', function() require"dap.ui.widgets".hover() end, {})
    end
  })

nvim-lua/plenary.nvim, 'nvim-tree/nvim-web-devicons' both have plugin/xxx.vim, mfussenegger/nvim-dap has plugin/xxx.lua.

Moreover, even if these loaded . vim and . lua files are small, as more plugins are installed, the startup speed of NVIM will significantly decrease.

lewis6991 commented 1 month ago

In practical use, it is impossible to require every plugin to fully implement lazy loading, especially for some old-fashioned Vimscript plugins.

I've written and maintain enough popular and large plugins to know for a fact that isn't true. Even a well written vimscript plugin can be structured properly to minimise startup time. vim-fugitive is a good example.

You can see the load time of each plugin by running Pckr status. For me most time is spent in config blocks which can be easily deferred without lazy loading the whole plugin, but even then these aren't long enough to bother with.

Moreover, even if these loaded . vim and . lua files are small, as more plugins are installed, the startup speed of NVIM will significantly decrease.

No it will not.

I do not lazy load a single plugin and my startup time is around 80ms and 100ms to a buffer. That's quick enough for any sane person.

Quite frankly, the amount of time you have probably spent thinking about lazy loading far outweighs any gains you've seen.

If you have some concrete examples where lazy loading makes an observable difference, then I would be happy to review them.

epheien commented 1 month ago

If you have some concrete examples where lazy loading makes an observable difference, then I would be happy to review them.

Some operating systems have additional startup delays when starting NVIM, such as Windows and macOS arm64 running x86 NVIM. On top of these delays, loading a few more files can result in a delay of over 100ms. As long as the startup delay exceeds 100ms, users will feel a significant delay.

Another reason is that this feature is a fundamental feature in lazy.nvim: https://github.com/folke/lazy.nvim/blob/main/lua/lazy/example.lua#L44

  {
    "hrsh7th/nvim-cmp",
    -- load cmp on InsertEnter
    event = "InsertEnter",
    -- these dependencies will only be loaded when cmp loads
    -- dependencies are always lazy-loaded unless specified otherwise
    dependencies = {
      "hrsh7th/cmp-nvim-lsp",
      "hrsh7th/cmp-buffer",
    },
    config = function()
      -- ...
    end,
  },

So why do I use pckr instead of lazy.nvim? Because pckr is compatible with Vim's junegunn/vim-plug plugin.

And because my configuration file is partially compatible with Vim, there is an additional delay in reading vimrc(init.vim). Therefore, I need to require all my plugins that can be lazily loaded to be set to lazy loading.

lewis6991 commented 1 month ago

Some operating systems have additional startup delays when starting NVIM, such as Windows and macOS arm64 running x86 NVIM.

Maybe don't run x86 binaries on aarch64 systems? That's certainly not a use case I will optimise for. And you get those delays whether you lazy load or not so that point is irrelevant.

On top of these delays, loading a few more files can result in a delay of over 100ms. As long as the startup delay exceeds 100ms, users will feel a significant delay.

100ms isn't a hard threshold; 200, or even 300ms is fine for slow systems. And there's no evidence that lazy loading a set of small files meaningfully improves this.

Another reason is that this feature is a fundamental feature in lazy.nvim:

Lazy loading is not a fundamental feature of pckr. Conditional loading is provided as a small feature with a small amount of code, and there are some very niche exceptional cases where conditional loading does provide some value.

Because pckr is compatible with Vim's junegunn/vim-plug plugin.

And because my configuration file is partially compatible with Vim, there is an additional delay in reading vimrc(init.vim). Therefore, I need to require all my plugins that can be lazily loaded to be set to lazy loading.

This doesn't make any sense. Pckr's configuration is defined in Lua, just like lazy.nvim. The interface is very similar.

I'm surprised you've still not provided any evidence of lazy loading meaningfully decreasing startup time.

epheien commented 1 month ago

I'm surprised you've still not provided any evidence of lazy loading meaningfully decreasing startup time.

nvim --startuptime startuptime.txt I can see unnecessary loading, which took about 10ms when I didn't use many plugins. (I am unable to provide this log at the moment as I have been using my fork version of pckr for a long time and immediately added a dependency plugin for delayed loading)

If you say 10ms may seem insignificant, but what I need to consider is that in the long run, if I use more plugins in the future, the increased latency of this hidden danger will make me feel uncomfortable using PCKR

lewis6991 commented 1 month ago

It sounds like lazy.nvim is what you want.