Follow up on autostart (#2380)

This commit is contained in:
Andrea Giammarchi
2025-09-30 15:46:37 +02:00
committed by GitHub
parent 2d3ad0ab2d
commit 1e62d0b1fe
4 changed files with 30 additions and 28 deletions

View File

@@ -21,6 +21,7 @@ def func_b():
### Options ### Options
* **pyscript**: the release version to automatically import if not already available on the page. If no version is provided the *developers' channel* version will be used instead (for developers' purposes only).
* **type**: `py` by default to bootstrap *Pyodide*. * **type**: `py` by default to bootstrap *Pyodide*.
* **worker**: `true` by default to bootstrap in a *Web Worker*. * **worker**: `true` by default to bootstrap in a *Web Worker*.
* **config**: either a *string* or a PyScript compatible config *JS literal* to make it possible to bootstrap files and whatnot. If specified, the `worker` becomes implicitly `true` to avoid multiple configs conflicting on the main thread. * **config**: either a *string* or a PyScript compatible config *JS literal* to make it possible to bootstrap files and whatnot. If specified, the `worker` becomes implicitly `true` to avoid multiple configs conflicting on the main thread.
@@ -39,6 +40,7 @@ no config
The [test.js](./test/test.js) files uses the following defaults: The [test.js](./test/test.js) files uses the following defaults:
* `pyscript` as `"2025.8.1"`
* `type` as `"mpy"` * `type` as `"mpy"`
* `worker` as `false` * `worker` as `false`
* `config` as `undefined` * `config` as `undefined`

View File

@@ -1,7 +1,9 @@
/*! (c) PyScript Development Team */ /*! (c) PyScript Development Team */
const { stringify } = JSON; const { stringify } = JSON;
const { create, entries } = Object; const { assign, create, entries } = Object;
const el = (name, props) => assign(document.createElement(name), props);
/** /**
* Transform a list of keys into a Python dictionary. * Transform a list of keys into a Python dictionary.
@@ -57,6 +59,7 @@ export default (url, {
config = null, config = null,
env = null, env = null,
serviceWorker = null, serviceWorker = null,
pyscript = null,
} = {}) => { } = {}) => {
const { protocol, host, pathname } = new URL(url); const { protocol, host, pathname } = new URL(url);
const py = pathname.replace(/\.m?js(?:\/\+\w+)?$/, '.py'); const py = pathname.replace(/\.m?js(?:\/\+\w+)?$/, '.py');
@@ -88,8 +91,17 @@ export default (url, {
// create the arguments for the `dispatchEvent` call // create the arguments for the `dispatchEvent` call
const eventArgs = `${stringify(name)},${name}to_ts(${detail})`; const eventArgs = `${stringify(name)},${name}to_ts(${detail})`;
// bootstrap the script element type and its attributes // bootstrap the script element type and its attributes
const script = document.createElement('script'); const script = el('script', { type, textContent: [
script.type = type; '\n', code, '\n',
// this is to avoid local scope name clashing
`from pyscript import window as ${name}`,
`from pyscript.ffi import to_js as ${name}to_ts`,
`${name}.dispatchEvent(${name}.CustomEvent.new(${eventArgs}))`,
// remove these references even if non-clashing to keep
// the local scope clean from undesired entries
`del ${name}`,
`del ${name}to_ts`,
].join('\n') });
// if config is provided it needs to be a worker to avoid // if config is provided it needs to be a worker to avoid
// conflicting with main config on the main thread (just like always) // conflicting with main config on the main thread (just like always)
@@ -102,19 +114,6 @@ export default (url, {
if (env) script.setAttribute('env', env); if (env) script.setAttribute('env', env);
if (serviceWorker) script.setAttribute('service-worker', serviceWorker); if (serviceWorker) script.setAttribute('service-worker', serviceWorker);
// augment the code with the previously accessed fields at the end
script.textContent = [
'\n', code, '\n',
// this is to avoid local scope name clashing
`from pyscript import window as ${name}`,
`from pyscript.ffi import to_js as ${name}to_ts`,
`${name}.dispatchEvent(${name}.CustomEvent.new(${eventArgs}))`,
// remove these references even if non-clashing to keep
// the local scope clean from undesired entries
`del ${name}`,
`del ${name}to_ts`,
].join('\n');
// let PyScript resolve and execute this script // let PyScript resolve and execute this script
document.body.appendChild(script); document.body.appendChild(script);
@@ -132,19 +131,15 @@ export default (url, {
// has been emitted and the interpreter evaluated the code // has been emitted and the interpreter evaluated the code
const { promise, resolve } = Promise.withResolvers(); const { promise, resolve } = Promise.withResolvers();
// ⚠️ This is just a *fallback* !!!
// Please always use an explicit PyScript release !!!
if (!(Symbol.for('@pyscript/core') in globalThis)) { if (!(Symbol.for('@pyscript/core') in globalThis)) {
// bring in PyScript via the `npm` developers' channel // bring in PyScript if not available already
const cdn = 'https://cdn.jsdelivr.net/npm/@pyscript/core/dist'; const cdn = pyscript ?
`https://pyscript.net/releases/${pyscript}` :
// ⚠️ fallback to developers' channel !!!
'https://cdn.jsdelivr.net/npm/@pyscript/core/dist'
;
document.head.appendChild( document.head.appendChild(
Object.assign( el('link', { rel: 'stylesheet', href: `${cdn}/core.css` }),
document.createElement('link'),
{
rel: 'stylesheet',
href: `${cdn}/core.css`,
}
)
); );
try { await import(`${cdn}/core.js`) } try { await import(`${cdn}/core.js`) }
catch {} catch {}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@pyscript/bridge", "name": "@pyscript/bridge",
"version": "0.2.0", "version": "0.2.2",
"description": "A JS based way to use PyScript modules", "description": "A JS based way to use PyScript modules",
"type": "module", "type": "module",
"module": "./index.js", "module": "./index.js",
@@ -14,6 +14,10 @@
"Python", "Python",
"bridge" "bridge"
], ],
"files": [
"index.js",
"README.md"
],
"author": "Anaconda Inc.", "author": "Anaconda Inc.",
"license": "APACHE-2.0", "license": "APACHE-2.0",
"repository": { "repository": {

View File

@@ -5,6 +5,7 @@ const { searchParams } = new URL(location.href);
// the named (or default) export for test.py // the named (or default) export for test.py
export const ffi = bridge(import.meta.url, { export const ffi = bridge(import.meta.url, {
pyscript: "2025.8.1",
env: searchParams.get("env"), env: searchParams.get("env"),
type: searchParams.get("type") || "mpy", type: searchParams.get("type") || "mpy",
worker: searchParams.has("worker"), worker: searchParams.has("worker"),