diff --git a/pyscriptjs/examples/simple_clock.html b/pyscriptjs/examples/simple_clock.html
index 4747e8893e4..fa3f937d325 100644
--- a/pyscriptjs/examples/simple_clock.html
+++ b/pyscriptjs/examples/simple_clock.html
@@ -14,6 +14,14 @@
- paths:
- ./utils.py
+
+ - autoclose_loader: false
+ - runtimes:
+ -
+ src: "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
+ name: pyodide-0.20
+ lang: python
+
@@ -43,6 +51,8 @@
else:
out3.clear()
+# close the global PyScript pyscript_loader
+pyscript_loader.close()
pyscript.run_until_complete(foo())
diff --git a/pyscriptjs/src/App.svelte b/pyscriptjs/src/App.svelte
index 71c131978ca..b257500ec1c 100644
--- a/pyscriptjs/src/App.svelte
+++ b/pyscriptjs/src/App.svelte
@@ -1,76 +1,5 @@
-
-
-
-
diff --git a/pyscriptjs/src/components/pyconfig.ts b/pyscriptjs/src/components/pyconfig.ts
index 6b928d89152..f6657ed5015 100644
--- a/pyscriptjs/src/components/pyconfig.ts
+++ b/pyscriptjs/src/components/pyconfig.ts
@@ -1,18 +1,133 @@
import * as jsyaml from 'js-yaml';
import { BaseEvalElement } from './base';
-import { appConfig } from '../stores';
+import { initializers, loadedEnvironments, mode, postInitializers, pyodideLoaded, scriptsQueue, globalLoader, appConfig, Initializer } from '../stores';
+import { loadInterpreter } from '../interpreter';
+import type { PyScript } from './pyscript';
-let appConfig_;
-appConfig.subscribe(value => {
- appConfig_ = value;
-});
+const DEFAULT_RUNTIME = {
+ src: "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js",
+ name: "pyodide-default",
+ lang: "python"
+}
+
+export type Runtime = {
+ src: string;
+ name?: string;
+ lang?: string;
+};
export type AppConfig = {
autoclose_loader: boolean;
name?: string;
version?: string;
- };
+ runtimes?: Array;
+};
+
+let appConfig_: AppConfig = {
+ autoclose_loader: true,
+};
+
+appConfig.subscribe( (value:AppConfig) => {
+ if (value){
+ appConfig_ = value;
+ }
+ console.log("config set!")
+});
+
+let initializers_: Initializer[];
+initializers.subscribe( (value:Initializer[]) => {
+ initializers_ = value;
+ console.log("initializers set")
+});
+
+let postInitializers_: Initializer[];
+postInitializers.subscribe( (value:Initializer[]) => {
+ postInitializers_ = value;
+ console.log("post initializers set")
+});
+
+let scriptsQueue_: PyScript[];
+scriptsQueue.subscribe( (value: PyScript[]) => {
+ scriptsQueue_ = value;
+ console.log("post initializers set")
+});
+
+let mode_: string;
+mode.subscribe( (value:string) => {
+ mode_ = value;
+ console.log("post initializers set")
+});
+
+
+let pyodideReadyPromise;
+let loader;
+
+
+globalLoader.subscribe(value => {
+ loader = value;
+});
+
+
+export class PyodideRuntime extends Object{
+ src: string;
+
+ constructor(url:string) {
+ super();
+ this.src = url;
+ }
+
+ async initialize(){
+ loader.log("Loading runtime...")
+ pyodideReadyPromise = loadInterpreter(this.src);
+ const pyodide = await pyodideReadyPromise;
+ const newEnv = {
+ id: 'a',
+ promise: pyodideReadyPromise,
+ runtime: pyodide,
+ state: 'loading',
+ };
+ pyodideLoaded.set(pyodide);
+
+ // Inject the loader into the runtime namespace
+ pyodide.globals.set("pyscript_loader", loader);
+
+ loader.log("Runtime created...")
+ loadedEnvironments.update((value: any): any => {
+ value[newEnv['id']] = newEnv;
+ });
+
+ // now we call all initializers before we actually executed all page scripts
+ loader.log("Initializing components...")
+ for (const initializer of initializers_) {
+ await initializer();
+ }
+
+ // now we can actually execute the page scripts if we are in play mode
+ loader.log("Initializing scripts...")
+ if (mode_ == 'play') {
+ for (const script of scriptsQueue_) {
+ script.evaluate();
+ }
+ scriptsQueue.set([]);
+ }
+
+ // now we call all post initializers AFTER we actually executed all page scripts
+ loader.log("Running post initializers...");
+
+ if (appConfig_ && appConfig_.autoclose_loader) {
+ loader.close();
+ console.log("------ loader closed ------");
+ }
+
+ setTimeout(() => {
+ for (const initializer of postInitializers_) {
+ initializer();
+ }
+ }, 3000);
+ }
+}
+
export class PyConfig extends BaseEvalElement {
shadow: ShadowRoot;
@@ -33,14 +148,21 @@ export class PyConfig extends BaseEvalElement {
this.code = this.innerHTML;
this.innerHTML = '';
- this.values = jsyaml.load(this.code);
- if (this.values === undefined){
+ const loadedValues = jsyaml.load(this.code);
+ if (loadedValues === undefined){
this.values = {
autoclose_loader: true,
};
+ }else{
+ this.values = Object.assign({}, ...loadedValues);
+ }
+ if (this.values.runtimes === undefined){
+ this.values.runtimes = [DEFAULT_RUNTIME];
}
appConfig.set(this.values);
console.log("config set", this.values);
+
+ this.loadRuntimes();
}
log(msg: string){
@@ -52,4 +174,17 @@ export class PyConfig extends BaseEvalElement {
close() {
this.remove();
}
+
+ loadRuntimes(){
+ console.log("Initializing runtimes...")
+ for (const runtime of this.values.runtimes) {
+ const script = document.createElement("script"); // create a script DOM node
+ const runtimeSpec = new PyodideRuntime(runtime.src);
+ script.src = runtime.src; // set its src to the provided URL
+ script.onload = () => {
+ runtimeSpec.initialize();
+ }
+ document.head.appendChild(script);
+ }
+ }
}
diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts
index 918625f570a..22f5b78567b 100644
--- a/pyscriptjs/src/interpreter.ts
+++ b/pyscriptjs/src/interpreter.ts
@@ -3,11 +3,12 @@ import { getLastPath } from './utils';
let pyodideReadyPromise;
let pyodide;
-const loadInterpreter = async function (): Promise {
+const loadInterpreter = async function (indexUrl:string): Promise {
console.log('creating pyodide runtime');
// eslint-disable-next-line
// @ts-ignore
pyodide = await loadPyodide({
+ // indexURL: indexUrl,
stdout: console.log,
stderr: console.log,
fullStdLib: false
diff --git a/pyscriptjs/src/main.ts b/pyscriptjs/src/main.ts
index d04778b6ffa..21c6c9a82e0 100644
--- a/pyscriptjs/src/main.ts
+++ b/pyscriptjs/src/main.ts
@@ -23,9 +23,8 @@ const xPyWidget = customElements.define('py-register-widget', PyWidget);
const xPyLoader = customElements.define('py-loader', PyLoader);
const xPyConfig = customElements.define('py-config', PyConfig);
-
// As first thing, loop for application configs
-const config = document.querySelector('py-config');
+const config: PyConfig = document.querySelector('py-config');
if (!config){
const loader = document.createElement('py-config');
document.body.append(loader);
diff --git a/pyscriptjs/src/stores.ts b/pyscriptjs/src/stores.ts
index b3c6cfbc341..065d2e96da4 100644
--- a/pyscriptjs/src/stores.ts
+++ b/pyscriptjs/src/stores.ts
@@ -1,7 +1,7 @@
import { writable } from 'svelte/store';
import type { PyScript } from './components/pyscript';
-type Initializer = () => Promise;
+export type Initializer = () => Promise;
export const pyodideLoaded = writable({
loaded: false,
diff --git a/pyscriptjs/tsconfig.json b/pyscriptjs/tsconfig.json
index 31509cef1a9..5b80dad3746 100644
--- a/pyscriptjs/tsconfig.json
+++ b/pyscriptjs/tsconfig.json
@@ -22,7 +22,6 @@
"sourceMap": true,
/** Requests the runtime types from the svelte modules by default. Needed for TS files or else you get errors. */
"types": ["svelte"],
-
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,