webrcli & spidyr: What’s new

3 minute(s) read

Find all my posts about webR here.

Note: the first post of this series explaining roughly what webR is, I won’t introduce it again here.

In this blogpost, you’ll find some updates about some recent changes made in webrcli & spidyr.

What webrcli & spidy wants to achieve

In a nutshell, the goal of webrcli & spidyr is to provide an interface for bringing your R functions inside a NodeJS runtime.

Think of it as something that wants to achieve the following interation:

  • An R dev writes, builds and shares a package called {rfuns}, which contains a function called hello_world()

  • A NodeJS dev takes this package, can call it with rfuns.hello_world(), access and manipulate the results with JavaScript.

An important note

With webR & the tools described below, there is no R session running while the NodeJS app is running. spidyr imports an R function converted to a native JS. rfuns.hello_world does not call an R session running somewhere else.

That also means that if you build a container containing the app, you don’t need to install R in it. It’s a NodeJS app.

Below are some updates recently made to both webrcli & spidyr.

Making the template code smaller

When drafting the first code of webrcli & spidyr, I focused on providing a minimal template for an index.js loading your R functions, contained in a subdirectory inside your node project.

This worked, but might have been a bit complex to grasp. Provided you don’t change the default names of the folders (in that case you’ll need to modify the default parameters), the new default index.js look like this:

const {
  initSpidyr,
  mountLocalPackage
} = require('spidyr');

(async () => {

  await initSpidyr()

  const rfuns = await mountLocalPackage("./rfuns");

  const hw = await rfuns.hello_world()

  console.log(hw.values);

  console.log("✅ Everything is ready!");
})();

This minimal template makes it easier to read and understand what the code does. Note that you’ll get this template if you run webrcli init myproject.

Let’s decompose what this code does :

  • await initSpidyr() will create an object called spidyr_webR stored as globalThis.spidyr_webR, init() it (as in webr.init()), and load the packages contained in the ./webr_packages folder inside your project dir, the one containing the packages installed with webrcli install.

  • const rfuns = await mountLocalPackage("./rfuns"); will take the R package contained in ./rfuns, load it into the webR instance (spidyr_webR), recursively get all the exported functions from your package, and store them inside the rfuns object.

  • const hw = await rfuns.hello_world() will call the hello_world() function from {rfuns}. The values are then console.loged.

new Library() is now library()

Calling a package is now const spongebob = library("spongebob") instead of the previous approach which was const spongebob = new Library("spongebob");await spongebob.load(globalThis.webR);

Better installation from package.json & DESCRIPTION

The previous version of webrcli did not stored nor re-installed the R package installed in the project, meaning that if you git cloned a project, you had to guess what R packages to re-install.

Now, a project initiated with webrcli will store all the packages installed with webrcli install inside the package.json file. Then, when running the npm install command, the R packages will also be redownloaded.

You can also installed a series of packages based on a DESCRIPTION file with webrcli installFromDesc.

Other tools

  • shareEnv allows to copy one, several or all env var from node to the webR instance.

Workflow summary

  • webrcli init myproject will create a project skeleton at ./myproject

  • webrcli install spongebob will download the version of {spongebob} compiled for webR, and add it to ./webr_packages.

  • You can then modify you R code with your own functions.

  • Call your R function from rfuns.xyz() in Node

  • Run with npm start

Please do give it a shot

I think I’ve been the only user for now 😅, so please do try these and let me know what you think.

Future works

Here are what I plan on working in the upcoming weeks:

  • webrcli init should allow for specifying a webr version from npm issue 17

  • initSpidyr should allow to pass params to webR.init() issue 12

  • Allow to install from r-universe, something like webrcli installFromRUniverse issue 16. Probably in the future it will be merged to webrcli install and we’ll have a way to guess what the user wants based on the input.

  • A small converter from R named list to JS objects Issue 3

  • More documentation, and probably documenting the conversion of an existing {shiny} app to a spidyr based one.

What do you think?