Package activateTime


#1

I am working on a package (https://atom.io/packages/code-annotations if anyone is interested :wink:) and try to improve the activateTime (the one that is shown in the Timecop package).

My problem is that the activation duration is about 4x times greater than the 2nd “slowest” package (see the screenshot). During development I have Atom open in dev mode. I have read that in dev mode things might start up slower than in non-dev mode and of course console logging also slows things down but the ratio (4x) is weird.

So I started looking how the activateTime is measured. https://github.com/atom/atom/blob/master/src/package.js seems the right place.
I have measured the duration of the activate method itself and it wasn’t long. So I figured the reason is some of the other activation functions called in package.activate i.e. activating keymaps, menus, stylesheets which I don’t have many of.

So the question is: What specific activation is taking so long?
Since I assume it’s not directly my code, could it be that using ES6 ('use babel') causing Atom to transpile code makes the package slow?


#2

Screenshot:


#3

The time appears to be used in your atom.workspace.observeActivePaneItem subscription. On closer look, it’s because you are awaiting the editor to load.

Removing this cut the declared activation time in half, but it is still my second highest activation time (below github).

It seems to have only a minor affect on the startup times though.

TL;DR: async is great, but difficult to measure.


#4

@Aerijo Thanks for the quick response. So you’re basically saying, the duration the timecop is showing for my package isn’t really as bad as it seems?

I could of course try to move more code into the window.setTimeout so it happens later (which makes sense in my case I guess), but it does not increase Atom’s startup time, right?


#5

IIRC, using top-level require() also has an impact on startup time. But since you’re using ES6 imports: have you considered using await import() instead?

I’m curious about the outcome. If it slows down the package at runtime, I’d probably prefer a longer activation time.


#6

@idleberg It makes sense that all the requires need time to actually be resolved and loaded.

After thinking about the dynamic import suggestion a bit, I think it’d be quite a lot of work figuring out what things to import on demand and make the code harder to read (since import would be scattered across a file instead of being grouped at the first few lines).

So wouldn’t it be best/easiest to transpile and bundle everything just like for non-Atom environments (using e.g.webpack)?


#8

I’ve never done anything that needs that before, so it sounds like it will just add a level of convolution for anyone who doesn’t know how it works.

Hmmm. Personally, I would prefer Atom loading faster over the package activating. Ideally, it would do the minimal setup at each stage (for any arbitrary package). After the first run of whatever command, everything should be loaded and it should be the same speed as a normal (non-lazy) package. Basically, I would prefer spreading the tasks over a (relatively) longer period of time, rather than all in one go.

E.g., with the code annotations package, what if I never use any annotations? It would have loaded all that stuff for nothing.

(I also restart Atom a lot, so that makes me appreciate quick load times more)


#9

I didn’t want to generalize, it really depends on the kind of package.


#10

Atom doesn’t have a way of knowing, without the package author telling it, which code should be loaded when it opens. Not all code gets used right away, but Atom has to read and compile everything in order to be ready when you need it. There is some support (the activationCommands key in package.json), but there could be more. The big problem would be getting package authors to be unified in setting their packages up in the most efficient manner.


#11

I meant putting stuff like requires and initialisations inside of the methods that use them. It’s not always practical, but I would use it if possible.

A really good example is the autocomplete-paths package. When I had it, it would greatly increase the window load time if I had a large folder open (ultimately to just give up and say there are too many files). If it had delayed the gathering of file paths, or done it in a separate process, it would have been less intrusive. (Of course, delaying just delays the issue. But I think a separate process could work)


#12

It would indeed by great if Atom would provide a way to easily define how a package is activated (in a declarative way). Is there an issue already or should we maybe create on on GitHub?

FYI, I tried out the bundling option cut the activation time in half (so imports do take some time I guess)! I’ll try the lazy-load-import option later.

Update

I tried dynamic imports (await import('...')) but Atom’s babel transpilation (using 'use babel' or a similar transpiler flag) does not support it: Failed to activate the package. .../lib/annotation-manager.js: Unexpected token. So transpilation must be done manually anyways (like I already did before using webpack).


#13

Might be useful for others if you could share your webpack.config.js


#14

Sure, this is my config for webpack 4:

const path = require('path')


module.exports = {
    mode: 'development',
    target: 'electron-main',
    context: __dirname,
    entry: './lib/annotation-manager.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        libraryTarget: 'commonjs2',
        libraryExport: 'default',
        library: '',
    },
    externals: {
        atom: 'atom',
        remote: 'remote',
    },
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                use: [
                    {loader: 'babel-loader'}
                ],
            },
        ],
    },
}

.babelrc:

{
    "presets": [
        [
            "env", {
                "targets": {
                    "electron": "1.7.11",
                },
                "useBuiltIns": true,
            }
        ],
        "stage-0",
        "react"
    ],
}

Update

As I realized just now, the package is not activated correctly which is probably what causes the activation time to be so “good”. :frowning: I’ve searched the atom repo but couldn’t find how exactly Atom transpiles babel JavaScript files. Any clues?

Update 2

After some research I found (in this issue) that my webpack config was not “correct enough”. So I added the libraryExport prop and everything works (probably pretty interesting for @idleberg ).
I also added my .babelrc file.


Latest regexp features in atom package
#15

Is there an error message in your console? I’ve tested your Webpack config in a boilerplate package, but maybe that was too basic to reproduce your problems.

I did have some problems, but they came from my package code, e.g. mixing import and module.export, which is not allowed.


#16

@idleberg I don’t get an error but the activate code is not executed. My main JS file default exports a class instead of a plain object:

export default class AnnotationManager {
    static activate(state) {
        // ...
    }

    // more methods here
}

So it seems this is a problem?! oO


#17

I have the same problem with ES6 import/ export, while require / module.export is working. I’ve played around with different targets, but haven’t had success yet. Would be great to find a solution, as I’ve started working on another generator for packages compiled with Webpack.


#18

See Update 2 of my reply.


#19

By the way, as of v1.28 Atom uses Electron v2


#20

@idleberg Yeah I know. The reason I chose 1.7.11 was because my package specifies

"engines": {
    "atom": ">=1.25.0 <2.0.0"
},

so I figures I should use the electron version of Atom 1.25.0. It was quite a lookup to find out which version of electron corresponds to a certain Atom version but I hope mine is right in my case. :wink:


#21

Can you explain this setting? Is it supposed to match the name of a named export?


library: ''