Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add maximum file size for bundling wasm assets #114

Merged
merged 5 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion R/export.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#' part of the output app's static assets. Defaults to `TRUE`.
#' @param package_cache Cache downloaded binary WebAssembly packages. Defaults
#' to `TRUE`.
#' @param max_filesize Maximum file size for bundling of WebAssembly package
#' assets. Parsed by [fs::fs_bytes()]. Defaults to `"100M"`. The default
#' value can be changed by setting the environment variable
#' `SHINYLIVE_DEFAULT_MAX_FILESIZE`. Set to `Inf`, `NA` or `-1` to disable.
#' @param assets_version The version of the Shinylive assets to use in the
#' exported app. Defaults to [assets_version()]. Note, not all custom assets
#' versions may work with this release of \pkg{shinylive}. Please visit the
Expand Down Expand Up @@ -59,6 +63,7 @@ export <- function(
quiet = getOption("shinylive.quiet", !is_interactive()),
wasm_packages = TRUE,
package_cache = TRUE,
max_filesize = NULL,
assets_version = NULL,
template_dir = NULL,
template_params = list(),
Expand Down Expand Up @@ -194,7 +199,7 @@ export <- function(
# Copy app package dependencies as Wasm binaries
# =========================================================================
if (wasm_packages) {
download_wasm_packages(appdir, destdir, package_cache)
download_wasm_packages(appdir, destdir, package_cache, max_filesize)
}

# =========================================================================
Expand Down
40 changes: 36 additions & 4 deletions R/packages.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
SHINYLIVE_DEFAULT_MAX_FILESIZE <- "100MB"

# Default maximum filesize for asset bundling
default_max_filesize <- function() {
Sys.getenv("SHINYLIVE_DEFAULT_MAX_FILESIZE", SHINYLIVE_DEFAULT_MAX_FILESIZE)
}
georgestagg marked this conversation as resolved.
Show resolved Hide resolved

# Resolve package list hard dependencies
resolve_dependencies <- function(pkgs, local = TRUE) {
pkg_refs <- if (local) {
Expand Down Expand Up @@ -178,7 +185,14 @@ env_download_wasm_core_packages <- function() {
strsplit(pkgs, "\\s*[ ,\n]\\s*")[[1]]
}

download_wasm_packages <- function(appdir, destdir, package_cache) {
download_wasm_packages <- function(appdir, destdir, package_cache, max_filesize) {
max_filesize_missing <- Sys.getenv("SHINYLIVE_DEFAULT_MAX_FILESIZE") == "" && is.null(max_filesize)
georgestagg marked this conversation as resolved.
Show resolved Hide resolved
max_filesize_cli_fn <- if (max_filesize_missing) cli::cli_warn else cli::cli_abort

max_filesize <- max_filesize %||% default_max_filesize()
georgestagg marked this conversation as resolved.
Show resolved Hide resolved
max_filesize <- if (is.na(max_filesize) || (max_filesize < 0)) Inf else max_filesize
max_filesize <- fs::fs_bytes(max_filesize)
georgestagg marked this conversation as resolved.
Show resolved Hide resolved

# Core packages in base webR image that we don't need to download
shiny_pkgs <- c("shiny", "bslib", "renv")
shiny_pkgs <- resolve_dependencies(shiny_pkgs, local = FALSE)
Expand Down Expand Up @@ -240,13 +254,31 @@ download_wasm_packages <- function(appdir, destdir, package_cache) {
# Create package ref and lookup download URLs
meta <- prepare_wasm_metadata(pkg, prev_meta)

if (!meta$cached && length(meta$assets) > 0) {
if (!meta$cached) {
# Download Wasm binaries and copy to static assets dir
for (file in meta$assets) {
utils::download.file(file$url, fs::path(pkg_subdir, file$filename))
path <- fs::path(pkg_subdir, file$filename)
utils::download.file(file$url, path)

# Disallow this package if an asset is too large
if (fs::file_size(path) > max_filesize) {
fs::dir_delete(pkg_subdir)
meta$assets = list()
max_filesize_cli_fn(c(
"!" = "The file size of package {.pkg {pkg}} is larger than the maximum allowed file size of {.strong {max_filesize}}.",
"!" = "This package will not be included as part of the WebAssembly asset bundle.",
"i" = "Set the maximum allowed size to {.code -1}, {.code Inf}, or {.code NA} to disable this check.",
"i" = if (max_filesize_missing) "Explicitly set the maximum allowed size to treat this as an error." else NULL
))
break
}
}

meta$cached <- TRUE
meta$path <- glue::glue("packages/{pkg}/{meta$assets[[1]]$filename}")
meta$path <- NULL
if (length(meta$assets) > 0) {
meta$path <- glue::glue("packages/{pkg}/{meta$assets[[1]]$filename}")
}
}
meta
})
Expand Down
2 changes: 1 addition & 1 deletion R/quarto_ext.R
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ build_app_resources <- function(app_json) {
# Download wasm binaries ready to embed into Quarto deps
withr::with_options(
list(shinylive.quiet = TRUE),
download_wasm_packages(appdir, destdir, package_cache = TRUE)
download_wasm_packages(appdir, destdir, package_cache = TRUE, max_filesize = NULL)
)

# Enumerate R package Wasm binaries and prepare the VFS images as html deps
Expand Down
6 changes: 6 additions & 0 deletions man/export.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions tests/testthat/apps/app-utf8/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
library(shiny)
library(utf8)

ui <- fluidPage()
server <- function(input, output) {}

shinyApp(ui, server)
48 changes: 47 additions & 1 deletion tests/testthat/test-export.R
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,50 @@ test_that("export with template", {
index_content,
"<meta name=\"description\" content=\"My custom export template param test app\">"
)
})
})

test_that("export - include R package in wasm assets", {
maybe_skip_test()

assets_ensure()

# Ensure pkgcache metadata has been loaded
invisible(pkgcache::meta_cache_list())

# Create a temporary output directory
out_dir <- file.path(tempfile(), "out")
pkg_dir <- file.path(out_dir, "shinylive", "webr", "packages")

# A package with an external dependency
app_dir <- test_path("apps", "app-utf8")
asset_package <- c("utf8")

# Default filesize 100MB
expect_silent_unattended({
export(app_dir, out_dir)
})
expect_contains(dir(pkg_dir), c(asset_package))
unlink_path(out_dir)

# No maximum filesize
expect_silent_unattended({
export(app_dir, out_dir, max_filesize = Inf)
})
expect_contains(dir(pkg_dir), c(asset_package))
unlink_path(out_dir)

# Set a maximum filesize
expect_error({
export(app_dir, out_dir, max_filesize = "1K")
})
unlink_path(out_dir)

expect_error({
withr::with_envvar(
list("SHINYLIVE_DEFAULT_MAX_FILESIZE" = "1K"),
export(app_dir, out_dir)
)
})
unlink_path(out_dir)

})
Loading