You are here

public function AmpCssCollectionRenderer::render in Accelerated Mobile Pages (AMP) 8.3

Renders an asset collection.

Parameters

array $assets: An asset collection.

Return value

array A render array to render the asset collection.

Overrides CssCollectionRenderer::render

File

src/Asset/AmpCssCollectionRenderer.php, line 102

Class

AmpCssCollectionRenderer
Renders CSS assets.

Namespace

Drupal\amp\Asset

Code

public function render(array $css_assets) {

  // Retrieve the normal css render array.
  $elements = parent::render($css_assets);

  // Intervene only if this is an AMP page.
  if (!$this->ampService
    ->isAmpRoute()) {
    return $elements;
  }

  // See if relative file rewrites are needed. They are needed only if the
  // css has not already been aggregated.
  $config = $this->configFactory
    ->get('system.performance');
  $needs_rewrite = empty($config
    ->get('css.preprocess'));

  // For tracking the size and contents of the inlined css:
  $size = 0;
  $files = [];
  foreach ($elements as $key => $element) {

    // This element contains @import values for the css files.
    if ($element['#tag'] == 'style' && array_key_exists('#value', $element)) {

      // Now split all the @imports into individual items so we can count,
      // load, and concatenate them.
      $urls = preg_match_all('/@import url\\("(.+)\\?/', $element['#value'], $matches);
      $all_css = [];
      foreach ($matches[1] as $url) {

        // Skip empty and missing files.
        if ($css = @file_get_contents(DRUPAL_ROOT . $url)) {
          if ($needs_rewrite) {
            $css = $this
              ->doRewrite($url, $css);
          }
          $css = $this
            ->strip($css);
          $size += strlen($css);
          $all_css[] = $css;
          $files[] = [
            $this
              ->format(strlen($css)),
            $url,
          ];
        }
      }

      // Implode, wrap in @media, and minify results.
      $value = implode("", $all_css);
      $value = '@media ' . $element['#attributes']['media'] . " {\n" . $value . "\n}\n";
      $value = $this
        ->minify($value);
      $value = $this
        ->strip($value);
      $element['#value'] = $value;
      $elements[$key] = $element;
      $elements[$key]['#merged'] = TRUE;
    }
    elseif ($element['#tag'] == 'link' && array_key_exists('href', $element['#attributes'])) {
      $url = $element['#attributes']['href'];
      $provider = parse_url($url, PHP_URL_HOST);
      if (!empty($provider)) {

        // External files rendered as links only if they are on the whitelist.
        if (!in_array($provider, $this->linkDomainWhitelist)) {
          unset($elements[$key]);
        }
      }
      else {

        // Strip any querystring off the url.
        if (strpos($url, '?') !== FALSE) {
          list($url, $query) = explode('?', $url);
        }
        $css = file_get_contents(DRUPAL_ROOT . $url);
        if ($needs_rewrite) {
          $css = $this
            ->doRewrite($url, $css);
        }
        $css = $this
          ->strip($css);
        $size += strlen($css);
        $all_css[] = $css;
        $files[] = [
          $this
            ->format(strlen($css)),
          $url,
        ];
        $element['#value'] = $css;
        $elements[$key] = $element;
        $elements[$key]['#merged'] = TRUE;
      }
    }
  }

  // Merge the inline results into a single style element with an
  // "amp-custom" attribute, using the amp_custom_style #type.
  $merged = '';
  $replacement_key = NULL;
  foreach ($elements as $key => $element) {
    if (isset($element['#merged'])) {
      $merged .= $element['#value'];
      unset($elements[$key]);

      // The first key found will become the new element's key.
      if (empty($replacement_key)) {
        $replacement_key = $key;
      }
    }
  }
  $elements[$replacement_key] = [
    '#tag' => 'style',
    '#type' => 'amp_custom_style',
    '#value' => $merged,
  ];

  // Display info about inline css if #development=1 is appended to url.
  if ($this->ampService
    ->isDevPage()) {
    $title = 'CSS Filesize';
    $difference = $size - 50000;
    $over = $difference > 0 ? t('so your css is :difference too big', [
      ':difference' => $this
        ->format(abs($difference)),
    ]) : '';
    $under = $difference <= 0 ? t('so you have :difference to spare', [
      ':difference' => $this
        ->format(abs($difference)),
    ]) : '';
    $output = t('The size of the css on this page is :size. The AMP limit is :limit, :overunder. The included css files and their sizes are listed for ease in finding large files to optimize. For the best information about individual file sizes, visit this page while optimization is turned off.', [
      ':size' => $this
        ->format($size),
      ':limit' => $this
        ->format(50000),
      ':overunder' => $over . $under,
    ]);
    $build = [
      '#type' => 'table',
      '#header' => [
        'Size',
        'File',
      ],
      '#rows' => $files,
    ];
    $table = $this->renderer
      ->renderRoot($build);
    if ($difference > 0) {
      $this->ampService
        ->devMessage($title, 'addError');
      $this->ampService
        ->devMessage($output, 'addError');
      $this->ampService
        ->devMessage($table, 'addError');
    }
    else {
      $this->ampService
        ->devMessage($title);
      $this->ampService
        ->devMessage($output);
      $this->ampService
        ->devMessage($table);
    }
  }
  return $elements;
}