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

diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php
index b88f740..cef7fd1 100644
--- a/core/modules/system/theme.api.php
+++ b/core/modules/system/theme.api.php
@@ -287,6 +287,132 @@
  * properties. Look through implementations of hook_element_info() to discover
  * elements defined this way.
  *
+ * @section sec_cacheability Cacheability
+ *
+ * Render arrays determine what is shown to the user. Therefore, arrays also
+ * determine how cacheable a response is.
+ *
+ * If code is generating very dynamic render arrays (generally speaking, if it
+ * is using a lot of if-statements), then that also means that Drupal cannot
+ * simply cache the HTML that was rendered from the render array: it needs to
+ * call the 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 5 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.
+ * 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.
+ *    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.
+ * 5. When does the representation of the thing I'm rendering become outdated?
+ *    I.e. is the data valid for a limited period of time only?
+ *    That is the max-age (maximum age). It defaults to "permanently (forever)
+ *    cacheable" (Cache::PERMANENT). When the representation is only valid for
+ *    a limited time, set a max-age, expressed in seconds. Zero means that it's
+ *    not cacheable at all.
+ *
+ * Cache contexts, tags and max-age must always be set, because they affect the
+ * cacheability of the entire response. Therefore they "bubble": parents
+ * automatically receive them.
+ *
+ * Cache keys must only be set if the render array should be cached.
+ *
+ * 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'].
+ * - cache max-age: the node teaser remains valid until the node is changed, not
+ *   for a limited time. So, there's no need to set a max-age: relying on the
+ *   default (Cache::PERMANENT) will do.
+ *
+ * (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.)
+ *
+ * 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. This is logical: 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 which 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 +429,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
  *
