I have an rmarkdown project that produces a lot of interactive plotly plots that can switch among multiple json data sources and I'm running into the problem that the html file is getting very large and it runs very slowly (or sometimes not at all) in the browser. I had the thought to, rather than putting the json inline, put it in external files, and source it in script tags with referrable ID's, but since rmarkdown
is set to render with self_contained: yes
, they all end up embedded in the document no matter what I do. If I try to write them to a file and source them, they end up base64 encoded, which makes things worse than if I just included them directly.
Is there a way to get rmarkdown to allow just some external files, or is my only option to set self_contained: no
and have all the various files be external?
See for example the following short example.
First, I'll make a file called test.js
:
$(function() {
console.log('test');
});
Then, the rmarkdown document, test.Rmd
:
---
title: "test"
author: "nobody"
date: "2025-07-16"
output:
html_document:
self_contained: yes
---
<script id="script1" type="application/javascript" src="test.js"></script>
```{r setup, include=FALSE}
library(readr)
knitr::opts_chunk$set(echo = FALSE,warn = FALSE)
```
```{r f, results='asis'}
json <- '{"one": [ "one", "two", "three ], "two": "false" }'
write_lines(json,"test.json")
cat('<script id="script2" type="application/json" src="test.json"></script>')
```
When knit to html, the two script tags look like this:
<script type="application/javascript">$(function() {
console.log("hello");
})</script>
<script src="data:application/json;base64,eyJvbmUiOiBbICJvbmUiLCAidHdvIiwgInRocmVlIF0sICJ0d28iOiAiZmFsc2UiIH0K" id="script2" type="application/json"></script>
Note that the id tag was stripped from the first script tag and its contents were embedded directly and the second one retained its id tag but the contents were included as base64 encoded data.
I can change self_contained
to no and get the effect I want, but then I end up with tons of external files (javascript, css, ttf, etc.) that it was nice to have embedded in the first place.
Is it all or nothing, or is there some way I can force it to allow just the external files I want it to?
Yes, it should be possible.
The self_contained
attribute is handled by Pandoc. As the Pandoc docs at https://pandoc.org/MANUAL.html say,
Elements with the attribute
data-external="1"
will be left alone; the documents they link to will not be incorporated in the document.
So change the second script inclusion to look like this:
cat('<script id="script2" type="application/json" src="test.json" data-external="1"></script>')
and then the resulting HTML will contain this:
<script type="application/javascript">$(function() {
console.log('test');
});</script>
<script id="script2" type="application/json" src="test.json" data-external="1"></script>
Of course you could also add the attribute in the first script inclusion and leave both files as external data.