diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt index 63748c2..69802ff 100644 --- a/core/MAINTAINERS.txt +++ b/core/MAINTAINERS.txt @@ -261,6 +261,10 @@ Basic Auth module - Klaus Purer 'klausi' https://www.drupal.org/u/klausi - Juampy Novillo Requena 'juampy' https://www.drupal.org/u/juampy +BigPipe module +- Wim Leers 'Wim Leers' https://www.drupal.org/u/wim-leers +- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx + Block module - Tim Plunkett 'tim.plunkett' https://www.drupal.org/u/tim.plunkett - Ben Dougherty 'benjy' https://www.drupal.org/u/benjy diff --git a/core/composer.json b/core/composer.json index e8120c6..dbe1db9 100644 --- a/core/composer.json +++ b/core/composer.json @@ -48,6 +48,7 @@ "drupal/bartik": "self.version", "drupal/ban": "self.version", "drupal/basic_auth": "self.version", + "drupal/big_pipe": "self.version", "drupal/block": "self.version", "drupal/block_content": "self.version", "drupal/book": "self.version", diff --git a/core/modules/big_pipe/big_pipe.info.yml b/core/modules/big_pipe/big_pipe.info.yml new file mode 100644 index 0000000..0108e1f --- /dev/null +++ b/core/modules/big_pipe/big_pipe.info.yml @@ -0,0 +1,6 @@ +name: BigPipe +type: module +description: 'Sends pages in a way that allows browsers to show them much faster. Uses the BigPipe technique.' +package: Core (Experimental) +version: VERSION +core: 8.x diff --git a/core/modules/big_pipe/big_pipe.libraries.yml b/core/modules/big_pipe/big_pipe.libraries.yml new file mode 100644 index 0000000..6da49b7 --- /dev/null +++ b/core/modules/big_pipe/big_pipe.libraries.yml @@ -0,0 +1,11 @@ +big_pipe: + version: VERSION + js: + js/big_pipe.js: {} + drupalSettings: + bigPipePlaceholderIds: [] + dependencies: + - core/jquery + - core/jquery.once + - core/drupal.ajax + - core/drupalSettings diff --git a/core/modules/big_pipe/big_pipe.module b/core/modules/big_pipe/big_pipe.module new file mode 100644 index 0000000..1970c27 --- /dev/null +++ b/core/modules/big_pipe/big_pipe.module @@ -0,0 +1,66 @@ +' . t('About') . ''; + $output .= '

' . t('The BigPipe module sends pages with dynamic content in a way that allows browsers to show them much faster. For more information, see the online documentation for the BigPipe module.', [':big_pipe-documentation' => 'https://www.drupal.org/documentation/modules/big_pipe']) . '

'; + $output .= '

' . t('Uses') . '

'; + $output .= '
'; + $output .= '
' . t('Speeding up your site') . '
'; + $output .= '
' . t('The module requires no configuration. Every part of the page contains metadata that allows BigPipe to figure this out on its own.') . '
'; + $output .= '
'; + + return $output; + } +} + +/** + * Implements hook_page_attachments(). + * + * @see \Drupal\big_pipe\Controller\BigPipeController::setNoJsCookie() + */ +function big_pipe_page_attachments(array &$page) { + // Routes that don't use BigPipe also don't need no-JS detection. + if (\Drupal::routeMatch()->getRouteObject()->getOption('_no_big_pipe')) { + return; + } + + $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. + $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; + if ($session_exists && !$has_big_pipe_nojs_cookie) { + $page['#attached']['html_head'][] = [ + [ + // Redirect through a 'Refresh' meta tag if JavaScript is disabled. + '#tag' => 'meta', + '#noscript' => TRUE, + '#attributes' => [ + 'http-equiv' => 'Refresh', + // @todo: Switch to Url::fromRoute() once https://www.drupal.org/node/2589967 is resolved. + 'content' => '0; URL=' . Url::fromUri('internal:/big_pipe/no-js', ['query' => \Drupal::service('redirect.destination')->getAsArray()])->toString(), + ], + ], + 'big_pipe_detect_nojs', + ]; + } +} diff --git a/core/modules/big_pipe/big_pipe.routing.yml b/core/modules/big_pipe/big_pipe.routing.yml new file mode 100644 index 0000000..c7981dc --- /dev/null +++ b/core/modules/big_pipe/big_pipe.routing.yml @@ -0,0 +1,9 @@ +big_pipe.nojs: + path: '/big_pipe/no-js' + defaults: + _controller: '\Drupal\big_pipe\Controller\BigPipeController:setNoJsCookie' + _title: 'BigPipe no-JS check' + options: + no_cache: TRUE + requirements: + _access: 'TRUE' diff --git a/core/modules/big_pipe/big_pipe.services.yml b/core/modules/big_pipe/big_pipe.services.yml new file mode 100644 index 0000000..b06255a --- /dev/null +++ b/core/modules/big_pipe/big_pipe.services.yml @@ -0,0 +1,25 @@ +services: + html_response.big_pipe_subscriber: + class: Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber + tags: + - { name: event_subscriber } + arguments: ['@big_pipe'] + placeholder_strategy.big_pipe: + class: Drupal\big_pipe\Render\Placeholder\BigPipeStrategy + arguments: ['@session_configuration', '@request_stack', '@current_route_match'] + tags: + - { name: placeholder_strategy, priority: 0 } + big_pipe: + class: Drupal\big_pipe\Render\BigPipe + arguments: ['@renderer', '@session', '@request_stack', '@http_kernel', '@event_dispatcher'] + html_response.attachments_processor.big_pipe: + public: false + class: \Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor + 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'] + + route_subscriber.no_big_pipe: + class: Drupal\big_pipe\EventSubscriber\NoBigPipeRouteAlterSubscriber + tags: + - { name: event_subscriber } diff --git a/core/modules/big_pipe/js/big_pipe.js b/core/modules/big_pipe/js/big_pipe.js new file mode 100644 index 0000000..41dbc67 --- /dev/null +++ b/core/modules/big_pipe/js/big_pipe.js @@ -0,0 +1,107 @@ +/** + * @file + * Renders BigPipe placeholders using Drupal's Ajax system. + */ + +(function ($, Drupal, drupalSettings) { + + 'use strict'; + + /** + * Executes Ajax commands in ' . "\n"; + flush(); + + // A BigPipe response consists of a HTML response plus multiple embedded + // AJAX responses. To process the attachments of those AJAX responses, we + // need a fake request that is identical to the master request, but with + // one change: it must have the right Accept header, otherwise the work- + // around for a bug in IE9 will cause not JSON, but