big_pipe.module | 15 ++---- big_pipe.services.yml | 5 ++ .../NoBigPipeRouteAlterSubscriber.php | 53 ++++++++++++++++++++++ src/Render/Placeholder/BigPipeStrategy.php | 8 +--- src/Tests/BigPipeTest.php | 19 ++++++++ .../big_pipe_test/big_pipe_test.routing.yml | 10 ++++ .../Render/Placeholder/BigPipeStrategyTest.php | 31 +++++++------ 7 files changed, 110 insertions(+), 31 deletions(-) diff --git a/big_pipe.module b/big_pipe.module index 485a0e1..af37695 100644 --- a/big_pipe.module +++ b/big_pipe.module @@ -33,16 +33,8 @@ function big_pipe_help($route_name, RouteMatchInterface $route_match) { * @see \Drupal\big_pipe\Controller\BigPipeController::setNoJsCookie() */ function big_pipe_page_attachments(array &$page) { - // Exclude a few very special routes from no-JS detection. - $excluded_routes = [ - // The batch system already uses a refresh to work with JS disabled. - 'system.batch_page.html', - // The BigPipe placeholder strategy is not applied on the module - // installation page, so the no-JS detection is also not necessary. - // @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy::processPlaceholders - 'system.modules_list', - ]; - if (in_array(\Drupal::routeMatch()->getRouteName(), $excluded_routes)) { + // Routes that don't use BigPipe also don't need no-JS detection. + if (\Drupal::routeMatch()->getRouteObject()->getOption('_no_big_pipe')) { return; } @@ -64,8 +56,7 @@ function big_pipe_page_attachments(array &$page) { '#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(), + 'content' => '0; URL=' . Url::fromRoute('big_pipe.nojs', [], ['query' => \Drupal::service('redirect.destination')->getAsArray()])->toString(), ], ], 'big_pipe_detect_nojs', diff --git a/big_pipe.services.yml b/big_pipe.services.yml index 9a78385..9209fc0 100644 --- a/big_pipe.services.yml +++ b/big_pipe.services.yml @@ -19,6 +19,11 @@ services: 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 } + # @todo Move this into Drupal 8 core. cache_context.session.exists: class: Drupal\big_pipe\Cache\Context\SessionExistsCacheContext diff --git a/src/EventSubscriber/NoBigPipeRouteAlterSubscriber.php b/src/EventSubscriber/NoBigPipeRouteAlterSubscriber.php new file mode 100644 index 0000000..973c2c5 --- /dev/null +++ b/src/EventSubscriber/NoBigPipeRouteAlterSubscriber.php @@ -0,0 +1,53 @@ + refresh to work without JavaScript. + 'system.batch_page.html', + // When a user would install the BigPipe module using a browser and with + // JavaScript disabled, the first response contains the status messages + // for installing a module, but then the BigPipe no-JS redirect occurs, + // which then causes the user to not see those status messages. + // @see https://www.drupal.org/node/2469431#comment-10901944 + 'system.modules_list', + ]; + + $route_collection = $event->getRouteCollection(); + foreach ($no_big_pipe_routes as $excluded_route) { + if ($route = $route_collection->get($excluded_route)) { + $route->setOption('_no_big_pipe', TRUE); + } + } + } + + /** + * {@inheritdoc} + */ + static function getSubscribedEvents() { + $events[RoutingEvents::ALTER][] = ['onRoutingRouteAlterSetNoBigPipe']; + return $events; + } + +} diff --git a/src/Render/Placeholder/BigPipeStrategy.php b/src/Render/Placeholder/BigPipeStrategy.php index 3a81b76..e24c9ad 100644 --- a/src/Render/Placeholder/BigPipeStrategy.php +++ b/src/Render/Placeholder/BigPipeStrategy.php @@ -110,12 +110,8 @@ class BigPipeStrategy implements PlaceholderStrategyInterface { * {@inheritdoc} */ public function processPlaceholders(array $placeholders) { - // Don't apply the BigPipe placeholder strategy on the module installation - // page. When a user would install the BigPipe module using a browser that - // has JavaScript disabled, the status messages shown immediately after - // installing the module would get lost. - // @see https://www.drupal.org/node/2469431#comment-10901944 - if ($this->routeMatch->getRouteName() === 'system.modules_list') { + // Routes can opt out from using the BigPipe HTML delivery technique. + if ($this->routeMatch->getRouteObject()->getOption('_no_big_pipe')) { return []; } diff --git a/src/Tests/BigPipeTest.php b/src/Tests/BigPipeTest.php index f44844b..d4cbf88 100644 --- a/src/Tests/BigPipeTest.php +++ b/src/Tests/BigPipeTest.php @@ -91,6 +91,8 @@ class BigPipeTest extends WebTestBase { $this->assertRaw(''); $this->assertBigPipeNoJsMetaRefreshRedirect(); $this->assertBigPipeNoJsCookieExists(TRUE); + $this->assertNoRaw(''); $this->assertBigPipeNoJsMetaRefreshRedirect(); $this->assertBigPipeNoJsCookieExists(TRUE); + $this->assertNoRaw('