Skip to content

Commit 20ae71a

Browse files
committed
Updating coincident to its latest
1 parent 036b48c commit 20ae71a

24 files changed

+280
-317
lines changed

cjs/package.json

-1
This file was deleted.

docs/README.md

+12-9
Original file line numberDiff line numberDiff line change
@@ -499,12 +499,13 @@ There are **alternative ways** to enable these headers for your site or local ho
499499
500500
Before showing any example, it's important to understand how the offered API differs from Web standard *workers*:
501501
502-
| name | example | behavior |
503-
| :-------- | :------------------------------------------------------- | :--------|
504-
| async | `XWorker('./file.py', async=True)` | The worker code is evaluated via `runAsync` utility where, if the *interpreter* allows it, top level *await* would be possible, among other *PL* specific asynchronous features. |
505-
| config | `XWorker('./file.py', config='./cfg.toml')` | The worker will either use the config object as it is or load and parse its referencing *JSON* or *TOML* file, or syntax, to configure itself. Please see [currently supported config values](https://docs.pyscript.net/latest/reference/elements/py-config.html#supported-configuration-values) as this is currently based on `<py-config>` features. |
506-
| type | `XWorker('./file.py', type='pyodide')` | Define the *interpreter* to use with this worker which is, by default, the same one used within the running code. Please read the [Terminology](#terminology) **interpreter** dedicated details to know more. |
507-
| version | `XWorker('./file.py', type='pyodide', version='0.23.2')` | Allow the usage of a specific version where, if numeric, must be available through the project *CDN* used by *core* but if specified as fully qualified *URL*, allows usage of any interpreter's version: `<script type="pyodide" version="http://localhost:8080/pyodide.local.mjs">` |
502+
| name | example | behavior |
503+
| :------------ | :--------------------------------------------------------------- | :--------|
504+
| async | `XWorker('./file.py', async=True)` | The worker code is evaluated via `runAsync` utility where, if the *interpreter* allows it, top level *await* would be possible, among other *PL* specific asynchronous features. |
505+
| config | `XWorker('./file.py', config='./cfg.toml')` | The worker will either use the config object as it is or load and parse its referencing *JSON* or *TOML* file, or syntax, to configure itself. Please see [currently supported config values](https://docs.pyscript.net/latest/reference/elements/py-config.html#supported-configuration-values) as this is currently based on `<py-config>` features. |
506+
| type | `XWorker('./file.py', type='pyodide')` | Define the *interpreter* to use with this worker which is, by default, the same one used within the running code. Please read the [Terminology](#terminology) **interpreter** dedicated details to know more. |
507+
| version | `XWorker('./file.py', type='pyodide', version='0.23.2')` | Allow the usage of a specific version where, if numeric, must be available through the project *CDN* used by *core* but if specified as fully qualified *URL*, allows usage of any interpreter's version: `<script type="pyodide" version="http://localhost:8080/pyodide.local.mjs">` |
508+
| serviceWorker | `XWorker('./file.py', type='pyodide', serviceWorker='../sw.js')` | When the server cannot enable *SharedArrayBuffer* or *mini-coi* like service worker is not usable or desired, it is still possible to fallback to a slower, yet working, orchestration provided by [sabayon](https://github.com/WebReflection/sabayon?tab=readme-ov-file#service-worker). |
508509
509510
The returning *JS* reference to any `XWorker(...)` call is literally a `Worker` instance that, among its default API, have the extra following feature:
510511
@@ -544,9 +545,11 @@ Within a *Worker* execution context, the `xworker` exposes the following feature
544545
545546
| name | example | behavior |
546547
| :------------ | :------------------------------------------| :--------|
547-
| sync | `xworker.sync.from_main(1, "two")` | Executes the exposed `from_main` function in the main thread. Returns synchronously its result, if any. |
548-
| window | `xworker.window.document.title = 'Worker'` | Differently from *pyodide* or *micropython* `import js`, this field allows every single possible operation directly in the main thread. It does not refer to the local `js` environment the interpreter might have decided to expose, it is a proxy to handle otherwise impossible operations in the main thread, such as manipulating the *DOM*, reading `localStorage` otherwise not available in workers, change location or anything else usually possible to do in the main thread. |
549-
| isWindowProxy | `xworker.isWindowProxy(ref)` | **Advanced** - Allows introspection of *JS* references, helping differentiating between local worker references, and main thread global JS references. This is valid both for non primitive objects (array, dictionaries) as well as functions, as functions are also enabled via `xworker.window` in both ways: we can add a listener from the worker or invoke a function in the main. Please note that functions passed to the main thread will always be invoked asynchronously.
548+
| polyfill | `xworker.polyfill` | Returns `true` if *sabayon* polyfill is used behind the scene. |
549+
| sync | `xworker.sync.from_main(1, "two")` | Executes the exposed `from_main` function in the main thread. Returns synchronously its result when *SharedArrayBuffer* can work synchronously. Returns asynchronously otherwise exposed callbacsk from the *main* thread. |
550+
| window | `xworker.window.document.title = 'Worker'` | Differently from *pyodide* or *micropython* `import js`, this field allows every single possible operation directly in the main thread when that is possible (*SharedArrayBuffer* either available or polyfilled for `sync` operations too). It does not refer to the local `js` environment the interpreter might have decided to expose, it is a proxy to handle otherwise impossible operations in the main thread, such as manipulating the *DOM*, reading `localStorage` otherwise not available in workers, change location or anything else usually possible to do in the main thread. |
551+
| isWindowProxy | `xworker.isWindowProxy(ref)` | **Advanced** - Allows introspection of *JS* references, helping differentiating between local worker references, and main thread global JS references. This is valid both for non primitive objects (array, dictionaries) as well as functions, as functions are also enabled via `xworker.window` in both ways: we can add a listener from the worker or invoke a function in the main. Please note that functions passed to the main thread will always be invoked asynchronously. |
552+
550553
551554
```python
552555
from polyscript import xworker

docs/index.js

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/index.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/zip-CGWtiqjJ.js

-2
This file was deleted.

docs/zip-gl8b5xR3.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/zip-CGWtiqjJ.js.map renamed to docs/zip-gl8b5xR3.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esm/utils.js

+12-8
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,20 @@ export const importJS = (source, name) => import(source).then(esm => {
110110
});
111111

112112
export const importCSS = href => new Promise((onload, onerror) => {
113-
if (document.querySelector(`link[href="${href}"]`)) onload();
114-
document.head.append(
115-
assign(
116-
document.createElement('link'),
117-
{ rel: 'stylesheet', href, onload, onerror },
118-
)
119-
)
113+
if (document.querySelector(`link[rel="stylesheet"][href="${href}"]`)) {
114+
onload();
115+
}
116+
else {
117+
document.head.append(
118+
assign(
119+
document.createElement('link'),
120+
{ rel: 'stylesheet', href, onload, onerror },
121+
)
122+
);
123+
}
120124
});
121125

122-
export const isCSS = source => /\.css/i.test(new URL(source).pathname);
126+
export const isCSS = source => /\.css$/i.test(new URL(source).pathname);
123127
/* c8 ignore stop */
124128

125129
export {

esm/worker/_template.js

+7-33
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// bigger than it used to be before any changes is applied to this file.
66

77
import * as JSON from '@ungap/structured-clone/json';
8-
import coincident from 'coincident/window';
8+
import coincident from 'coincident/window/worker';
99

1010
import { assign, create, createFunction, createOverload, createResolved, dispatch, registerJSModules } from '../utils.js';
1111
import createJSModules from './js_modules.js';
@@ -32,17 +32,19 @@ const add = (type, fn) => {
3232

3333
const { parse, stringify } = JSON;
3434

35-
const { proxy: sync, window, isWindowProxy } = coincident(self, {
35+
const { proxy: sync, sync: syncMainAndWorker, polyfill, window, isWindowProxy } = await coincident({
3636
parse,
3737
stringify,
3838
transform: value => transform ? transform(value) : value
3939
});
4040

4141
const xworker = {
42+
// propagate the fact SharedArrayBuffer is polyfilled
43+
polyfill,
4244
// allows synchronous utilities between this worker and the main thread
4345
sync,
44-
// allow access to the main thread world
45-
window,
46+
// allow access to the main thread world whenever it's possible
47+
window: syncMainAndWorker ? window : null,
4648
// allow introspection for foreign (main thread) refrences
4749
isWindowProxy,
4850
// standard worker related events / features
@@ -61,38 +63,10 @@ add('message', ({ data: { options, config: baseURL, configURL, code, hooks } })
6163

6264
const interpreter = await getRuntime(runtimeID, baseURL, configURL, config);
6365

64-
const { js_modules, sync_main_only } = configs.get(runtimeID);
66+
const { js_modules } = configs.get(runtimeID);
6567

6668
const mainModules = js_modules?.main;
6769

68-
// this flag allows interacting with the xworker.sync exposed
69-
// *only in the worker* and eventually invoked *only from main*.
70-
// If that flag is `false` or not present, then SharedArrayBuffer
71-
// must be available or not much can work in here.
72-
let syncMainAndWorker = !sync_main_only;
73-
74-
// bails out out of the box with a native/meaningful error
75-
// in case the SharedArrayBuffer is not available
76-
try {
77-
new SharedArrayBuffer(4);
78-
// if this does not throw there's no reason to
79-
// branch out of all the features ... but ...
80-
syncMainAndWorker = true;
81-
}
82-
// eslint-disable-next-line no-unused-vars
83-
catch (_) {
84-
// if it does throw and `sync_main_only` was not `true`
85-
// then there's no way to go further
86-
if (syncMainAndWorker) {
87-
throw new Error(
88-
[
89-
'Unable to use SharedArrayBuffer due insecure environment.',
90-
'Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements',
91-
].join('\n'),
92-
);
93-
}
94-
}
95-
9670
const details = create(registry.get(type));
9771

9872
const resolved = createResolved(

esm/worker/class.js

+21-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import * as JSON from '@ungap/structured-clone/json';
21
import fetch from '@webreflection/fetch';
3-
import coincident from 'coincident/window';
42
import xworker from './xworker.js';
53
import { getConfigURLAndType } from '../loader.js';
64
import { assign, create, defineProperties, importCSS, importJS } from '../utils.js';
@@ -14,6 +12,8 @@ import Hook from './hook.js';
1412
* @prop {string} [configURL] the optional configURL used to resolve config entries
1513
*/
1614

15+
// REQUIRES INTEGRATION TEST
16+
/* c8 ignore start */
1717
export default (...args) =>
1818
/**
1919
* A XWorker is a Worker facade able to bootstrap a channel with any desired interpreter.
@@ -22,7 +22,8 @@ export default (...args) =>
2222
* @returns {Worker}
2323
*/
2424
function XWorker(url, options) {
25-
const worker = xworker();
25+
const serviceWorker = options?.serviceWorker;
26+
const worker = xworker({ serviceWorker });
2627
const { postMessage } = worker;
2728
const isHook = this instanceof Hook;
2829

@@ -37,28 +38,31 @@ export default (...args) =>
3738
// fallback to a generic, ignored, config.txt file to still provide a URL.
3839
const [ config ] = getConfigURLAndType(options.config, options.configURL);
3940

40-
const bootstrap = fetch(url)
41-
.text()
42-
.then(code => {
43-
const hooks = isHook ? this.toJSON() : void 0;
44-
postMessage.call(worker, { options, config, code, hooks });
45-
});
46-
4741
const sync = assign(
48-
coincident(worker, JSON).proxy,
42+
worker.proxy,
4943
{ importJS, importCSS },
5044
);
5145

5246
const resolver = Promise.withResolvers();
5347

48+
let bootstrap = fetch(url)
49+
.text()
50+
.then(code => {
51+
const hooks = isHook ? this.toJSON() : void 0;
52+
postMessage.call(worker, { options, config, code, hooks });
53+
})
54+
.then(() => {
55+
// boost postMessage performance
56+
bootstrap = { then: fn => fn() };
57+
});
58+
5459
defineProperties(worker, {
5560
sync: { value: sync },
5661
ready: { value: resolver.promise },
5762
postMessage: {
58-
value: (data, ...rest) =>
59-
bootstrap.then(() =>
60-
postMessage.call(worker, data, ...rest),
61-
),
63+
value: (data, ...rest) => bootstrap.then(
64+
() => postMessage.call(worker, data, ...rest),
65+
),
6266
},
6367
onerror: {
6468
writable: true,
@@ -87,3 +91,5 @@ export default (...args) =>
8791

8892
return worker;
8993
};
94+
95+
/* c8 ignore stop */

0 commit comments

Comments
 (0)