设置 use-package 的 defer 为 t 后,Emacs 是如何加载这个 package 的?展开 use-package 宏后,也没看到有 load 对应 package 的 autoload 文件的命令,难道是等其他地方 require 或者 autoload?这里有些迷惑。
按道理,autoload 语句必须要 evaluated 才能被知道哪个函数是 autoload 的吧?
补充:user-package 文档里的一句话:
In almost all cases you don’t need to manually specify :defer t. This is implied whenever :bind or :mode or :interpreter is used. Typically, you only need to specify :defer if you know for a fact that some other package will do something to cause your package to load at the appropriate time, and thus you would like to defer loading even though use-package isn’t creating any autoloads for you.
这句话意思是不是表示必须要确认有其他package 会导致 load 该 package 的时候,才能使用 defer?
也就是说 defer 并不能乱用? 乱用会导致 package 不能被 load,是这意思吧?
Samray
2017 年10 月 10 日 03:17
2
贴一下我之前写的关于use-package
加载机制的博文:
:after
;;; Export to twitter bootstrap
(use-package ox-twbs
:after org
:ensure ox-twbs
)
:after
关键字的作用基本跟 with-eval-after-load
的作用是相同的,所以我所
有类似的org-mode 插件包都会在org-mode 加载以后才会加载
:commands
(use-package avy
:commands (avy-goto-char avy-goto-line)
:ensure t)
这里就直接贴上 use-package 文档的说明了:
When you use the :commands keyword, it creates autoloads for those commands
and defers loading of the module until they are used
也就是 :commands
关键字就创建了后面所接的命令的 autoloads
机制了
:bind :mode
(use-package hi-lock
:bind (("M-o l" . highlight-lines-matching-regexp)
("M-o r" . highlight-regexp)
("M-o w" . highlight-phrase)))
(use-package vue-mode
:ensure t
:mode ("\\.vue\\'" . vue-mode)
:config (progn
(setq mmm-submode-decoration-level 0)
))
附上文档说明
In almost all cases you don’t need to manually specify :defer t
. This is implied
whenever :bind
or :mode
or :interpreter
is used
也就是说,当你使用了 :bind
或者 :mode
关键字的时候,不用明确指定 :defer
也可以实现延迟加载机制。当然你也可以,直接使用 :defer
关键字来指定延迟加载
不过前提是,你要明确它加载的时机
Typically, you only need to specify :defer if you know for a fact that some
other package will do something to cause your package to load at the appropriate
time, and thus you would like to defer loading even though use-package isn’t
creating any autoloads for you.
贴上我自己的代码,可以更加清晰
(use-package anaconda-mode
:defer t
:ensure t
:init(progn
(add-hook 'python-mode-hook 'anaconda-mode)
(add-hook 'python-mode-hook 'anaconda-eldoc-mode)
))
这样 anaconda-mode
就会在 python-mode
加载以后被加载
1 个赞
恩,看着跟我理解的是一样的,使用 defer 必须要自己明确加载时机,如果没有其他 package 或者 add-hook/ with-evil-after-load 等,那么这个package就不会被加载了。
LdBeth
2017 年10 月 10 日 03:29
4
对于 elpa 安装的包,会自动根据代码中的 ;;;###autoload
标记生成 autoloads 文件并加载,
自定义的包应该要自己明确指定加载时机。对于 elpa 的包,自动生成 autoload 文件后,是在哪儿加载的?
是 emacs 自己做的事情还是 use-package 做的事情?
use-package 宏展开后没有看到相关代码,如果是 emacs 自己做的这个事情,那对于直接 require 的 package,岂不是多执行了一次 autoload 的文件?
LdBeth
2017 年10 月 10 日 03:43
6
elpa 自动加载 autoloads 文件,里面就是一堆 autoload 定义,比如这样:
;;; parinfer-autoloads.el --- automatically extracted autoloads
;;
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "parinfer" "parinfer.el" (23001 7231 113740
;;;;;; 239000))
;;; Generated autoloads from parinfer.el
(autoload 'parinfer-mode "parinfer" "\
Parinfer mode.
\(fn &optional ARG)" t nil)
(autoload 'parinfer-region-mode "parinfer" "\
Available when region is active.
\(fn &optional ARG)" t nil)
;;;***
;;;### (autoloads nil nil ("parinfer-ext.el" "parinfer-pkg.el" "parinferlib.el")
;;;;;; (23001 7231 115752 444000))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; End:
;;; parinfer-autoloads.el ends here
这些 autoloads 在 (package-initialize)
的时候会被加载。
use-package
用了 defer 以后就不负责加载,只负责在相关包加载时执行对应配置。
举例,你安装了 notmuch,用 use-package defer,并用它配置了按键,刚打开时,notmuch 是没有加载的, 只有一个 autoload notmuch 的定义,只有执行 M-x notmuch
以后才会根据 autoload 加载对应的文件。
1 个赞
好的,那就是 package-initialize 干的事情了
另外,问个问题,你这个配置最后的:
(add-hook 'python-mode-hook 'anaconda-mode)
这个 add-hook 会去调用 (require 'anaconda-mode) ?
如果没有加载 anaconda-mode.el,而 add-hook 只是把 anaconda-mode 当做一个 function,那如果没有加载 autoload 文件和 anaconda-mode.el 文件,那应该会出现找不到 anaconda-mode 的错误吧?
补充:
测试后确实是这样的,你最后的配置能够正常工作是因为,anaconda 是 elpa package,有 autoload 文件,并在 package-initialize 时候加载了 autoload 文件,这样当你 add-hook 后,会通过 autoloading 机制加载 anaconda,然后再去执行 anaconda-mode 。但是对于自定义的 package,这样是不行的了,只能通过 bind, commands 等方案将某个函数声明一次 autoload,然后就可以autoload了,或者自己生成 autoload 文件后,在 user-package 的 init 阶段 load一下自定义 package 的 autoload 文件
Samray
2017 年10 月 10 日 03:58
9
我感觉应该会出现这样的问题,只是我在add-hook
之前是看了一下anaconda-mode
的源码
;;;###autoload
(define-minor-mode anaconda-mode
"Code navigation, documentation lookup and completion for Python.
\\{anaconda-mode-map}"
:lighter anaconda-mode-lighter
:keymap anaconda-mode-map)
;;;###autoload
(define-minor-mode anaconda-eldoc-mode
"Toggle echo area display of Python objects at point."
:lighter ""
(if anaconda-eldoc-mode
(turn-on-anaconda-eldoc-mode)
(turn-off-anaconda-eldoc-mode)))
所以手动指定defer
一般是我最后的选择,可以的话,都是先用其他的方式