This is a short note explaining how slidify handles dependencies. Let us start with the YAML front matter in index.Rmd. I am only including the portions relevant to this note.
First, when slidify parses this front-matter, it knows that there are four dependencies. The framework and widget dependencies are hardcoded to be searched for in the slidifyLibraries package, while ext_widgets uses the package name as the key and an array of folders relative to the package. Slidify copies all these dependencies into the libraries folder.
Parse Configuration
Second, slidify looks for a config.yml file in each of these dependencies. Take for example the config.yml file in the nvd3 widget. It specifies the paths to the css and js files that need to be included. jshead is used to emphasise that these files need to be included in the head of the document, since there might be inline charts that make use of them and so sticking them at the end might lead to errors. If there is no config.yml, slidify assembles one by looking into the css and js folders and including all the css and js files it finds. The idea is convention over configuration ala ruby.
Here is another config.yml file from the highlight.js highlighter widget. You would notice that there is a ready field which contains javascript that needs to be loaded after the highlight.pack.js is loaded.
The next step is to assemble a payload of assets to be injected, to be made available under page$assets. This involves combining the parsed configuration files across all dependencies, resolving duplicates (currently based only on the basename of the files). This step results in a list with four components: css, jshead, js and ready, each of which is a vector.
If the onefile option is specified, these files are converted into DataURIs, with simple or base64 encoding (requires the base64enc package). Depending on the asset type, they are converted into link or script elements, ready to be inserted into HTML.
Insert in Document
The final step is inserting these dependencies into the HTML. Slidify uses mustache templates to handle the final converstion to HTML. This provides a lot of flexibility, since mustache one of the simplest templating languages out there. The assets payload can be easily accessed in a mustache template. For example, {{{ page.assets.css }}} inserts the css payload assembled in the earlier step, into the HTML.
Notes
Overriding Defaults
There are several other features that allow default configuration of widgets to be overloaded from the main YAML front matter. For example, specifying the configuration shown below in the YAML front matter of the main Rmd document will override the default specified by the highlightjs widget. This provides a lot of flexibility to the user.
highlightjs:
css: "css/solarized_dark.css"
Dependency Detection
Ideally, dependencies should be automatically injected in most cases. For example, if there is an rCharts NVD3 plot, the R function should be able to communicate to knitr that the nvd3 widget needs to be used and so a user will not have to specify ext_widgets: {rCharts: libraries/nvd3}. Currently I do it via a hack, where there is a .slidifyEnv variable, which detects presence of plots and silently modifies the payload. But there is a strong need for a more robust mechanism to achieve this.
Update: One solution is for the R function creating the plot to return the list of dependencies as attributes, which can be picked up by knitr automatically. This would make dependency overriding tricky, but perhaps can be managed using chunk options.
This is a short note explaining how slidify handles dependencies. Let us start with the YAML front matter in index.Rmd. I am only including the portions relevant to this note.
Copy Dependencies
First, when slidify parses this front-matter, it knows that there are four dependencies. The
framework
andwidget
dependencies are hardcoded to be searched for in theslidifyLibraries
package, whileext_widgets
uses the package name as the key and an array of folders relative to the package. Slidify copies all these dependencies into thelibraries
folder.Parse Configuration
Second, slidify looks for a
config.yml
file in each of these dependencies. Take for example theconfig.yml
file in thenvd3
widget. It specifies the paths to thecss
andjs
files that need to be included.jshead
is used to emphasise that these files need to be included in the head of the document, since there might be inline charts that make use of them and so sticking them at the end might lead to errors. If there is noconfig.yml
, slidify assembles one by looking into thecss
andjs
folders and including all the css and js files it finds. The idea is convention over configuration ala ruby.Here is another
config.yml
file from thehighlight.js
highlighter widget. You would notice that there is aready
field which contains javascript that needs to be loaded after thehighlight.pack.js
is loaded.Create Payload
The next step is to assemble a payload of assets to be injected, to be made available under
page$assets
. This involves combining the parsed configuration files across all dependencies, resolving duplicates (currently based only on the basename of the files). This step results in a list with four components:css
,jshead
,js
andready
, each of which is a vector.If the
onefile
option is specified, these files are converted into DataURIs, with simple or base64 encoding (requires the base64enc package). Depending on the asset type, they are converted intolink
orscript
elements, ready to be inserted into HTML.Insert in Document
The final step is inserting these dependencies into the HTML. Slidify uses mustache templates to handle the final converstion to HTML. This provides a lot of flexibility, since mustache one of the simplest templating languages out there. The assets payload can be easily accessed in a mustache template. For example,
{{{ page.assets.css }}}
inserts the css payload assembled in the earlier step, into the HTML.Notes
Overriding Defaults
There are several other features that allow default configuration of widgets to be overloaded from the main YAML front matter. For example, specifying the configuration shown below in the YAML front matter of the main Rmd document will override the default specified by the
highlightjs
widget. This provides a lot of flexibility to the user.Dependency Detection
Ideally, dependencies should be automatically injected in most cases. For example, if there is an
rCharts NVD3
plot, the R function should be able to communicate toknitr
that thenvd3
widget needs to be used and so a user will not have to specifyext_widgets: {rCharts: libraries/nvd3}
. Currently I do it via a hack, where there is a.slidifyEnv
variable, which detects presence of plots and silently modifies the payload. But there is a strong need for a more robust mechanism to achieve this.Update: One solution is for the R function creating the plot to return the list of dependencies as attributes, which can be picked up by
knitr
automatically. This would make dependency overriding tricky, but perhaps can be managed using chunk options.