mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
[next] Bootstrap plugins directly (#1698)
This commit is contained in:
committed by
GitHub
parent
7994207c78
commit
3aef5a99dc
@@ -10,7 +10,11 @@ for (const file of readdirSync(join(__dirname, "..", "src", "plugins"))) {
|
|||||||
? name
|
? name
|
||||||
: `[${JSON.stringify(name)}]`;
|
: `[${JSON.stringify(name)}]`;
|
||||||
const value = JSON.stringify(`./plugins/${file}`);
|
const value = JSON.stringify(`./plugins/${file}`);
|
||||||
plugins.push(` ${key}: () => import(${value}),`);
|
plugins.push(
|
||||||
|
// this comment is needed to avoid bundlers eagerly embedding lazy
|
||||||
|
// dependencies, causing all sort of issues once in production
|
||||||
|
` ${key}: () => import(/* webpackIgnore: true */ ${value}),`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
pyscript.core/src/config.js
Normal file
44
pyscript.core/src/config.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* This file parses a generic <py-config> or config attribute
|
||||||
|
* to use as base config for all py-script elements, importing
|
||||||
|
* also a queue of plugins *before* the interpreter (if any) resolves.
|
||||||
|
*/
|
||||||
|
import { $ } from "basic-devtools";
|
||||||
|
|
||||||
|
import allPlugins from "./plugins.js";
|
||||||
|
import { robustFetch as fetch, getText } from "./fetch.js";
|
||||||
|
|
||||||
|
// TODO: this is not strictly polyscript related but handy ... not sure
|
||||||
|
// we should factor this utility out a part but this works anyway.
|
||||||
|
import { parse } from "../node_modules/polyscript/esm/toml.js";
|
||||||
|
|
||||||
|
// find the shared config for all py-script elements
|
||||||
|
let config, plugins, parsed;
|
||||||
|
let pyConfig = $("py-config");
|
||||||
|
if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent;
|
||||||
|
else {
|
||||||
|
pyConfig = $('script[type="py"][config]');
|
||||||
|
if (pyConfig) config = pyConfig.getAttribute("config");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load its content if remote
|
||||||
|
if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText);
|
||||||
|
|
||||||
|
// parse config only if not empty
|
||||||
|
if (config?.trim()) {
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(config);
|
||||||
|
} catch (_) {
|
||||||
|
parsed = await parse(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse all plugins and optionally ignore only
|
||||||
|
// those flagged as "undesired" via `!` prefix
|
||||||
|
const toBeAwaited = [];
|
||||||
|
for (const [key, value] of Object.entries(allPlugins)) {
|
||||||
|
if (!parsed?.plugins?.includes(`!${key}`)) toBeAwaited.push(value());
|
||||||
|
}
|
||||||
|
if (toBeAwaited.length) plugins = Promise.all(toBeAwaited);
|
||||||
|
|
||||||
|
export { config, plugins };
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
/*! (c) PyScript Development Team */
|
/*! (c) PyScript Development Team */
|
||||||
|
|
||||||
import "@ungap/with-resolvers";
|
import "@ungap/with-resolvers";
|
||||||
import { $ } from "basic-devtools";
|
|
||||||
import { define, XWorker } from "polyscript";
|
import { define, XWorker } from "polyscript";
|
||||||
import sync from "./sync.js";
|
|
||||||
|
|
||||||
import stdlib from "./stdlib.js";
|
|
||||||
import plugins from "./plugins.js";
|
|
||||||
|
|
||||||
// TODO: this is not strictly polyscript related but handy ... not sure
|
// TODO: this is not strictly polyscript related but handy ... not sure
|
||||||
// we should factor this utility out a part but this works anyway.
|
// we should factor this utility out a part but this works anyway.
|
||||||
@@ -14,29 +9,21 @@ import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js";
|
|||||||
import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js";
|
import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js";
|
||||||
import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js";
|
import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js";
|
||||||
|
|
||||||
import { robustFetch as fetch } from "./fetch.js";
|
import sync from "./sync.js";
|
||||||
|
import stdlib from "./stdlib.js";
|
||||||
|
import { config, plugins } from "./config.js";
|
||||||
|
import { robustFetch as fetch, getText } from "./fetch.js";
|
||||||
|
|
||||||
const { assign, defineProperty, entries } = Object;
|
const { assign, defineProperty, entries } = Object;
|
||||||
|
|
||||||
const getText = (body) => body.text();
|
const TYPE = "py";
|
||||||
|
|
||||||
// allows lazy element features on code evaluation
|
// allows lazy element features on code evaluation
|
||||||
let currentElement;
|
let currentElement;
|
||||||
|
|
||||||
// create a unique identifier when/if needed
|
// create a unique identifier when/if needed
|
||||||
let id = 0;
|
let id = 0;
|
||||||
const getID = (prefix = "py") => `${prefix}-${id++}`;
|
const getID = (prefix = TYPE) => `${prefix}-${id++}`;
|
||||||
|
|
||||||
// find the shared config for all py-script elements
|
|
||||||
let config;
|
|
||||||
let pyConfig = $("py-config");
|
|
||||||
if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent;
|
|
||||||
else {
|
|
||||||
pyConfig = $('script[type="py"]');
|
|
||||||
config = pyConfig?.getAttribute("config");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText);
|
|
||||||
|
|
||||||
// generic helper to disambiguate between custom element and script
|
// generic helper to disambiguate between custom element and script
|
||||||
const isScript = ({ tagName }) => tagName === "SCRIPT";
|
const isScript = ({ tagName }) => tagName === "SCRIPT";
|
||||||
@@ -70,7 +57,7 @@ const fetchSource = async (tag, io, asText) => {
|
|||||||
if (asText) return dedent(tag.textContent);
|
if (asText) return dedent(tag.textContent);
|
||||||
|
|
||||||
console.warn(
|
console.warn(
|
||||||
'Deprecated: use <script type="py"> for an always safe content parsing:\n',
|
`Deprecated: use <script type="${TYPE}"> for an always safe content parsing:\n`,
|
||||||
tag.innerHTML,
|
tag.innerHTML,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -140,14 +127,10 @@ const workerHooks = {
|
|||||||
[...hooks.codeAfterRunWorkerAsync].map(dedent).join("\n"),
|
[...hooks.codeAfterRunWorkerAsync].map(dedent).join("\n"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// avoid running further script if the previous one had
|
|
||||||
// some import that would inevitably delay its execution
|
|
||||||
let queuePlugins;
|
|
||||||
|
|
||||||
// define the module as both `<script type="py">` and `<py-script>`
|
// define the module as both `<script type="py">` and `<py-script>`
|
||||||
define("py", {
|
define(TYPE, {
|
||||||
config,
|
config,
|
||||||
env: "py-script",
|
env: `${TYPE}-script`,
|
||||||
interpreter: "pyodide",
|
interpreter: "pyodide",
|
||||||
...workerHooks,
|
...workerHooks,
|
||||||
onWorkerReady(_, xworker) {
|
onWorkerReady(_, xworker) {
|
||||||
@@ -173,21 +156,8 @@ define("py", {
|
|||||||
registerModule(pyodide);
|
registerModule(pyodide);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load plugins unless specified otherwise
|
// ensure plugins are bootstrapped already
|
||||||
const toBeAwaited = [];
|
if (plugins) await plugins;
|
||||||
for (const [key, value] of entries(plugins)) {
|
|
||||||
if (!pyodide.config?.plugins?.includes(`!${key}`))
|
|
||||||
toBeAwaited.push(value());
|
|
||||||
}
|
|
||||||
|
|
||||||
// this grants queued results when first script/tag has plugins
|
|
||||||
// and the second one *might* rely on first tag execution
|
|
||||||
if (toBeAwaited.length) {
|
|
||||||
const all = Promise.all(toBeAwaited);
|
|
||||||
queuePlugins = queuePlugins ? queuePlugins.then(() => all) : all;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queuePlugins) await queuePlugins;
|
|
||||||
|
|
||||||
// allows plugins to do whatever they want with the element
|
// allows plugins to do whatever they want with the element
|
||||||
// before regular stuff happens in here
|
// before regular stuff happens in here
|
||||||
@@ -215,7 +185,7 @@ define("py", {
|
|||||||
defineProperty(element, "target", { value: show });
|
defineProperty(element, "target", { value: show });
|
||||||
|
|
||||||
// notify before the code runs
|
// notify before the code runs
|
||||||
dispatch(element, "py");
|
dispatch(element, TYPE);
|
||||||
pyodide[`run${isAsync ? "Async" : ""}`](
|
pyodide[`run${isAsync ? "Async" : ""}`](
|
||||||
await fetchSource(element, pyodide.io, true),
|
await fetchSource(element, pyodide.io, true),
|
||||||
);
|
);
|
||||||
@@ -249,7 +219,7 @@ class PyScriptElement extends HTMLElement {
|
|||||||
this.srcCode = await fetchSource(this, io, !this.childElementCount);
|
this.srcCode = await fetchSource(this, io, !this.childElementCount);
|
||||||
this.replaceChildren();
|
this.replaceChildren();
|
||||||
// notify before the code runs
|
// notify before the code runs
|
||||||
dispatch(this, "py");
|
dispatch(this, TYPE);
|
||||||
runner(this.srcCode);
|
runner(this.srcCode);
|
||||||
this.style.display = "block";
|
this.style.display = "block";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { FetchError, ErrorCode } from "./exceptions.js";
|
import { FetchError, ErrorCode } from "./exceptions.js";
|
||||||
|
import { getText } from "../node_modules/polyscript/esm/fetch-utils.js";
|
||||||
|
|
||||||
|
export { getText };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a fetch wrapper that handles any non 200 responses and throws a
|
* This is a fetch wrapper that handles any non 200 responses and throws a
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// ⚠️ This file is an artifact: DO NOT MODIFY
|
// ⚠️ This file is an artifact: DO NOT MODIFY
|
||||||
export default {
|
export default {
|
||||||
error: () => import("./plugins/error.js"),
|
error: () => import(/* webpackIgnore: true */ "./plugins/error.js"),
|
||||||
};
|
};
|
||||||
|
|||||||
2
pyscript.core/types/config.d.ts
vendored
Normal file
2
pyscript.core/types/config.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export let config: any;
|
||||||
|
export let plugins: any;
|
||||||
3
pyscript.core/types/core.d.ts
vendored
3
pyscript.core/types/core.d.ts
vendored
@@ -21,6 +21,5 @@ export namespace hooks {
|
|||||||
let codeAfterRunWorker: Set<string>;
|
let codeAfterRunWorker: Set<string>;
|
||||||
let codeAfterRunWorkerAsync: Set<string>;
|
let codeAfterRunWorkerAsync: Set<string>;
|
||||||
}
|
}
|
||||||
declare let config: any;
|
import { config } from "./config.js";
|
||||||
import sync from "./sync.js";
|
import sync from "./sync.js";
|
||||||
export {};
|
|
||||||
|
|||||||
1
pyscript.core/types/fetch.d.ts
vendored
1
pyscript.core/types/fetch.d.ts
vendored
@@ -8,3 +8,4 @@
|
|||||||
* @returns {Promise<Response>}
|
* @returns {Promise<Response>}
|
||||||
*/
|
*/
|
||||||
export function robustFetch(url: string, options?: Request): Promise<Response>;
|
export function robustFetch(url: string, options?: Request): Promise<Response>;
|
||||||
|
export { getText };
|
||||||
|
|||||||
Reference in New Issue
Block a user