Closed georgestagg closed 2 months ago
Notes on implementation:
For all packages found by {renv}
; Use pak::pkg_deps(pkgs, upgrade=FALSE, dependencies=NA)
to get default package deps.
if (FALSE) { library(FOO) }
meta data: list of lists where each list item is:
paste0(desc$RemotePkgRef, "-", desc$RemoteSha)
when desc$RemoteType == "github"
desc$Version
when desc$Repository == "CRAN"
desc$RemoteSha
when grepl("r-universe\\.dev$", desc$Repository)
Only update package builds if the metadata changes.
======================================================================
Building bundles:
info <- utils::available.packages(contriburl = contrib)
; contrib <- "http://repo.r-wasm.org/bin/emscripten/contrib/4.3.3"
info[pkg, "Version", drop=TRUE]
data_url <- paste0(contrib, "/", paste0(pkg, "_", pkg_ver, ".data"))
; Ex: https://repo.r-wasm.org/bin/emscripten/contrib/4.3.3/Matrix_1.5-4.1.data
info <- utils::available.packages(contriburl = contrib)
; contrib <- paste0(r_universe, "/bin/emscripten/contrib/4.3")
; r_universe <- "https://r-lib.r-universe.dev"
info[pkg, "Version", drop=TRUE]
data_url <- paste0(contrib, "/", paste0(pkg, "_", pkg_ver, ".data"))
; Ex: https://repo.r-wasm.org/bin/emscripten/contrib/4.3.3/Matrix_1.5-4.1.data
desc$RemotePkgRef, desc$RemoteSha
gh::gh("/repos/{owner}/{repo}/releases/tags/{tag}", owner = "r-wasm", repo="shiny", tag="v1.8.0.9900")
library.data
and library.js.metadata
from assetsGiven bundle files
_webr/packages/FOO/FILE
_webr/metadata.Rdata
The PR at https://github.com/posit-dev/shinylive/pull/121 now attempts to read the metadata file _webr/metadata.rds
, produced by something like,
saveRDS(
list(
list(name = "cli", path = "packages/cli/cli_3.6.2.data", type = "package", version = "3.6.2", ref = "3.6.2"),
list(name = "dplyr", path = "packages/dplyr/library.data", type = "library", version = "1.1.4", ref = "1.1.4")
)
)
and automatically downloads and mounts the VFS images from the URL paths e.g. [...]/shinylive/webr/packages/cli/cli_3.6.2.data
at app startup. Note that the static directory [...]/shinylive/webr
already exists as part of a distributed app. r-shinylive
will need to create and populate the new directory [...]/shinylive/webr/packages
, though.
The code adds the mounted directory to the .libPaths()
, if it is an image of a full package library rather than a single package. It decides to do this or not based on the type
property in the metadata.
I was originally thinking metadata.rds
could be distributed as part of the static assets somewhere under [...]/shinylive/webr/
, to be downloaded at runtime, but I'm thinking now we should just add it to app.json
as a base64 encoded binary file. This saves on a full HTTP round-trip to the server.
Below is an example app.json
I've been using to test this:
[
{
"name": "app.R",
"content": "library(shiny)\n\n# Define UI for app that draws a histogram ----\nui <- fluidPage(\n\n # App title ----\n titlePanel(\"Hello Shiny!\"),\n\n # Sidebar layout with input and output definitions ----\n sidebarLayout(\n\n # Sidebar panel for inputs ----\n sidebarPanel(\n\n # Input: Slider for the number of bins ----\n sliderInput(inputId = \"bins\",\n label = \"Number of bins:\",\n min = 1,\n max = 50,\n value = 30)\n\n ),\n\n # Main panel for displaying outputs ----\n mainPanel(\n\n # Output: Histogram ----\n plotOutput(outputId = \"distPlot\")\n\n )\n )\n)\n\n# Define server logic required to draw a histogram ----\nserver <- function(input, output) {\n\n # Histogram of the Old Faithful Geyser Data ----\n # with requested number of bins\n # This expression that generates a histogram is wrapped in a call\n # to renderPlot to indicate that:\n #\n # 1. It is \"reactive\" and therefore should be automatically\n # re-executed when inputs (input$bins) change\n # 2. Its output type is a plot\n output$distPlot <- renderPlot({\n\n x <- faithful$waiting\n bins <- seq(min(x), max(x), length.out = input$bins + 1)\n\n hist(x, breaks = bins, col = \"#75AADB\", border = \"white\",\n xlab = \"Waiting time to next eruption (in mins)\",\n main = \"Histogram of waiting times\")\n\n })\n\n}\n\n# Create Shiny app ----\nshinyApp(ui = ui, server = server)\n",
"type": "text"
},
{
"name": "DESCRIPTION",
"content": "Title: Hello Shiny!\nAuthor: RStudio, Inc.\nAuthorUrl: http://www.rstudio.com/\nLicense: MIT\nDisplayMode: Showcase\nTags: getting-started\nType: Shiny\n",
"type": "text"
},
{
"name": "Readme.md",
"content": "This small Shiny application demonstrates Shiny's automatic UI updates. \n\nMove the *Number of bins* slider and notice how the `renderPlot` expression is automatically re-evaluated when its dependant, `input$bins`, changes, causing a histogram with a new number of bins to be rendered.\n",
"type": "text"
},
{
"name": "_webr/metadata.rds",
"content": "H4sIAAAAAAAAA4vgYmBgYGZgYWZkYGYFMhlYQ0PcdC2ADGEgZgIiEA2SEQBiRgYWBk6QhuSc\nTDQh6YLE5OzE9NRifaAcCMcb65npGemlJJYkoillhypFE2YFa8AhyMKELJiXmJtaDFXJChVk\nAQnC2AWJJRkwdkllAUycvSy1qDgzPw/mjaLUNCD1D4cvWVMKciqLcPoTLKufk5lUlFhUidWf\nUDk0YUZDLAIg/zH+p56XAFiF71XYAQAA",
"type": "binary"
}
]
This issue should be closed when we update the default shinylive assets version, correct?
@schloerke: Here is THE PLAN:
1) Run
renv::dependencies()
on shiny app to list dependencies at build time2) Loop through the list of packages, use
packageDescription()
to find information.3) Lookup information about package list:
If "Repository" is CRAN, talk to (& eventually p3m) using base R repo functions.
Otherwise, use "Repository" URL (e.g. https://r-lib.r-universe.dev)
.../emscripten/...
path to look for a wasm binary (e.g. HTTPHEAD
request).stop()
.If "RemoteType" is
github
, look for a Wasm release using GitHub API.stop()
stop()
. Print a message asking the user to use r-wasm/actions.4) Build package library for inclusion as part of exported static files
Create:
.../exported/webr/packages/[PACKAGE_NAME]/
Generate metadata (e.g. GitHub asset ID)
If metadata matches existing metadata in
export.json
, don't bother re-downloading.Download and copy to e.g.
exported_app/webr/packages/ggplot2/library.data
exported_app/webr/packages/ggplot2/library.metadata
Save metadata:
exported_app/webr/packages/ggplot2/export.json
5) (At runtime, using Shinylive & JavaScript):
library(shiny)
packages are handled by Shinylive. //TODO: https://github.com/posit-dev/shinylive/pull/82/files - Blocked by AWSrenv
at runtime to get the package list.webr::mount("/lib/[PACKAGENAME]", "./exported_app/webr/packages/[PACKAGENAME]/library.data")
/lib/[PACKAGENAME]
to.libPaths()
.@schloerke to handle 1-4, @georgestagg to handle upgrade of webR in Shinylive to v0.3.0 and then 5).