@@ -58,41 +58,36 @@ This is the most common error new PyScript users face:
5858
5959#### When
6060
61- This error occurs when code running in a worker tries to access ` window `
62- or ` document ` objects that exist on the main thread.
61+ This error occurs when code running in a worker tries to access
62+ ` window ` or ` document ` objects from the main thread.
6363
64- The error indicates either ** your web server is incorrectly configured**
65- or ** a ` service-worker ` attribute is missing from your script element** .
64+ It indicates one of three situations:
6665
67- Specifically, one of three situations applies:
66+ 1 . ** Server misconfiguration:** Your script has a ` worker ` attribute and
67+ accesses ` window ` or ` document ` , but your web server isn't configured to
68+ enable SharedArrayBuffer/Atomics.
6869
69- Your web server configuration prevents the browser from enabling Atomics
70- (a technology for cross-thread communication). When your script element
71- has a ` worker ` attribute and your Python code uses ` window ` or
72- ` document ` objects that exist on the main thread, this browser
73- limitation causes failure unless you reconfigure your server.
70+ 2 . ** Missing service-worker attribute:** You're using
71+ ` <script type="py-editor"> ` (which always runs in a worker) without
72+ providing a ` service-worker ` attribute for fallback synchronous operations.
7473
75- You're using ` <script type="py-editor"> ` (which always runs in a worker)
76- without providing a fallback via a ` service-worker ` attribute on that
77- element .
74+ 3 . ** PyWorker without fallback: ** You've created a ` PyWorker ` or ` MPWorker `
75+ instance without providing a ` service_worker ` fallback (see:
76+ [ this API class ] ( ./api/context.md/#pyscript.context.PyWorker ) ) .
7877
79- You've explicitly created a ` PyWorker ` or ` MPWorker ` instance somewhere
80- in your code without providing a ` service_worker ` fallback.
81-
82- The [ workers guide] ( ./user-guide/workers.md ) documents all these cases
78+ The [ workers guide] ( ./user-guide/workers.md ) documents all these use cases
8379with code examples and solutions.
8480
8581#### Why
8682
87- For ` document.getElementById('some-id').value ` to work in a worker,
88- JavaScript requires two primitives:
89-
90- [ SharedArrayBuffer] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer )
91- allows multiple threads to read and write shared memory.
83+ Workers often require two browser based features to access main thread objects
84+ like ` window ` and ` document ` .
9285
93- [ Atomics] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics )
94- provides ` wait(sab, index) ` and ` notify(sab, index) ` to coordinate
95- threads, where ` sab ` is a SharedArrayBuffer.
86+ 1 . [ SharedArrayBuffer] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer )
87+ allows multiple threads to read and write shared memory.
88+ 2 . [ Atomics] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics )
89+ provides ` wait(sab, index) ` and ` notify(sab, index) ` to coordinate
90+ threads, where ` sab ` is a SharedArrayBuffer.
9691
9792Whilst a worker waits for a main thread operation, it doesn't consume
9893CPU. It idles until the referenced buffer index changes, effectively
@@ -105,8 +100,124 @@ responsive during heavy computation.
105100
106101Unfortunately, we cannot patch or work around these primitives - they're
107102defined by web standards. However, various solutions exist for working
108- within these limitations. The [ workers guide] ( ./user-guide/workers.md )
109- explains how.
103+ within these limitations.
104+
105+ The easiest fix is to ensure your webserver is correctly configured to
106+ serve responses with the following headers:
107+
108+ ```
109+ Access-Control-Allow-Origin: *
110+ Cross-Origin-Opener-Policy: same-origin
111+ Cross-Origin-Embedder-Policy: require-corp
112+ Cross-Origin-Resource-Policy: cross-origin
113+ ```
114+
115+ If you are unable to reconfigure your webserver (perhaps, for example,
116+ you're using a third party for hosting), you have two options:
117+
118+ ** Option 1:** ` mini-coi `
119+
120+ The ` mini-coi ` project ensures a browser's
121+ [ complicated Cross Origin Isolation (COI) settings] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements )
122+ "just work" for web workers. This is especially useful when you have no
123+ control over the HTTP headers returned by the server.
124+
125+ For performance reasons, this is the preferred option so Atomics works at
126+ native speed.
127+
128+ The simplest way to use mini-coi is to copy the
129+ [ ` mini-coi.js ` ] ( https://raw.githubusercontent.com/WebReflection/mini-coi/main/mini-coi.js )
130+ file to the root of your website (i.e. ` / ` ), and reference it as the first
131+ child tag in the ` <head> ` of your HTML documents:
132+
133+ ``` html
134+ <html >
135+ <head >
136+ <script src =" /mini-coi.js" ></script >
137+ <!-- etc -->
138+ </head >
139+ <!-- etc -->
140+ </html >
141+ ```
142+
143+ ** Option 2:** ` service-worker ` attribute
144+
145+ This allows you to slot in a custom
146+ [ service worker] ( https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API )
147+ to handle requirements for synchronous operations.
148+
149+ Each ` <script type="m/py"> ` or ` <m/py-script> ` may optionally have a
150+ ` service-worker ` attribute pointing to a locally served file (the same way
151+ ` mini-coi.js ` needs to be served).
152+
153+ This file needs to orchestrate _ coincident POST_ requests so that:
154+
155+ * You can copy and paste
156+ [ the coincident Service Worker] ( https://cdn.jsdelivr.net/npm/coincident/dist/sw.js )
157+ into your local project and point at that via the ` service-worker `
158+ attribute. This will not change the original behavior of your project, it
159+ will not interfere with the default or pre-defined headers your application
160+ uses already but it will ** fallback to a (slower but working) synchronous
161+ operation** that allows both ` window ` and ` document ` access in your worker
162+ logic.
163+ * You can import
164+ [ coincident listeners] ( https://github.com/WebReflection/coincident/blob/main/src/sabayon/listeners.js )
165+ in your project and at least add the ` fetch ` one before your listeners. It
166+ will automatically stop propagation when a request is meant to be handled
167+ so that the rest of your logic will not be affected or change by any mean.
168+
169+ ``` html
170+ <html >
171+ <head >
172+ <!-- PyScript link and script -->
173+ </head >
174+ <body >
175+ <script type =" py" service-worker =" ./sw.js" worker >
176+ from pyscript import window, document
177+
178+ document .body .append (" Hello PyScript!" )
179+ </script >
180+ </body >
181+ </html >
182+ ```
183+
184+ !!! warning
185+
186+ Using _coincident_ as the fallback for synchronous operations via Atomics
187+ should be **the last solution to consider**. It is inevitably slower than
188+ using native Atomics.
189+
190+ If you must use `service-worker` attribute, always reduce the amount of
191+ synchronous operations by caching references from the _main_ thread.
192+
193+ ```python
194+ # ❌ THIS IS UNNECESSARILY SLOWER
195+ from pyscript import document
196+
197+ # add a data-test="not ideal attribute"
198+ document.body.dataset.test = "not ideal"
199+ # read a data-test attribute
200+ print(document.body.dataset.test)
201+
202+ # - - - - - - - - - - - - - - - - - - - - -
203+
204+ # ✔️ THIS IS FINE
205+ from pyscript import document
206+
207+ # if needed elsewhere, reach it once
208+ body = document.body
209+ dataset = body.dataset
210+
211+ # add a data-test="not ideal attribute"
212+ dataset.test = "not ideal"
213+ # read a data-test attribute
214+ print(dataset.test)
215+ ```
216+
217+ In latter example the number of operations has been reduced from six to
218+ just four. The rule of thumb is: _if you ever need a DOM reference more
219+ than once, cache it_.
220+
110221
111222### Borrowed proxy
112223
0 commit comments