How to determine what triggered package to load? Unable to defer package

What happened?

Hello. I’m a bit confused about what is run at startup and when does it happen. I understand that Doom doesn’t load all packages at startup. I also understand that the code under :config is loaded only after the package is loaded.

What did you expect to happen?

(use-package! package-name
  :defer 200

For a declaration like this, I expect package-name to only be loaded after 200 seconds of idle time; and for whatever is under :config to load after that. However, the package is loaded at startup. I know this because I have some code in :config that takes 1-2 minutes to run, and it is greatly increasing my startup time.

To debug, I therefore wanted to know if there a way to figure out what triggered the loading of any package in general?

As a secondary question, I also wanted to find out what’s the difference between :config and (after! package-name). Thanks!!

Steps to reproduce

I would like to ask a general Doom question with no steps to reproduce.

System information

generated Oct 18, 2022 23:40:32 system Ubuntu 20.04.2 LTS Linux 5.4.72-microsoft-standard-WSL2 x86_64 x emacs 28.1 ~/doom-emacs/ → ~/doom-emacs/ doom 3.0.0-dev HEAD → master b06fd63d 2022-08-08 23:41:06 +0200 ~/.doom.d/ → ~/.doom.d/ shell /bin/bash features ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND THREADS TIFF TOOLKIT_SCROLL_BARS X11 XDBE XIM XPM XWIDGETS GTK3 ZLIB traits gui daemon server-running chemacs-2.0 envvar-file modules :completion company ivy :ui deft doom doom-dashboard doom-quit (&nopath fill-column) hl-todo minimap modeline ophints (popup +defaults) treemacs vc-gutter vi-tilde-fringe workspaces zen :editor (evil +everywhere) file-templates fold (format +onsave) multiple-cursors snippets :emacs dired electric undo vc :term eshell vterm :checkers syntax (spell +flyspell) grammar :tools ein (eval +overlay) lookup lsp magit pdf :os tty :lang emacs-lisp markdown (org +pretty +journal +roam2 +dragndrop +present) (python +lsp +pyright +conda) sh yaml :config (default +bindings +smartparens) packages (evil-tutor) (mixed-pitch) (org-fancy-priorities) (org-download) (org-noter) (org-ref) (org-roam-bibtex) (f) (phscroll :recipe (:host github :repo misohena/phscroll)) (org-roam-ui) unpin org-roam

  • benchmark-init package

    See this comment for setup instructions. After reloading Emacs, do M-x benchmark-init/show-durations-tree to display dependency tree.

  • load-history variable

    A less user-friendly variant of the previous option. Lookup (require . package-name) form to see, the file package-name has been required from.

  • after-load-functions variable

    Find which function a package was loaded from.

    Put something like this in “init.el” and reload Emacs

    (add-hook 'after-load-functions
              (defun my/after-load-package-name-h (file)
                (when (member '(provide . gnus-sum)
                              (cdr (assoc file load-history)))

    Find backtrace in the M-x view-echo-area-messages (SPC h e) buffer.

See docstring of the after! macro. It provides a simple DSL to wait for multiple packages to load.

However, in case of a single feature, these two are the same.

(after! FEATURE
  (message "FEATURE LOADED"))
(use-package! FEATURE
  :defer t
  (message "FEATURE LOADED"))

BTW, try macrostep-expand command (SPC m m) in elisp-mode buffers to interactively (and recursively) expand them. This really helps avoid guessing.