Refactor py-config and the general initialization logic of the page (#806)

This PR is the first step to improve and rationalize the life-cycle of a pyscript app along the lines of what I described in #763 .
It is not a complete solution, more PRs will follow.
Highlights:

- py-config is no longer a web component: the old code relied on PyConfig.connectedCallback to do some logic, but then if no <py-config> tag was present, we had to introduce a dummy one with the sole goal of activating the callback. Now the logic is much more linear.

- the new pyconfig.ts only contains the code which is needed to parse the config; I also moved some relevant code from utils.ts because it didn't really belong to it

- the old PyConfig class did much more than dealing with the config: in particular, it contained the code to initialize the env and the runtime. Now this logic has been moved directly into main.ts, inside the new PyScriptApp class. I plan to refactor the initialization code in further PRs

- the current code relies too much on global state and global variables, they are everywhere. This PR is a first step to solve the problem by introducing a PyScriptApp class, which will hold all the mutable state of the page. Currently only config is stored there, but eventually I will migrate more state to it, until we will have only one global singleton, globalApp

- thanks to what I described above, I could kill the appConfig svelte store: one less store to kill :).
This commit is contained in:
Antonio Cuni
2022-10-04 14:26:12 +02:00
committed by GitHub
parent 4011a51013
commit c75f885cb4
12 changed files with 526 additions and 463 deletions

View File

@@ -1,3 +1,4 @@
import type { AppConfig } from './pyconfig';
import type { PyodideInterface } from 'pyodide';
import type { PyLoader } from './components/pyloader';
import {
@@ -8,7 +9,6 @@ import {
postInitializers,
Initializer,
scriptsQueue,
appConfig,
} from './stores';
import { createCustomElements } from './components/elements';
import type { PyScript } from './components/pyscript';
@@ -19,33 +19,6 @@ const logger = getLogger('pyscript/runtime');
export const version = "<<VERSION>>";
export type RuntimeInterpreter = PyodideInterface | null;
export interface AppConfig extends Record<string, any> {
name?: string;
description?: string;
version?: string;
schema_version?: number;
type?: string;
author_name?: string;
author_email?: string;
license?: string;
autoclose_loader?: boolean;
runtimes?: Array<RuntimeConfig>;
packages?: Array<string>;
paths?: Array<string>;
plugins?: Array<string>;
pyscript?: PyScriptMetadata;
}
export type PyScriptMetadata = {
version?: string;
time?: string;
}
export type RuntimeConfig = {
src?: string;
name?: string;
lang?: string;
};
let loader: PyLoader | undefined;
globalLoader.subscribe(value => {
@@ -67,15 +40,6 @@ scriptsQueue.subscribe((value: PyScript[]) => {
scriptsQueue_ = value;
});
let appConfig_: AppConfig = {
autoclose_loader: true
};
appConfig.subscribe((value: AppConfig) => {
if (value) {
appConfig_ = value;
}
});
/*
Runtime class is a super class that all different runtimes must respect
@@ -95,6 +59,7 @@ For an example implementation, refer to the `PyodideRuntime` class
in `pyodide.ts`
*/
export abstract class Runtime extends Object {
config: AppConfig;
abstract src: string;
abstract name?: string;
abstract lang?: string;
@@ -104,6 +69,11 @@ export abstract class Runtime extends Object {
* */
abstract globals: any;
constructor(config: AppConfig) {
super();
this.config = config;
}
/**
* loads the interpreter for the runtime and saves an instance of it
* in the `this.interpreter` property along with calling of other
@@ -187,7 +157,7 @@ export abstract class Runtime extends Object {
// Finally create the custom elements for pyscript such as pybutton
createCustomElements();
if (appConfig_ && appConfig_.autoclose_loader) {
if (this.config.autoclose_loader) {
loader?.close();
}