Examples using WebR

Starting webR

Once webR has been downloaded and made available for use, it can be initialised by creating a new instance of the WebR class.

const webR = new WebR();

A configuration object of type WebROptions can be passed to the above constructor. This optional argument provides access to advanced webR settings such as WebAssembly binary URLs, communication channel settings, and control over the Emscripten environment that the WebAssembly binaries are to be executed in.

Awaiting initialisation

WebR is ready to use once the promise returned by WebR.init() resolves. In a modern asynchronous JavaScript environment (e.g. within an async function), the await keyword can be used to ensure webR has finished starting before continuing.

await webR.init();

Example Snippets

Evaluating R code and retrieving results

This example demonstrates running R code with WebR.evalR() and getting the result in the form of an RObject proxy. The result is then converted into a JavaScript object before being output to the JavaScript console.

let result = await webR.evalR('rnorm(10,5,1)');
let output = await result.toArray();

console.log('Result of running `rnorm` from webR: ', output);
Result of running `rnorm` from webR: [4.811743371393964,
3.9713199286446246, 5.752161964201946, 4.699964764731866,
6.793839154500917, 5.80036239061935, 5.342100112394279,
5.555879371932934, 4.314676418095938, 5.113592217724398]

The options argument of WebR.evalR() has been designed so that the default is sufficient for general R evaluation. However, the default behaviour can be changed by passing an options argument of type EvalROptions, if required.

Capturing console output from R code

The following snippet demonstrates using a webR shelter to capture R output during evaluation. This differs from the example above in that the output is retrieved in the form of lines of text from the stdout stream, rather than a reference to an R object in the form of an RObject proxy.

Once the result is no longer needed, the shelter is purged for the purpose of memory management.

let shelter = await new webR.Shelter();
let result = await shelter.captureR('print(rnorm(10,5,1))');

console.log('Output obtained from running `rnorm` from webR:')
console.log(result.output);

shelter.purge();
Output obtained from running `rnorm` from webR:
[
  {type: 'stdout', data: ' [1] 5.322551 6.924352 4.592612 6.357413 7.198339 5.152446 4.185396'}
  {type: 'stdout', data: ' [8] 4.995504 6.034569 6.295957'}
]

Executing an R function from JavaScript

The following snippet demonstrates executing an R function from JavaScript. A reference to the R function is first obtained as an RFunction JavaScript proxy, and then executed in a similar way to a normal JavaScript function.

let sin = await webR.evalR('sin');
let result = await sin([1,2,3]);

console.log('Result of running `await sin([1,2,3])`:')
console.log(result.values);
Result of running `await sin([1,2,3])`:
[0.8414709848078965, 0.9092974268256817, 0.1411200080598672]

Evaluating R code within an environment

The options argument of WebR.evalR() can be used to control how R code is executed. In this example the options argument is used to create a new environment for the R code to be evaluated in.

let result = await webR.evalR('foo + bar', { env: { foo: 1234, bar: 1 } });
let output = await result.toNumber();

console.log(output);
1235

Bind a JavaScript object into the R global environment

The following snippet demonstrates binding a JavaScript object into the R global environment. The JavaScript object is automatically converted into an R object, and the value is then used in the subsequent R evaluation.

await webR.objs.globalEnv.bind('arr', [2,4,6,8,9]);
let result = await webR.evalR('sample(arr, 3)');
let output = await result.toArray();

console.log(output);
[2, 9, 6]

Cleaning up after an R object is no longer in use

R object references in the form of an RObject are subject to memory management and should be destroyed when they are no longer required. This signals to R that the object referenced may be deleted by the garbage collector.

let result = await webR.evalR('rnorm(3,5,1)');
let output = await result.toArray();
console.log(output);

webR.destroy(result);
[5.373198157561013, 4.493213148077507, 5.134879842881727]

Fully worked examples

Creating an interactive webR REPL console

The following HTML document loads webR from CDN and creates a simple interactive R console. This demonstrates using the Console class with JavaScript callbacks to interface with the built-in R REPL.

<html>
  <head>
    <title>WebR Test Console</title>
  </head>
  <body>
    <div>
      <pre><code id="out">Loading webR, please wait...</code></pre>
      <input spellcheck="false" autocomplete="off" id="input" type="text">
      <button onclick="globalThis.sendInput()" id="run">Run</button>
    </div>
    
    <script type="module">
      /* Create a webR console using the Console helper class */
      import { Console } from 'https://webr.r-wasm.org/latest/webr.mjs';
      const webRConsole = new Console({
        stdout: line => document.getElementById('out').append(line + '\n'),
        stderr: line => document.getElementById('out').append(line + '\n'),
        prompt: p => document.getElementById('out').append(p),
      });
      webRConsole.run();
      
      /* Write to the webR console using the ``stdin()`` method */
      let input = document.getElementById('input');
      globalThis.sendInput = () => {
        webRConsole.stdin(input.value);
        document.getElementById('out').append(input.value + '\n');
        input.value = "";
      }
      
      /* Send input on Enter key */
      input.addEventListener(
        "keydown",
        (evt) => {if(evt.keyCode === 13) globalThis.sendInput()}
      );
    </script>
  </body>
</html>

After loading, the resulting web page should present an interactive R console similar to the following,

Loading webR, please wait...
>

Creating a webR React app using create-react-app

A simple React app incorporating webR can be bootstrapped using create-react-app. First, ensure create-react-app is available. For example, install it with npm using,

npm i -g create-react-app

Next, bootstrap a new React app with create-react-app. Enter the new app directory and install webR using npm.

npx create-react-app my-app
cd my-app
npm i @r-wasm/webr

Next, set up a middleware for the app’s Express instance so that the app is served with the required cross-origin isolation headers. To do this, create the following JavaScript file with the path my-app/src/setupProxy.js,

module.exports = function (app) {
    app.use(function (req, res, next) {
        res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
        res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
        next();
    });
};

Finally, update src/App.js to load and use webR,

import './App.css';
import React, { useEffect, useState } from 'react'
import { WebR } from '@r-wasm/webr';
const webR = new WebR();

function App() {
  const [ result, updateResult ] = useState(['Loading webR...']);
  useEffect(() => {
    async function runRCode() {
      await webR.init();
      const rnorm = await webR.evalR('rnorm(5,1,1)');
      try {
        const result = await rnorm.toArray();
        updateResult(result);
      } finally {
        webR.destroy(rnorm);
      }
    }
    runRCode();
  }, []);
  return (
    <div className="App">
      <p>Result of running R code: {result.join(',')}</p>
    </div>
  );
}

export default App;

Test the new app by running npm start. The app should automatically open in your browser and show the result of evaluating R code.