# Polyscript PyScript single core to rule them all - - - * [Terminology](#terminology) - what we mean by "_term_" in this document * [Bootstrapping core](#bootstrapping-core) - how to enable Polyscript in your page * [How Scripts Work](#how-scripts-work) - how ` ``` ℹ️ - Please note we decided on purpose to not use the generic programming language name instead of its interpreter project name to avoid being too exclusive for alternative projects that would like to target that very same Programming Language (i.e. note *pyodide* & *micropython* not using *python* indeed as interpreter name). Custom values for the `type` attribute can also be created which alias (and potential build on top of) existing interpreter types. We include `
``` When it comes to the `property` or `field` attached to a `
``` ℹ️ - Please note that if no `target` attribute is specified, the *script* will automatically create a "_companion element_" when the `target` property/field is accessed for the very first time: ```html ```
Env
ℹ️ - This is an **advanced feature** that is worth describing but usually it is not needed for most common use cases. Mostly due its terseness that plays nicely as attribute's suffix, among its commonly understood meaning, we consider an *env* an identifier that guarantee the used *interpreter* would always be the same and no other interpreters, even if they point at very same project, could interfere with globals, behavior, or what's not. In few words, every single *env* would spawn a new interpreter dedicated to such env, and global variables defined elsewhere will not affect this "_environment_" and vice-versa, an *env* cannot dictate what will happen to other interpreters. ```html ``` ℹ️ - Please note if the interpreter takes 1 second to bootstrap, multiple *environments* will take *that* second multiplied by the number of different environments, which is why this feature is considered for **advanced** use cases only and it should be discouraged as generic practice.
## Bootstrapping core In order to have anything working at all in our pages, we need to at least bootstrap *polyscript* functionalities, otherwise all examples and scripts mentioned in this document would just sit there ... sadly ignored by every browser: ```html ``` As *core* exposes some utility/API, using the following method would also work: ```html ``` Please keep reading this document to understand how to use those utilities or how to have other *Pogramming Languages* enabled in your page via ` ``` Not only this is helpful to crawl the surrounding *DOM* or *HTML*, every script will also have a `target` property that will point either to the element reachable through the `target` attribute, or it lazily creates once a companion element that will be appended right after the currently executing *script*. Please read the [Terminology](#terminology) **target** dedicated details to know more.
XWorker
With or without access to the `document`, every (*non experimental*) interpreter will have defined, either at the global level or after an import (i.e.`from polyscript import XWorker` in *Python* case), a reference to the `XWorker` "_class_" (it's just a *function*!), which goal is to enable off-loading heavy operations on a worker, without blocking the main / UI thread (the current page) and allowing such worker to even reach the `document` or anything else available on the very same main / UI thread. ```html ``` Please read the [XWorker](#xworker) dedicated section to know more.
## Extra `config` features It is possible to land in either the *main* world or the *worker* one native *JS* modules (aka: *ESM*). In *polyscript*, this is possible by defining one or more `[js_modules.X]` fields in the config, where `X` is either *main* or *worker*: * `sync_main_only` which if `true` avoids throwing out of the box if the *SharedArrayBuffer* cannot be used and still allows invokes **from the main** to methods exposes **through the worker** (so that basically interactions can only be *async*). * `[js_modules.main]` is a list of *source* -> *module name* pairs, similarly to how `[files]` field work, where the *module* name will then be reachable via `polyscript.js_modules.actual_name` in both *main* and *worker* world. As the *main* module lands on the main thread, where there is also likely some UI, it is also possible to define one or more related *CSS* to that module, as long as they target the very same name (see the example to better understand). * `[js_modules.worker]` is a list of *source* -> *module name* pairs that actually land only in ` ``` ### .tar.gz and .zip files If the `[files]` entry in the *config* contains a `xxxxx.tar.gz` or `xxxxx.zip` **source**, and it's destination / target is a folder with a star, such as `/*` for root or `./dest/*` for local folders, both *Pyodide* and *MicroPython* runtimes will be able to extract that compressed archive automatically into the Virtual File System and at exactly that location. This feature is hence available on *PyScript* too. ## The `polyscript` Module The module is registered within the interpreter as *JS* module and it offers various helpers or utilities accordingly if it's running on the **main** thread or the **worker** one. ### Main exports | name | example | description | | :-------------- | :--------------------------------------- | :---------- | | XWorker | `from polyscript import XWorker` | described in the [XWorker](#xworker) part. | | config | `from polyscript import config` | **custom only**: the used config as object literal | currentScript | `from polyscript import currentScript` | it's an explicit, always correct, reference to the current node running the generic script code. | | js_modules | `from polyscript import js_modules` | described in the [Extra config Features](#extra-config-features) part. | | lazy_py_modules | `from polyscript import lazy_py_modules` | allows, only in *Python* related interpreters, and without needing static config entries, to import lazily any available module. | storage | `from polyscript import storage` | a utility to instantiate a named [idb-map](https://github.com/WebReflection/idb-map/#readme) that can be consumed synchronously. | JSON | `from polyscript import JSON` | a utility to stringify/parse more complex or recursive data via [@ungap/structured-clone/json](https://github.com/ungap/structured-clone/#readme). #### lazy_py_modules ```html ``` #### storage ```html ``` ### Worker exports | name | example | description | | :------------ | :------------------------------------- | :---------- | | xworker | `from polyscript import xworker` | described in the [XWorker](#xworker) part. | | config | `from polyscript import config` | **custom only**: the used config as object literal | currentScript | `from polyscript import currentScript` | it's an explicit, always correct, reference to the current node running the generic script code via a worker. | | js_modules | `from polyscript import js_modules` | described in the [Extra config Features](#extra-config-features) part. | | target | `from polyscript import target` | returns the element referenced by the `target` attribute, if any, or create a target node to display output when this has not been provided. ## How Events Work The event should contain the *interpreter* or *custom type* prefix, followed by the *event* type it'd like to handle. ```html ``` Differently from *Web* inline events, there's no code evaluation at all within the attribute: it's just a globally available name that will receive the current event and nothing else. #### The type-env attribute Just as the `env` attribute on a ` ``` As mentioned before, this will work with `py-env` too, or any custom type defined out there. ## XWorker Whenever computing relatively expensive stuff, such as a *matplot* image, or literally anything else that would take more than let's say 100ms to answer, running your *interpreter* of choice within a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is likely desirable, so that the main / UI thread won't block users' actions, listeners, or any other computation going on in these days highly dynamic pages. `polyscript` adds a functionality called `XWorker` to all of the interpreters it offers, which works in each language the way `Worker` does in JavaScript. In each Interpreter, `XWorker` is either global reference or an import (i.e.`from polyscript import XWorker` in *Python* case) module's utility, with a counter `xworker` (lower case) global reference, or an import (i.e.`from polyscript import xworker` in *Python* case) module's utility, within the worker code. In short, the `XWorker` utility is to help, without much thinking, to run any desired interpreter out of a *Worker*, enabling extra features on the *worker*'s code side. ### Enabling XWorker We use the latest Web technologies to allow fast, non-blocking, yet synchronous like, operations from any non-experimental interpreter's worker, and the standard requires some special header to enable such technologies and, most importantly, the [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer). There is an exhaustive [section](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements) around this topic but the *TL;DR* version is: * to protect your page from undesired attacks, the `Cross-Origin-Opener-Policy` header should be present with the `same-origin` value * to protect other sites from your pages' code, the `Cross-Origin-Embedder-Policy` header should be present with either the `credentialless` value (Chrome and Firefox browsers) or the `require-corp` one (Safari + other browsers) * when the `Cross-Origin-Embedder-Policy` header is set with the `require-corp` value, the `Cross-Origin-Resource-Policy` header should also be available with [one of these options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy): `same-site`, `same-origin` or `cross-origin` There are **alternative ways** to enable these headers for your site or local host, and [this script](https://github.com/gzuidhof/coi-serviceworker#readme) is just one of these, one that works with most free-hosting websites too. ### XWorker options Before showing any example, it's important to understand how the offered API differs from Web standard *workers*: | name | example | behavior | | :-------- | :------------------------------------------------------- | :--------| | 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. | | 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 `` features. | | 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. | | 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: `