Breaking: new Polyscript Hooks mechanism (#1811)

* Breaking: new Polyscript Hooks mechanism

* Added proper smoke test
This commit is contained in:
Andrea Giammarchi
2023-10-26 17:13:36 +02:00
committed by GitHub
parent 28d37cdead
commit e67eb06d8b
11 changed files with 394 additions and 195 deletions

View File

@@ -1,18 +1,19 @@
{
"name": "@pyscript/core",
"version": "0.2.10",
"version": "0.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pyscript/core",
"version": "0.2.10",
"version": "0.3.0",
"license": "APACHE-2.0",
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"polyscript": "^0.4.20",
"polyscript": "^0.5.1",
"sticky-module": "^0.1.0",
"to-json-callback": "^0.1.1",
"type-checked-collections": "^0.1.7"
},
"devDependencies": {
@@ -20,7 +21,7 @@
"@rollup/plugin-terser": "^0.4.4",
"@webreflection/toml-j0.4": "^1.1.3",
"chokidar": "^3.5.3",
"eslint": "^8.51.0",
"eslint": "^8.52.0",
"rollup": "^4.1.4",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string": "^3.0.0",
@@ -85,21 +86,21 @@
}
},
"node_modules/@eslint/js": {
"version": "8.51.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
"integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
"version": "8.52.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz",
"integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
"integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
"integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
"dev": true,
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
"@humanwhocodes/object-schema": "^2.0.1",
"debug": "^4.1.1",
"minimatch": "^3.0.5"
},
@@ -121,9 +122,9 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
"node_modules/@jridgewell/gen-mapping": {
@@ -764,12 +765,13 @@
}
},
"node_modules/coincident": {
"version": "0.13.10",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.13.10.tgz",
"integrity": "sha512-gzSTDRMMVvo40+zj7sRUFMsc5Fpu865qn4gf/FUAaukBal+c2lxvnTigT7HSZLGPYEj6Sm5vPDTik31Uqei3qg==",
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.2.tgz",
"integrity": "sha512-Xc/lh56dl/v5GT1R3bEWxiLzF5ZTiXE5Flcd0+qvrBGhZsvDha8bgqhpocrvJmELuerhDO3+EQKDdCzPBPodJQ==",
"dependencies": {
"@ungap/structured-clone": "^1.2.0",
"@ungap/with-resolvers": "^0.1.0"
"@ungap/with-resolvers": "^0.1.0",
"gc-hook": "^0.2.1"
},
"optionalDependencies": {
"ws": "^8.14.2"
@@ -1126,18 +1128,19 @@
}
},
"node_modules/eslint": {
"version": "8.51.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
"integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
"version": "8.52.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
"integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
"@eslint/js": "8.51.0",
"@humanwhocodes/config-array": "^0.11.11",
"@eslint/js": "8.52.0",
"@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -1385,6 +1388,11 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/gc-hook": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.2.3.tgz",
"integrity": "sha512-XfA+XiE7QzJzonfvNjTXmcyGtprD6m85KEH9fngmxghVR7PJ4f3ZKsLI22QNpWJiDO5EIR6iMzz9wSxLBqw6+A=="
},
"node_modules/generic-names": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz",
@@ -2053,15 +2061,15 @@
"integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA=="
},
"node_modules/polyscript": {
"version": "0.4.20",
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.20.tgz",
"integrity": "sha512-MNpZQPcJ0047Gq/SXZTw8H929nMKcc3dqxbegd42remBJ0y2UwrKXiE0NMhlO85cbxLrV+sGD2ZCt8+/2m55EQ==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.1.tgz",
"integrity": "sha512-jMFFWCJjYKcan7RV5UBVNg9IfVSss7wB6l5RIdx28pnBu1WSyA7sApLz7NEVbF14g5a5OjwtlvZCphQEA4CfQQ==",
"dependencies": {
"@ungap/structured-clone": "^1.2.0",
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"codedent": "^0.1.2",
"coincident": "^0.13.10",
"coincident": "^0.14.2",
"html-escaper": "^3.0.3",
"sticky-module": "^0.1.0"
}
@@ -3092,6 +3100,11 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/to-json-callback": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/to-json-callback/-/to-json-callback-0.1.1.tgz",
"integrity": "sha512-BzOeinTT3NjE+FJ2iCvWB8HvyuyBzoH3WlSnJ+AYVC4tlePyZWSYdkQIFOARWiq0t35/XhmI0uQsFiUsRksRqg=="
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@pyscript/core",
"version": "0.2.10",
"version": "0.3.0",
"type": "module",
"description": "PyScript",
"module": "./index.js",
@@ -40,8 +40,9 @@
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"polyscript": "^0.4.20",
"polyscript": "^0.5.1",
"sticky-module": "^0.1.0",
"to-json-callback": "^0.1.1",
"type-checked-collections": "^0.1.7"
},
"devDependencies": {
@@ -49,7 +50,7 @@
"@rollup/plugin-terser": "^0.4.4",
"@webreflection/toml-j0.4": "^1.1.3",
"chokidar": "^3.5.3",
"eslint": "^8.51.0",
"eslint": "^8.52.0",
"rollup": "^4.1.4",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string": "^3.0.0",

View File

@@ -14,16 +14,18 @@ import {
dispatch,
queryTarget,
unescape,
whenDefined,
} from "polyscript/exports";
import "./all-done.js";
import TYPES from "./types.js";
import configs from "./config.js";
import hooks from "./hooks.js";
import sync from "./sync.js";
import stdlib from "./stdlib.js";
import bootstrapNodeAndPlugins from "./plugins-helper.js";
import { ErrorCode } from "./exceptions.js";
import { robustFetch as fetch, getText } from "./fetch.js";
import { hooks, main, worker, codeFor, createFunction } from "./hooks.js";
// allows lazy element features on code evaluation
let currentElement;
@@ -31,25 +33,6 @@ let currentElement;
// generic helper to disambiguate between custom element and script
const isScript = ({ tagName }) => tagName === "SCRIPT";
// helper for all script[type="py"] out there
const before = (script) => {
defineProperty(document, "currentScript", {
configurable: true,
get: () => script,
});
};
const after = () => {
delete document.currentScript;
};
// common life-cycle handlers for any node
const bootstrapNodeAndPlugins = (wrap, element, callback, hook) => {
// make it possible to reach the current target node via Python
callback(element);
for (const fn of hooks[hook]) fn(wrap, element);
};
let shouldRegister = true;
const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
// automatically use the pyscript stderr (when/if defined)
@@ -73,33 +56,31 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") });
};
const workerHooks = {
codeBeforeRunWorker: () =>
[stdlib, ...hooks.codeBeforeRunWorker].map(dedent).join("\n"),
codeBeforeRunWorkerAsync: () =>
[stdlib, ...hooks.codeBeforeRunWorkerAsync].map(dedent).join("\n"),
codeAfterRunWorker: () =>
[...hooks.codeAfterRunWorker].map(dedent).join("\n"),
codeAfterRunWorkerAsync: () =>
[...hooks.codeAfterRunWorkerAsync].map(dedent).join("\n"),
};
// avoid multiple initialization of the same library
const [
{
PyWorker: exportedPyWorker,
hooks: exportedHooks,
config: exportedConfig,
whenDefined: exportedWhenDefined,
},
alreadyLive,
] = stickyModule("@pyscript/core", { PyWorker, hooks, config: {} });
] = stickyModule("@pyscript/core", {
PyWorker,
hooks,
config: {},
whenDefined,
});
export {
exportedPyWorker as PyWorker,
exportedHooks as hooks,
exportedConfig as config,
exportedWhenDefined as whenDefined,
};
const hooked = new Map();
for (const [TYPE, interpreter] of TYPES) {
// avoid any dance if the module already landed
if (alreadyLive) break;
@@ -149,107 +130,141 @@ for (const [TYPE, interpreter] of TYPES) {
// possible early errors sent by polyscript
const errors = new Map();
// specific main and worker hooks
const hooks = {
main: {
...codeFor(main),
async onReady(wrap, element) {
if (shouldRegister) {
shouldRegister = false;
registerModule(wrap);
}
// allows plugins to do whatever they want with the element
// before regular stuff happens in here
for (const callback of main("onReady"))
await callback(wrap, element);
// now that all possible plugins are configured,
// bail out if polyscript encountered an error
if (errors.has(element)) {
let { message } = errors.get(element);
errors.delete(element);
const clone = message === INVALID_CONTENT;
message = `(${ErrorCode.CONFLICTING_CODE}) ${message} for `;
message += element.cloneNode(clone).outerHTML;
wrap.io.stderr(message);
return;
}
if (isScript(element)) {
const {
attributes: { async: isAsync, target },
} = element;
const hasTarget = !!target?.value;
const show = hasTarget
? queryTarget(element, target.value)
: document.createElement("script-py");
if (!hasTarget) {
const { head, body } = document;
if (head.contains(element)) body.append(show);
else element.after(show);
}
if (!show.id) show.id = getID();
// allows the code to retrieve the target element via
// document.currentScript.target if needed
defineProperty(element, "target", { value: show });
// notify before the code runs
dispatch(element, TYPE, "ready");
dispatchDone(
element,
isAsync,
wrap[`run${isAsync ? "Async" : ""}`](
await fetchSource(element, wrap.io, true),
),
);
} else {
// resolve PyScriptElement to allow connectedCallback
element._wrap.resolve(wrap);
}
console.debug("[pyscript/main] PyScript Ready");
},
onWorker(_, xworker) {
assign(xworker.sync, sync);
for (const callback of main("onWorker"))
callback(_, xworker);
},
onBeforeRun(wrap, element) {
currentElement = element;
bootstrapNodeAndPlugins(
main,
wrap,
element,
"onBeforeRun",
);
},
onBeforeRunAsync(wrap, element) {
currentElement = element;
return bootstrapNodeAndPlugins(
main,
wrap,
element,
"onBeforeRunAsync",
);
},
onAfterRun(wrap, element) {
bootstrapNodeAndPlugins(
main,
wrap,
element,
"onAfterRun",
);
},
onAfterRunAsync(wrap, element) {
return bootstrapNodeAndPlugins(
main,
wrap,
element,
"onAfterRunAsync",
);
},
},
worker: {
...codeFor(worker),
// these are lazy getters that returns a composition
// of the current hooks or undefined, if no hook is present
get onReady() {
return createFunction(this, "onReady", true);
},
get onBeforeRun() {
return createFunction(this, "onBeforeRun", false);
},
get onBeforeRunAsync() {
return createFunction(this, "onBeforeRunAsync", true);
},
get onAfterRun() {
return createFunction(this, "onAfterRun", false);
},
get onAfterRunAsync() {
return createFunction(this, "onAfterRunAsync", true);
},
},
};
hooked.set(TYPE, hooks);
define(TYPE, {
config,
interpreter,
hooks,
env: `${TYPE}-script`,
version: config?.interpreter,
onerror(error, element) {
errors.set(element, error);
},
...workerHooks,
onWorkerReady(_, xworker) {
assign(xworker.sync, sync);
for (const callback of hooks.onWorkerReady)
callback(_, xworker);
},
onBeforeRun(wrap, element) {
currentElement = element;
bootstrapNodeAndPlugins(
wrap,
element,
before,
"onBeforeRun",
);
},
onBeforeRunAsync(wrap, element) {
currentElement = element;
bootstrapNodeAndPlugins(
wrap,
element,
before,
"onBeforeRunAsync",
);
},
onAfterRun(wrap, element) {
bootstrapNodeAndPlugins(wrap, element, after, "onAfterRun");
},
onAfterRunAsync(wrap, element) {
bootstrapNodeAndPlugins(
wrap,
element,
after,
"onAfterRunAsync",
);
},
async onInterpreterReady(wrap, element) {
if (shouldRegister) {
shouldRegister = false;
registerModule(wrap);
}
// allows plugins to do whatever they want with the element
// before regular stuff happens in here
for (const callback of hooks.onInterpreterReady)
callback(wrap, element);
// now that all possible plugins are configured,
// bail out if polyscript encountered an error
if (errors.has(element)) {
let { message } = errors.get(element);
errors.delete(element);
const clone = message === INVALID_CONTENT;
message = `(${ErrorCode.CONFLICTING_CODE}) ${message} for `;
message += element.cloneNode(clone).outerHTML;
wrap.io.stderr(message);
return;
}
if (isScript(element)) {
const {
attributes: { async: isAsync, target },
} = element;
const hasTarget = !!target?.value;
const show = hasTarget
? queryTarget(element, target.value)
: document.createElement("script-py");
if (!hasTarget) {
const { head, body } = document;
if (head.contains(element)) body.append(show);
else element.after(show);
}
if (!show.id) show.id = getID();
// allows the code to retrieve the target element via
// document.currentScript.target if needed
defineProperty(element, "target", { value: show });
// notify before the code runs
dispatch(element, TYPE, "ready");
dispatchDone(
element,
isAsync,
wrap[`run${isAsync ? "Async" : ""}`](
await fetchSource(element, wrap.io, true),
),
);
} else {
// resolve PyScriptElement to allow connectedCallback
element._wrap.resolve(wrap);
}
console.debug("[pyscript/main] PyScript Ready");
},
});
customElements.define(
@@ -305,12 +320,13 @@ for (const [TYPE, interpreter] of TYPES) {
* @returns {Worker & {sync: ProxyHandler<object>}}
*/
function PyWorker(file, options) {
const hooks = hooked.get("py");
// this propagates pyscript worker hooks without needing a pyscript
// bootstrap + it passes arguments and enforces `pyodide`
// as the interpreter to use in the worker, as all hooks assume that
// and as `pyodide` is the only default interpreter that can deal with
// all the features we need to deliver pyscript out there.
const xworker = XWorker.call(new Hook(null, workerHooks), file, {
const xworker = XWorker.call(new Hook(null, hooks), file, {
type: "pyodide",
...options,
});

View File

@@ -1,28 +1,91 @@
import { typedSet } from "type-checked-collections";
import { dedent } from "polyscript/exports";
import toJSONCallback from "to-json-callback";
import stdlib from "./stdlib.js";
export const main = (name) => hooks.main[name];
export const worker = (name) => hooks.worker[name];
const code = (hooks, branch, key, lib) => {
hooks[key] = () => {
const arr = lib ? [lib] : [];
arr.push(...branch(key));
return arr.map(dedent).join("\n");
};
};
export const codeFor = (branch) => {
const hooks = {};
code(hooks, branch, `codeBeforeRun`, stdlib);
code(hooks, branch, `codeBeforeRunAsync`, stdlib);
code(hooks, branch, `codeAfterRun`);
code(hooks, branch, `codeAfterRunAsync`);
return hooks;
};
export const createFunction = (self, name) => {
const cbs = [...worker(name)];
if (cbs.length) {
const cb = toJSONCallback(
self[`_${name}`] ||
(name.endsWith("Async")
? async (wrap, xworker, ...cbs) => {
for (const cb of cbs) await cb(wrap, xworker);
}
: (wrap, xworker, ...cbs) => {
for (const cb of cbs) cb(wrap, xworker);
}),
);
const a = cbs.map(toJSONCallback).join(", ");
return Function(`return(w,x)=>(${cb})(w,x,...[${a}])`)();
}
};
const SetFunction = typedSet({ typeof: "function" });
const SetString = typedSet({ typeof: "string" });
export default {
/** @type {Set<function>} */
onInterpreterReady: new SetFunction(),
/** @type {Set<function>} */
onBeforeRun: new SetFunction(),
/** @type {Set<function>} */
onBeforeRunAsync: new SetFunction(),
/** @type {Set<function>} */
onAfterRun: new SetFunction(),
/** @type {Set<function>} */
onAfterRunAsync: new SetFunction(),
/** @type {Set<function>} */
onWorkerReady: new SetFunction(),
/** @type {Set<string>} */
codeBeforeRunWorker: new SetString(),
/** @type {Set<string>} */
codeBeforeRunWorkerAsync: new SetString(),
/** @type {Set<string>} */
codeAfterRunWorker: new SetString(),
/** @type {Set<string>} */
codeAfterRunWorkerAsync: new SetString(),
export const hooks = {
main: {
/** @type {Set<function>} */
onWorker: new SetFunction(),
/** @type {Set<function>} */
onReady: new SetFunction(),
/** @type {Set<function>} */
onBeforeRun: new SetFunction(),
/** @type {Set<function>} */
onBeforeRunAsync: new SetFunction(),
/** @type {Set<function>} */
onAfterRun: new SetFunction(),
/** @type {Set<function>} */
onAfterRunAsync: new SetFunction(),
/** @type {Set<string>} */
codeBeforeRun: new SetString(),
/** @type {Set<string>} */
codeBeforeRunAsync: new SetString(),
/** @type {Set<string>} */
codeAfterRun: new SetString(),
/** @type {Set<string>} */
codeAfterRunAsync: new SetString(),
},
worker: {
/** @type {Set<function>} */
onReady: new SetFunction(),
/** @type {Set<function>} */
onBeforeRun: new SetFunction(),
/** @type {Set<function>} */
onBeforeRunAsync: new SetFunction(),
/** @type {Set<function>} */
onAfterRun: new SetFunction(),
/** @type {Set<function>} */
onAfterRunAsync: new SetFunction(),
/** @type {Set<string>} */
codeBeforeRun: new SetString(),
/** @type {Set<string>} */
codeBeforeRunAsync: new SetString(),
/** @type {Set<string>} */
codeAfterRun: new SetString(),
/** @type {Set<string>} */
codeAfterRunAsync: new SetString(),
},
};

View File

@@ -0,0 +1,26 @@
import { defineProperty } from "polyscript/exports";
// helper for all script[type="py"] out there
const before = (script) => {
defineProperty(document, "currentScript", {
configurable: true,
get: () => script,
});
};
const after = () => {
delete document.currentScript;
};
// common life-cycle handlers for any node
export default async (main, wrap, element, hook) => {
const isAsync = hook.endsWith("Async");
const isBefore = hook.startsWith("onBefore");
// make it possible to reach the current target node via Python
// or clean up for other scripts executing around this one
(isBefore ? before : after)(element);
for (const fn of main(hook)) {
if (isAsync) await fn(wrap, element);
else fn(wrap, element);
}
};

View File

@@ -1,9 +1,9 @@
// PyScript Error Plugin
import { hooks } from "../core.js";
hooks.onInterpreterReady.add(function override(pyScript) {
hooks.main.onReady.add(function override(pyScript) {
// be sure this override happens only once
hooks.onInterpreterReady.delete(override);
hooks.main.onReady.delete(override);
// trap generic `stderr` to propagate to it regardless
const { stderr } = pyScript.io;

View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PyScript Next Plugin Bug?</title>
<link rel="stylesheet" href="../dist/core.css">
<script type="module">
import { hooks } from "../dist/core.js";
// Worker
hooks.worker.onReady.add((wrap, xworker) => {
console.log("worker", "onReady");
console.log("worker", "wrap", wrap);
console.log("worker", "xworker", xworker);
});
hooks.worker.onBeforeRun.add(() => {
console.log("worker", "onBeforeRun");
});
hooks.worker.codeBeforeRun.add('print("worker", "codeBeforeRun")');
hooks.worker.codeAfterRun.add('print("worker", "codeAfterRun")');
hooks.worker.onAfterRun.add(() => {
console.log("worker", "onAfterRun");
});
// Main
hooks.main.onReady.add((wrap, element) => {
console.log("main", "onReady");
console.log("main", "wrap", wrap);
console.log("main", "element", element);
});
hooks.main.onBeforeRun.add(() => {
console.log("main", "onBeforeRun");
});
hooks.main.codeBeforeRun.add('print("main", "codeBeforeRun")');
hooks.main.codeAfterRun.add('print("main", "codeAfterRun")');
hooks.main.onAfterRun.add(() => {
console.log("main", "onAfterRun");
});
</script>
</head>
<body>
<script type="py" worker>
print("actual code in worker")
</script>
<script type="py">
print("actual code in main")
</script>
</body>
</html>

View File

@@ -8,8 +8,10 @@
<!-- the PyWorker approach -->
<script type="module">
import { PyWorker } from '../dist/core.js';
PyWorker('./worker.py', {config: {fetch: [{files: ['./a.py']}]}});
import { PyWorker, whenDefined } from '../dist/core.js';
whenDefined('py').then(() => {
PyWorker('./worker.py', {config: {fetch: [{files: ['./a.py']}]}});
});
// the type is overwritten as "pyodide" in PyScript as the module
// lives in that env too
</script>

View File

@@ -1,4 +1,5 @@
declare const exportedPyWorker: any;
declare const exportedHooks: any;
declare const exportedConfig: any;
export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config };
declare const exportedWhenDefined: any;
export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };

View File

@@ -1,13 +1,38 @@
declare namespace _default {
let onInterpreterReady: Set<Function>;
let onBeforeRun: Set<Function>;
let onBeforeRunAsync: Set<Function>;
let onAfterRun: Set<Function>;
let onAfterRunAsync: Set<Function>;
let onWorkerReady: Set<Function>;
let codeBeforeRunWorker: Set<string>;
let codeBeforeRunWorkerAsync: Set<string>;
let codeAfterRunWorker: Set<string>;
let codeAfterRunWorkerAsync: Set<string>;
export function main(name: any): any;
export function worker(name: any): any;
export function codeFor(branch: any): {};
export function createFunction(self: any, name: any): any;
export namespace hooks {
namespace main {
let onWorker: Set<Function>;
let onReady: Set<Function>;
let onBeforeRun: Set<Function>;
let onBeforeRunAsync: Set<Function>;
let onAfterRun: Set<Function>;
let onAfterRunAsync: Set<Function>;
let codeBeforeRun: Set<string>;
let codeBeforeRunAsync: Set<string>;
let codeAfterRun: Set<string>;
let codeAfterRunAsync: Set<string>;
}
namespace worker {
let onReady_1: Set<Function>;
export { onReady_1 as onReady };
let onBeforeRun_1: Set<Function>;
export { onBeforeRun_1 as onBeforeRun };
let onBeforeRunAsync_1: Set<Function>;
export { onBeforeRunAsync_1 as onBeforeRunAsync };
let onAfterRun_1: Set<Function>;
export { onAfterRun_1 as onAfterRun };
let onAfterRunAsync_1: Set<Function>;
export { onAfterRunAsync_1 as onAfterRunAsync };
let codeBeforeRun_1: Set<string>;
export { codeBeforeRun_1 as codeBeforeRun };
let codeBeforeRunAsync_1: Set<string>;
export { codeBeforeRunAsync_1 as codeBeforeRunAsync };
let codeAfterRun_1: Set<string>;
export { codeAfterRun_1 as codeAfterRun };
let codeAfterRunAsync_1: Set<string>;
export { codeAfterRunAsync_1 as codeAfterRunAsync };
}
}
export default _default;

View File

@@ -0,0 +1,2 @@
declare function _default(main: any, wrap: any, element: any, hook: any): Promise<void>;
export default _default;