Repository: pyscript/pyscript
File: pyscriptjs/src/plugin.ts (TypeScript)

Code before:
        this._plugins = [];
        this._pythonPlugins = [];
    }

    add(...plugins: Plugin[]) {
        for (const p of plugins) this._plugins.push(p);
    }

    addPythonPlugin(plugin: any) {
        this._pythonPlugins.push(plugin);
    }

    configure(config: AppConfig) {
        for (const p of this._plugins) p.configure?.(config);

        for (const p of this._pythonPlugins) p.configure?.(config);
    }

    beforeLaunch(config: AppConfig) {
        for (const p of this._plugins) {
            try {
                p?.beforeLaunch?.(config);
            } catch (e) {
                logger.error(`Error while calling beforeLaunch hook of plugin ${p.constructor.name}`, e);
            }
        }
    }

    afterSetup(interpreter: Interpreter) {
        for (const p of this._plugins) {
            try {
                p.afterSetup?.(interpreter);
            } catch (e) {
                logger.error(`Error while calling afterSetup hook of plugin ${p.constructor.name}`, e);
            }
        }

        for (const p of this._pythonPlugins) p.afterSetup?.(interpreter);
    }

    afterStartup(interpreter: Interpreter) {
        for (const p of this._plugins) p.afterStartup?.(interpreter);

        for (const p of this._pythonPlugins) p.afterStartup?.(interpreter);
    }

    beforePyScriptExec(options: {interpreter: Interpreter, src: string, pyScriptTag: HTMLElement}) {
        for (const p of this._plugins) p?.beforePyScriptExec?.(options);

        for (const p of this._pythonPlugins) p.beforePyScriptExec?.callKwargs(options);
    }

Review comment (suggestion):
I think we can remove the try/catch all over the lifecycle, this was my silly way to not have plugins blow up if they don't implement a certain method 😅 

I didn't know that you could do `?.` just before passing an argument to the function haha

Code after:

    constructor() {
        this._plugins = [];
        this._pythonPlugins = [];
    }

    add(...plugins: Plugin[]) {
        for (const p of plugins) this._plugins.push(p);
    }

    addPythonPlugin(plugin: any) {
        this._pythonPlugins.push(plugin);
    }

    configure(config: AppConfig) {
        for (const p of this._plugins) p.configure?.(config);

        for (const p of this._pythonPlugins) p.configure?.(config);
    }

    beforeLaunch(config: AppConfig) {
        for (const p of this._plugins) {
            try {
                p?.beforeLaunch?.(config);
            } catch (e) {
                logger.error(`Error while calling beforeLaunch hook of plugin ${p.constructor.name}`, e);
            }
        }
    }

    afterSetup(interpreter: Interpreter) {
        for (const p of this._plugins) {
            try {
                p.afterSetup?.(interpreter);
            } catch (e) {
                logger.error(`Error while calling afterSetup hook of plugin ${p.constructor.name}`, e);
            }
        }

        for (const p of this._pythonPlugins) p.afterSetup?.(interpreter);
    }

    afterStartup(interpreter: Interpreter) {
        for (const p of this._plugins) p.afterStartup?.(interpreter);

        for (const p of this._pythonPlugins) p.afterStartup?.(interpreter);
    }

    beforePyScriptExec(options: {interpreter: Interpreter, src: string, pyScriptTag: PyScriptTag}) {
        for (const p of this._plugins) p.beforePyScriptExec?.(options);