r-wasm / webr

The statistical language R compiled to WebAssembly via Emscripten, for use in web browsers and Node.
https://docs.r-wasm.org/webr/latest/
Other
848 stars 67 forks source link

How to infer R is running in WebR? #414

Closed HenrikBengtsson closed 5 months ago

HenrikBengtsson commented 5 months ago

How can one check, programmatically, that we're running R via WebR?

A naive approach would be to use:

is_webr <- "webr" %in% loadedNamespaces()

but that assumes such a loaded package is WebR, but it could be another package with the same name, including the one on CRAN (Issue #165).

What other evidence can I look for conclude that we're running within WebR? I'm looking for something more robust, but also something that is sustainable. For example, looking for expected R options is not guaranteed. Neither is the attached webr_sham environment and its content.

yutannihilation commented 5 months ago

I think .Platform$r_arch could be some meaningful value. Currently, it seems it's empty.

georgestagg commented 5 months ago

There's some information in R.Version() that you can use:

> R.Version()
$platform
[1] "wasm32-unknown-emscripten"

$arch
[1] "wasm32"

$os
[1] "emscripten"

$system
[1] "wasm32, emscripten"
[...]

> version$os
[1] "emscripten"

We usually look for the "emscripten" string. This makes sense to me, Emscripten is like an alternative OS in many ways, and one day if R core supports building for wasm/Emscripten independently from webR your code will still work.

Checking for "wasm32" is an option, but one day we might migrate to "wasm64" when it is better supported in browsers.


This information should probably be documented somewhere in https://docs.r-wasm.org, I'll tag the issue as such.

HenrikBengtsson commented 5 months ago

Thanks. Though, strictly speaking, can't there be other alternative Wasm implementation for R showing up in the future that would show the same R.Version() information as WebR?

CLARIFICATION: I'm after detecting when running with WebR specifically.

georgestagg commented 5 months ago

Yes, strictly speaking, that is true assuming the implementation also uses Emscripten as their Unix environment. A project compiling R for WASI/WASIX would likely have a different value there.

I guess we could possibly tweak $platform so that webr is part of the target triple in the vendor slot?

wasm32-webr-emscripten
georgestagg commented 5 months ago

CLARIFICATION: I'm after detecting when running with WebR specifically.

Part of the problem is that the WebAssembly R binary itself knows little about the surrounding webR JavaScript/TypeScript environment other than through the supporting webr R package, which talks to the outside world using Emscripten's C API.

Most of webR's functionality is exposed through a JavaScript Module object, but Emscripten provides a Unix-like API so that while JavaScript functions like Module.print() are eventually called, to the R Wasm binary it just looks like it's running under a Unix-like OS.

Thinking about it, I suppose the webR JavaScript environment is more akin to RStudio than an OS or platform detail and so the host_vendor is not really the right place for this.

Perhaps we could add an export to the webR support package to signal in some way that this is webR, and not the CRAN {webr} package? Maybe webr::is_webr() to always return TRUE, or a webr::version() function.

Alternatively, we could just set some environment variables, similar to RSTUDIO=1? We could set WEBR=1 and perhaps WEBR_VERSION=0.3.2. Of course, environment variables are not entirely robust either.


A hacky check that would work right now could be something like:

webr::eval_js("'webr' in Module")

which directly checks the JavaScript environment to see if the webr property has been defined on the module. This will return 1 when running under webR. Unfortunately, it relies on the webr support package to run the JavaScript check, which would only be available under webR in any case. So, possibly not that useful for you.

HenrikBengtsson commented 5 months ago

Part of the problem is that the WebAssembly R binary itself knows little about the surrounding webR JavaScript/TypeScript environment other than through the supporting webr R package, which talks to the outside world using Emscripten's C API.

Thanks for clarifying this - this is useful; my understanding how webR works is at best so-and-so right now.

Perhaps we could add an export to the webR support package to signal in some way that this is webR, and not the CRAN {webr} package? Maybe webr::is_webr() to always return TRUE, or a webr::version() function.

I think webr::is_webr() could work. Not sure if webr::version() would help? Are you thinking about something different that packageVersion("webr") here?

Alternatively, we could just set some environment variables, similar to RSTUDIO=1? We could set WEBR=1 and perhaps WEBR_VERSION=0.3.2. Of course, environment variables are not entirely robust either.

That would definitely work too.

The reason why I came to this is that I wanted to add a flag webr to startup::sysinfo() to indicate whether running in webR or not. I already detect other environments this way. Here's a summary of flags that I currently detect and how:

A hacky check that would work right now could be something like:

webr::eval_js("'webr' in Module")

That works for my needs. I can do something like:

is_webr <- function() {
  if (!"webr" %in% loadedNamespaces()) return(FALSE)
  ns <- getNamespace("webr")
  if (!exists("eval_js", mode = "function", envir = ns)) return(FALSE)
  eval_js <- get("eval_js", mode = "function", envir = ns)
  eval_js("'webr' in Module") == 1L
}

BTW, is 'webR' how you want to refer to it? I've been using WebR thus far, but better to use the official notation.

georgestagg commented 5 months ago

Thank you for sharing those other examples -- I think that's enough to convince me that an environment variable is indeed the right way to go. I'll try to get that in before next release.


BTW, is 'webR' how you want to refer to it? I've been using WebR thus far, but better to use the official notation.

I use "webR" unless it's at the start of a sentence, in which case I use "WebR". I don't mind how people refer to it, other than that it should never be "WEBR".