Skip to contents

The Emscripten WebAssembly (Wasm) environment provides a virtual filesystem (VFS) which supports the concept of mounting. With this, an entire file and directory structure can be packaged into a filesystem image, efficiently making individual files or entire R package libraries available for use in webR.

Create filesystem images

Emscripten’s file_packager tool

The file_packager tool, provided by Emscripten, takes in a directory structure as input and produces a webR compatible filesystem image as output. The file_packager tool may be invoked from the rwasm package:

> rwasm::file_packager("./input", out_dir = ".", out_name = "output")

It can also be invoked directly using its CLI1, if you prefer:

$ file_packager output.data --preload ./input@/ \
    --separate-metadata --js-output=output.js

In the above examples, the files in the directory ./input are packaged and an output filesystem image is created2 consisting of a data file, output.data, and a metadata file, output.js.metadata.

To prepare for mounting the filesystem image with webR, ensure that both files have the same basename (in this example, output). The resulting URLs or relative paths for the two files should differ only by the file extension.

Compression

Filesystem image .data files may optionally be gzip compressed prior to deployment. The file extension for compressed filesystem images should be .data.gz, and compression should be indicated by setting the property gzip: true on the metadata JSON stored in the .js.metadata file.

NOTE: Loading compressed VFS images requires at least version 0.4.1 of webR.

Mount .tar archives as a filesystem image

Archives in .tar format, optionally gzip compressed as .tar.gz or .tgz files, can also be used as filesystem images by pre-processing the .tar archive using the rwasm::add_tar_index() function. The function reads archive contents and appends the required filesystem metadata to the end of the .tar archive data in a way that is understood by webR. For further information about the format see the Technical details for .tar archive metadata article.

> rwasm::add_tar_index("./path/to/archive.tar.gz")
# Appending virtual filesystem metadata for: ./path/to/archive.tar.gz

Once processed by rwasm::add_tar_index(), the .tar archive can be deployed and used directly as a filesystem image.

Mounting filesystem images

When running in a web browser, the webr::mount() function downloads and mounts a filesystem image from a URL source, using the WORKERFS filesystem type.

webr::mount(
  mountpoint = "/data",
  source = "https://example.com/output.data"
)

Filesystem images should be deployed to static file hosting3 and the resulting URL provided as the source argument. The image will be mounted in the virtual filesystem under the path given by the mountpoint argument. If the mountpoint directory does not exist, it will be created prior to mounting.

When running under Node.js, the source may also be provided as a relative path to a filesystem image on disk.

To test filesystem images before deployment, serve them using a local static webserver. See the Local Testing section below for an example using httpuv::runStaticServer() in R.

Building an R package library image

A collection of R packages can be collected and bundled into a single filesystem image for mounting.

To build an R package library image we must first build one or more Wasm R packages using add_pkg(). As an example, let’s build a package with a few hard dependencies. Ensure that you are running R in an environment with access to Wasm development tools4, then run:

rwasm::add_pkg("dplyr")

After the build process has completed, the new repo directory contains a CRAN-like package repository with R packages build for Wasm.

Next, run the following to build an Emscripten VFS image:

By default, this function will create a new directory named vfs if it does not exist. The files vfs/library.data and vfs/library.js.metadata together form an Emscripten filesystem image containing an R package library consisting of all the packages previously added to the CRAN-like repository in repo using add_pkg().

Local testing

The following R command starts a local web server to serve your filesystem image for testing5. When serving your files locally, be sure to include the Access-Control-Allow-Origin: * HTTP header, required for downloading files from a cross-origin server by the CORS mechanism.

httpuv::runStaticServer(
  dir = ".",
  port = 9090,
  browse = FALSE,
  headers = list("Access-Control-Allow-Origin" =  "*")
)

Once the web server is running start a webR session in your browser, such as the console at https://webr.r-wasm.org/latest/. Use webr::mount() to make the R library image available somewhere on the VFS6:

webr::mount("/my-library", "http://127.0.0.1:9090/vfs/library.data")

Once mounted, the contents of the filesystem image are available at /my-library in the virtual filesystem.

list.files("/my-library")
#>  [1] "R6"         "cli"        "dplyr"     "fansi"      "generics"   "glue"
#>  [7] "lifecycle"  "magrittr"   "pillar"    "pkgconfig"  "rlang"      "tibble"
#> [13] "tidyselect" "utf8"       "vctrs"     "withr"

This new directory should be added to R’s .libPaths(), so that R packages may be loaded from the new library.

.libPaths(c(.libPaths(), "/my-library"))
library(dplyr)
#> Attaching package: ‘dplyr’
#>
#> The following objects are masked from ‘package:stats’:
#>
#>     filter, lag
#>
#> The following objects are masked from ‘package:base’:
#>
#>     intersect, setdiff, setequal, union