Open barryrowlingson opened 10 months ago
Not sure if there is a built-in function call and/or session status to detect if the app running using Shiny or Shinylive.
However, the following should work to detect whether the app is running using shinylive
as it checks how base R was compiled:
is_shinylive <- function() { R.Version()$arch == "wasm32"}
Feel free check the detection with this Demo app.
The only other way would be to check if the webr
support package is present in the instance and contains the canvas
function. The latter matters as there is a different R package using the name webr
on CRAN.
That works nicely. Until people start running entire servers using wasm32 architecture, of course. Sounds silly now, but who would have thought of nodejs when Netscape introduced Javascript! :)
For completeness, here's a chunk of my ui
object with shinylive detection using your function:
tabPanel(h6("Interviewer feedback"),
uiOutput("interviewer_names"),
uiOutput("interviewer_feedback"),
plotOutput("interviewer_feedback_graph"),
if(is_shinylive()){
h6("No screenshots with shinylive")
}else{
screenshotButton(label = "Save feedback", selector = ".tab-content")
}
)
@barryrowlingson I understand the concern; but, given the intricacies of the WASM build and Shiny requirements + communication, I'm not sure we'll ever see shiny running on wasm outside of the shinylive case.
Agree, this is fine. Would you add an is_shinylive
function to the package in due course or is the advice to users to write their own as above?
I think this would be great to include in the shinylive R package. Would either of you like to contribute a PR?
I think @coatless's proposed approach is great; for future compatibility we might want to account for wasm64
.
BTW, I made a little app showcasing the function on shinylive.io.
There's also the possibility of
R.Version()$os == "emscripten"
if we're worried about just checking for wasm32
/wasm64
. However, I think the arch
checks alone are reasonable, at least for now.
I think this would be great to include in the shinylive R package.
Perhaps it makes sense as part of the shiny package itself? The shinylive R package is more useful for building and exporting an app, rather than at runtime in the app. For example, in the shinylive.io example above you can remove library(shinylive)
and the app still works as expected.
Perhaps it makes sense as part of the shiny package itself? The shinylive R package is more useful for building and exporting an app, rather than at runtime in the app. For example, in the shinylive.io example above you can remove
library(shinylive)
and the app still works as expected.
True; I was including library(shinylive)
to test that using the shinylive package inside shinylive wasn't going to cause problems. 😄
Personally, I'd rather keep this check in shinylive. It's a bit closer to the place where the implementation might change. And shiny's a bigger and much slower to move package. Not that I'm super worried about this particular function, but it does seem possible that other runtime utility needs might pop up in the future.
Ah, gotcha, that makes sense.
One minor issue with loading the shinylive
package within shinylive is that it depends on the curl
package, currently unsupported by webR. So, you do see a couple of extra warnings in the logs as the app launches in the browser.
We should probably also check with @wch to see if there is some equivalent test for Python apps already in place that we should mimic.
@georgestagg a quick grep through the {py-shiny}
found a check against pyodide
:
For parity with the Python version of shiny, I suppose this means is_shinylive()
should be a function in {shiny}
R package. It's also probably more efficient to check the full OS name instead of two checks against the arch (wasm32
/wasm64
[is this coming?]).
So, I suppose the PR'd function should be:
is_shinylive <- function() { R.Version()$os == "emscripten" }
wasm32/wasm64 [is this coming?]
Not in the short term for webR. Perhaps in the future, when the Memory64 proposal has been standardised as part of the Wasm spec.
is_pyodide
in Shiny for Python is needed to correctly run shiny apps; in Shiny for R we don't have such a need. If added to Shiny for R, the analogous function would be is_emscripten()
or is_wasm()
, but it's worth noting that the python version is internal so we don't necessarily need to follow its lead.
If we keep the function in shinylive, it makes it easier to adjust if we end up needing to differentiate between flavors of shinylive (shinylive.io vs self-hosted shinylive apps). It also opens the door to having shinylive (the package) help with runtime calls inside shinylive apps if anything comes up in the future.
Also we should consider using in_
or on_
as the function prefix, i.e. in_emscripten()
or on_wasm()
or in_shinylive()
.
@gadenbuie if we opted to place the is_shinylive()
function with the {r-shinylive}
package that would be another R package required to be downloaded, installed, and loaded during runtime of the app. So, I'm a huge fan of being able to avoid adding any further dependencies.
How about adding to the upstream {shinylive}
assets different environment variables and two different check functions in {r-shiny}
that read from the different set environment variables?
is_shinylive_app()
: addresses @barryrowlingson & I's case of just detecting the runtime.is_shinylive_io_app()
: for understanding if the app is running on a posit hosted domain.For the is_shinylive_app()
, there could be the following environment variable set during the preload routine:
Sys.setenv("SHINYLIVE_APP" = "TRUE")
Around line 144 in useWebR.tsx
:
Then, there could be a check function defined inside of {r-shiny}
as:
is_shinylive_app <- function() { Sys.getenv("SHINYLIVE_APP", "FALSE") == "TRUE" }
On the need to detect shinylive.io
, maybe modify the runAppOpts
passed to runApp()
in the different upstream {shinylive}
site templates to flag its an official app? This would allow the appropriate environment definition to be added or omitted.
Another possible option here would be to define a function that can access session$clientData$url_hostname
to retrieve the domain and check against a fixed string.
is_shinylive_io_app <- function() { session$clientData$url_hostname == "shinylive.io"}
Feel free to tinker with the suggestions inside of the demo app.
FWIW I think Garrick's argument is sound. Shiny is indeed a slow-moving package and if we start thinking about the possibility of other runtime utility functions, perhaps even functions that only make sense when running under Shinylive, it would probably be better to group and organise such functions within the shinylive
R package. The development flexibility of making changes outside a wider Shiny release is a benefit too.
The environment variable is also a strong idea. It sounds perfectly reasonable to me that we could see if we are running in the Shinylive environment by checking an environment variable, and they could be set by posit-dev/shinylive as part of the runtime initialisation so that they are set for all apps.
Then, a user who wants to check for Shinylive without loading the shinylive
package would simply check the env var using base R's Sys.getenv()
, rather than using a convenience function.
So, my vote would be for some setup like:
IN_SHINYLIVE
env var, potentially others, in the Wasm environment.Then, some or all of the following convenience functions are added to the shinylive
R package, depending on what we think is really useful:
shinylive::in_shinylive
checks for the IN_SHINYLIVE
environment variable.shinylive::in_emscripten
checks R.Version()$os == "emscripten"
.shinylive::in_shinylive_io
checks session$clientData$url_hostname == "shinylive.io"
.I should also mention that I just realised that, technically, posit-dev/shinylive could also directly define an in_shinylive()
function in the global environment as part of initialisation, but personally I don't think that's such a good solution here.
This package is intended for use outside of shinylive -- it creates shinylive bundles. Runtime environment checks are a completely different set of functionality. Because of that, and because the proposed functions are so simple, I think it would be best not to put them in this package. It's also possible that this package will evolve in ways in the future that make it larger, which will increase the overhead even more for doing one of these checks.
It'll never be possible to run non-shinylive shiny in emscripten, so if you have a shiny app and you are running on emscripten, you can be certain that you're in shinylive. I've added an is_emscripten()
function to staticimports, so people can just cut and paste it.
is_emscripten <- function() Sys.info()[["sysname"]] == "Emscripten"
(@georgestagg note that I used Sys.info()[["sysname"]]
intead of R.Version()$os
, to keep it consistent with the other similar functions.)
I think it could make sense to add a is_shinylive()
function to shiny that basically is just the same as this is_emscripten
function. If there are unforeseen changes in the future so that this for some reason is no longer an effective test, we can just change that function.
Regarding environment variables, another interesting option to consider is setting R_CONFIG_ACTIVE
to something like "shinylive"
in a shinylive context. This env var is consulted by the config package and is set by Posit Connect.
Following up on the environment variable discussion above, it's likely we don't need to set any environment variables from Shinylive after all, since R itself already sets R_PLATFORM
in the environment.
So, some other base R options could be,
in_emscripten <- function() grepl("emscripten", Sys.getenv('R_PLATFORM'))
in_wasm <- function() Sys.getenv('R_PLATFORM') == "wasm32-unknown-emscripten"
or similar.
We briefly discussed setting a WEBR
environment variable within webR itself, but Pyodide does not do this for Python so it would have no direct equivalent there.
I'm proposing we do it for convenience with existing R tooling, rather than out of necessity or feature parity with Python. I'll move that suggestion to a new issue in https://github.com/posit-dev/shinylive/
I've got a shiny app which has some issues running under shiny live, which I think I've narrowed down to its use of
shinyscreenshot
. Commenting out thescreenshotButton
in theui
fixes it.But is there a way of testing if the app is running under shinylive so I can include the button if it is running on a server and therefore does work? Something like:
or maybe an
ifelse
structure.