Skip to main content
Tag

r-hub

From R Hub – JavaScript for the R package developer

By Blog

Originally posted on the R Hub blog

JS and R, what a clickbait! Come for JS, stay for our posts about Solaris and WinBuilder. 😉 No matter how strongly you believe in JavaScript being the language of the future (see below), you might still gain from using it in your R practice, be it back-end or front-end.

In this blog post, Garrick Aden-Buie and I share a roundup of resources around JavaScript for R package developers.

JavaScript in your R package

Why and how you include JavaScript in your R package?

Bundling JavaScript code

JavaScript’s being so popular these days, you might want to bundle JavaScript code with your package. Bundling instead of porting (i.e. translating to R) JavaScript code might be a huge time gain and less error-prone (your port would be hard to keep up-to-date with the original JavaScript library).

The easiest way to interface JavaScript code from an R package is using the V8 package. From its docs, “A major advantage over the other foreign language interfaces is that V8 requires no compilers, external executables or other run-time dependencies. The entire engine is contained within a 6MB package (2MB zipped) and works on all major platforms.” V8 documentation includes a vignette on how to use JavaScript libraries with V8. Some examples of use include the js package, “A set of utilities for working with JavaScript syntax in R“; jsonld for working with, well, JSON-LD where LD means Linked Data; slugify (not on CRAN) for creating slugs out of strings.

For another approach, depending on a local NodeJS and Node Package Manager (NPM) installation, see Colin Fay’s blog post “How to Write an R Package Wrapping a NodeJS Module”. An interesting read about NPM and R, even if you end up going the easier V8 route.

JavaScript for your package documentation

Now, maybe you’re not using JavaScript in your R package at all, but you might want to use it to pimp up your documentation! Here are some examples for inspiration. Of course, they all only work for the HTML documentation, in a PDF you can’t be that creative.

Manual

The roxygenlabs package, that is an incubator for experimental roxygen features, includes a way to add JS themes to your documentation. With its default JS script, your examples gain a copy-paste button!

Noam Ross once described a way to include a searchable table in reference pages, with DT.

In writexl docs, the infamous Clippy makes an appearance. It triggers a tweet nearly once a week, which might be a way to check people are reading the docs?

For actual analytics in manual pages, it seems the unknown package found a trick by adding a script from statcounter.

Vignettes

In HTML vignettes, you can also use web dependencies. On a pkgdown website, you might encounter some incompatibilities between your, say, HTML widgets, and Boostrap (that powers pkgdown).

Web dependency management

HTML Dependencies

A third, and most common, way in which you as an R package developer might interact with JavaScript is to repackage web dependencies, such as JavaScript and CSS libraries, that enhance HTML documents and Shiny apps! For that, you’ll want to learn about the htmltools package, in particular for its htmlDependency() function.

As Hadley Wickham describes in the Managing JavaScript/CSS dependencies section of Mastering Shiny, an HTML dependency object describes a single JavaScript/CSS library, which often contains one or more JavaScript and/or CSS files and additional assets. As an R package author providing reusable web components for Shiny or R Markdown, in Hadley’s words, you “absolutely should be using HTML dependency objects rather than calling tags$link()tags$script()includeCSS(), or includeScript() directly.”

htmlDependency()

There are two main advantages to using htmltools::htmlDependency(). First, HTML dependencies can be included with HTML generated with htmltools, and htmltools will ensure that the dependencies are loaded only once per page, even if multiple components appear on a page. Second, if components from different packages depend on the same JavaScript or CSS library, htmltools can detect and resolve conflicts and load only the most recent version of the same dependency.

Here’s an example from the applause package. This package wraps applause-button, a zero-configuration button for adding applause/claps/kudos to web pages and blog posts. It was also created to demonstrate how to package a web component in an R package using htmltools. For a full walk through of the package development process, see the dev log in the package README.

html_dependency_applause <- function() {
  htmltools::htmlDependency(
    name = "applause-button",
    version = "3.3.2",
    package = "applause",
    src = c(
      file = "applause-button",
      href = "https://unpkg.com/applause-button@3.3.2/dist"
    ),
    script = "applause-button.js",
    stylesheet = "applause-button.css"
  )
}

The HTML dependency for applause-button is provided in the html_dependency_applause() function. htmltools tracks all of the web dependencies being loaded into a document, and conflicts are determined by the name of the dependency where the highest version of a dependency will be loaded. For this reason, it’s important for package authors to use the package name as known on npm or GitHub and to ensure that the version is up to date.

Inside the R package source, the applause button dependencies are stored in inst/applause-button.

applause
└── inst
    └── applause-button
          ├── applause-button.js
          └── applause-button.css

The packagesrc, and script or stylesheet arguments work together to locate the dependency’s resources: htmlDependency() finds the package‘s installation directory (i.e. inst/), then finds the directory specified by src, where the script (.js) and/or stylesheet (.css) files are located. The src argument can be a named vector or a single character of the directory in your package’s inst folder. If src is named, the file element indicates the directory in the inst folder, and the href element indicates the URL to the containing folder on a remote server, like a CDN.

To ship dependencies in your package, copy the dependencies into a sub-directory of inst in your package (but not inst/src or inst/lib, these are reserved directory names1). As long as the dependencies are a reasonable size2, it’s best to include the dependencies in your R package so that an internet connection isn’t strictly required. Users who want to explicitly use the version hosted at a CDN can use shiny::createWebDependency().

Finally, it’s important that the HTML dependency be provided by a function and not stored as a variable in your package namespace. This allows htmltools to correctly locate the dependency’s files once the package is installed on a user’s computer. By convention, the function providing the dependency object is typically prefixed with html_dependency_.

Using an HTML dependency

Functions that provide HTML dependencies like html_dependency_applause() aren’t typically called by package users. Instead, package authors provide UI functions that construct the HTML tags required for the component, and the HTML dependency is attached to this, generally by including the UI and the dependency together in an htmltools::tagList().

applause_button <- function(...) {
  htmltools::tagList(
    applause_button_html(...),
    html_dependency_applause()
  )
}

Note that package authors can and should attach HTML dependencies to any tags produced by package functions that require the web dependencies shipped by the package. This way, users don’t need to worry about having to manually attach dependencies and htmltools will ensure that the web dependency files are added only once to the output. This way, for instance, to include a button, using the applause package an user only needs to type in e.g. their Hugo blog post3 or Shiny app:

applause::button()

Some web dependencies only need to be included in the output document and don’t require any HTML tags. In these cases, the dependency can appear alone in the htmltools::tagList(), as in this example from xaringanExtra::use_webcam(). The names of these types of functions commonly include the use_ prefix.

use_webcam <- function(width = 200, height = 200, margin = "1em") {
htmltools::tagList(
    html_dependency_webcam(width, height)
  )
}

JS and package robustness

How do you test JS code for your package, and how do you test your package that helps managing JS dependencies? We’ll simply offer some food for thought here. If you bundle or help bundling an existing JS library, be careful to choose dependencies as you would with R packages. Check the reputation and health of that library (is it tested?). If you are packaging your own JS code, also make sure you use best practice for JS development. 😉 Lastly, if you want to check how using your package works in a Shiny app, e.g. how does that applause button turn out, you might find interesting ideas in the book “Engineering Production-Grade Shiny Apps” by Colin Fay, Sébastien Rochette, Vincent Guyader and Cervan Girard, in particular the quote “instead of deliberately clicking on the application interface, you let a program do it for you”.

Learning and showing JavaScript from R

Now, what if you want to learn JavaScript? Besides the resources that one would recommend to any JS learner, there are interesting ones just for you as R user!

Learning materials

The resources for learning we found are mostly related to Shiny, but might be relevant anyway.

Literate JavaScript programming

As an R user, you might really appreciate literate R programming. You’re lucky, you can actually use JavaScript in R Markdown.

At a basic level, knitr includes a JavaScript chunk engine that writes the code in JavaScript chunks marked with ```{js} into a <script> tag in the HTML document. The JS code is then rendered in the browser when the reader opens the output document!

Now, what about executing JS code at compile time i.e. when knitting? For that the experimental bubble package provides a knitr engines that uses Node to run JavaScript chunks and insert the results in the rendered output.

The js4shiny package blends of the above approaches in html_document_js(), an R Markdown output for literate JavaScript programming. In this case, JavaScript chunks are run in the reader’s browser and console outputs and results are written into output chunks in the page, mimicking R Markdown’s R chunks.

Different problem, using JS libraries in Rmd documents

More as a side-note let us mention the htmlwidgets package for adding elements such as leaflet maps to your HTML documents and Shiny apps.

Playground

When learning a new language, using a playground is great. Did you know that the js4shiny package provides a JS playground you can use from RStudio? Less new things at once if you already use RStudio, so more confidence for learning!

And if you’d rather stick to the command line, bubble can launch a Node terminal where you can interactively run JavaScript, just like the R console.

R from JavaScript?

Before we jump to the conclusion, let us mention a few ways to go the other way round, calling R from JavaScript…

Shiny, “an R package that makes it easy to build interactive web apps straight from R.”, and the golemverse, a set of packages for developing Shiny apps as packages

OpenCPU is “An API for Embedded Scientific Computing” that can allow you to use JS and R together.

If you use the plumber R package to make a web API out of R code, you can then interact with that API from e.g. Node.

Colin Fay wrote an experimental Node package for calling R.

Conclusion

In this post we went over some resources useful to R package developers looking to use JavaScript code in the backend or docs of their packages, or to help others use JavaScript dependencies. Do not hesitate to share more links or experience in the comments below!

R Consortium Community Grants and Sponsorships Top USD $1,000,000

By Announcement

Fall Grant Application Cycle Starts September 2019

SAN FRANCISCO, August 28, 2019 – The R Consortium, a Linux Foundation project supporting the R Foundation and R community, today announced a major milestone of $1,000,000 in grants and sponsorships approved. This includes both grants for R projects like R-hub, R-Ladies, RC RUGS, and many more, and community event sponsorships, like financial support for useR! 2019, R Cascadia, R/Medicine, and other R events large and small worldwide. The nonprofit organization also announced that they will begin accepting Fall Grant Cycle proposals starting September 2019.

Grants are awarded in areas of software development, developing new teaching materials, documenting best practices, standardising APIs or other areas of research that “broadly help the R community.” Full details for submitting a proposal, deadlines, and a list of previously funded projects is available at: https://www.r-consortium.org/projects/call-for-proposals

“The goal of the R Consortium is to strengthen the R community by improving infrastructure and building for long term stability,” said Hadley Wickham, Infrastructure Steering Committee Chair, R Consortium. “The grants help support important projects that impact many R users through better software and stronger communities. We are so grateful for the immense work that the R community does and so happy that we can contribute back.”

Example sponsorship and grant recipients include:

  • R-hub, a centralised tool for checking R packages;
  • R-Ladies, a world-wide organization whose mission is to promote diversity in the R community;
  • RC RUGS, the R Consortium’s R user group and small conference support program;
  • SatRDays, bootstrapping a system for local R conferences;
  • Testing DBI and improving key open source database backends.

A complete list of projects that previously received grants is available at https://www.r-consortium.org/projects/awarded-projects

“In the R-hub project we created and operate a multi-platform build and check service for R packages, free to use for everyone in the R community, thanks to the support of the R Consortium,” said Gábor Csárdi, software engineer at RStudio, and author and maintainer of R-hub. “As of today R-hub supports 20 platforms on four operating systems (macOS, Windows, Linux, Solaris), and since its start it has handled 68,000 submissions, for more than 3,000 different R packages, from more than 2,000 package maintainers. It has become a key tool for R developers around the world.”

“Thanks to R Consortium for their support in helping R-Ladies grow to 167 groups in 47 countries with close to 50,000 members,” said Gabriela de Queiroz, Senior Engineering and Data Science Manager at IBM and Founder of R-Ladies. “With their support, we’re able to help people who identify as underrepresented minority achieve their programming potential through our network of R leaders, mentors, and learners.”

“RC RUGS is able to focus on supporting user groups and smaller conferences around the world, filling a real need to support grass-roots organizations that are not in large cities or other well-known locations. There are great R communities around the world in many different locations. This year we are delighted to see user groups applying from Latin America, Africa, South Asia and other underserved regions throughout the world,” said Joseph Rickert, R Consortium Director and administrator of the program. “We are trying very hard to connect R users with limited resources into the greater R Community”. 

The 2019 Fall grant cycle open September 2019. More information on submitting a proposal for a grant is available at: https://www.r-consortium.org/projects/call-for-proposals

About The R Consortium 

The R Consortium is a 501(c)6 nonprofit organization and Linux Foundation project dedicated to the support and growth of the R user community. The R Consortium provides support to the R Foundation and to the greater R Community for projects that assist R package developers, provide documentation and training, facilitate the growth of the R Community and promote the use of the R language. For more information about R Consortium, please visit: http://www.r-consortium.org.