forked from hadley/r-pkgs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
website.Rmd
451 lines (337 loc) · 21.4 KB
/
website.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# Website {#sec-website}
```{r, echo = FALSE}
source("common.R")
```
At this point, we've discussed many ways to document your package:
- Function documentation or, more generally, help topics (@sec-man).
- Documentation of datasets (@sec-documenting-data).
- Vignettes (and articles) (@sec-vignettes).
- README and NEWS (@sec-other-markdown).
Wouldn't it be divine if all of that somehow got bundled up together into a beautiful website for your package?
The [pkgdown package](https://pkgdown.r-lib.org) is meant to provide exactly this magic and that is the topic of this chapter.
## Initiate a site
Assuming your package has a valid structure, pkgdown should be able to make a website for it.
Obviously that website will be more substantial if your package has more of the documentation elements listed above.
But something reasonable should happen for any valid R package.
::: callout-tip
We hear that some folks put off "learning pkgdown", because they think it's going to be a lot of work.
But then they eventually execute the two commands we show next and have a decent website in less than five minutes!
:::
`usethis::use_pkgdown()` is a function you run once and it does the initial, minimal setup necessary to start using pkgdown:
```{r}
#| eval: false
usethis::use_pkgdown()
```
```{r}
#| include: FALSE
#| cache: FALSE
temp_pkg <- fs::path_temp("mypackage")
withr::with_options(
list(usethis.description = NULL),
usethis::create_package(
temp_pkg, open = FALSE, rstudio = TRUE, check_name = FALSE
)
)
```
```{r}
#| echo: false
usethis::with_project(temp_pkg, code = usethis::use_pkgdown(), setwd = FALSE)
```
Here's what `use_pkgdown()` does:
- Creates `_pkgdown.yml`, which is the main configuration file for pkgdown.
In an interactive session, `_pkgdown.yml` will be opened for inspection and editing.
But there's no immediate need to change or add anything here.
- Adds various patterns to `.Rbuildignore`, to keep pkgdown-specific files and directories from being included in your package bundle.
- Adds `docs`, the default destination for a rendered site, to `.gitignore`.
This is harmless for those who don't use Git.
For those who do, this opts you in to our recommended lifestyle, where the definitive source for your pkgdown site is built and deployed elsewhere (probably via GitHub Actions and Pages; more on this soon).
This means the rendered website at `docs/` just serves as a local preview.
`pkgdown::build_site()` is a function you'll call repeatedly, to re-render your site locally.
In an extremely barebones package, you'll see something like this:
```{r}
#| eval: false
pkgdown::build_site()
```
```{r}
#| echo: false
usethis::with_project(temp_pkg, code = pkgdown::build_site(), setwd = TRUE)
```
In an interactive session your newly rendered site should appear in your default web browser.
::: callout-tip
## RStudio
Another nice gesture to build your site is via *Addins \> pkgdown \> Build pkgdown*.
:::
You can look in the local `docs/` directory to see the files that constitute your package's website.
To manually browse the site, open `docs/index.html` in your preferred browser.
This is almost all you truly need to know about pkgdown.
It's certainly a great start and, as your package and ambitions grow, the best place to learn more is the pkgdown-made website for the pkgdown package itself: <https://pkgdown.r-lib.org>.
## Deployment {#sec-website-deployment}
Your next task is to deploy your pkgdown site somewhere on the web, so that your users can visit it.
The path of least resistance looks like this:
- Use Git and host your package on GitHub.
The reasons to do this go well beyond offering a package website, but this will be one of the major benefits to adopting Git and GitHub, if you're on the fence.
- Use GitHub Actions (GHA) to build your website, i.e. to run `pkgdown::build_site()`.
GHA is a platform where you can configure certain actions to happen automatically when some event happens.
We'll use it to rebuild your website every time you push to GitHub.
- Use GitHub Pages to serve your website, i.e. the files you see below `docs/` locally.
GitHub Pages is a static website hosting service that creates a site from files found in a GitHub repo.
The advice to use GitHub Action and Pages are implemented for you in the function `usethis::use_pkgdown_github_pages()`.
It's not an especially difficult task, but there are several steps and it would be easy to miss or flub one.
The output of `use_pkgdown_github_pages()` should look something like this:
```{r}
#| eval: false
usethis::use_pkgdown_github_pages()
#> ✔ Initializing empty, orphan 'gh-pages' branch in GitHub repo 'jane/mypackage'
#> ✔ GitHub Pages is publishing from:
#> • URL: 'https://jane.github.io/mypackage/'
#> • Branch: 'gh-pages'
#> • Path: '/'
#> ✔ Creating '.github/'
#> ✔ Adding '^\\.github$' to '.Rbuildignore'
#> ✔ Adding '*.html' to '.github/.gitignore'
#> ✔ Creating '.github/workflows/'
#> ✔ 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>.
#> ✔ Recording 'https://jane.github.io/mypackage/' as site's url in '_pkgdown.yml'
#> ✔ Adding 'https://jane.github.io/mypackage/' to URL field in DESCRIPTION
#> ✔ Setting 'https:/jane.github.io/mypackage/' as homepage of GitHub repo 'jane/mypackage'
```
Like `use_pkgdown()`, this is a function you basically call once, when setting up a new site.
In fact, the first thing it does is to call `use_pkgdown()` (it's OK if you've already called `use_pkgdown()`), so we usually skip straight to `use_pkgdown_github_pages()` when setting up a new site.
Let's walk through what `use_pkgdown_github_pages()` actually does:
- Initializes an empty, "orphan" branch in your GitHub repo, named `gh-pages` (for "GitHub Pages").
The `gh-pages` branch will only live on GitHub (there's no reason to fetch it to your local computer) and it represents a separate, parallel universe from your actual package source.
The only files tracked in `gh-pages` are those that constitute your package's website (the files that you see locally below `docs/`).
- Turns on GitHub Pages for your repo and tells it to serve a website from the files found in the `gh-pages` branch.
- Copies the configuration file for a GHA workflow that does pkgdown "build and deploy".
The file shows up in your package as `.github/workflows/pkgdown.yaml`.
If necessary, some related additions are made to `.gitignore` and `.Rbuildignore`.
- Adds the URL for your site as the homepage for your GitHub repo.
- Adds the URL for your site to `DESCRIPTION` and `_pkgdown.yml`.
The autolinking behaviour we've touted elsewhere relies on your package listing its URL in these two places, so this is a high-value piece of configuration.
After successful execution of `use_pkgdown_github_pages()`, you should be able to visit your new site at the URL displayed in the output above.[^website-1]
By default the URL has this general form: `https://USERNAME.github.io/REPONAME/`.
[^website-1]: Sometimes there's a small delay, so give it up to a couple of minutes to deploy.
## Now what?
For a typical package, you could stop here --- after creating a basic pkgdown site and arranging for it to be re-built and deployed regularly --- and people using (or considering using) your package would benefit greatly.
Everything beyond this point is a "nice to have".
Overall, we recommend `vignette("pkgdown", package = "pkgdown")` as a good place to start, if you think you want to go beyond the basic defaults.
In the sections below, we highlight a few areas that are connected to other topics in the book or customizations that are particularly rewarding.
## Logo
It's fun to have a package logo!
In the R community, we have a strong tradition of hex stickers, so it can be nice to join in with a hex logo of your own.
Keen R user Amelia McNamara [made herself a dress](https://www.amelia.mn/blog/2019-08-17-Tidy-Dress/) out of custom hex logo fabric and useR!
2018 featured a [spectacular hex photo wall](https://www.mitchelloharawild.com/blog/hexwall/).
Here are some resources to guide your logo efforts:
- The convention is to orient the logo with a vertex at the top and bottom, with flat vertical sides.
- If you think you might print stickers, make sure to comply with the *de facto* standard for sticker size.
[hexb.in](http://hexb.in/sticker.html) is a reliable source for the dimensions and also provides a list of potential vendors for printed stickers.
```{r}
#| label: fig-hex-sticker-spec
#| echo: false
#| out-width: 35%
#| fig-cap: >
#| Standard dimensions of a hex sticker.
#| fig-alt: >
#| A hexagon oriented with points at the top and bottom
#| and flat vertical sides. It is labelled with dimensions:
#| 5.08cm (2") vertically (point to point), and
#| 4.39cm (1.73") horizontally (flat side to flat side).
# https://github.com/terinjokes/StickersStandard/blob/master/assets/hex-image.png
knitr::include_graphics("diagrams/hex-image.png")
```
- The [hexSticker package](https://cran.r-project.org/package=hexSticker) helps you make your logo from within the comfort of R.
Once you have your logo, the `usethis::use_logo()` function places an appropriately scaled copy of the image file at `man/figures/logo.png` and also provides a copy-paste-able markdown snippet to include your logo in your `README`.
pkgdown will also discover a logo placed in the standard location and incorporate it into your site.
## Reference index
pkgdown creates a function reference in `reference/` that includes one page for each `.Rd` help topic in `man/`.
This is one of the first pages you should admire in your new site.
As you look around, there are a few things to contemplate, which we review below.
### Rendered examples
pkgdown executes all your examples (@sec-man-examples) and inserts the rendered results.
We find this is a fantastic improvement over just showing the source code.
This view of your examples can be eye-opening and often you'll notice things you want to add, omit, or change.
If you're not satisfied with how your examples appear, this is a good time to review techniques for including code that is expected to error (@sec-man-examples-errors) or that can only be executed under certain conditions (@sec-man-examples-dependencies-conditional-execution).
### Linking {#sec-website-reference-linking}
These help topics will be linked to from many locations within and, potentially, beyond your pkgdown site.
This is what we are talking about in @sec-man-key-md-features when we recommend putting functions inside square brackets when mentioning them in a roxygen comment:
```{r}
#' I am a big fan of [thisfunction()] in my package. I
#' also have something to say about [otherpkg::otherfunction()]
#' in somebody else's package.
```
On pkgdown sites, those square-bracketed functions become hyperlinks to the relevant pages in your pkgdown site.
This is automatic within your package.
But inbound links from *other* people's packages (and websites, etc.) require two things[^website-2]:
[^website-2]: Another pre-requisite is that your package has been released on CRAN, because the auto-linking machinery has to look up the `DESCRIPTION` somewhere.
It is possible to allow locally installed packages to link to each other, which is described in `vignette("linking", package = "pkgdown")`.
- The `URL` field of your `DESCRIPTION` file must include the URL of your pkgdown site (preferably followed by the URL of your GitHub repo):
``` yaml
URL: https://dplyr.tidyverse.org, https://github.com/tidyverse/dplyr
```
- Your `_pkgdown.yml` file must include the URL for your site:
``` yaml
url: https://dplyr.tidyverse.org
```
devtools takes every chance it gets to do this sort of configuration for you.
But if you elect to do things manually, this is something you might overlook.
A general resource on auto-linking in pkgdown is `vignette("linking", package = "pkgdown")`.
### Index organization
By default, the reference index is just an alphabetically-ordered list of functions.
For packages with more than a handful of functions, it's often worthwhile to curate the index and organize the functions into groups.
For example, dplyr uses this technique: <https://dplyr.tidyverse.org/reference/index.html>.
You achieve this by providing a `reference` field in `_pkgdown.yml`.
Here's a redacted excerpt from dplyr's `_pkgdown.yml` file that gives you a sense of what's involved:
``` yaml
reference:
- title: Data frame verbs
- subtitle: Rows
desc: >
Verbs that principally operate on rows.
contents:
- arrange
- distinct
...
- subtitle: Columns
desc: >
Verbs that principally operate on columns.
contents:
- glimpse
- mutate
...
- title: Vector functions
desc: >
Unlike other dplyr functions, these functions work on individual vectors,
not data frames.
contents:
- between
- case_match
...
- title: Built in datasets
contents:
- band_members
- starwars
- storms
...
- title: Superseded
desc: >
Superseded functions have been replaced by new approaches that we believe
to be superior, but we don't want to force you to change until you're
ready, so the existing functions will stay around for several years.
contents:
- sample_frac
- top_n
...
```
To learn more, see `?pkgdown::build_reference`.
## Vignettes and articles
@sec-vignettes deals with vignettes, which are long-form guides for a package.
They afford various opportunities beyond what's possible in function documentation.
For example, you have much more control over the integration of prose and code and over the presentation of code itself, e.g. code can be executed but not seen, seen but not executed, and so on.
It's much easier to create the reading experience that best prepares your users for authentic usage of your package.
A package's vignettes appear, in rendered form, in its website, in the *Articles* dropdown menu.
"Vignette" feels like a technical term that we might not expect all R users to know, which is why pkgdown uses the term "articles" here.
To be clear, the *Articles* menu lists your package's official vignettes (the ones that are included in your package bundle) and, optionally, other non-vignette articles (@sec-vignettes-article), which are only available on the website.
### Linking
Like function documentation, vignettes can also be the target of automatic inbound links from within your package and, potentially, beyond.
We've talked about this elsewhere in the book.
In @sec-man-key-md-features, we introduced the idea of referring to a vignette with an inline call like `vignette("some-topic")`.
The rationale behind this syntax is because the code can literally be copied, pasted, and executed for local vignette viewing.
So it "works" in any context, even without automatic links.
But, in contexts where the auto-linking machinery is available, it knows to look for this exact syntax and turn it into a hyperlink to the associated vignette, within a pkgdown site.
The need to specify the host package depends on the context:
- `vignette("some-topic")`: Use this form in your own roxygen comments, vignettes, and articles, to refer to a vignette in your package.
The host package is implied.
- `vignette("some-topic", package = "somepackage")`: Use this form to refer to a vignette in some other package.
The host package must be explicit.
Note that this shorthand does **not** work for linking to non-vignette articles.
Since the syntax leans so heavily on the `vignette()` function, it would be too confusing, i.e. evaluating the code in the console would fail because R won't be able to find such a vignette.
Non-vignette articles must be linked like any other URL.
When you refer to a function in your package, in your vignettes and articles, make sure to put it inside backticks and to include parentheses.
Qualify functions from other packages with their namespace.
Here's an example of prose in one of your own vignettes or articles:
``` markdown
I am a big fan of `thisfunction()` in my package. I also have something to
say about `otherpkg::otherfunction()` in somebody else's package.
```
Remember that automatic inbound links from *other* people's packages (and websites, etc.) require that your package advertises the URL of its website in `DESCRIPTION` and `_pkgdown.yaml`, as configured by `usethis:: use_pkgdown_github_pages()` and as described in @sec-website-reference-linking.
### Index organization
As with the reference index, the default listing of the articles (broadly defined) in a package is alphabetical.
But if your package has several articles, it can be worthwhile to provide additional organization.
For example, you might feature the articles aimed at the typical user and tuck those meant for advanced users or developers behind "More articles ...".
You can learn more about this in `?pkgdown::build_articles`.
### Non-vignette articles
In general, @sec-vignettes is our main source of advice on how to approach vignettes and that also includes some coverage of non-vignette articles (@sec-vignettes-article).
Here we review some reasons to use a non-vignette article and give some examples.
An article is morally like a vignette (e.g. it tells a story that involves multiple functions and is written with R markdown), except it does not ship with the package bundle.
`usethis::use_article()` is the easiest way to create an article.
The main reason to use an article is when you want to show code that is impossible or very painful to include in a vignette or official example.
Possible root causes of this pain:
- Use of a package you don't want to formally depend on.
In vignettes and examples, it's forbidden to show your package working with a package that you don't list in `DESCRIPTION`, e.g. in `Imports` or `Suggests`.
There is a detailed example of this in @sec-dependencies-nonstandard-config-needs, featuring a readxl article that uses the tidyverse meta-package.
The key idea is to list such a dependency in the `Config/Needs/website` field of `DESCRIPTION`.
This keeps tidyverse out of readxl's dependencies, but ensures it's installed when the website is built.
- Code that requires authentication or access to specific assets, tools, or secrets that are not available on CRAN.
The [googledrive package](https://googledrive.tidyverse.org) has no true vignettes, only non-vignette articles, because it's essentially impossible to demonstrate usage without authentication.
It is possible to access secure environment variables on GitHub Actions, where the pkgdown site is built and deployed, but this is impossible to do on CRAN.
- Content that involves a lot of figures, which cause your package to bump up against CRAN's size constraints.
The ggplot2 package [presents several FAQs as articles](https://ggplot2.tidyverse.org/articles/index.html) for this reason.
## Development mode
Every pkgdown site has a so-called [*development mode*](https://pkgdown.r-lib.org/reference/build_site.html#development-mode), which can be specified via the `development` field in `_pkgdown.yml`.
If unspecified, the default is `mode: release`, which results in a single pkgdown site.
Despite the name, this single site reflects the state of the current source package, which could be either a released state or a development state.
The diagram below shows the evolution of a hypothetical package that is on CRAN and that has a pkgdown site in "release" mode.
```
...
|
V
Tweaks before release v0.1.9000
|
V
Increment version number v0.2.0 <-- install.packages() gets this
|
V
Increment version number v0.2.9000
|
V
Improve error message v0.2.9000 <-- site documents this
|
V
...
```
Users who install from CRAN get version 0.2.0.
But the pkgdown site is built from the development version of the package.
This creates the possibility that users will read about some new feature on the website that is not present in the package version that they have installed with `install.packages()`.
We find that the simplicity of this setup outweighs the downsides, until a package has a broad user base, i.e. lots of users of varying levels of sophistication.
It's probably safe to stay in "release" mode until you actually hear from a confused user.
Packages with a substantial user base should use "auto" development mode:
``` yaml
development:
mode: auto
```
This directs pkgdown to generate a top-level site from the released version and to document the development version in a `dev/` subdirectory.
We revisit the same hypothetical package as above, but assuming the pkdown site is in "auto" mode.
```
...
|
V
Tweaks before release v0.1.9000
|
V
Increment version number v0.2.0 <-- install.packages() gets this
| main site documents this
V
Increment version number v0.2.9000
|
V
Improve error message v0.2.9000 <-- dev/ site documents this
|
V
...
```
All of the core tidyverse packages use "auto" mode.
For example, consider the website of the readr package:
- [readr.tidyverse.org](https://readr.tidyverse.org) documents the released version, i.e. what `install.packages("readr")` delivers.
- [readr.tidyverse.org/dev/](https://readr.tidyverse.org/dev/) documents the dev version, i.e. what `install_github("tidyverse/readr")` delivers.
Automatic development mode is recommended for packages with a broad user base, because it maximizes the chance that a user will read web-based documentation that reflects the package version that is locally installed.