mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 10:47:35 -05:00
committed by
GitHub
parent
6df5905b2b
commit
bccd5e3750
@@ -14,7 +14,7 @@ repos:
|
|||||||
- id: check-docstring-first
|
- id: check-docstring-first
|
||||||
- id: check-executables-have-shebangs
|
- id: check-executables-have-shebangs
|
||||||
- id: check-json
|
- id: check-json
|
||||||
exclude: tsconfig.json pyscript.core/cjs/package.json
|
exclude: tsconfig\.json|pyscript\.core/cjs/package\.json
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: check-xml
|
- id: check-xml
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
@@ -46,6 +46,7 @@ repos:
|
|||||||
rev: "v3.0.0-alpha.6"
|
rev: "v3.0.0-alpha.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
|
exclude: pyscript\.core/test
|
||||||
args: [--tab-width, "4"]
|
args: [--tab-width, "4"]
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
|
import "@ungap/with-resolvers";
|
||||||
import { $$ } from "basic-devtools";
|
import { $$ } from "basic-devtools";
|
||||||
|
|
||||||
import { create } from "./utils.js";
|
import { assign, create } from "./utils.js";
|
||||||
import { getDetails } from "./script-handler.js";
|
import { getDetails } from "./script-handler.js";
|
||||||
import { registry, configs } from "./interpreters.js";
|
import {
|
||||||
|
registry as defaultRegistry,
|
||||||
|
prefixes,
|
||||||
|
configs,
|
||||||
|
} from "./interpreters.js";
|
||||||
import { getRuntimeID } from "./loader.js";
|
import { getRuntimeID } from "./loader.js";
|
||||||
import { io } from "./interpreter/_utils.js";
|
import { io } from "./interpreter/_utils.js";
|
||||||
|
import { addAllListeners } from "./listeners.js";
|
||||||
|
|
||||||
import workerHooks from "./worker/hooks.js";
|
import workerHooks from "./worker/hooks.js";
|
||||||
|
|
||||||
export const PLUGINS_SELECTORS = [];
|
export const CUSTOM_SELECTORS = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Runtime plugin configuration
|
* @typedef {Object} Runtime custom configuration
|
||||||
* @prop {string} type the interpreter type
|
|
||||||
* @prop {object} interpreter the bootstrapped interpreter
|
* @prop {object} interpreter the bootstrapped interpreter
|
||||||
* @prop {(url:string, options?: object) => Worker} XWorker an XWorker constructor that defaults to same interpreter on the Worker.
|
* @prop {(url:string, options?: object) => Worker} XWorker an XWorker constructor that defaults to same interpreter on the Worker.
|
||||||
* @prop {object} config a cloned config used to bootstrap the interpreter
|
* @prop {object} config a cloned config used to bootstrap the interpreter
|
||||||
@@ -22,23 +27,33 @@ export const PLUGINS_SELECTORS = [];
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const patched = new Map();
|
const patched = new Map();
|
||||||
|
const types = new Map();
|
||||||
|
const waitList = new Map();
|
||||||
|
|
||||||
// REQUIRES INTEGRATION TEST
|
// REQUIRES INTEGRATION TEST
|
||||||
/* c8 ignore start */
|
/* c8 ignore start */
|
||||||
/**
|
/**
|
||||||
* @param {Element} node any DOM element registered via plugin.
|
* @param {Element} node any DOM element registered via define.
|
||||||
*/
|
*/
|
||||||
export const handlePlugin = (node) => {
|
export const handleCustomType = (node) => {
|
||||||
for (const name of PLUGINS_SELECTORS) {
|
for (const selector of CUSTOM_SELECTORS) {
|
||||||
if (node.matches(name)) {
|
if (node.matches(selector)) {
|
||||||
const { options, known } = plugins.get(name);
|
const type = types.get(selector);
|
||||||
|
const { resolve } = waitList.get(type);
|
||||||
|
const { options, known } = registry.get(type);
|
||||||
if (!known.has(node)) {
|
if (!known.has(node)) {
|
||||||
known.add(node);
|
known.add(node);
|
||||||
const { type, version, config, env, onRuntimeReady } = options;
|
const {
|
||||||
const name = getRuntimeID(type, version);
|
interpreter: runtime,
|
||||||
|
version,
|
||||||
|
config,
|
||||||
|
env,
|
||||||
|
onRuntimeReady,
|
||||||
|
} = options;
|
||||||
|
const name = getRuntimeID(runtime, version);
|
||||||
const id = env || `${name}${config ? `|${config}` : ""}`;
|
const id = env || `${name}${config ? `|${config}` : ""}`;
|
||||||
const { interpreter: engine, XWorker } = getDetails(
|
const { interpreter: engine, XWorker } = getDetails(
|
||||||
type,
|
runtime,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
version,
|
version,
|
||||||
@@ -46,7 +61,7 @@ export const handlePlugin = (node) => {
|
|||||||
);
|
);
|
||||||
engine.then((interpreter) => {
|
engine.then((interpreter) => {
|
||||||
if (!patched.has(id)) {
|
if (!patched.has(id)) {
|
||||||
const module = create(registry.get(type));
|
const module = create(defaultRegistry.get(runtime));
|
||||||
const {
|
const {
|
||||||
onBeforeRun,
|
onBeforeRun,
|
||||||
onBeforeRunAsync,
|
onBeforeRunAsync,
|
||||||
@@ -120,9 +135,10 @@ export const handlePlugin = (node) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
patched.set(id, resolved);
|
patched.set(id, resolved);
|
||||||
|
resolve(resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRuntimeReady(patched.get(id), node);
|
onRuntimeReady?.(patched.get(id), node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,27 +148,58 @@ export const handlePlugin = (node) => {
|
|||||||
/**
|
/**
|
||||||
* @type {Map<string, {options:object, known:WeakSet<Element>}>}
|
* @type {Map<string, {options:object, known:WeakSet<Element>}>}
|
||||||
*/
|
*/
|
||||||
const plugins = new Map();
|
const registry = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} PluginOptions plugin configuration
|
* @typedef {Object} PluginOptions custom configuration
|
||||||
* @prop {string} type the interpreter/interpreter type to receive
|
* @prop {'pyodide' | 'micropython' | 'wasmoon' | 'ruby-wasm-wasi'} interpreter the interpreter to use
|
||||||
* @prop {string} [version] the optional interpreter version to use
|
* @prop {string} [version] the optional interpreter version to use
|
||||||
* @prop {string} [config] the optional config to use within such interpreter
|
* @prop {string} [config] the optional config to use within such interpreter
|
||||||
* @prop {string} [env] the optional environment to use
|
* @prop {(environment: object, node: Element) => void} [onRuntimeReady] the callback that will be invoked once
|
||||||
* @prop {(node: Element, interpreter: Runtime) => void} onRuntimeReady the callback that will be invoked once
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows plugins and components on the page to receive interpreters to execute any code.
|
* Allows custom types and components on the page to receive interpreters to execute any code
|
||||||
* @param {string} name the unique plugin name
|
* @param {string} type the unique `<script type="...">` identifier
|
||||||
* @param {PluginOptions} options the plugin configuration
|
* @param {PluginOptions} options the custom type configuration
|
||||||
*/
|
*/
|
||||||
export const registerPlugin = (name, options) => {
|
export const define = (type, options) => {
|
||||||
if (PLUGINS_SELECTORS.includes(name))
|
if (defaultRegistry.has(type) || registry.has(type))
|
||||||
throw new Error(`plugin ${name} already registered`);
|
throw new Error(`<script type="${type}"> already registered`);
|
||||||
PLUGINS_SELECTORS.push(name);
|
|
||||||
plugins.set(name, { options, known: new WeakSet() });
|
if (!defaultRegistry.has(options?.interpreter))
|
||||||
$$(name).forEach(handlePlugin);
|
throw new Error(`Unspecified interpreter`);
|
||||||
|
|
||||||
|
// allows reaching out the interpreter helpers on events
|
||||||
|
defaultRegistry.set(type, defaultRegistry.get(options?.interpreter));
|
||||||
|
|
||||||
|
// ensure a Promise can resolve once a custom type has been bootstrapped
|
||||||
|
whenDefined(type);
|
||||||
|
|
||||||
|
// allows selector -> registry by type
|
||||||
|
const selectors = [`script[type="${type}"]`, `${type}-script`];
|
||||||
|
for (const selector of selectors) types.set(selector, type);
|
||||||
|
|
||||||
|
CUSTOM_SELECTORS.push(...selectors);
|
||||||
|
prefixes.push(`${type}-`);
|
||||||
|
|
||||||
|
// ensure always same env for this custom type
|
||||||
|
registry.set(type, {
|
||||||
|
options: assign({ env: type }, options),
|
||||||
|
known: new WeakSet(),
|
||||||
|
});
|
||||||
|
|
||||||
|
addAllListeners(document);
|
||||||
|
$$(selectors.join(",")).forEach(handleCustomType);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves whenever a defined custom type is bootstrapped on the page
|
||||||
|
* @param {string} type the unique `<script type="...">` identifier
|
||||||
|
* @returns {Promise<object>}
|
||||||
|
*/
|
||||||
|
export const whenDefined = (type) => {
|
||||||
|
if (!waitList.has(type)) waitList.set(type, Promise.withResolvers());
|
||||||
|
return waitList.get(type).promise;
|
||||||
};
|
};
|
||||||
/* c8 ignore stop */
|
/* c8 ignore stop */
|
||||||
@@ -1,71 +1,16 @@
|
|||||||
import { $x, $$ } from "basic-devtools";
|
import { $$ } from "basic-devtools";
|
||||||
|
|
||||||
import xworker from "./worker/class.js";
|
import xworker from "./worker/class.js";
|
||||||
import { handle, interpreters } from "./script-handler.js";
|
import { handle } from "./script-handler.js";
|
||||||
import { all, assign, create, defineProperty } from "./utils.js";
|
import { assign } from "./utils.js";
|
||||||
import { registry, selectors, prefixes } from "./interpreters.js";
|
import { selectors, prefixes } from "./interpreters.js";
|
||||||
import { PLUGINS_SELECTORS, handlePlugin } from "./plugins.js";
|
import { CUSTOM_SELECTORS, handleCustomType } from "./custom-types.js";
|
||||||
|
import { listener, addAllListeners } from "./listeners.js";
|
||||||
|
|
||||||
export { registerPlugin } from "./plugins.js";
|
export { define, whenDefined } from "./custom-types.js";
|
||||||
export const XWorker = xworker();
|
export const XWorker = xworker();
|
||||||
|
|
||||||
const RUNTIME_SELECTOR = selectors.join(",");
|
const INTERPRETER_SELECTORS = selectors.join(",");
|
||||||
|
|
||||||
// ensure both interpreter and its queue are awaited then returns the interpreter
|
|
||||||
const awaitRuntime = async (key) => {
|
|
||||||
if (interpreters.has(key)) {
|
|
||||||
const { interpreter, queue } = interpreters.get(key);
|
|
||||||
return (await all([interpreter, queue]))[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const available = interpreters.size
|
|
||||||
? `Available interpreters are: ${[...interpreters.keys()]
|
|
||||||
.map((r) => `"${r}"`)
|
|
||||||
.join(", ")}.`
|
|
||||||
: `There are no interpreters in this page.`;
|
|
||||||
|
|
||||||
throw new Error(`The interpreter "${key}" was not found. ${available}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
defineProperty(globalThis, "pyscript", {
|
|
||||||
value: {
|
|
||||||
env: new Proxy(create(null), { get: (_, name) => awaitRuntime(name) }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let index = 0;
|
|
||||||
globalThis.__events = new Map();
|
|
||||||
|
|
||||||
// attributes are tested via integration / e2e
|
|
||||||
/* c8 ignore next 17 */
|
|
||||||
const listener = async (event) => {
|
|
||||||
const { type, currentTarget } = event;
|
|
||||||
for (let { name, value, ownerElement: el } of $x(
|
|
||||||
`./@*[${prefixes.map((p) => `name()="${p}${type}"`).join(" or ")}]`,
|
|
||||||
currentTarget,
|
|
||||||
)) {
|
|
||||||
name = name.slice(0, -(type.length + 1));
|
|
||||||
const interpreter = await awaitRuntime(
|
|
||||||
el.getAttribute(`${name}-env`) || name,
|
|
||||||
);
|
|
||||||
const i = index++;
|
|
||||||
try {
|
|
||||||
globalThis.__events.set(i, event);
|
|
||||||
registry.get(name).runEvent(interpreter, value, i);
|
|
||||||
} finally {
|
|
||||||
globalThis.__events.delete(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// attributes are tested via integration / e2e
|
|
||||||
/* c8 ignore next 8 */
|
|
||||||
for (let { name, ownerElement: el } of $x(
|
|
||||||
`.//@*[${prefixes.map((p) => `starts-with(name(),"${p}")`).join(" or ")}]`,
|
|
||||||
)) {
|
|
||||||
name = name.slice(name.lastIndexOf("-") + 1);
|
|
||||||
if (name !== "env") el.addEventListener(name, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mo = new MutationObserver((records) => {
|
const mo = new MutationObserver((records) => {
|
||||||
for (const { type, target, attributeName, addedNodes } of records) {
|
for (const { type, target, attributeName, addedNodes } of records) {
|
||||||
@@ -92,12 +37,15 @@ const mo = new MutationObserver((records) => {
|
|||||||
}
|
}
|
||||||
for (const node of addedNodes) {
|
for (const node of addedNodes) {
|
||||||
if (node.nodeType === 1) {
|
if (node.nodeType === 1) {
|
||||||
if (node.matches(RUNTIME_SELECTOR)) handle(node);
|
addAllListeners(node);
|
||||||
|
if (node.matches(INTERPRETER_SELECTORS)) handle(node);
|
||||||
else {
|
else {
|
||||||
$$(RUNTIME_SELECTOR, node).forEach(handle);
|
$$(INTERPRETER_SELECTORS, node).forEach(handle);
|
||||||
if (!PLUGINS_SELECTORS.length) continue;
|
if (!CUSTOM_SELECTORS.length) continue;
|
||||||
handlePlugin(node);
|
handleCustomType(node);
|
||||||
$$(PLUGINS_SELECTORS.join(","), node).forEach(handlePlugin);
|
$$(CUSTOM_SELECTORS.join(","), node).forEach(
|
||||||
|
handleCustomType,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,4 +64,5 @@ assign(Element.prototype, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$$(RUNTIME_SELECTOR, observe(document)).forEach(handle);
|
addAllListeners(observe(document));
|
||||||
|
$$(INTERPRETER_SELECTORS, document).forEach(handle);
|
||||||
|
|||||||
71
pyscript.core/esm/listeners.js
Normal file
71
pyscript.core/esm/listeners.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { $x } from "basic-devtools";
|
||||||
|
|
||||||
|
import { interpreters } from "./script-handler.js";
|
||||||
|
import { all, create, defineProperty } from "./utils.js";
|
||||||
|
import { registry, prefixes } from "./interpreters.js";
|
||||||
|
|
||||||
|
// TODO: this is ugly; need to find a better way
|
||||||
|
defineProperty(globalThis, "pyscript", {
|
||||||
|
value: {
|
||||||
|
env: new Proxy(create(null), {
|
||||||
|
get: (_, name) => awaitInterpreter(name),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
globalThis.__events = new Map();
|
||||||
|
|
||||||
|
/* c8 ignore start */ // attributes are tested via integration / e2e
|
||||||
|
// ensure both interpreter and its queue are awaited then returns the interpreter
|
||||||
|
const awaitInterpreter = async (key) => {
|
||||||
|
if (interpreters.has(key)) {
|
||||||
|
const { interpreter, queue } = interpreters.get(key);
|
||||||
|
return (await all([interpreter, queue]))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const available = interpreters.size
|
||||||
|
? `Available interpreters are: ${[...interpreters.keys()]
|
||||||
|
.map((r) => `"${r}"`)
|
||||||
|
.join(", ")}.`
|
||||||
|
: `There are no interpreters in this page.`;
|
||||||
|
|
||||||
|
throw new Error(`The interpreter "${key}" was not found. ${available}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listener = async (event) => {
|
||||||
|
const { type, currentTarget } = event;
|
||||||
|
for (let { name, value, ownerElement: el } of $x(
|
||||||
|
`./@*[${prefixes.map((p) => `name()="${p}${type}"`).join(" or ")}]`,
|
||||||
|
currentTarget,
|
||||||
|
)) {
|
||||||
|
name = name.slice(0, -(type.length + 1));
|
||||||
|
const interpreter = await awaitInterpreter(
|
||||||
|
el.getAttribute(`${name}-env`) || name,
|
||||||
|
);
|
||||||
|
const i = index++;
|
||||||
|
try {
|
||||||
|
globalThis.__events.set(i, event);
|
||||||
|
registry.get(name).runEvent(interpreter, value, i);
|
||||||
|
} finally {
|
||||||
|
globalThis.__events.delete(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look for known prefixes and add related listeners.
|
||||||
|
* @param {Document | Element} root
|
||||||
|
*/
|
||||||
|
export const addAllListeners = (root) => {
|
||||||
|
for (let { name, ownerElement: el } of $x(
|
||||||
|
`.//@*[${prefixes
|
||||||
|
.map((p) => `starts-with(name(),"${p}")`)
|
||||||
|
.join(" or ")}]`,
|
||||||
|
root,
|
||||||
|
)) {
|
||||||
|
name = name.slice(name.lastIndexOf("-") + 1);
|
||||||
|
if (name !== "env") el.addEventListener(name, listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* c8 ignore stop */
|
||||||
@@ -5,7 +5,7 @@ import { getText } from "../fetch-utils.js";
|
|||||||
import workerHooks from "./hooks.js";
|
import workerHooks from "./hooks.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} WorkerOptions plugin configuration
|
* @typedef {Object} WorkerOptions custom configuration
|
||||||
* @prop {string} type the interpreter type to use
|
* @prop {string} type the interpreter type to use
|
||||||
* @prop {string} [version] the optional interpreter version to use
|
* @prop {string} [version] the optional interpreter version to use
|
||||||
* @prop {string} [config] the optional config to use within such interpreter
|
* @prop {string} [config] the optional config to use within such interpreter
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<title>Plugins</title>
|
<title>Plugins</title>
|
||||||
<style>
|
<style>
|
||||||
py-script {
|
mpy-script {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -13,9 +13,10 @@
|
|||||||
{ "imports": { "@pyscript/core": "../../min.js" } }
|
{ "imports": { "@pyscript/core": "../../min.js" } }
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { registerPlugin } from "@pyscript/core";
|
import { define, whenDefined } from "@pyscript/core";
|
||||||
registerPlugin("mpy-script", {
|
whenDefined("mpy").then(console.log);
|
||||||
type: "micropython",
|
define("mpy", {
|
||||||
|
interpreter: "micropython",
|
||||||
async onRuntimeReady(micropython, element) {
|
async onRuntimeReady(micropython, element) {
|
||||||
console.log(micropython);
|
console.log(micropython);
|
||||||
// Somehow this doesn't work in MicroPython
|
// Somehow this doesn't work in MicroPython
|
||||||
@@ -25,11 +26,21 @@
|
|||||||
micropython.run(element.textContent);
|
micropython.run(element.textContent);
|
||||||
element.replaceChildren("See console ->");
|
element.replaceChildren("See console ->");
|
||||||
element.style.display = "block";
|
element.style.display = "block";
|
||||||
|
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.textContent = "click";
|
||||||
|
button.setAttribute("mpy-click", "test_click(event)");
|
||||||
|
document.body.append(button);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<mpy-script> print('Hello Console!') </mpy-script>
|
<mpy-script mpy-click="test_click(event)">
|
||||||
|
def test_click(event):
|
||||||
|
print(event.type)
|
||||||
|
|
||||||
|
print('Hello Console!')
|
||||||
|
</mpy-script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<title>Plugins</title>
|
<title>Plugins</title>
|
||||||
<style>
|
<style>
|
||||||
py-script {
|
lua-script {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
{ "imports": { "@pyscript/core": "../../min.js" } }
|
{ "imports": { "@pyscript/core": "../../min.js" } }
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { registerPlugin } from "@pyscript/core";
|
import { define } from "@pyscript/core";
|
||||||
registerPlugin("lua-script", {
|
define("lua", {
|
||||||
type: "wasmoon",
|
interpreter: "wasmoon",
|
||||||
async onRuntimeReady(wasmoon, element) {
|
async onRuntimeReady(wasmoon, element) {
|
||||||
// Somehow this doesn't work in Wasmoon
|
// Somehow this doesn't work in Wasmoon
|
||||||
wasmoon.io.stdout = (message) => {
|
wasmoon.io.stdout = (message) => {
|
||||||
@@ -29,6 +29,8 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<lua-script> print('Hello Console!') </lua-script>
|
<lua-script lua-click="print(event.type)">
|
||||||
|
print('Hello Console!')
|
||||||
|
</lua-script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { registerPlugin } from "@pyscript/core";
|
import { define } from "@pyscript/core";
|
||||||
|
|
||||||
// append ASAP CSS to avoid showing content
|
// append ASAP CSS to avoid showing content
|
||||||
document.head.appendChild(document.createElement("style")).textContent = `
|
document.head.appendChild(document.createElement("style")).textContent = `
|
||||||
@@ -17,9 +17,9 @@ let bootstrap = true,
|
|||||||
const sharedPyodide = new Promise((resolve) => {
|
const sharedPyodide = new Promise((resolve) => {
|
||||||
const pyConfig = document.querySelector("py-config");
|
const pyConfig = document.querySelector("py-config");
|
||||||
const config = pyConfig?.getAttribute("src") || pyConfig?.textContent;
|
const config = pyConfig?.getAttribute("src") || pyConfig?.textContent;
|
||||||
registerPlugin("py-script", {
|
define("py", {
|
||||||
config,
|
config,
|
||||||
type: "pyodide",
|
interpreter: "pyodide",
|
||||||
codeBeforeRunWorker: `print('codeBeforeRunWorker')`,
|
codeBeforeRunWorker: `print('codeBeforeRunWorker')`,
|
||||||
codeAfterRunWorker: `print('codeAfterRunWorker')`,
|
codeAfterRunWorker: `print('codeAfterRunWorker')`,
|
||||||
onBeforeRun(pyodide, node) {
|
onBeforeRun(pyodide, node) {
|
||||||
|
|||||||
Reference in New Issue
Block a user