Improve Obsidian Startup Time on Older Devices with the FastStart Script

Just published an article on improving startup time. Obsidian is fast, but with a lot of plugins, some experience a startup delay.

I present a simple hack to get around this.

8 Likes

Hey!

I made a little python script to accelerate the process.

First, edit the template for plugins list (FastStart-GenerateListOfInstalledPlugins) with :

<% "- [ ] " + Object.values(app.plugins.manifests).map(p=>p.id).sort((a,b)=>a.localeCompare(b)).join('\n- [ ] ') 
%>

The list generated from this template will be a task list

Now, you need to class your plugins :

  • - [x] (check) will mark as a short delay plugins.
  • Any checked mark not x and not empty (so any - [char]) will be marked as a long delay
  • To keep the state (disabled/start when Obsidian open), you can remove from list or leave - [ ].

Note

  • I use - [>] for short delay here, but you can use any character in your check mark*
  • I use a empty check mark to keep the state of my plugins (disabled forever or start at obsidian’s opening)

After, download this little python file.

You need to edit the path :

  • short : The (absolute) path to FastStart-Plugins-ShortDelay.md
  • long : The (absolute) path to FastStart-Plugins-LongDelay.md
  • plugin : The absolute path to generated list by FastStart-GenerateListOfInstalledPlugins

After, you just have to run using python -m class_list.py

:bulb: You can put the python script in your Obsidian vault without problem :D.

Moreover, if you don’t like to use checked mark for short delay you can edit the script here, editing the - [x] for any value you want (you can also use ctrl + f & edition…)

2 Likes

Thanks a ton. It was exactly what I was looking for.

1 Like

Hello!
With the plugin User Plugins you can create an user script mimic-ing a plugin, that will start the module for you, so you can write in all JS instead of relying on templater.
I first created this fast-start.js file (don’t forget to configure your User plugins and put the file in the configured folder) :

module.exports = {}

class Settings {
    /**
     * Constructor for the settings, for mobile & PC
     * @param {number} shortDelay the short delay in seconds
     * @param {number} longDelay the long delay in seconds
     * @param {string} file the file containing the list of plugins for PC or mobile
     * @param {boolean} noticeMe whether to show a notice when the plugin is loaded
     */
    constructor(shortDelay, longDelay, file, noticeMe) {
        this.shortDelay = shortDelay;
        this.longDelay = longDelay;
        this.file = file;
        this.noticeMe = noticeMe;
    }
}

const pcSettings = new Settings(2, 8, "Outils/Plugins/FastStarts/PC.md", true);
const mobileSettings = new Settings(8, 15, "Outils/Plugins/FastStarts/Mobile.md", true);

module.exports.onload = async (plugin) => {
    console.log('loading fast-start')
    /**
     * Fast start function to start in a short / long delay the plugins
     * @param {Settings} settings Settings for the plugin
     * @returns {Promise<void>}
    */
    async function fastStart(settings) {
        const getFile = plugin.app.metadataCache.getFirstLinkpathDest(settings.file, '');
        const contents = await plugin.app.vault.read(getFile);
        let allPlugins = contents.split(/r?\n/);
        let short = [];
        let long = [];
        let disable = [];
        for (let i = 0; i < allPlugins.length; i++) {
            if (allPlugins[i].startsWith('- [x]')) {
                short.push(allPlugins[i].slice(6, allPlugins.lenth))
            } else if (allPlugins[i].startsWith('- [>]')) {
                long.push(allPlugins[i].slice(6, allPlugins.lenth))
            } else if (allPlugins[i].startsWith('- [c]')) {
                disable.push(allPlugins[i].slice(6, allPlugins.lenth))
            }
        }
        setTimeout(async () => {
            short.forEach(async p => {
                await plugin.app.plugins.enablePlugin(p)
            }, settings.shortDelay * 1000);
        });
        setTimeout(async () => {
            long.forEach(async p => {
                await plugin.app.plugins.enablePlugin(p)
            }, settings.longDelay * 1000);
        });

        disable.forEach(async p => {
            await plugin.app.plugins.disablePlugin(p)
        });
        if (settings.noticeMe) {
            new Notice('=== Fast-start loaded ===');
        }
    }

    try {
        if (!plugin.app.isMobile) {
            await fastStart(pcSettings);
        } else {
            await fastStart(mobileSettings);
        }
    } catch (error) {
        new Notice(error);
        console.log(error);
    }


    plugin.addCommand({
        id: 'List-plugins',
        name: 'List loaded plugins',
        checkCallback: async (checking) => {
            var plugins = Object.values(plugin.app.plugins.manifests).map(p => p.id).sort((a, b) => a.localeCompare(b));
            let written = [];
            const actualOpenedFile = plugin.app.workspace.getActiveFile();
            if (actualOpenedFile && actualOpenedFile.extension === 'md') {
                if (!checking) {
                    let contents = await plugin.app.vault.read(actualOpenedFile);
                    const listedPlugin = contents.split(/\r?\n/);
                    written = listedPlugin.map(p => p.slice(6));
                    let missingPlugin = plugins.filter(val => !written.includes(val)).filter(val => val.length > 0);
                    let removedPlugin = written.filter(val => !plugins.includes(val)).filter(val => val.length > 0);
                    let msg = 'Upaded list of plugins. ';
                    if (missingPlugin.length === 0 && removedPlugin.length === 0) {
                        msg = 'List of plugins is up to date and alphabetical sorted.';
                    }
                    if (removedPlugin.length > 0) {
                        removedPlugin.forEach(p => {
                            const replacer = new RegExp('\\- \\[.?\\] ' + p, "i");
                            contents = contents.replace(replacer, '');
                        });
                        msg += `${removedPlugin.length} plugin(s) deleted`;
                    }
                    contents = contents.split('\n')
                        .sort((a, b) => a.replace(/\- ((\[{2})|(\[.\]) )?/i, '')
                            .toLowerCase()
                            .localeCompare(b.replace(/\- ((\[{2})|(\[.\]) )?/i, '')
                                .toLowerCase()))
                        .join('\n');
                    if (missingPlugin.length > 0) {
                        contents = contents + '\n- [ ] ' + missingPlugin.join('\n- [ ] ');
                        msg += `${missingPlugin.length} plugin(s) added`;
                    }
                    await plugin.app.vault.modify(actualOpenedFile, contents.trim());
                    await new Notice(msg);
                }
                return true;
            }
            return false;
        }
    });
}
6 Likes

I’ve played with the script here (possibly not doing it right) and with Lazy Plugin Loader, and the only things that make a difference for me are:

  • Use only essential plugins. If I can find an acceptable workflow that doesn’t need a plugin, I use that.
  • when startup time is getting slow, turn on restricted mode to disable all plugins, restart, then turn off again to enable plugins.

I’ve currently got my vault (9200 files, 303 MB) opening in 4–5 seconds on Android.

Times are taken from the “Startup time” page in settings (I think the actual total time is about 1–2 seconds longer, in practice):
Settings > General > Advanced > Notify if startup takes longer than expected > (click stopwatch icon on right)

Also, on Android I use the ObsiNote Flash app to very quickly capture thoughts, without having to open Obsidian or navigate to the right note. I just have to remember to process them.