I'm not sure if this is a remark.js issue, a xaringan.js issue, or an RStudio Connect issue. As this issue only occurs when publishing with RStudio Connect, I can't provide a reproducible example (only 1 slide and 1 image is needed though).
Issue: When publishing to RStudio Connect, images imported from a project folder (e.g., resources/myImage.svg) will not display.
Works --- when knitting to HTML on our RStudio Server Pro (not published), the HTML references the image.
Works --- when manually exporting the HTML and the resources folder to a non-server filesystem (i.e., is served locally), the HTML still references the image and renders correctly.
Extra info
I am including "resource_files: resources" in the YAML header.
The Rstudio GUI confirms that I am including the resources directory when deploying the bundle.
I can't manually access the deployment folder (/var/lib/rstudio-connect/) to confirm the resources folder and image were deployed since I don't have root access at my company.
Here's a reproducible example. Knitting the document works just fine. When publishing to connect, the image does not display. The tag looks just fine, but the console outputs "Failed to load resource: the server responded with a status of 404 (Not Found)."
When publishing, the RStudio IDE indicates the image file was included in the bundle.
---
title: "Images on RStudio Connect"
resource_files: resources
output:
xaringan::moon_reader:
lib_dir: libs
---
```{r setup, include=FALSE}
options(htmltools.dir.version = FALSE)
First, save Sharingan_triple.svg locally in a resources folder. Then:
```html

Anyone have any thoughts?
I assume most xaringan users don't use RStudio Connect and therefore haven't faced the issue yet and are not eager to reproduce/fix it.
Maybe you would have more luck posting this in the corresponding repo that deals with RStudio connect? (idk which one that is tbh).
Also I have no clue about the magic going on behind Rstudio Connect and hence cannot help in any way here.
The main problem is that xaringan slides are not self-contained by default, and I don't favor or support the self-contained mode well in this package (see ?xaringan::moon_reader). HTML files that are not self-contained are probably tricky for RStudio Connect. I don't use RStudio Connect to publish my slides, and I have never tested it myself.
I'm documenting a workaround here, but will also speak to the RStudio Connect team and the rmarkdown team to identify a proper solution.
The underlying problem is that RStudio Connect doesn't construct the bundle correctly. Specifically, not all of the theme and other dependencies are discovered correctly when creating the bundle.
The workaround is to explicitly list all of your included files and other dependencies in your R Markdown document. This must be done by doing both of the following:
In the following example I deploy a markdown with a structure of:
00_introduction.Rmd
--- include
* rstudio.css
--- images/00
* image_1.png
* image_2.png
You must explicitly specify resource_files in the YAML header. This can contain the names of folders, e.g. an include folder where you have css files.
---
title: "title"
output:
xaringan::moon_reader:
lib_dir: libs
css: [ "include/rstudio.css" ]
resource_files:
- include
- images/00
---
To tell Connect to include files in the bundle, use rmarkdown::output_metadata$set(). Specifically, you must provide a list of file names to rsc_output_files.
In the following example I use list.files() to automatically detect all files in a specific folder. This only works because I put all of my embedded images in a subfolder called images/00, but you could also explicitly name all of your files.
``````r
{r, include=FALSE}
rmarkdown::output_metadata$set(
rsc_output_files = list.files("images/00", recursive = TRUE, full.names = TRUE)
)
``````
I think this issue has two sides depending on how the xaringan presentation is deployed (From Html or from Rmd) and if it is with the IDE or with rsconnect::deployDoc
I use an account on beta.rstudioconnect.com to do the test with https://github.com/cderv/test-xaringan
I inlcuded:
include/custom.cssimages/xaringan.png and included in the doc as <img src = "images/xaringan.png", width = 100> slide 3.This means the xaringan presentation is rendered locally and only html file and its dependencies should be published
rsconnect::deployDocrsconnect::deployDoc("test-prez.html", server = "beta.rstudioconnect.com")
this will use rmarkdown::find_external_resources on the html file to find the ressources to include with deployment. The algorithm can work on an html file and find all <link href, <img src=
or other. It got those
rmarkdown::find_external_resources("test-prez.html")
result
#> path explicit web
#> 1 libs/htmlwidgets/htmlwidgets.js FALSE TRUE
#> 2 libs/jquery/jquery.min.js FALSE TRUE
#> 3 libs/leaflet/leaflet.css FALSE TRUE
#> 4 libs/leaflet/leaflet.js FALSE TRUE
#> 5 libs/leafletfix/leafletfix.css FALSE TRUE
#> 6 libs/Proj4Leaflet/proj4-compressed.js FALSE TRUE
#> 7 libs/Proj4Leaflet/proj4leaflet.js FALSE TRUE
#> 8 libs/rstudio_leaflet/rstudio_leaflet.css FALSE TRUE
#> 9 libs/leaflet-binding/leaflet.js FALSE TRUE
#> 10 libs/datatables-css/datatables-crosstalk.css FALSE TRUE
#> 11 libs/datatables-binding/datatables.js FALSE TRUE
#> 12 libs/dt-core/css/jquery.dataTables.min.css FALSE TRUE
#> 13 libs/dt-core/css/jquery.dataTables.extra.css FALSE TRUE
#> 14 libs/dt-core/js/jquery.dataTables.min.js FALSE TRUE
#> 15 libs/crosstalk/css/crosstalk.css FALSE TRUE
#> 16 libs/crosstalk/js/crosstalk.min.js FALSE TRUE
#> 17 include\\custom.css FALSE TRUE
#> 18 test-prez_files FALSE TRUE
So it find a number of files including the libs file, the css file and presentation files in test-prez_files.
Everything is found but the image file. This is because of remark.js behavior. The html code in the markdown presentation is put as markdown in the source html, and remark.js does the rendering live in the client. See code there. That is why rmarkdown::find_external_resources does not find this file.
There could be a way to adapt this function to work better with xaringan... 馃
Otherwise, it would require a special deployXaringan function that encapsulate deployApp and deals with the dependencies cleverly - but not sure it would work considering the other findings below 馃
It doesn't seem to work that way with the IDE publish button. The rmarkdown::find_external_resources is not used to find ressources. It seems to parse the Rmd file, even when clicking from the viewer.
This means we send the source code and its dependencies to the server, and that the presentation should be render on the rstudio connect server
deployDocThe function rmarkdown::find_external_resources will also be used to find the dependencies.
rmarkdown::find_external_resources("test-prez.Rmd")
#> Le chargement a n茅cessit茅 le package : leaflet
#> Le chargement a n茅cessit茅 le package : DT
#> path explicit web
#> 1 include\\custom.css FALSE TRUE
The image file is not found either automatically. It requires to be specified in the yaml header as indicated by @andrie
resource_files:
- images
In this case
rmarkdown::find_external_resources("test-prez.Rmd")
#> Le chargement a n茅cessit茅 le package : leaflet
#> Le chargement a n茅cessit茅 le package : DT
#> path explicit web
#> 1 images/xaringan.png TRUE TRUE
#> 2 include\\custom.css FALSE TRUE
The image is found and will be included when deployed with
rsconnect::deployDoc("test-prez.Rmd", server = "beta.rstudioconnect.com", appTitle="test-prez_Rmd")
The libs folder is not an issue because it is created when the render is happening in the server.
However, the problem is the folder images that is in the bundle but is not made accessible by rstudio connect server to the html presentation unless you explicitly do indicate it in the yaml header
rmd_output_metadata:
rsc_output_files:
- images/xaringan.png
However, you have to be explicit (file by file) because a folder is not possible here. So, the other option is like @andrie shows, to create this metadata from R code. The documentation about this is in RStudio Connect user's doc
It work the same in this case.
So the issue with xaringan presentation is with the dependencies that are used inside the presentation and not available to the web page because not exposed by RStudio Connect. One thing I noticed in the code source of the html when sent to render on the server is that all the resources (custom.css and js libs) where included in the html file as inline code. And in the Rstudio connect deployment log we can see the --self-contained flag in pandoc conversion
log extract
2019/06/08 21:19:19.427857755 /opt/rstudio-connect/ext/pandoc2/pandoc +RTS -K512m -RTS test-prez.utf8.md
--to html4 --from markdown+autolink_bare_uris+ascii_identifiers+tex_math_single_backslash+smart
--output /opt/rstudio-connect/mnt/report/test-prez.html --email-obfuscation none
--self-contained -V 'mathjax-url=https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-MML-AM_CHTML' -V 'title-slide-class=center, middle, inverse, title-slide'
--standalone --section-divs --template /opt/rstudio-connect/mnt/packrat/3.4.0/v2/library/xaringan/e15e68ee43911de64c81d071e65d4ed6/xaringan/rmarkdown/templates/xaringan/resources/default.html --no-highlight --css include/custom.css --include-in-header /opt/rstudio-connect/mnt/tmp/RtmpeWSBGe/rmarkdown-str272b55ad814c.html --include-before-body /opt/rstudio-connect/mnt/tmp/RtmpeWSBGe/xaringan272b22aab6e9.md --include-after-body /opt/rstudio-connect/mnt/tmp/RtmpeWSBGe/xaringan272b2c8cd899.js --variable title-slide=true --variable math=true
That means RStudio connect is rendering Rmardown with self_contained = TRUE even if the yaml file says FALSE. This would make perfect sense because file are not exposed by default on RStudio connect, and it also explains why other format are not an issue, because there work better than xaringan with self_contained = TRUE (often as the default like with revealjs::revealjs_presentation)
We should note that even with self_contained = TRUE, the image file included in markdown or html in the body are not transform by pandoc to self contained because it is remark.js which does the job in the browser directly. This is how xaringan presentation works. As @yihui says, xaringan is better when self_contained = FALSE
That is why it needs the files to be available from the server. The rsc_output_files is key here to expose the files through RStudio connect.
I hope this search and analysis could be useful to help document or find a fix.
@Yihui, @andrie I can give you access to the files deployed to RStudio connect beta if you want to dig further with the product team or rsconnect one. I would be happy to do it myself if you point me to the correct person to show this. I can even make a more detailed report if necessary.
Currently, the better workaround to publish a xaringan presentation to rstudio connect is to put all dependencies in the same folder and use @andrie trick to add the to the metadata by a list.files.
This may be wrapped into an helper function - I'll look into that.
Hope it helps.
This is the helper function that I use:
library(rsconnect)
deploy_xaringan <- function(doc){
qualified_doc <- normalizePath(doc, winslash = "/")
app_files <- c(
basename(qualified_doc),
list.files("images", pattern = ".*.png", full.names = TRUE, recursive = TRUE),
list.files("images", pattern = ".*.gif", full.names = TRUE, recursive = TRUE),
list.files("include", pattern = ".*.png", full.names = TRUE, recursive = TRUE),
list.files("include", pattern = ".*.jpg", full.names = TRUE, recursive = TRUE),
list.files("theme", pattern = "*.png", full.names = TRUE, recursive = TRUE)
# list.files("libs", full.names = TRUE, recursive = TRUE)
)
res_files <- rmarkdown::find_external_resources(qualified_doc)
app_files <- c(app_files, res_files$path)
rsconnect::deployApp(
appDir = dirname(qualified_doc),
appPrimaryDoc = basename(qualified_doc),
appTitle = "Taking TensorFlow into Production ThinkR 2019",
appFiles = app_files,
forceUpdate = TRUE,
server = "colorado.rstudio.com"
)
}
deploy_xaringan("tensorflow-production-2019-06.html")
Most helpful comment
This is the helper function that I use: