# install.packages('pak')
pak::pak('mjfrigaard/shinypak')22 pkgdown
In this chapter, we’ll cover setting up a pkgdown website for our app-package. Building a package website isn’t required, but it’s a great way to confirm your package is documented and structured correctly, and it gives you an opportunity to share all of your hard work! pkgdown can be configured to automatically generate a beautiful website from a pre-specified Git branch GitHub Actions.
A pkgdown website makes our Shiny app and its accompanying package more accessible to potential users by providing them with a central location for any information they need (app features, updates, etc.).
22.1 Setting up pkgdown
The magic of pkgdown is it’s conversion of an existing R package structure into a website with documentation for our application.
install.packages("pkgdown")pkgdown has a usethis function similar to testthat for setup:1
usethis::use_pkgdown_github_pages()use_pkgdown_github_pages() takes care of (most of) the setup for our app-package website, but we’ll break down the steps below.2
22.1.1 _pkgdown.yml
The initial output after running use_pkgdown_github_pages() looks something like the following:
✔ Setting active project to '/Users/<UserName>/projects/<pkgName>'
✔ Adding '^_pkgdown\\.yml$', '^docs$', '^pkgdown$' to '.Rbuildignore'
✔ Adding 'docs' to '.gitignore'
✔ Writing '_pkgdown.yml'
• Modify '_pkgdown.yml'
✔ Recording 'https://<UserName>.github.io/<pkgName>/' as site's url in '_pkgdown.yml'
✔ Adding 'https://<UserName>.github.io/<pkgName>/' to URL
✔ Setting 'https://<UserName>.github.io/<pkgName>/' as homepage of GitHub repo '<UserName>/<pkgName>'_pkgdown.yml is initially created with only the url, template, and bootstrap version:
url: https://<UserName>.github.io/<pkgName>/
template:
bootstrap: 5These fields are all that’s required to launch your pkgdown site, but in the following sections we’ll cover how to edit _pkgdown.yml to customize the fonts, colors, contents, and layout of our site.
22.1.2 gh-pages branch
use_pkgdown_github_pages() sets up publishing our app-package site from an ‘orphan branch from GitHub pages’:
✔ Initializing empty, orphan 'gh-pages' branch in GitHub repo '<UserName>/<pkgName>'
✔ GitHub Pages is publishing from:
• URL: 'https://<UserName>.github.io/<pkgName>/'
• Branch: 'gh-pages'We’re also told GitHub pages will be publishing our app-package website at the following URL: https://<UserName>.github.io/<pkgName>/
22.1.3 .github/workflows/
use_pkgdown_github_pages() creates a GitHub Action workflow folder (.github/workflows/) with a YAML file (pkgdown.yaml):
• Path: "/"
✔ Adding "*.html" to .github/.gitignore.
✔ Saving "r-lib/actions/examples/pkgdown.yaml@v2" to .github/workflows/pkgdown.yaml.
☐ Learn more at <https://github.com/r-lib/actions/blob/v2/examples/README.md>.We’re also told the contents in this file are copied from the r-lib/actions repository (which we’ve covered previously in Section 21.1 and Section 21.2).
22.2 Building site
usethis has two functions for building your pkgdown site:
build_site()build_site_github_pages()
We used use_pkgdown_github_pages() to configure our app-package, so we’ll use build_site_github_pages() to build our site.
pkgdown::build_site_github_pages()In the following sections, we’ll take a look at how the files and folders in our app-package are used to create the site’s contents. As mentioned above, the great thing about pkgdown sites is that they use our existing package structure to build a beautiful site that’s easy to navigate (with minimal changes).
22.2.1 docs/
The docs/ folder contains the .html files for our website (that’s why ^docs$ was added to the .Rbuildignore and docs was added to the .gitignore). After creating a home for our site contents, the site initialization files are copied from the local pkgdown installation into docs/
== Building pkgdown site ======================================================
Reading from: '/Users/<UserName>/<pkgName>'
Writing to: '/Users/<UserName>/<pkgName>/docs'22.2.2 README.md -> index.html
The landing page (index.html) for our app-package website is built from the README.md file. An example of the site URL is below:
https://<UserName>.github.io/<pkgName>/index.htmlThe <UserName> is our GitHub username, and the <pkgName> is the name of our package. The authors.html is built from the Author and Maintainer fields in the DESCRIPTION file. Long-form documentation can be stored in vignettes (Section 1.15.3) which will be converted into articles (covered below).
22.2.3 man/ -> Reference
The functions documented in the man/ folder are converted into individual items in the Reference menu item (see Chapter 5). I’ve included two examples below:
man/
├── display_type.Rd
└── launch_app.Rd── Building function reference ───────────
Writing reference/index.html
Reading man/display_type.Rd
Writing reference/display_type.html
Reading man/launch_app.Rd
Writing reference/launch_app.htmlFunctions will only be included in the Reference if they’ve been exported (see Section 6.1)
The
@seealsoand@familytags will create hyperlinks between our utility functions, modules, UI/server/standalone app functions (see Section 5.2)All
@exampleswill be run and displayed (Section 5.1.6)
22.2.4 vignettes -> Articles
The .Rmd files in the vignettes folder are rendered as HTML files and displayed under an Articles menu item. The exception to this is any vignettes with the same name as our app-package. This vignette will automatically be listed under a menu dropdown titled “Get Started”:3
vignettes/
├── sap.Rmd
└── specs.Rmd-- Building articles -------------
Writing 'articles/index.html'
Reading 'vignettes/sap.Rmd'
Writing 'articles/sap.html'
Reading 'vignettes/specs.Rmd'
Writing 'articles/specs.html'
== DONE ==========================The final step in the build process is to add a .nojekyll file in the repository (this hidden file is necessary for pkgdown sites configured to deploy from GitHub pages).
-- Extra files for GitHub pages ----------------------------------------------
Writing '.nojekyll'22.3 Customize layout
We can customize the look of our pkgdown site by editing the contents of _pkgdown.yml.
22.3.1 Themes, colors and fonts
Below are some examples of the fields that control the bootswatch theme (<THEME>), code syntax highlighting(<HIGHLIGHTING>):
YAML Fields
template:
bootstrap: 5
bootswatch: <THEME>
theme: <HIGHLIGHTING>In _pkgdown.yml
template:
bootstrap: 5
bootswatch: united
theme: atom-one-lightWe can use the bslib package for additional control over the fonts and colors on our site. The <COLOR> should be replaced with a color hex, and <FONT> can include any freely available Google fonts.4
YAML Fields
bslib:
primary: "<COLOR>"
code-color: "<COLOR>"
code-bg: "<COLOR>"
base_font:
google: <FONT>
heading_font:
google: <FONT>
code_font:
google: <FONT>In _pkgdown.yml
bslib:
primary: "#02577A"
code-color: "#007bff"
code-bg: "#EAE9EA"
base_font:
google: Ubuntu
heading_font:
google: Fira Sans Condensed
code_font:
google: Ubuntu MonoYou can see the theme, color, and font choices below:
22.3.2 Articles
The articles should include a link to the landing page for our app, and provide detailed examples of how it works, including links to any additional resources or documentation.
The navbar components can also be customized with titles, sections, and article names. In _pkgdown.yml, the articles are listed under components, and we will add a text title (Docs) and sub-heading (Specs):
As noted above, any vignette with a filename that matches the package name will be automatically named ‘Getting Started’ in the navbar. We can also add sections with article titles by placing them in text fields. These are listed under the menu (note the indentation), with a path to the html file.
- I’ve listed the
App Specificationsvignette under a"Specs"section (see Chapter 15), and linked toarticles/specs.html:
Use ------- with a text field to create horizontal separators between sections (without a corresponding href).
- I’ve added a
Modulessection and aApplication Modulesvignette (stored invignettes/modules.Rmdand published toarticles/modules.html):
22.3.3 Function reference
pkgdown will automatically generate a Package index section for any object with an .Rd file in the man/ folder. This includes functions we’ve explicitly exported with (i.e., with @export) and functions we’ve documented with @keywords internal.5
By default, the function are sorted alphabetically, but we can customize them into sections with titles and descriptions using the fields below in _pkgdown.yml:
reference:
- title: "<TITLE>"
desc: >
<DESCRIPTION>
contents:
- <FUNCTION>For example, we can include a section for the modules we’re exporting from our app-package:
To help organize and display the functions in your app-package, we can use tidyselect helpers6 in the bullets below contents.
For example, we can list modules with starts_with("mod"):7
We can also use _pkgdown.yml to list any datasets we’ve documented (see Section 7.3) in our app-package.
22.4 Deploying your site
The .github/workflows/pkgdown.yaml file automates building and deploying our app-package’s pkgdown site. This workflow file is configured to be triggered by a specific GitHub event, build the website using the standard R package files, then deploys the site to GitHub Pages. Below we’ll breakdown the fields and values of the workflow (and their functions):
22.4.1 Event
1. Set to trigger on push to the 22_pkgdown branch
on:
push:
branches: [22_pkgdown]
a. Also triggers when a release is published, allowing the website to showcase the latest version of the package.8
release:
types: [published]
b. workflow_dispatch allows the workflow to be manually triggered from the GitHub Actions web interface (for ad-hoc updates).9
workflow_dispatch:22.4.2 Jobs
2. name defines a single job with the ID pkgdown.
name: pkgdown22.4.3 Runner
3. The pkgdown job ID runs on the latest Ubuntu runner provided by GitHub Actions.
jobs:
pkgdown:
runs-on: ubuntu-latest4. The comment Only restrict concurrency for non-PR jobs refers to the concurrency field,10 which prevents concurrent runs of the job for non-pull request events (avoiding conflicts or redundant deployments). group11 uses a dynamic expression to differentiate between pull_request events and github.event_name, using the run ID (github.run_id) for pull requests to allow concurrency.
# Only restrict concurrency for non-PR jobs
concurrency:
group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}22.4.4 Map
5. env maps the GITHUB_PAT environment variable using the GitHub token, secrets.GITHUB_TOKEN (which allows the workflow to authenticate and perform operations within the repository).
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}6. permissions explicitly grants the workflow write permissions to the repository, enabling it to push changes (like an updated website).
permissions:
contents: write22.4.5 Steps
7. Checks out the repository’s code, making it available to subsequent steps.
steps:
- uses: actions/checkout@v48. Installs pandoc, which is necessary for rendering markdown documents and vignettes.
- uses: r-lib/actions/setup-pandoc@v29. Sets up the R environment and configures it to use the public RStudio package manager (use-public-rspm) for faster package installations.
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true10. Installs the dependencies required by our app-package and pkgdown.
- uses: r-lib/actions/setup-r-dependencies@v2
a. Specifies installing any::thing from pkgdown and the local:: package (our app-package).12
with:
extra-packages: any::pkgdown, local::.
needs: website11. Executes pkgdown::build_site_github_pages() within an R script shell to build the pkgdown website. It’s configured not to start a new R process for the build and not to install our app-package (assuming dependencies are already handled in step 10).
- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}12. Uses JamesIves/github-pages-deploy-action@v4.5.0 to deploy the site to GitHub Pages (provided the event is not a pull request).
- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4.5.0
a. Specifies not to clean the deployment branch, deploys it to the gh-pages branch, and sets the site content source folder to docs
with:
clean: false
branch: gh-pages
folder: docs.github/workflows/pkgdown.yaml performs more operations than the previous workflows. However, these extra steps allow us to use the gh-pages branch to maintain and showcase up-to-date package documentation for users, contributors, and collaborators. When we’re happy with the layout of our website in _pkgdown.yml, we can add, commit, and push the changes back to the repo:
git add .
git commit -m "updates to _pkgdown.yml"
git push22.5 GitHub
After pushing the changes to the 22_pkgdown branch, we can see our new 22_pkgdown workflow listed with the previous 21.1_gha-style (Section 21.1) and 21.2_gha-shiny-deploy (Section 21.2) workflows in the Actions tab:
Launch app with the shinypak package:
launch('22_pkgdown')The pkgdown sites can take a few minutes to build, but we can monitor it’s progress from the Actions tab:
The workflow file triggers the following steps:
Back in the Actions tab, we see a new pages build and deployment workflow has been created with a ‘bot’ tag:
The updates to _pkgdown.yml workflow represents the changes we committed and pushed to the 22_pkgdown branch (#21), but we configured our website to be served from the gh-pages branch (#22). Each time we push changes to 22_pkgdown and trigger the pkgdown workflow, a corresponding pages build and deployment workflow will be triggered to build and deploy the site:
This automated deployment process is essential for maintaining up-to-date documentation or website content for R packages (like sap) without manual intervention, making it easier for developers to focus on development while ensuring that users always have access to the latest information.
View the package website here.
Recap
pkgdown is handy for creating beautiful, functional websites for your app-package. Package sites help share your app-package with others in a more engaging and informative way.
usethisalso has a generic function for usingpkgdown(use_pkgdown()), but we’re going to cover building and deploying our app-package site using GitHub pages. Read more aboutuse_pkgdown()in theusethisdocumentation.↩︎Internally, this function calls
usethis::use_pkgdown(),usethis::use_github_pages(), andusethis::use_github_action("pkgdown"). Read more in theusethisdocumentation.↩︎I created this vignette with
usethis::use_vignette("sap")and included instructions for launching the various apps insap.↩︎Read more about
bslibinpkgdownsites in the documentation.↩︎Functions with
@keywords internalaren’t listed in the package index, but can be accessed withpkg:::fun()(like thetest_logger()function insap).↩︎Using the
mod_as a prefix for module functions is a habit I’ve adopted from thegolempackage (specifically, theadd_module()function).↩︎“You can create releases to bundle and deliver iterations of a project to users.”↩︎
“To enable a workflow to be triggered manually, you need to configure the
workflow_dispatchevent.”↩︎“Use concurrency to ensure that only a single job or workflow using the same concurrency group will run at a time.”↩︎
“Concurrency groups provide a way to manage and limit the execution of workflow runs or jobs that share the same concurrency key.”↩︎
The
needs: websitefields might be a placeholder? I’m unaware of theneedskeyword applied within awithclause for setting up dependencies. This also could be intended as a comment or note for future adjustments…↩︎












