How do I put a GLSL script into an `htmlDependency()`?

52 Views Asked by At

The htmltools::htmlDependency function allows me to set Javascript and CSS files as a dependency of a tag. This means I can have tags on a page that use the code without including multiple copies of it, and in rmarkdown, if I set self_contained: false, I don't include any copies of the files in the HTML, just references to external copies.

Now I'd like to have a GLSL shader program as part of the dependency as well.

I can insert something like <script type="text/plain" id="shader"> ... shader code </script> as the head argument to htmlDependency(), and that inserts the shader into the header section of the page, but self_contained: false makes no difference: I always get a copy there.

Is there a way to get htmlDependency to treat a text/plain script the way it treats the Javascript scripts?

Here's an example in an RMarkdown document:

---
title: "Untitled"
output: 
  html_document:
    self_contained: false
---

```{r}
javascript <- 'console.log("this is Javascript to write to the console");'
f1 <- tempfile(fileext = ".js")
writeLines(javascript, f1)

text <- 'this is some text to go in a script'
f2 <- tempfile(fileext = ".txt")
writeLines(text, f2)
```

```{r}
library(htmltools)
deps <- htmlDependency("test", "1.0",
                       src = tempdir(),
                       script = basename(f1),
                       head = as.character(includeScript(f2,
                                                         type = "text/plain",
                                                         id = "shader")))
tag <- tags$p("this is visible text", deps)
tag
```

If you process that and look at the generated HTML page, you'll see something like this in the header after a lot of code to load other scripts:

<script src="Untitled_files/test-1.0/file60301b7b90b0.js"></script>
<script type="text/plain" id="shader">this is some text to go in a script</script>

The first line loads the Javascript to write to the console, and the second line contains the script that I didn't want to include in the document.

1

There are 1 best solutions below

0
On

Turns out it's not so hard. The script argument to htmlDependency() can take a mixture of filenames and more complicated things. To get what I wanted, I would use

deps <- htmlDependency("test", "1.0",
                       src = tempdir(),
                       script = list(basename(f1),
                                     list(src = basename(f2),
                                          type = "text/plain",
                                          id = "shader")))

The second item in the script argument contains the attributes for the <script> tag that will be inserted.

EDITED to add: I want to point out two things:

  1. There's a bug in htmltools version 0.5.2 which can cause this to fail. This PR should fix it.

  2. My original goal of using this to share GLSL shaders between pages isn't going to be met: it's not easy for the code on the page to read the content of the text/plain external script. (I'd love for someone to contradict this!)