 core/modules/system/theme.api.php | 130 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 1 deletion(-)

diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php
index b88f740..e555eef 100644
--- a/core/modules/system/theme.api.php
+++ b/core/modules/system/theme.api.php
@@ -287,6 +287,134 @@
  * properties. Look through implementations of hook_element_info() to discover
  * elements defined this way.
  *
+ * @section sec_cacheability Cacheability
+ *
+ * Since the contents of a render array determine what is shown to the user, it
+ * also depends on render arrays "how cacheable" a page is. If your code is
+ * generating very dynamic render arrays (generally speaking, if it is using a
+ * lot of if-statements), then it also means that Drupal cannot simply cache the
+ * HTML that was rendered from your render array: it needs to call your code
+ * (and all those if-statements) when appropriate!
+ *
+ * In other words: Drupal needs to be aware of how dynamic your code is. If it's
+ * not aware, then it may send the same cached HTML to the wrong user!
+ *
+ * This is why it is of the utmost importance that you inform the Render API of
+ * the cacheability of a render array.
+ *
+ * Whenever you are generating a render array, use the following 4 steps:
+ * 1. I'm rendering something. That means I must think of cacheability!
+ * 2. Is this something that's expensive to render, and therefore is worth
+ *    caching? If the answer is "yes", then what identifies this particular
+ *    representation of the thing I'm rendering?
+ *    Those are the cache keys.
+ *    They're only necessary if I want to cache this render array.
+ * 3. Does the representation of the thing I'm rendering vary per role (needs
+ *    permission), per URL (needs something of the request), per language, per …
+ *    something? Those are the cache contexts.
+ *    They're always necessary, because they affect the cacheability of the
+ *    entire page. Therefore they "bubble": parents automatically receive them.
+ *    Note: cache contexts are completely analogous to HTTP's Vary header!
+ * 4. When does the representation of the thing I'm rendering become outdated?
+ *    I.e. which things does it depend upon, so that when those things change,
+ *    so should my representation?
+ *    Those are the cache tags.
+ *    They're always necessary, because they affect the cacheability of the
+ *    entire page. Therefore they "bubble": parents automatically receive them.
+ *
+ * Cache keys, contexts and tags together form the cache metadata trifecta.
+ *
+ * Let's apply this to a concrete example:
+ * - cache keys: when rendering a node (thing) in the teaser view mode
+ *   (configuration indicating a specific representation), my cache keys would
+ *   be e.g. ['node', 5, 'teaser']
+ * - cache contexts: a teaser node is rendered differently for users in
+ *   different timezones (because of the "authored on" date field), so my cache
+ *   contexts would be e.g. ['timezone'].
+ * - cache tags: the node teaser shows the node title, authoring date, author,
+ *   author's profile picture and body, the dependencies are the node itself,
+ *   the user entity associated with the author, the file entity associated with
+ *   the profile picture and the text format associated with the body field. If
+ *   any of them change, then the cached HTML for the node 5 teaser must be
+ *   regenerated. So my cache tags would be: ['node:5', 'user:3', 'file:4',
+ *   'config:filter.format.basic_html'].
+ *
+ * (Note: Drupal sets all the cache metadata in the above example automatically:
+ * the entity view builder and field formatters take care of that. It's just
+ * meant to be a concrete example that is intuitively understood by all.)
+ *
+ * In summary: when a render array represents a thing, then:
+ * - cache keys identify a representation of a thing
+ *   - may only be set if this render array should be cached
+ *   - will trigger caching of this render array (subtree)
+ * - cache contexts identify the variations of the representation of the thing
+ *   -  must always be set (because they bubble & affect the entire page)
+ * - cache tags identify the dependencies of the representation
+ *   - must always be set (because they bubble & affect the entire page).
+ *
+ * Note that every Entity and Config has a ::getCacheTags() method, with which
+ * one can easily get the cache tags of the objects a render array depends upon.
+ *
+ * Looking at a concrete example:
+ * @code
+ * $config = \Drupal::config('system.site');
+ * $current_user = \Drupal::currentUser();
+ *
+ * $build = [
+ *   '#prefix' => '<aside>',
+ *   '#markup' => t('Hi, %name, welcome back to @site!', [
+ *     '%name' => $current_user->getUsername(),
+ *     '@site' => $config->get('name'),
+ *   ]),
+ *   '#suffix' => '</aside>',
+ *   '#cache' => [
+ *     'contexts' => [
+ *       'user',
+ *     ],
+ *     'tags' => \Drupal\Core\Cache\Cache::mergeTags(
+ *       $config->getCacheTags(),
+ *       \Drupal\user\Entity\User::load($current_user->id())->getCacheTags()
+ *     ),
+ *   ],
+ * ];
+ * @encode
+ *
+ * We're generating markup that contains the user name and the site name. The
+ * user name is tied to a User entity, so we want to associate its cache tags.
+ * And since that output varies per user (it's a personal welcome message, after
+ * all), we must also specify the 'user' cache context. The site name is stored
+ * in config, so we want to associate the cache tags of the config that the
+ * output depends on as well.
+ *
+ * That's quite a bit of code. But we're now informing Drupal correctly about
+ * the cacheability of this render array & markup!
+ *
+ * Let's see how that changes if we make the welcome message not personal, but
+ * generic:
+ * @code
+ * $config = \Drupal::config('system.site');
+ *
+ * $build = [
+ *   '#prefix' => '<aside>',
+ *   '#markup' => t('Hi, welcome back to @site!', [
+ *     '@site' => $config->get('name'),
+ *   ]),
+ *   '#suffix' => '</aside>',
+ *   '#cache' => [
+ *     'tags' => $config->getCacheTags(),
+ *   ],
+ * ];
+ * @encode
+ *
+ * The generated markup is only slightly different, but the code became much
+ * simpler! It's logical though: the markup can now be used for all users, so
+ * less cacheability metadata is necessary. Most notably, no cache contexts are
+ * present anymore (after all, there's only a single variation left now).
+ *
+ * Finally: it is easy to see what cache contexts a certain page varies by and
+ * which cache tags it is invalidated by: one must only look at the
+ * X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers!
+ *
  * @section sec_attached Attaching libraries in render arrays
  *
  *
@@ -303,7 +431,7 @@
  * values. Example:
  * @code
  * $build['#attached']['library'][] = 'core/jquery';
- * $build['#attached']['drupalSettings']['foo] = 'bar';
+ * $build['#attached']['drupalSettings']['foo'] = 'bar';
  * $build['#attached']['feed'][] = ['aggregator/rss', $this->t('Feed title')];
  * @endcode
  *
