I’ve done some testing in an attempt to loading new windows faster. The major issues are caused by packages. When writing packages, here are some tips.

Do not require modules before activation.

Node.js promotes the pattern of putting all your “imports” at the top of the file. Do not do this on your main module. Remember that your mainModule is require()'d whenever a window loads, but all of your code need not be as well. You should know that require() does not scale well.

?= will check if the variable is null, and if so, will assign the value. If it’s not null, it’ll skip assigning the value.

Set activationEvents in your package.json

If your package doesn’t need to be activated before user input (which is every single package that isn’t part of the UI) then you should have an activationEvent set. These are either keybindings defined a ./keymap/*.cson file, or atom defined events.

Tips for obtaining metrics

Use timecop

The first time you load/activate a package, all .coffee files will be compiled and put into the coffeescript cache. So open a new window, then open a second window and open timecop on that second window.

Or does Atom now handle this all more efficiently, to the point where it isn’t any less optimal to just put all the requires at the top?

Atom has done a lot of optimization around compile and module caching. I haven’t looked at numbers recently, unfortunately. To my knowledge, these changes were targeting startup perf. But …

One thing to keep in mind is that even though it might be much faster to load because things don’t have to compile, if you’re the first package to load that module then you still take the perf hit for loading it. And if you don’t need to load it because it is something that might not be used … then why not load it later if it becomes necessary? So, it is still potentially better if you load only things when needed. But you have to balance that against the complexity of things and supportability, etc.

Nice… I see you have multiple commands here though (any of which rely on ./tabs-to-spaces). I’m currently working on a modular-keymaps package (it’s ready to publish actually) but here I only need fs.readdir and only on activation. Anyway here is my code at the moment…

I think it doesn’t work like that, since the module’s path is still in the require cache (and updates don’t clear the cache, remember my PR on that subject). The only exception is the package’s main file which is forcefully reloaded - hence the numerous errors when the main file use a new version of an API that haven’t been updated because it comes from another file that was not reloaded.

What I do now in the minimap is to put the following code at the top of my main file:

/*
The following hack clears the require cache of all the paths to the minimap when this file is loaded. It should prevents errors of partial reloading after an update.
*/
import path from 'path'
if (!atom.inSpecMode()) {
Object.keys(require.cache).filter((p) => {
return p !== __filename && p.indexOf(path.resolve(__dirname, '..') + path.sep) > -1
}).forEach((p) => {
delete require.cache[p]
})
}

May be out of topic, but I would like to share my experience, should it be useful to somebody.
My package atom-math was quite slow to activate and load (~300ms on my working machine - Arch Linux with Intel i7 @2.5GHz). This was quite weird, since the package actually does nothing when activated beside adding a few commands.

I used to require mathjs, one of the modules I’m using, at the beginning of the main file, in such fashion: