-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ChannelType communication channel option. Closes Consider allowing use of `ChannelType.PostMessage` in webR config #3 * Update README documentation to document the new `channel-type` option. * Add a new piece of documentation describing webR communication channels within the quarto-webr scope. * Switch channel type
- Loading branch information
Showing
6 changed files
with
271 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
--- | ||
title: "webR Communication Channel Options" | ||
subtitle: "Using the `channel-type` meta variable of the `webr` filter" | ||
format: | ||
html: | ||
toc: true | ||
engine: knitr | ||
webr: | ||
channel-type: "post-message" | ||
filters: | ||
- webr | ||
--- | ||
|
||
# Making R Computations Run Smoothly | ||
|
||
As you dive deeper into using webR, it's crucial to grasp how webR manages communication between R and your web browser. Think of it as a conversation between two active workers or "threads": | ||
|
||
1. **Web Browser**: This is your web browser, like Chrome or Firefox, which you use to surf the internet and interact with web pages. | ||
2. **webR**: This is like a dedicated helper that specializes in running R code. It operates separately from your main web browser. | ||
|
||
Now, here's why this separation is so important: webR's special version of R can tackle complicated and time-consuming calculations without causing your web browser to freeze or become unresponsive when you're on a web page that uses webR. | ||
|
||
Imagine trying to watch a video online while your computer is running a heavy software update. Without separating them, your video might start buffering, freeze, or even crash. But by putting the update in the background (on a separate worker, like webR), your video can continue to play smoothly. It's the same concept with webR and your web browser – keeping things running smoothly without hiccups. | ||
|
||
For more details, please see the [official webR documentation](https://docs.r-wasm.org/webr/latest/) on [Worker Communication](https://docs.r-wasm.org/webr/latest/communication.html#webr-channels) and [Serving Web Pages with webR](https://docs.r-wasm.org/webr/latest/serving.html). | ||
|
||
# Communication Channels: How Web Browser and webR Talk | ||
|
||
Now, let's explore how your main web browser and the webR worker thread communicate with each other. They use what we call "communication channels" to swap information. Think of it like like passing notes between two people, but in a high-tech way. | ||
|
||
There are a few different types of communication channels available: | ||
|
||
1. **"automatic" or `0` (Default):** | ||
- **Requirements:** Your setup should be prepared for either `"shared-array-buffer"` or `"service-worker"`. | ||
- **Limitations:** It's not clear which option is being used. | ||
|
||
2. **"shared-array-buffer" or `1`:** | ||
- **Requirements:** This option requires something called "cross-origin isolation," which you can read more about [here](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated). | ||
- **Limitations:** There aren't any significant limitations to worry about. | ||
|
||
3. **"service-worker" or `2`:** | ||
- **Requirements:** You need to have JavaScript service workers set up, like `webr-serviceworker.js` and `webr-worker.js`. | ||
- **Limitations:** The script for the service worker must be on the same website as the one using WebR. | ||
|
||
4. **"post-message" or `3`:** | ||
- **Requirements:** No special requirements are needed for this option. | ||
- **Limitations:** R code can't be interrupted easily. Some advanced R features, like nested R REPLs, might not work as expected. | ||
|
||
When you start using WebR, it usually picks the best communication channel for you. However, you can manually choose a channel type if needed. Just remember that each option comes with its own set of requirements and limitations, so pick the one that suits your project best. | ||
|
||
In simpler terms, it's like choosing the right tool for the job. Depending on what you're doing, you might use different methods to pass messages between your web browser and webR. | ||
|
||
## Choosing How WebR Communicates | ||
|
||
In a Quarto document's YAML header, you can tell webR which communication channel to use by setting the `channel-type` option. It's like telling webR how you want it to talk with your web browser. For example, if you want to use the `"post-message"` channel, you can do it like this: | ||
|
||
```yaml | ||
--- | ||
title: "Setting Up webR to use the PostMessage Channel" | ||
format: html | ||
webr: | ||
channel-type: "post-message" | ||
filters: | ||
- webr | ||
--- | ||
``` | ||
|
||
# Your Communication Channel Choices | ||
|
||
The remainder of the document describes the different communication methods alongside ways to satisfy the requirements. | ||
|
||
## Using "automatic" for Communication (Default) | ||
|
||
By default, the `quarto-webr` extension guides webR to use the `"automatic"` option for `channel-type`, if you don't specify the `channel-type` in your document's YAML header. Let's break down how this default setting works: | ||
|
||
1. **Communication Attempts:** webR will try two different communication channels in order: | ||
- First, it attempts to establish a communication channel using `"shared-array-buffer"`. | ||
- If that doesn't work, it will then try to use `"service-worker"`. | ||
2. **Fallback Behavior:** If both of these attempts are unsuccessful, webR code cells in your document will be shown in a deactivated state. This means they won't run or execute any R code. | ||
|
||
:::callout-note | ||
It's important to note that the `"automatic"` option doesn't try to use the `"post-message"` option for communication. | ||
::: | ||
|
||
:::callout-warning | ||
One thing to be aware of is that when the `"automatic"` option is used, it adds two additional files, `webr-serviceworker.js` and `webr-worker.js`, into the output directory. These files must be present alongside the rendered HTML document if you intend to use the `"service-worker"` option. For more details on this, please refer to the `"service-worker"` section of the documentation. | ||
::: | ||
|
||
In summary, when you leave the `channel-type` unspecified, webR will follow the `"automatic"` option, attempting to use `"shared-array-buffer"` and then `"service-worker"`. If both attempts fail, your webR code cells will be inactive. | ||
|
||
## Using "shared-array-buffer" for Communication | ||
|
||
Now, let's explore the `"shared-array-buffer"` option for communication. When you specify `channel-type` as `"shared-array-buffer"`, webR aims to use something called [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer). This choice, however, comes with some specific requirements and benefits: | ||
|
||
**Requirements:** | ||
- Your web server needs to send web pages with webR using specific HTTP headers. This is to ensure that the page is [cross-origin isolated](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated). In simple terms, your server should be set up to allow this kind of communication. | ||
|
||
**Benefits:** | ||
- The benefit of using this approach is that webR runs notably faster. It's like giving webR a high-speed lane for its operations. | ||
|
||
::: callout-note | ||
It's important to note that the `"shared-array-buffer"` option isn't currently available on platforms like [GitHub Pages](https://pages.github.com/) or [Quarto Pub](https://quartopub.com/). If you're using these services, we recommend using the `channel-type: "post-message"` option instead. There's a possibility that GitHub Pages may offer the option to set the necessary headers in the future, as discussed [here](https://github.com/community/community/discussions/13309). | ||
::: | ||
|
||
To help you set up the necessary headers for cross-origin isolation, we provide some guidance for both Netlify and nginx web server administrators: | ||
|
||
**For Netlify Configuration:** | ||
|
||
If you're hosting your website with [Netlify](https://www.netlify.com/), you can add the following code to your [netlify.toml configuration file](https://docs.netlify.com/routing/headers/#syntax-for-the-netlify-configuration-file): | ||
|
||
```toml | ||
[[headers]] | ||
for = "/directory/with/webr/content/*" | ||
|
||
[headers.values] | ||
Cross-Origin-Opener-Policy = "same-origin" | ||
Cross-Origin-Embedder-Policy = "require-corp" | ||
``` | ||
|
||
**For nginx Web Server Administrators:** | ||
|
||
If you're managing a server with `nginx`, you can use the [`add_header`](http://nginx.org/en/docs/http/ngx_http_headers_module.html) directive in your server's configuration file, which is usually found at `/etc/nginx/nginx.conf`. Here's an example: | ||
|
||
```nginx | ||
server { | ||
# Enable headers for the webr directory | ||
location ^~ /directory/with/webr/content { | ||
add_header "Cross-Origin-Opener-Policy" "same-origin"; | ||
add_header "Cross-Origin-Embedder-Policy" "require-corp"; | ||
} | ||
} | ||
``` | ||
|
||
By following these instructions, you'll ensure that your web server is set up to display web pages with a cross-origin isolated status, allowing you to use the `"shared-array-buffer"` option effectively. | ||
|
||
## Using "service-worker" for Communication | ||
|
||
Here, we'll dive into the `"service-worker"` option for communication. | ||
|
||
:::callout-warning | ||
The `"service-worker"` option doesn't work with [Quarto Pub](https://quartopub.com/). If you're hosting documents with Quarto Pub, please use the `channel-type: "post-message"` option instead. There's an ongoing effort to address the service worker upload issue with the Quarto team, which you can track [here](https://github.com/quarto-dev/quarto-cli/issues/6828). | ||
::: | ||
|
||
When you set `channel-type` to `"service-worker"`, webR changes its communication channel to use the [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). This means you need two worker scripts, `webr-worker.js` and `webr-serviceworker.js`, hosted on the same website as the page using webR. | ||
|
||
Here's what you need to ensure: | ||
|
||
**1. Worker Scripts:** The `quarto-webr` extension will automatically create and register these workers when your Quarto document is rendered. | ||
|
||
**2. Directory Structure:** Your initial directory structure should include these files: | ||
|
||
```sh | ||
. | ||
├── _extensions/coatless/quarto-webr | ||
└── demo-quarto-webr.qmd | ||
``` | ||
|
||
After rendering the Quarto document with the `"service-worker"` option, your directory will look like this: | ||
|
||
```sh | ||
. | ||
├── _extensions/coatless/quarto-webr | ||
├── demo-quarto-webr.qmd | ||
├── demo-quarto-webr.html # Rendered document | ||
├── webr-serviceworker.js # Service workers | ||
└── webr-worker.js | ||
``` | ||
|
||
**3. Hosting:** When hosting your rendered document, you need to make sure the rendered HTML document and the service worker files (`webr-serviceworker.js` and `webr-worker.js`) are present on the server. This is important for everything to work correctly: | ||
|
||
```sh | ||
. | ||
├── demo-quarto-webr.html # Rendered document | ||
├── webr-serviceworker.js # Service workers | ||
└── webr-worker.js | ||
``` | ||
|
||
If you want to change where the service workers are located, you can set the `service-worker-url` option in the document YAML. By default, the rendered document will search for the service workers in its current directory. | ||
|
||
In a nutshell, the "service-worker" option is a powerful choice for communication with webR, but you need to ensure the correct setup and hosting to make it work smoothly. | ||
|
||
|
||
## Using "post-message" for Communication | ||
|
||
Now, let's delve into the `"post-message"` option. This sets up a communication channel using something called [Post Message](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage). It's a good choice when you can't use cross-isolation or service workers. This option is simpler to set up and works in more places, like RStudio's preview pane or the built-in browser in VSCode. | ||
|
||
However, there are some trade-offs. While it's easier to get started, certain R features that need to pause and wait for input (like `readline()`, `menu()`, `browser()`, etc.) won't work as expected. Instead, they'll return empty values like `""` or `c('', '')`. Also, you won't have the option to stop or interrupt long-running R code. In those cases, you'll need to refresh the page to regain control. | ||
|
||
Feel free to experiment with the `"post-message"` interface in this webR code cell: | ||
|
||
```{webr-r} | ||
# Attempt to used an input-blocked function | ||
x = readline("What is your favorite color?") | ||
## View the value of x | ||
# print(x) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,8 @@ format: | |
html: | ||
toc: true | ||
engine: knitr | ||
webr: | ||
channel-type: "post-message" | ||
filters: | ||
- webr | ||
--- | ||
|