@@ -128,162 +128,162 @@ for (const [TYPE, interpreter] of TYPES) {
128
128
// define the module as both `<script type="py">` and `<py-script>`
129
129
// but only if the config didn't throw an error
130
130
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
+ }
206
186
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 ;
211
202
}
212
- if ( ! show . id ) show . id = getID ( ) ;
213
203
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
+ } ) ;
217
240
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
+ ) ;
233
280
} ) ;
234
281
}
235
282
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
-
280
283
// export the used config without allowing leaks through it
281
284
exportedConfig [ TYPE ] = structuredClone ( config ) ;
282
285
}
283
286
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
-
287
287
/**
288
288
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
289
289
* @param {string } file the python file to run ina worker.
@@ -297,8 +297,8 @@ export function PyWorker(file, options) {
297
297
// and as `pyodide` is the only default interpreter that can deal with
298
298
// all the features we need to deliver pyscript out there.
299
299
const xworker = XWorker . call ( new Hook ( null , workerHooks ) , file , {
300
- ...options ,
301
300
type : "pyodide" ,
301
+ ...options ,
302
302
} ) ;
303
303
assign ( xworker . sync , sync ) ;
304
304
return xworker ;
0 commit comments