diff --git a/core/includes/common.inc b/core/includes/common.inc index 19beefa..63372e3 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -630,7 +630,8 @@ function drupal_merge_attached(array $a, array $b) { */ function drupal_process_attached(array $elements) { // Asset attachments are handled by \Drupal\Core\Asset\AssetResolver. - foreach (array('library', 'drupalSettings') as $type) { + // @todo This needs to be configurable somehow. + foreach (array('library', 'drupalSettings', 'big_pipe_placeholders') as $type) { unset($elements['#attached'][$type]); } diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php index d50ab39..5cfa312 100644 --- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php @@ -13,7 +13,6 @@ use Drupal\Core\Display\PageVariantInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Render\BubbleableMetadata; -use Drupal\Core\Render\BigPipeResponse; use Drupal\Core\Render\HtmlResponse; use Drupal\Core\Render\PageDisplayVariantSelectionEvent; use Drupal\Core\Render\RenderCacheInterface; @@ -167,26 +166,9 @@ public function renderResponse(array $main_content, Request $request, RouteMatch // entire render cache, regardless of the cache bin. $content['#cache']['tags'][] = 'rendered'; - if (!empty($content['#attached']['big_pipe_placeholders'])) { - $response = new BigPipeResponse('', 200, [ - 'Content-Type' => 'text/html; charset=UTF-8', - ]); - - // Inject the placeholders and service into the response. - $response->setBigPipePlaceholders($content['#attached']['big_pipe_placeholders']); - $response->setBigPipeService(reset($content['#attached']['big_pipe_service'])); - - unset($content['#attached']['big_pipe_placeholders']); - unset($content['#attached']['big_pipe_service']); - - // Now after all pre-processing finally set the content. - $response->setContent($content); - } - else { - $response = new HtmlResponse($content, 200, [ - 'Content-Type' => 'text/html; charset=UTF-8', - ]); - } + $response = new HtmlResponse($content, 200, [ + 'Content-Type' => 'text/html; charset=UTF-8', + ]); return $response; } diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index bb8f1ff..7870042 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -167,7 +167,7 @@ public function renderPlain(&$elements) { * * @todo Make public as part of https://www.drupal.org/node/2469431 */ - protected function renderPlaceholder($placeholder, array $elements) { + public function renderPlaceholder($placeholder, array $elements) { // Get the render array for the given placeholder $placeholder_elements = $elements['#attached']['placeholders'][$placeholder]; 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..c10cc4f --- /dev/null +++ b/core/modules/big_pipe/big_pipe.info.yml @@ -0,0 +1,6 @@ +name: big_pipe +type: module +description: 'Enables BigPipe for authenticated users; first send+render the cheap parts of the page, then the expensive parts.' +package: Core +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..88ecff6 --- /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: + bigPipePlaceholders: [] + dependencies: + - core/jquery + - core/drupal + - 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..a4abe2d --- /dev/null +++ b/core/modules/big_pipe/big_pipe.module @@ -0,0 +1,2 @@ +bigPipe = $big_pipe; + } + + /** + * Processes placeholders for HTML responses. + * + * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event + * The event to process. + */ + public function onRespond(FilterResponseEvent $event) { + if (!$event->isMasterRequest()) { + return; + } + + $response = $event->getResponse(); + if (!$response instanceof HtmlResponse) { + return; + } + + $attachments = $response->getAttachments(); + if (empty($attachments['big_pipe_placeholders'])) { + return; + } + + // Create a new Response. + $big_pipe_response = new BigPipeResponse(); + + // Clone the response. + $big_pipe_response->headers = clone $response->headers; + $big_pipe_response->setStatusCode($response->getStatusCode()); + $big_pipe_response->setContent($response->getContent()); + $big_pipe_response->addCacheableDependency($response->getCacheableMetadata()); + + // Inject the placeholders and service into the response. + $big_pipe_response->setBigPipePlaceholders($attachments['big_pipe_placeholders']); + $big_pipe_response->setBigPipeService($this->bigPipe); + unset($attachments['big_pipe_placeholders']); + + // Set the remaining attachments. + $big_pipe_response->setAttachments($attachments); + + // And set the new response. + $event->setResponse($big_pipe_response); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + // Run as pretty much last subscriber. + $events[KernelEvents::RESPONSE][] = ['onRespond', -10000]; + return $events; + } + +} diff --git a/core/modules/big_pipe/src/Render/BigPipe.php b/core/modules/big_pipe/src/Render/BigPipe.php index 9119e18..09508cf 100644 --- a/core/modules/big_pipe/src/Render/BigPipe.php +++ b/core/modules/big_pipe/src/Render/BigPipe.php @@ -2,13 +2,15 @@ /** * @file - * Contains \Drupal\Core\Render\BigPipe. + * Contains \Drupal\big_pipe\Render\BigPipe. */ -namespace Drupal\Core\Render; +namespace Drupal\big_pipe\Render; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; +use Drupal\Core\Render\RendererInterface; +use Drupal\Core\Render\AttachmentsResponseProcessorInterface; /** * A class that allows sending the main content first, then replace diff --git a/core/modules/big_pipe/src/Render/BigPipeInterface.php b/core/modules/big_pipe/src/Render/BigPipeInterface.php index 884b294..221791d 100644 --- a/core/modules/big_pipe/src/Render/BigPipeInterface.php +++ b/core/modules/big_pipe/src/Render/BigPipeInterface.php @@ -2,10 +2,10 @@ /** * @file - * Contains \Drupal\Core\Render\BigPipeInterface. + * Contains \Drupal\big_pipe\Render\BigPipeInterface. */ -namespace Drupal\Core\Render; +namespace Drupal\big_pipe\Render; /** * An interface that allows sending the main content first, then replace diff --git a/core/modules/big_pipe/src/Render/BigPipeResponse.php b/core/modules/big_pipe/src/Render/BigPipeResponse.php index bf82bef..168b0d1 100644 --- a/core/modules/big_pipe/src/Render/BigPipeResponse.php +++ b/core/modules/big_pipe/src/Render/BigPipeResponse.php @@ -2,10 +2,12 @@ /** * @file - * Contains \Drupal\Core\Render\BigPipeResponse. + * Contains \Drupal\big_pipe\Render\BigPipeResponse. */ -namespace Drupal\Core\Render; +namespace Drupal\big_pipe\Render; + +use Drupal\Core\Render\HtmlResponse; /** * A response that allows to send placeholders after the main content has been @@ -23,7 +25,7 @@ class BigPipeResponse extends HtmlResponse { /** * The BigPipe service. * - * @var \Drupal\Core\Render\BigPipeInterface + * @var \Drupal\big_pipe\Render\BigPipeInterface */ protected $bigPipe; @@ -40,7 +42,7 @@ public function setBigPipePlaceholders(array $placeholders) { /** * Sets the big pipe service to use. * - * @param \Drupal\Core\Render\BigPipeInterface $big_pipe + * @param \Drupal\big_pipe\Render\BigPipeInterface $big_pipe * The BigPipe service. */ public function setBigPipeService(BigPipeInterface $big_pipe) { diff --git a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php index 443cf90..a956ff2 100644 --- a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php +++ b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php @@ -2,14 +2,14 @@ /** * @file - * Contains \Drupal\Core\Render\Placeholder\BigPipeStrategy + * Contains \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy */ -namespace Drupal\Core\Render\Placeholder; +namespace Drupal\big_pipe\Render\Placeholder; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Html; -use Drupal\Core\Render\BigPipeInterface; +use Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface; /** * Defines the 'big_pipe' render strategy. @@ -19,23 +19,6 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { /** - * The BigPipe service. - * - * @var object - */ - protected $bigPipe; - - /** - * Constructs a BigPipeStrategy class. - * - * @param \Drupal\Core\Render\BigPipeInterface $big_pipe - * The BigPipe service. - */ - public function __construct(BigPipeInterface $big_pipe) { - $this->bigPipe = $big_pipe; - } - - /** * {@inheritdoc} */ public function processPlaceholders(array $placeholders) { @@ -57,7 +40,7 @@ public function processPlaceholders(array $placeholders) { '#attached' => [ // Use the big_pipe library. 'library' => [ - 'core/drupal.big_pipe', + 'big_pipe/big_pipe', ], // Add the placeholder to a white list of JS processed placeholders. 'drupalSettings' => [ @@ -66,7 +49,6 @@ public function processPlaceholders(array $placeholders) { 'big_pipe_placeholders' => [ $html_placeholder => $placeholder_elements, ], - 'big_pipe_service' => [ $this->bigPipe ], ], ]; }