Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d5b6935

Browse filesBrowse files
Wait for plugins before defining the custom type (#1788)
1 parent b4503ef commit d5b6935
Copy full SHA for d5b6935

File tree

2 files changed

+148
-148
lines changed
Filter options

2 files changed

+148
-148
lines changed

‎pyscript.core/src/config.js

Copy file name to clipboardExpand all lines: pyscript.core/src/config.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const syntaxError = (type, url, { message }) => {
5050
const configs = new Map();
5151

5252
for (const [TYPE] of TYPES) {
53-
/** @type {Promise<any> | undefined} A Promise wrapping any plugins which should be loaded. */
53+
/** @type {Promise<[...any]>} A Promise wrapping any plugins which should be loaded. */
5454
let plugins;
5555

5656
/** @type {any} The PyScript configuration parsed from the JSON or TOML object*. May be any of the return types of JSON.parse() or toml-j0.4's parse() ( {number | string | boolean | null | object | Array} ) */
@@ -119,7 +119,7 @@ for (const [TYPE] of TYPES) {
119119
}
120120

121121
// assign plugins as Promise.all only if needed
122-
if (toBeAwaited.length) plugins = Promise.all(toBeAwaited);
122+
plugins = Promise.all(toBeAwaited);
123123

124124
configs.set(TYPE, { config: parsed, plugins, error });
125125
}

‎pyscript.core/src/core.js

Copy file name to clipboardExpand all lines: pyscript.core/src/core.js
+146-146Lines changed: 146 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -128,162 +128,162 @@ for (const [TYPE, interpreter] of TYPES) {
128128
// define the module as both `<script type="py">` and `<py-script>`
129129
// but only if the config didn't throw an error
130130
if (!error) {
131-
// possible early errors sent by polyscript
132-
const errors = new Map();
133-
134-
define(TYPE, {
135-
config,
136-
interpreter,
137-
env: `${TYPE}-script`,
138-
version: config?.interpreter,
139-
onerror(error, element) {
140-
errors.set(element, error);
141-
},
142-
...workerHooks,
143-
onWorkerReady(_, xworker) {
144-
assign(xworker.sync, sync);
145-
for (const callback of hooks.onWorkerReady)
146-
callback(_, xworker);
147-
},
148-
onBeforeRun(wrap, element) {
149-
currentElement = element;
150-
bootstrapNodeAndPlugins(wrap, element, before, "onBeforeRun");
151-
},
152-
onBeforeRunAsync(wrap, element) {
153-
currentElement = element;
154-
bootstrapNodeAndPlugins(
155-
wrap,
156-
element,
157-
before,
158-
"onBeforeRunAsync",
159-
);
160-
},
161-
onAfterRun(wrap, element) {
162-
bootstrapNodeAndPlugins(wrap, element, after, "onAfterRun");
163-
},
164-
onAfterRunAsync(wrap, element) {
165-
bootstrapNodeAndPlugins(
166-
wrap,
167-
element,
168-
after,
169-
"onAfterRunAsync",
170-
);
171-
},
172-
async onInterpreterReady(wrap, element) {
173-
if (shouldRegister) {
174-
shouldRegister = false;
175-
registerModule(wrap);
176-
}
177-
178-
// ensure plugins are bootstrapped already
179-
if (plugins) await plugins;
180-
181-
// allows plugins to do whatever they want with the element
182-
// before regular stuff happens in here
183-
for (const callback of hooks.onInterpreterReady)
184-
callback(wrap, element);
185-
186-
// now that all possible plugins are configured,
187-
// bail out if polyscript encountered an error
188-
if (errors.has(element)) {
189-
let { message } = errors.get(element);
190-
errors.delete(element);
191-
const clone = message === INVALID_CONTENT;
192-
message = `(${ErrorCode.CONFLICTING_CODE}) ${message} for `;
193-
message += element.cloneNode(clone).outerHTML;
194-
wrap.io.stderr(message);
195-
return;
196-
}
197-
198-
if (isScript(element)) {
199-
const {
200-
attributes: { async: isAsync, target },
201-
} = element;
202-
const hasTarget = !!target?.value;
203-
const show = hasTarget
204-
? queryTarget(element, target.value)
205-
: document.createElement("script-py");
131+
// ensure plugins are bootstrapped already before custom type definition
132+
// NOTE: we cannot top-level await in here as plugins import other utilities
133+
// from core.js itself so that custom definition should not be blocking.
134+
plugins.then(() => {
135+
// possible early errors sent by polyscript
136+
const errors = new Map();
137+
138+
define(TYPE, {
139+
config,
140+
interpreter,
141+
env: `${TYPE}-script`,
142+
version: config?.interpreter,
143+
onerror(error, element) {
144+
errors.set(element, error);
145+
},
146+
...workerHooks,
147+
onWorkerReady(_, xworker) {
148+
assign(xworker.sync, sync);
149+
for (const callback of hooks.onWorkerReady)
150+
callback(_, xworker);
151+
},
152+
onBeforeRun(wrap, element) {
153+
currentElement = element;
154+
bootstrapNodeAndPlugins(
155+
wrap,
156+
element,
157+
before,
158+
"onBeforeRun",
159+
);
160+
},
161+
onBeforeRunAsync(wrap, element) {
162+
currentElement = element;
163+
bootstrapNodeAndPlugins(
164+
wrap,
165+
element,
166+
before,
167+
"onBeforeRunAsync",
168+
);
169+
},
170+
onAfterRun(wrap, element) {
171+
bootstrapNodeAndPlugins(wrap, element, after, "onAfterRun");
172+
},
173+
onAfterRunAsync(wrap, element) {
174+
bootstrapNodeAndPlugins(
175+
wrap,
176+
element,
177+
after,
178+
"onAfterRunAsync",
179+
);
180+
},
181+
async onInterpreterReady(wrap, element) {
182+
if (shouldRegister) {
183+
shouldRegister = false;
184+
registerModule(wrap);
185+
}
206186

207-
if (!hasTarget) {
208-
const { head, body } = document;
209-
if (head.contains(element)) body.append(show);
210-
else element.after(show);
187+
// allows plugins to do whatever they want with the element
188+
// before regular stuff happens in here
189+
for (const callback of hooks.onInterpreterReady)
190+
callback(wrap, element);
191+
192+
// now that all possible plugins are configured,
193+
// bail out if polyscript encountered an error
194+
if (errors.has(element)) {
195+
let { message } = errors.get(element);
196+
errors.delete(element);
197+
const clone = message === INVALID_CONTENT;
198+
message = `(${ErrorCode.CONFLICTING_CODE}) ${message} for `;
199+
message += element.cloneNode(clone).outerHTML;
200+
wrap.io.stderr(message);
201+
return;
211202
}
212-
if (!show.id) show.id = getID();
213203

214-
// allows the code to retrieve the target element via
215-
// document.currentScript.target if needed
216-
defineProperty(element, "target", { value: show });
204+
if (isScript(element)) {
205+
const {
206+
attributes: { async: isAsync, target },
207+
} = element;
208+
const hasTarget = !!target?.value;
209+
const show = hasTarget
210+
? queryTarget(element, target.value)
211+
: document.createElement("script-py");
212+
213+
if (!hasTarget) {
214+
const { head, body } = document;
215+
if (head.contains(element)) body.append(show);
216+
else element.after(show);
217+
}
218+
if (!show.id) show.id = getID();
219+
220+
// allows the code to retrieve the target element via
221+
// document.currentScript.target if needed
222+
defineProperty(element, "target", { value: show });
223+
224+
// notify before the code runs
225+
dispatch(element, TYPE, "ready");
226+
dispatchDone(
227+
element,
228+
isAsync,
229+
wrap[`run${isAsync ? "Async" : ""}`](
230+
await fetchSource(element, wrap.io, true),
231+
),
232+
);
233+
} else {
234+
// resolve PyScriptElement to allow connectedCallback
235+
element._wrap.resolve(wrap);
236+
}
237+
console.debug("[pyscript/main] PyScript Ready");
238+
},
239+
});
217240

218-
// notify before the code runs
219-
dispatch(element, TYPE, "ready");
220-
dispatchDone(
221-
element,
222-
isAsync,
223-
wrap[`run${isAsync ? "Async" : ""}`](
224-
await fetchSource(element, wrap.io, true),
225-
),
226-
);
227-
} else {
228-
// resolve PyScriptElement to allow connectedCallback
229-
element._wrap.resolve(wrap);
230-
}
231-
console.debug("[pyscript/main] PyScript Ready");
232-
},
241+
customElements.define(
242+
`${TYPE}-script`,
243+
class extends HTMLElement {
244+
constructor() {
245+
assign(super(), {
246+
_wrap: Promise.withResolvers(),
247+
srcCode: "",
248+
executed: false,
249+
});
250+
}
251+
get id() {
252+
return super.id || (super.id = getID());
253+
}
254+
set id(value) {
255+
super.id = value;
256+
}
257+
async connectedCallback() {
258+
if (!this.executed) {
259+
this.executed = true;
260+
const isAsync = this.hasAttribute("async");
261+
const { io, run, runAsync } = await this._wrap
262+
.promise;
263+
this.srcCode = await fetchSource(
264+
this,
265+
io,
266+
!this.childElementCount,
267+
);
268+
this.replaceChildren();
269+
this.style.display = "block";
270+
dispatch(this, TYPE, "ready");
271+
dispatchDone(
272+
this,
273+
isAsync,
274+
(isAsync ? runAsync : run)(this.srcCode),
275+
);
276+
}
277+
}
278+
},
279+
);
233280
});
234281
}
235282

236-
class PyScriptElement extends HTMLElement {
237-
constructor() {
238-
assign(super(), {
239-
_wrap: Promise.withResolvers(),
240-
srcCode: "",
241-
executed: false,
242-
});
243-
}
244-
get _pyodide() {
245-
// TODO: deprecate this hidden attribute already
246-
// currently used by integration tests
247-
return this._wrap;
248-
}
249-
get id() {
250-
return super.id || (super.id = getID());
251-
}
252-
set id(value) {
253-
super.id = value;
254-
}
255-
async connectedCallback() {
256-
if (!this.executed) {
257-
this.executed = true;
258-
const isAsync = this.hasAttribute("async");
259-
const { io, run, runAsync } = await this._wrap.promise;
260-
this.srcCode = await fetchSource(
261-
this,
262-
io,
263-
!this.childElementCount,
264-
);
265-
this.replaceChildren();
266-
this.style.display = "block";
267-
dispatch(this, TYPE, "ready");
268-
dispatchDone(
269-
this,
270-
isAsync,
271-
(isAsync ? runAsync : run)(this.srcCode),
272-
);
273-
}
274-
}
275-
}
276-
277-
// define py-script only if the config didn't throw an error
278-
if (!error) customElements.define(`${TYPE}-script`, PyScriptElement);
279-
280283
// export the used config without allowing leaks through it
281284
exportedConfig[TYPE] = structuredClone(config);
282285
}
283286

284-
// TBD: I think manual worker cases are interesting in pyodide only
285-
// so for the time being we should be fine with this export.
286-
287287
/**
288288
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
289289
* @param {string} file the python file to run ina worker.
@@ -297,8 +297,8 @@ export function PyWorker(file, options) {
297297
// and as `pyodide` is the only default interpreter that can deal with
298298
// all the features we need to deliver pyscript out there.
299299
const xworker = XWorker.call(new Hook(null, workerHooks), file, {
300-
...options,
301300
type: "pyodide",
301+
...options,
302302
});
303303
assign(xworker.sync, sync);
304304
return xworker;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.