Activation events
Activation events tell the host when to load an extension's main JS. Loading is lazy: the sandbox boots and activate() runs only when one of the declared events fires. This keeps Aero light — code you don't use never loads.
When you need them
You need activation events only if your extension has a main (i.e. command logic). Theme-only, snippet-only, and keybinding-only extensions need no activation events and no main — their declarative contributions register directly from the manifest at install/enable time.
| Extension ships… | main | activationEvents |
|---|---|---|
| Themes / snippets / keybindings | no | no |
| Commands with JS handlers | yes | yes |
The events
Declare them in aero.json:
"activationEvents": ["onCommand:dracula-warm.apply"]| Event | Fires when… |
|---|---|
onCommand:<commandId> | the user runs that command. The common case. |
onStartup | the IDE finishes booting. Use sparingly. |
* | eager — loads immediately. Discouraged; reserve for tiny extensions. |
The schema validates each event against ^(onCommand:[A-Za-z0-9_.-]+|onStartup|\*)$.
onCommand:<commandId>
The recommended pattern. The host loads main the first time the user runs the command (from the palette or a keybinding), then calls activate(context) and your registered handler. One activation event per command you handle:
{
"main": "extension.js",
"activationEvents": [
"onCommand:my-ext.format",
"onCommand:my-ext.toggle"
]
}onStartup
Fires once when the IDE finishes booting. Use it only if your extension genuinely needs to do work before the user invokes anything (rare in v1). Prefer onCommand: so you stay out of the boot path.
* (eager)
Loads the extension immediately, every launch. Discouraged — it defeats lazy loading and adds to startup. Reserve for very small extensions where the cost is negligible.
The activation lifecycle
When an activation event fires, the host:
- boots the sandboxed
<iframe>for the extension (one in-flight activation per extension is enforced); - loads
mainand callsactivate(context); - emits
ext:activated { id }onAeroBus.
Your activate receives a context and should push every Disposable it creates onto context.subscriptions so the host can clean them up on deactivate:
'use strict';
function activate(context) {
const sub = aero.commands.registerCommand('my-ext.format', () => {
/* … */
});
context.subscriptions.push(sub);
}
// Optional. Called when the extension is disabled/uninstalled.
function deactivate() {}The context shape ({ extensionId, subscriptions }) is documented in The aero.* API.
Related
- Commands — what
activateregisters. - The
aero.*API — what the handler can call.