big_pipe.module | 8 +-- big_pipe.services.yml | 7 +++ src/Cache/Context/SessionExistsCacheContext.php | 70 +++++++++++++++++++++++++ src/Render/Placeholder/BigPipeStrategy.php | 12 +++-- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/big_pipe.module b/big_pipe.module index 516b29b..4cacef4 100644 --- a/big_pipe.module +++ b/big_pipe.module @@ -14,15 +14,17 @@ use Drupal\Core\Url; * @see \Drupal\big_pipe\Controller\BigPipeController::setNoJsCookie() */ function big_pipe_page_attachments(array &$page) { + $request = \Drupal::request(); // BigPipe is only used when there is an actual session, so only add the no-JS // detection when there actually is a session. // @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy. - $page['#cache']['contexts'][] = 'cookies:' . session_name(); + $session_exists = \Drupal::service('session_configuration')->hasSession($request); + $page['#cache']['contexts'][] = 'session.exists'; // Only do the no-JS detection while we don't know if there's no JS support: // avoid endless redirect loops. + $has_big_pipe_nojs_cookie = $request->cookies->has(BigPipeStrategy::NOJS_COOKIE); $page['#cache']['contexts'][] = 'cookies:' . BigPipeStrategy::NOJS_COOKIE; - $cookies = \Drupal::request()->cookies; - if ($cookies->has(session_name()) && !$cookies->has(BigPipeStrategy::NOJS_COOKIE)) { + if ($session_exists && !$has_big_pipe_nojs_cookie) { $page['#attached']['html_head'][] = [ [ // Redirect through a 'Refresh' meta tag if JavaScript is disabled. diff --git a/big_pipe.services.yml b/big_pipe.services.yml index b8ff9d4..cf5ca80 100644 --- a/big_pipe.services.yml +++ b/big_pipe.services.yml @@ -18,3 +18,10 @@ services: decorates: html_response.attachments_processor decoration_inner_name: html_response.attachments_processor.original arguments: ['@html_response.attachments_processor.original', '@asset.resolver', '@config.factory', '@asset.css.collection_renderer', '@asset.js.collection_renderer', '@request_stack', '@renderer', '@module_handler'] + + # @todo Move this into Drupal 8 core. + cache_context.session.exists: + class: Drupal\big_pipe\Cache\Context\SessionExistsCacheContext + arguments: ['@session_configuration', '@request_stack'] + tags: + - { name: cache.context} diff --git a/src/Cache/Context/SessionExistsCacheContext.php b/src/Cache/Context/SessionExistsCacheContext.php new file mode 100644 index 0000000..eaf02e1 --- /dev/null +++ b/src/Cache/Context/SessionExistsCacheContext.php @@ -0,0 +1,70 @@ +sessionConfiguration = $session_configuration; + $this->requestStack = $request_stack; + } + + /** + * {@inheritdoc} + */ + public static function getLabel() { + return t('Session exists'); + } + + /** + * {@inheritdoc} + */ + public function getContext() { + return $this->sessionConfiguration->hasSession($this->requestStack->getCurrentRequest()) ? '1' : '0'; + } + + /** + * {@inheritdoc} + */ + public function getCacheableMetadata() { + return new CacheableMetadata(); + } + +} diff --git a/src/Render/Placeholder/BigPipeStrategy.php b/src/Render/Placeholder/BigPipeStrategy.php index d5b6c4c..96524be 100644 --- a/src/Render/Placeholder/BigPipeStrategy.php +++ b/src/Render/Placeholder/BigPipeStrategy.php @@ -116,9 +116,6 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { * The BigPipe placeholders. */ protected function doProcessPlaceholders(array $placeholders) { - $non_html_placeholder_cache_contexts = ['cookies:' . session_name()]; - $html_placeholder_cache_contexts = ['cookies:' . session_name(), 'cookies:' . static::NOJS_COOKIE]; - $overridden_placeholders = []; foreach ($placeholders as $placeholder => $placeholder_elements) { // BigPipe uses JavaScript and the DOM to find the placeholder to replace. @@ -136,7 +133,6 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { // @see \Drupal\Core\Form\FormBuilder::renderPlaceholderFormAction() if ($placeholder[0] !== '<' || $placeholder !== Html::normalize($placeholder)) { $overridden_placeholders[$placeholder] = static::createBigPipeNoJsPlaceholder($placeholder, $placeholder_elements); - $overridden_placeholders[$placeholder]['#cache']['contexts'] = $non_html_placeholder_cache_contexts; } else { // If the current request/session doesn't have JavaScript, fall back to @@ -147,7 +143,7 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { else { $overridden_placeholders[$placeholder] = static::createBigPipeJsPlaceholder($placeholder, $placeholder_elements); } - $overridden_placeholders[$placeholder]['#cache']['contexts'] = $html_placeholder_cache_contexts; + $overridden_placeholders[$placeholder]['#cache']['contexts'][] = 'cookies:' . static::NOJS_COOKIE; } } @@ -186,6 +182,9 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { '#markup' => '
', '#cache' => [ 'max-age' => 0, + 'contexts' => [ + 'session.exists', + ], ], '#attached' => [ 'library' => [ @@ -222,6 +221,9 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { '#markup' => '', '#cache' => [ 'max-age' => 0, + 'contexts' => [ + 'session.exists', + ], ], '#attached' => [ 'big_pipe_nojs_placeholders' => [