You can exclude a block from BigPipe by disabling placeholdering in the block build (preprocess is too late).
/**
* Implements hook_block_build_BASE_BLOCK_ID_alter().
*/
function mymodule_block_build_example_block_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Disable placeholdering of this block.
$build['#create_placeholder'] = FALSE;
}
But if this is one of the blocks always having a delay it could make the entire module BigPipe useless.
You can solve the content shift in CSS. Delay or stop the block rendering (in this case you can use preprocess) and fill the gap in the partially loaded page with CSS.
Or make the header block more granular. When all dynamic parts are placeholdered the rest of the block is cacheable and loads with the initial page load.
Example block:
public function build() {
$build = [];
$build[] = [
'#markup' => '<p>Static part of the block, loads with the initial page.</p>',
];
$build[] = [
'#lazy_builder' => ['\Drupal\mymodule\LazyBuilders::getUser', []],
'#cache' => ['contexts' => ['user']],
// contexts user, session or max-age 0 are automatically placeholdered
];
return $build;
}
/src/LazyBuilders.php:
<?php
namespace Drupal\mymodule;
use Drupal\Core\Render\Element\RenderCallbackInterface;
class LazyBuilders implements RenderCallbackInterface {
public static function getUser() {
return [
'#markup' => \Drupal::currentUser()->getDisplayName(),
];
}
}