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;
        }
    });
}
4 Likes