15

After recently learning about use-package I decided to port my configuration to it but found myself reluctant to give up the convenience of using package.el to install packages and keep them updated. I've found it a little tricky to combine use-package and package.el.

I'm generally interested in learning how people combine use-package with the package.el system, but for a more specific question, keep reading.

Here's what I want:

  1. To have packages installed by the package manager so I can easily browse for packages and keep them updated through list-packages.
  2. To configure and load packages exclusively through use-package, so I can easily see in my init file exactly what I'm loading and how it is configured.
  3. Optionally, I'd like to also be able to install packages through use-package's :ensure keyword.

If I'm understanding correctly I want very little of what package-initialize does, basically only the way it sets up the load-path. Currently I have this in my configuration:

;(package-initialize)
(setq package-enable-at-startup nil)
(let ((default-directory "~/.emacs.d/elpa"))
  (normal-top-level-add-subdirs-to-load-path))
(require 'use-package)

The first, commented, line is so Emacs 25 doesn't helpfully add a (package-initialize) to my init file. The bit with normal-top-level-add-subdirs-to-load-path is an approximation to what package-initialize would make the load-path, an approximation that seems good enough.

This seems to achieve my desires 1 and 2, but not 3. If I try to use :ensure, I get an error message saying that package.el is not initialized. Calling package-initialize would fix that, but I wish to avoid that since a) I don't want all the myriad autoloads to be loaded (I prefer to use use-package to create precisely the autoloads I need), and b) I want to be able to easily avoid loading certain installed packages whenever I want (which is easy to do with use-package).

Does anyone have a recommendation for how to do this?

11

IIUC what you want to do is:

(package-initialize t)

Note the t argument, which is the key to your happiness here since it will (or should, at least) initialize package.el without activating all the installed packages.

  • 1
    This answers my question, even though now I'm leaning towards using package-initialize which renders my question moot. – Omar Oct 5 '15 at 18:59
15

With your current configuration, you've effectively disabled package.el, as you don't initialise the package manager and prevent Emacs from automatically initialising it. All you do in return is to add ELPA to the load-path, but that's just a small subset of what package.el does. I'm not sure why you do that, but it's not a setup that I'd recommend.

Specifically, you'll not get package autoloads with your approach, which means that initially no commands from any package will be available.

In other words, M-x will only offer you built-in commands. To add in commands from your packages you'd have to add explicit :commands definitions to all your use-package declarations, which amounts to a lot of maintenance effort—particularly for large packages such as Magit—for essentially zero gain—package.el gives you autoloads for free.


Combining use-package with package.el is actually very simple—y entire setup is based on this combination—but it's much better to let package.el actually to its job. Just initialise package.el at the very beginning of your init file:

(require 'package)
(setq package-enable-at-startup nil)   ; To prevent initialising twice
(add-to-list 'package-archives '("melpa" . "https://stable.melpa.org/packages/"))

(package-initialize)

For convenience you may subsequently want to bootstrap use-package, if it's not already installed:

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

This let's you start an Emacs session on a fresh system, and your init.el will automatically install use-package.

Ultimately you need to load use-package:

(eval-when-compile
  (require 'use-package))

Now you can use use-package to install and configure packages:

(use-package magit                      ; The one and only Git frontend
  :ensure t
  :bind (("C-c v c" . magit-clone)
         ("C-c v v" . magit-status)
         ("C-c v g" . magit-blame)
         ("C-c v l" . magit-log-buffer-file)
         ("C-c v p" . magit-pull))
   :config (setq magit-save-repository-buffers 'dontask))

When Emacs now evaluates this form during startup, use-package will check whether Magit is already installed, and automatically install it if necessary.

  • 3
    "I'm not sure why you do that": the only reason I can see is about startup times: package-initialize takes some time to populate the path, define autoloads and do the rest of its stuff. I think I read somewhere that Jon Wiegley himself (the author of use-package) prefers declaring all autoloaded commands in use-package stanzas rather than relying on package.el. – ffevotte Sep 22 '15 at 8:44
  • Last time I looked he did not use package.el at all, and in any case, I don't think you'll gain a lot. You need to populate the load-path and add autoloads in either case, whether via use-package or via package.el. I doubt that there's a measurable difference, particularly if you've got a modern system with a fast disk. – lunaryorn Sep 22 '15 at 9:03
  • 3
    Agreed. I did the timings myself. With a fast disk, you effectively don't see much of a difference. With a slow disk, the startup can be noticeably slower (something like 0.2s) with package-initialize than a custom list in load-path. I attribute this to the "exploration" of the filesystem that package.el does. However, I never measured any significant difference in performance between loading autoload definitions from files and having them in use-package stanzas. – ffevotte Sep 22 '15 at 9:32
  • Well, I wouldn't say I've disabled the package.el system, I'd say I only disabled package-initialize! The reason is that while I like list-packages to browse for new packages and specially to update all my currently installed packages, I think I prefer the targeted loading of use-package. For me having autoloads only for commands I use sounds like a good thing! – Omar Sep 22 '15 at 13:59
  • 1
    @OmarAntolín-Camarena Why not? Autoloads are essentially the public interface of a user-facing package, and since package.el became the standard way of distributing packages we can rely upon their presence. – lunaryorn Oct 5 '15 at 20:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.