Search code examples
emacshookmajor-modeeval-after-load

When to use add-hook, eval-after-load in Emacs


I'v read eval-after-load vs add-hook. According to the page, code in eval-after-load is executed once.
On the other hand, code inside add-hook will run every time a buffer of that mode in opened.

Ok. But How can I figure out which code should be inside eval-after-load block or add-hook block? for example,

(eval-after-load "js2-mode"
  '(progn
      (js2-basic-offset 2)))

or

(eval-after-load "js2-mode"
  '(progn
      (defun custom:js2-config ()
        (js2-basic-offset 2))
      (add-hook 'js2-mode-hook 'custom:js2-config)))

I'm not asking about js2-basic-offset.
Is there a general rule? or.. whenever I use eval-after-load, I have to ask?


Solution

  • Are you setting a global variable or a local variable?

    If you're setting a buffer-local variable (one whose value may be different in different buffers), it has to be done after the file is loaded, so in the major mode hook. The same thing goes if you're calling a function which has an effect on the current buffer.

    If you're setting a global variable, it doesn't make sense to do that in a mode hook: you'd be changing a global variable whenever you happen to load a file in a certain mode. The same thing goes if you're calling a function which affects global settings.

    Many global variables can be set directly in your .emacs, without waiting for the library that will declare and use it to be loaded. In fact, this is usually the case for global variables.

    js2-basic-offset is a variable, not a function. If you want to configure the indentation in all JS buffers, set it directly in your .emacs, either with

    (setq js2-basic-offset 2)
    

    or through the Customize interface.

    If you want to set the value differently in different files, then you would set it in the major mode hook — something like

    (defun custom:js2-config ()
      (when (…)
        (make-local-variable 'js2-basic-offset)
        (setq js2-basic-offset 2)))
    (add-hook 'js2-mode-hook 'custom:js2-config)
    

    You don't need to wait for the library to be loaded to add a hook.

    Note that Emacs has built-in facilities that cover typical use cases of setting a variable on a per-file or per-project basis: file-local variables and directory-local variables.