Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This post is the fifth one of a series of post about webR:
- Using webR in an Express JS REST API
- The Old Faithful Geyser Data shiny app with webR, Bootstrap & ExpressJS
- Preloading your R packages in webR in an Express JS API
- Using my own R functions in webR in an Express JS API, and thoughts on building web apps with Node & webR
- Rethinking webR package & functions preloading with webR 0.2.2
Note: the first post of this series explaining roughly what webR is, I won’t introduce it again here.
When I wrote my blogpost about Preloading your R packages in webR in an Express JS API, I mentioned that there was no native way to preload things in the webR filesystem — meaning that you had to reinstall all the R packages whenever the app was launched (and reported it in a Github issue). This also meant that I couldn’t easily take my own functions and run them in the webR environment, as described in Using my own R functions in webR in an Express JS API, and thoughts on building web apps with Node & webR. These needs made me write the webrtools NodeJS package, to do just that:
- Download the R packages compiled for webR, to a local folder
- Bundle them in the webR lib (by reading the folder tree and reproducing it in webR filesystem)
- Load your local package to access its functions in webR
The last webR version now exposes Emscripten’s FS.mount
, so this makes the process easier, as there is now no need to read the file tree and recreate it: the folder from the server can be mounted into webR filesystem.
That implied some rework (now integrated to webrtools
) :
- Use
webR.FS.mkdir
to create a local lib: the module can’t mount the package library into the libPath as is, because it would overwrite the already bundled library (in other words, if you mount into a folder that is not empty, the content from the server overwrites the content from webR). - Use
webR.FS.mount
to mount the local directory into the newly created library - Ensure that this new library is in the libPath()
Here is the new code for loadPackages
, bundled into webrtools
:
async function loadPackages(webR, dirPath, libName = "webr_packages") { // Create a custom lib so that we don't have to worry about // overwriting any packages that are already installed. await webR.FS.mkdir(`/usr/lib/R/${libName}`) // Mount the custom lib await webR.FS.mount("NODEFS", { root: dirPath }, `/usr/lib/R/${libName}`); // Add the custom lib to the R search path await webR.evalR(`.libPaths(c('/usr/lib/R/${libName}', .libPaths()))`); }
I’ve also decided to deprecate the loadFolder
function, as it is now native with webR.FS.mkdir
+ webR.FS.mount
.
So here is a rewrite of the app from Using my own R functions in webR in an Express JS API, and thoughts on building web apps with Node & webR.
const app = require('express')() const path = require('path'); const { loadPackages } = require('webrtools'); const { WebR } = require('webr'); (async () => { globalThis.webR = new WebR(); await globalThis.webR.init(); console.log("🚀 webR is ready 🚀"); await loadPackages( globalThis.webR, path.join(__dirname, 'webr_packages') ) await globalThis.webR.FS.mkdir("/home/rfuns") await globalThis.webR.FS.mount( "NODEFS", { root: path.join(__dirname, 'rfuns') }, "/home/rfuns" ) console.log("📦 Packages written to webR 📦"); // see https://github.com/r-wasm/webr/issues/292 await globalThis.webR.evalR("options(expressions=1000)") await globalThis.webR.evalR("pkgload::load_all('/home/rfuns')"); app.listen(3000, '0.0.0.0', () => { console.log('http://localhost:3000') }) })(); app.get('/', async (req, res) => { let result = await globalThis.webR.evalR( 'unique_species()' ); try { let js_res = await result.toJs() res.send(js_res.values) } finally { webR.destroy(result); } }) app.get('/:n', async (req, res) => { let result = await globalThis.webR.evalR( 'star_wars_by_species(n)', { env: { n: req.params.n } } ); try { const result_js = await result.toJs(); res.send(result_js) } finally { webR.destroy(result); } });
Full code is at ColinFay/webr-examples/.
Further exploration to be done: webR now bundles a way to package a file system in a file, which can then be downloaded and mounted into the runtime, as described here. This might come handy for our current structure, but I’ll have to explore it a bit more.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.