rmarkdown icon indicating copy to clipboard operation
rmarkdown copied to clipboard

shiny issue addResourcePath

Open heimschf opened this issue 4 years ago • 20 comments

I deployed a shiny app that is generated with the package learn, shinydashboard and shiny. Prior to updating rmarkdown to the latest version (before I used version 1.12) everything worked fine.

I obtain the following error when deploying my shiny-app (both locally and in Browser):

Couldn't normalize path in `addResourcePath`, with arguments: `prefix` = 'shinydashboard-0.7.1'; `directoryPath` = ''

Below you find my sessionInfo():

locale:
[1] LC_COLLATE=German_Switzerland.1252  LC_CTYPE=German_Switzerland.1252    LC_MONETARY=German_Switzerland.1252 LC_NUMERIC=C                       
[5] LC_TIME=German_Switzerland.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] DT_0.18              rmarkdown_2.9        forcats_0.5.1        shinydashboard_0.7.1 shiny_1.6.0          dplyr_1.0.7          ggplot2_3.3.5       
[8] e1071_1.7-7          learnr_0.10.1       

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.7        compiler_4.1.0    pillar_1.6.1      later_1.2.0       class_7.3-19      tools_4.1.0       digest_0.6.27     jsonlite_1.7.2   
 [9] evaluate_0.14     lifecycle_1.0.0   tibble_3.1.2      gtable_0.3.0      pkgconfig_2.0.3   rlang_0.4.11      DBI_1.1.1         yaml_2.2.1       
[17] xfun_0.24         fastmap_1.1.0     withr_2.4.2       knitr_1.33        generics_0.1.0    vctrs_0.3.8       htmlwidgets_1.5.3 tidyselect_1.1.1 
[25] rprojroot_2.0.2   grid_4.1.0        glue_1.4.2        R6_2.5.0          fansi_0.5.0       purrr_0.3.4       magrittr_2.0.1    scales_1.1.1     
[33] promises_1.2.0.1  ellipsis_0.3.2    htmltools_0.5.1.1 assertthat_0.2.1  mime_0.11         xtable_1.8-4      colorspace_2.0-2  httpuv_1.6.1     
[41] utf8_1.2.1        proxy_0.4-26      munsell_0.5.0     crayon_1.4.1      markdown_1.1     

You find a minimal working example below, please advise on this issue.

---
title: "Minimal Example"
output: learnr::tutorial
runtime: shiny_prerendered
--- 
   

```{r setup, include=FALSE}
library(learnr)
#library(manipulate)
#library(manipulateWidget) 
library(e1071)
library(ggplot2)
library("dplyr")
library(shiny)
library(shinydashboard)
library(forcats)
#ev noch zu installieren
library(rmarkdown)
#library(shinyFiles)
 
library(DT)
#library(shinythemes)
 
#library(googleLanguageR)
knitr::opts_chunk$set(echo = FALSE)

#gl_auth("www/geocoding-R-df7e8c111682.json")

```

## APP zu deskriptiven Statistiken
 
```{r,inputall,echo=FALSE}
#shinythemes::themeSelector()
sidebar <- dashboardSidebar(
  sidebarMenu(
    menuItem("Deskriptive Statistiken", tabName = "deskr")
  )
)

body <- dashboardBody(
   
)  
dashboardPage(
  dashboardHeader(title = "Deskriptive Statistiken"),
  sidebar, 
  body
)

``` 
 
```{r,context="server"}

observeEvent(input$update,{
  updateTextAreaInput(session=session,"vecbox",value = input$eingabe)
})
```

Describe the problem in detail

heimschf avatar Jul 09 '21 16:07 heimschf

Attaching @cderv and @gadenbuie as this might be a rmarkdown/learnr issue

cpsievert avatar Jul 09 '21 16:07 cpsievert

@cpsievert, @cderv, @gadenbuie many thanks for digging into this. Hope you find a solution, Thanks.

heimschf avatar Jul 11 '21 10:07 heimschf

Typically that error indicates that the learnr document needs be re-rendered. The best way to confirm that you've completely re-rendered the document is to click on Clear Prerendered Output in the drop down menu of the Run Document button. Then click run document again to prerender and run the app.

gadenbuie avatar Jul 11 '21 12:07 gadenbuie

Thanks for your comment, @gadenbuie , I have tried the proposed procedure using both clear prerendered output and clear knitr cache. But this did not help. Also, I tried to move the .Rmd file in a new folder and renamed it and have re-run again. But the error message from "couldn't normalize path in addresourcepath..." persists, unfortunately.

heimschf avatar Jul 11 '21 12:07 heimschf

Okay, well that rules out the easy answer. I wonder if the issue you're seeing is specific to shinydashboard? I'll try to investigate further this week.

gadenbuie avatar Jul 11 '21 12:07 gadenbuie

thanks, @gadenbuie , it seems that it is specific to shinydashboard but the error only arises together in use with rmarkdown package, which is imported using the learn package. Using a "single shinydashboard" in a app.R file works without problems.

heimschf avatar Jul 11 '21 12:07 heimschf

The other thing you could try is to see if shiny dashboard components work as expected in the runtime: shiny_prerendered context, without learnr. For example in a document with the following YAML frontmatter

---
title: "Minimal Example"
output: html_document
runtime: shiny_prerendered
--- 

gadenbuie avatar Jul 11 '21 13:07 gadenbuie

Thanks for the idea, but same result... (same error message)

heimschf avatar Jul 11 '21 13:07 heimschf

That's a good data point! Does it also fail (in a regular html_document) if you remove the library(learnr) call?

gadenbuie avatar Jul 11 '21 14:07 gadenbuie

sorry I should have mentioned, yes, in addition have also checked this, but still fails...

heimschf avatar Jul 11 '21 14:07 heimschf

No worries! That reduces the scope of the problem a bit and indicates that learnr isn't specifically involved. Most likely this is an issue with shinydashboard when used in a shiny prerendered document.

gadenbuie avatar Jul 11 '21 15:07 gadenbuie

@cpsievert @cderv This is really a problem with shiny prerendered rmarkdown documents. Here's a minimal reprex:

---
title: "Minimal Example"
output: html_document
runtime: shiny_prerendered
--- 

```{r setup, include = FALSE}
library(shinydashboard)
```

```{r ui, echo=FALSE}
dashboardPage( 
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(),
  title = "Dashboard example"
)
``` 

I tracked down the problem to these lines in rmarkdown:::shiny_prerendered_html(). The shinydashboard dependency is included in the prerendered doc

# before L145-L154
str(dependencies[[10]])
List of 11
 $ name      : chr "shinydashboard"
 $ version   : chr "0.7.1"
 $ src       :List of 1
  ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.6/Resources/library/shinydashboard"
 $ meta      : NULL
 $ script    : chr "shinydashboard.min.js"
 $ stylesheet: chr "shinydashboard.css"
 $ head      : NULL
 $ attachment: NULL
 $ package   : chr "shinydashboard"
 $ all_files : logi TRUE
 $ pkgVersion: chr "0.7.1"
 - attr(*, "class")= chr "html_dependency"

but the $src$file is replaced with "", which obviously leads to errors.

# after L145-154
str(dependencies[[10]])
List of 10
 $ name      : chr "shinydashboard"
 $ version   : chr "0.7.1"
 $ src       :List of 1
  ..$ file: chr ""
 $ meta      : NULL
 $ script    : chr "shinydashboard.min.js"
 $ stylesheet: chr "shinydashboard.css"
 $ head      : NULL
 $ attachment: NULL
 $ all_files : logi TRUE
 $ pkgVersion: chr "0.7.1"
 - attr(*, "class")= chr "html_dependency"

The primary cause is a conflation of two things:

  • $package is not NULL in the dependency stored in the prerendered document (before example above)
  • shinydashboard uses system.file() rather than the package= argument of htmlDependency() when declaring its dependencies

Resolving either one could resolve this particular issue. But we may not need to replicate htmltools' package dependency resolution step in rmarkdown since it was added to rmarkdown 5 years ago when the package= argument was just being introduced.

gadenbuie avatar Jul 12 '21 15:07 gadenbuie

Thanks @gadenbuie !

Based on all this investigation, I'll have a closer look on the rmarkdown side regarding this mechanism. Thanks for looking into this !

cderv avatar Jul 12 '21 16:07 cderv

Ok I understand now better.

I think this is also a edge case because shinydasboard resources are at the root of the package. When inserting the dependencies into the prerendered HTML, rmarkdown will process the dependencies and add the package field + normalize the src$file relative to the package dir root. THis happens here: https://github.com/rstudio/rmarkdown/blob/bab481aa016f38a94d08f4c03284e9273804b3d4/R/shiny_prerendered.R#L309-L325

However, as the root installed package is used as src$file in shinydashboard, the normalize relative to doesn't work as expected. At least I think so

# what happens
rmarkdown:::normalized_relative_to(system.file(package = "shinydashboard"), system.file(package = "shinydashboard"))
#> [1] "C:/Users/chris/Documents/R/win-library/4.1/shinydashboard"
# this does work
rmarkdown:::normalized_relative_to("a/b", "a/b/c")
#> [1] "c"
# not work as expected
rmarkdown:::normalized_relative_to("a/b", "a/b")
#> [1] "C:/Users/chris/AppData/Local/Temp/Rtmpqev1CI/reprex-df473ab7310-waspy-bunny/a/b"
# what should happen
xfun::relative_path(xfun::normalize_path("a/b"), dir = xfun::normalize_path("a/b"))
#> [1] "."

So we may be able to fix this, by fixing the relative path function. I'll try it.

However, I understand that:

  • rmarkdown is doing a roundtrip
    • Adding package= when missing, and changing src$file to relative path
    • but then later, removing package= and recreating the src$file as a absolute path including package path. I am not sure yet to understand why this double process.
  • shinydashboard uses an old way of defining a dependency without package=. This could also change
  • rmarkdown has old code dealing with dependencies instead of htmltools, and this may need to be clean somehow.

Do you think we should change one of the above ?

cderv avatar Jul 13 '21 10:07 cderv

So we may be able to fix this, by fixing the relative path function. I'll try it.

As expected, it fixes the above issue. This lives currently in rstudio/rmarkdown@fix/relative-same-dir and can be tested with

pak::pak("rstudio/rmarkdown@fix/relative-same-dir")

Not sure this is the right fix for this. The HTML deps processing still puzzles me (but it is there since years ago for a reason I am sure)

However, it shows once again than file path handling is critical. I'd really like to consider fs for this as maybe it could be more robuste on the long term.

cderv avatar Jul 13 '21 11:07 cderv

Thanks for the follow up @cderv. I think it's likely that we no longer need the shiny prerendered process to be so hands-on with the html dependencies, but it'd be good to talk through that a bit more. Should we move this issue into rmarkdown?

gadenbuie avatar Jul 13 '21 13:07 gadenbuie

Should we move this issue into rmarkdown?

Yes we could. I don't have right to do that. @cpsievert ?

I think it's likely that we no longer need the shiny prerendered process to be so hands-on with the html dependencies, but it'd be good to talk through that a bit more

I agree. I think shinydashboard could also use the package argument in htmlDependency now.

cderv avatar Jul 13 '21 13:07 cderv

Seems I don't have permission to transfer either

cpsievert avatar Jul 13 '21 13:07 cpsievert

This happens now with the new version of leaflet and leaflet.providers

Dummy example

---
title: "Unexpected Parameter values"
output: html_document
server: shiny
---

```{r}
library(leaflet)

leaflet()  |>
  setView(lng = -71.0589, lat = 42.3601, zoom = 12) |>
  addTiles() |>
  addProviderTiles("OpenTopoMap")
```

```{r}
#| context: server
```

Image

shinydashboard uses system.file() rather than the package= argument of htmlDependency() when declaring its dependencies

And it probably define the same way: https://github.com/rstudio/leaflet.providers/blob/526ee9a426f60ec709ece0b28d360f45f925942e/R/get_current_providers.R#L81-L94

I need to get back to this... 🤔

cderv avatar Sep 18 '25 19:09 cderv

@cderv I tried updating leaflet.providers to use the standard package="leaflet.providers" format, but it isn't resolving the issue. Try with this PR: https://github.com/rstudio/leaflet.providers/pull/43

gadenbuie avatar Sep 22 '25 13:09 gadenbuie