【Drupal】モジュールでCSSやJavascriptを読み込んで使用する

こちらのサイトではDRUPAL10に関連する記事を掲載しています。

本記事は下記のDrupal公式リファレンスを翻訳しています。

*.libraries.yml を介して Drupal モジュールにアセット (CSS、JS) を追加する

はじめに

このドキュメントはモジュール用です。 テーマについては、 「Drupal テーマへのスタイルシート (CSS) と JavaScript (JS) の追加」を参照してください。

Drupal 8 以降のバージョンでは、スタイルシート (CSS) と JavaScript (JS) は、モジュール (コード) とテーマ、アセット ライブラリなどすべての同じシステムを通じてロードされます。 アセット ライブラリには、1 つ以上の CSS アセット、1 つ以上の JS アセット、および 1 つ以上の JS 設定を含めることができます。

Drupal は高レベルの原則を使用します。アセット (CSS または JS) は、Drupal にロードするように指示した場合にのみロードされます。 Drupal は、フロントエンドのパフォーマンスに悪影響を与えるため、すべてのアセット (CSS/JS) をすべてのページにロードしません。

プロセス

アセット (CSS/JS) をロードする一般的な手順は次のとおりです。

  1. CSS または JS をファイルに保存します。
  2. CSS ファイルと JS ファイルの両方を含めることができる「ライブラリ」を定義します。
  3. フック内のレンダー配列にライブラリを「アタッチ」します。

ただし、テーマの場合は、ステップ 3 の代替手段があります。テーマは、 すべてのページに任意の数のアセット ライブラリをロードすることを選択できます。

ライブラリの定義

1 つ以上の (アセット) ライブラリを定義するには、 *.libraries.ymlファイルをモジュール フォルダーのルートに (.info.yml ファイルと一緒に) 追加します。 (モジュールの名前が fluffinessの場合、ファイル名は次のようになります。 fluffiness.libraries.yml)。 ファイル内の各「ライブラリ」は、次のような CSS および JS ファイル (アセット) の詳細を示すエントリです。
 

cuddly-slider:
  version: 1.x
  css:
    layout:
      css/cuddly-slider-layout.css: {}
    theme:
      css/cuddly-slider-theme.css: {}
  js:
    js/cuddly-slider.js: {}

CSS には「layout」キーと「theme」キーがあり、js には存在しないことに気づくかもしれません。 これは、CSS ファイルが属するスタイル タイプを示します。

設定できます CSS5 つの異なるレベルのスタイルを備えたウェイト:

  • base: CSS のリセット/正規化と HTML 要素のスタイル設定。 キーは次の重みを割り当てます CSS_BASE = -200
  • layout: グリッド システムを含む、Web ページのマクロ配置。 キーは次の重みを割り当てます CSS_LAYOUT = -100
  • component: 個別の再利用可能な UI 要素。 キーは次の重みを割り当てます CSS_COMPONENT = 0
  • state: コンポーネントに対するクライアント側の変更を処理するスタイル。 キーは次の重みを割り当てます CSS_STATE = 100
  • theme: コンポーネントの純粋に視覚的なスタイル (「ルック アンド フィール」)。 キーは次の重みを割り当てます CSS_THEME = 200

標準によって定義されています これはSMACSS。 したがって、ここでテーマを指定すると、CSS ファイルには純粋なルック アンド フィールであるテーマ関連のスタイルが含まれることになります。 詳細については、こちらをご覧ください。 。 使用できません 他の キーを使用すると厳しい警告が発生するため、

この例では、実際の JavaScript が cuddly-slider.jsサブフォルダーにあります jsあなたのモジュールの。 外部 URL から JS を取得したり、CSS ファイルを含めたりすることもできます。その他の可能性もあります。 参照してください 詳細については、「CDN / 外部でホストされるライブラリ」を

ただし、Drupal はデフォルトですべてのページに jQuery をロードしなくなったことに注意してください。 Drupal は必要なものだけを読み込みます。 したがって、モジュールの cuddly-sliderlibrary は、 依存関係を宣言します jQuery を含むライブラリへの 。 これは jQuery を提供するモジュールでもテーマでもありません。Drupal コアです。 core/jqueryは宣言したい依存関係です。 (これは、拡張子の後にスラッシュが続き、その後にライブラリ名が続きます。そのため、他のライブラリが私たちのライブラリに依存したい場合は、 cuddly-sliderライブラリの場合、依存関係を宣言する必要があります fluffiness/cuddly-slider、 なぜなら fluffinessはモジュールの名前です。)

したがって、jQuery が確実に利用できるようにするには、 js/cuddly-slider.js、上記を次のように更新します。

cuddly-slider:
  version: 1.x
  css:
    theme:
      css/cuddly-slider.css: {}
  js:
    js/cuddly-slider.js: {}
  dependencies:
    - core/jquery

ご想像のとおり、CSS および JS アセットがリストされる順序は、それらがロードされる順序でもあります。

ではデフォルト、Drupal はページの下部に JS アセットを添付して、DOM コンテンツの読み込みブロック、まだ読み込まれていないプレゼンス DOM 要素を必要とするコードの実行などの一般的な問題を回避します。 必要があります そのため、 JS アセットを <head> セクションに添付するオプションを使用してこれを行うことができます 。ヘッダー

cuddly-slider:
  version: 1.x
  header: true
  js:
    js/cuddly-slider.js: {}

これで、 js/cuddly-slider.js が ページのトップに添付されます

Js ではさらにカスタマイズすることもできます。

cuddly-slider:
  version: 1.x
  js:
    js/cuddly-slider.js: {
      minified: true,
      attributes: { id : "script-cuddly-slider" }
    }

minifiedすでに縮小されていることをコンパイラに示し、スキップします。
スクリプトに属性が必要な場合は、次を使用して属性を追加できます。 attributesそして、置きます idまたは内部のカスタム属性
他にもありますが、最も一般的な用途です。

ライブラリをページにアタッチする

どのアセットをロードする必要があるかに応じて、対応するアセット ライブラリを別の方法でアタッチする必要があります。 結局のところ、すべてのページで必要なアセット ライブラリもあれば、ごくまれに必要なアセット ライブラリもあれば、すべてではなくてもほとんどのページで必要なアセット ライブラリもあります。

)に基づいてライブラリをアタッチするかどうかを決定するのではなく、 しかし、最も重要なことは、現在どのページにいるか (つまり、どの URL または Route かに基づいてライブラリをアタッチするかどうかを決定することです。 ものそのページに表示されている '#type' => 'table''#type' => 'dropbutton'そして '#type' => 'foobar'、その後、それらのそれぞれに関連付けられたライブラリのみをロードします '#type's.
しかし、これに限定されません。 '#type'アセット ライブラリを、 のみ: おそらく、特定'#type'。 その場合は、そのインスタンスのレンダー配列にアタッチするだけです。

もちろん、 ごくまれに、ページ上の「もの」に関係なく、すべてのページに特定のアセットを実際に読み込む正当な理由があることがあります (たとえば、ページの読み込みを追跡する一部の分析 JavaScript)。

ここのサブセクションでは、これらのことを行う方法の例を示します。

特定のものに執着する '#type'(すべてのインスタンスに対して)

ライブラリを特定の既存のライブラリにアタッチするには '#type'、そのすべてのインスタンスに対して、次を使用します。 hook_element_info_alter():

function yourmodule_element_info_alter(array &$types) {
  if (isset($types['table'])) {
    $types['table']['#attached']['library'][] = 'your_module/library_name';
  }
}

次に、 キャッシュをクリアします。追加した新しいフック実装を Drupal が認識できるように

レンダー配列へのアタッチ

ライブラリをレンダー配列 (およびおそらくは特定のインスタンスの特定のインスタンス) にアタッチするには '#type')、そのレンダー配列にアクセスできる必要があります。 おそらく、レンダリング配列を定義しているのでしょう。 おそらくフック内で変更している可能性があります。 いずれの場合も、次のようになります。

$build['the_element_that_needs_the_asset_library']['#attached']['library'][] = 'your_module/library_name';

ライブラリには数値以外のキーを使用しないでください

Drupal を支援し、数値以外のキーを使用して重複したライブラリ エントリを生成しないようにしたい場合があります。

// Do NOT do this:
$build['the_element_that_needs_the_asset_library']['#attached']['library']['your_module/library_name'] = 'your_module/library_name';

その理由は、Drupal の配列を結合する方法により、無効なネストされた配列が生成され、次のような通知が表示されるためです (googlefood):

Warning: explode() expects parameter 2 to be string, array given in Drupal\Core\Asset\LibraryDependencyResolver->doGetDependencies()
Notice: Array to string conversion in system_js_settings_alter()
Notice: Array to string conversion in Drupal\Core\Asset\AttachedAssets->setLibraries()

ブロック プラグインのレンダー配列にアタッチする

ライブラリをレンダー配列にアタッチする別の例を挙げると、モジュール内でブロック プラグインを構築している場合は、BlockBase クラス (Drupal 以降) を拡張するクラスの build() 関数でライブラリをレンダー配列にアタッチできます。 8ベータ6)。

    return [
      '#theme' => 'your_module_theme_id',
      '#someVariable' => $some_variable,
      '#attached' => [
        'library' => [
          'your_module/library_name',
        ],
      ],
    ];

ライブラリをフォームにアタッチする

フォームは単なるレンダリング配列であるため、ライブラリのアタッチはまったく同じように機能します。

/**
 * Implements hook_form_alter().
 */
function yourmodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  /* @var Drupal\Core\Entity\FieldableEntityInterface $entity */
  $formObject = $form_state->getFormObject();
  if ($formObject instanceof \Drupal\Core\Entity\EntityFormInterface) {
    $entity = $formObject->getEntity();
    if (
      $entity->getEntityTypeId() === 'node'
      && in_array($entity->bundle(), ['organisation', 'location', 'event', 'article'])
    ) {
      $form['#attached']['library'][] = 'yourmodule/yourlibrary';
    }
  }
}

 ライブラリをビューにアタッチする

フックを追加できます .moduleファイルまたは .themeファイル:

// Top of the file.
use Drupal\views\ViewExecutable;

// ...

/**
* Implements hook_views_pre_render().
*/
function yourmodule_views_pre_render(ViewExecutable $view) {
  if (isset($view) && ($view->storage->id() == 'super_awesome_view')) {
    $view->element['#attached']['library'][] = 'custom/custom_view';
  }
}

すべてのページ (または一部のページ) にライブラリをアタッチする

場合によっては、アセット ライブラリはページ全体に関連付けられているため、ページの特定の部分に関連付けられていないことがあり ます。 この場合、 hook_page_attachments()存在します。 明確な例は、コンテキスト リンク モジュールにあります。

// From core/modules/contextual/contextual.module.
function contextual_page_attachments(array &$page) {
  if (!\Drupal::currentUser()->hasPermission('access contextual links')) {
    return;
  }

  $page['#attached']['library'][] = 'contextual/drupal.contextual-links';
}

*.info.yml を介してすべてのページにライブラリをアタッチする

これは通常、悪い習慣と考えられていますが、 fluffiness.info.ymlファイルに次の内容を含めます:

# Available to every page presented by the theme libraries: - fluffiness/cuddly-slider

前処理関数でのライブラリのアタッチ

特殊キーを使用して、前処理関数でライブラリをアタッチできます。 '#attached':

function yourmodule_preprocess_maintenance_page(&$variables) {
  $variables['#attached']['library'][] =  'your_module/library_name';
}

小枝テンプレートにライブラリをアタッチする

また、attach_library() 小枝関数を使用して、小枝テンプレートにライブラリを添付することもできます。 したがって、任意の *.html.twig では次のようになります。

{{ attach_library('your_module/library_name') }}
<div>Some markup {{ message }}</div>

トークン置換時のライブラリのアタッチ

フィルターされたテキストにカスタム トークンが存在する場合は、hook_tokens() での置換中にライブラリを BubbleableMetadata オブジェクトに追加することで、ライブラリをアタッチすることもできます。

/**
 * Implements hook_tokens().
 */
function your_module_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
    $replacements = [];
    if ($type == 'your_module') {
        foreach ($tokens as $name => $original) {
            switch ($name) {
                case 'your-token':
                    $your_render_array = your_module_build_your_renderable_thing();
                    $replacements[$original] =  \Drupal::service('renderer')->render($your_render_array);
                    // LOOK HERE! WE CAN ADD LIBRARIES TOO!
                    $bubbleable_metadata->addAttachments(['library' => ['your_module/library_name'] ]);
                break;
            }
        }
    }

    return $replacements;
}

この例は、置換中にライブラリの添付を行う方法のみを示していることに注意してください。カスタム トークンを完全に実装するには、hook_token_info() も実装する必要があります。

フィルタープラグインでのライブラリのアタッチ

モジュールがテキスト フィルターを提供する場合は、 setAttachments()また addAttachments()クラスのメソッド FilterProcessResult。 たとえば、 filter_captionフィルターはこれを行います:

    if (...) { ...
      $result->setProcessedText(Html::serialize($dom))
        ->addAttachments([
          'library' => [
            'filter/caption',
          ],
        ]);
    }

    return $result;

構成可能なJavaScriptの添付

場合によっては、計算された PHP 情報に依存するページに JavaScript を追加することが必要になる場合があります。 これは次のように行うことができます drupalSettings(Drupal 7 の後継 Drupal.settings)、JavaScript の設定オブジェクトとしてアクセスできる、PHP スクリプトで定義された設定の配列。

使用する場合 drupalSettingsライブラリでは、まず依存関係を宣言する必要があります。 core/drupalSettingsライブラリ定義で。

したがって、前の例のライブラリ定義は次のようになります。

cuddly-slider:
  version: 1.x
  js:
    js/cuddly-slider.js: {}
  dependencies:
    - core/jquery
    - core/drupalSettings

PHP ファイルで、必要な内容を渡すことができるようになりました。 drupalSettings私たちの図書館の隣にあります。 使用し 慣例により、 lowerCamelCaseモジュール名を設定のキーとして lowerCamelCase名をサブキーとして追加します。、ライブラリの

計算された値を渡したい場合 'foo''baz'PHP からこの例の JavaScript に変換すると、次のようになります。

$computed_settings = [
  'foo' => 'bar',
  'baz' => 'qux',
];

$build['#attached']['library'][] = 'your_module/library_name';
$build['#attached']['drupalSettings']['fluffiness']['cuddlySlider'] = $computed_settings;

それから cuddly-slider.jsアクセスできるようになります drupalSettings.fluffiness.cuddlySlider.foodrupalSettings.fluffiness.cuddlySlider.bazの値になります。 'bar''qux'それぞれ。

レンダリング配列は キャッシュされます。 計算値の性質とアタッチしているコンポーネントに応じて drupalSettingsを変更する必要がある場合があります に応じて、キャッシュ機能メタデータ

スクリプト要素への属性の追加

スクリプト タグに属性を追加する場合は、スクリプト URL に続く JSON に属性キーを追加する必要があります。 オブジェクト内で、属性キーの後に、スクリプトに新しいキーとして表示する属性名を追加します。 このキーの値が属性値になります。 その値が true に設定されている場合、属性は要素の値なしで単独で表示されます。

例えば:

https://maps.googleapis.com/maps/api/js?key=myownapikey&signed_in=true&libraries=drawing&callback=initMap:
  type: external
  attributes: { defer: true, async: true, data-test: map-link }

これにより、次のようなマークアップが生成されます。

<script src="https://maps.googleapis.com/maps/api/js?key=myownapikey&signed_in=true&libraries=drawing&callback=initMap" async defer data-test="map-link"></script>

集約の無効化

デフォルトでは、複数のローカル ファイルが可能な場合には集約されます。 ファイルに対してこれを無効にするには、その「前処理」フラグを false に設定します。

cuddly-slider:
  version: 1.x
  js:
    js/cuddly-slider.js: {preprocess: false}
  dependencies:
    - core/jquery
    - core/drupalSettings

CDN / 外部でホストされているライブラリ

ページの読み込み速度を向上させるために、CDN (コンテンツ配信ネットワーク) 上の外部にある JavaScript を使用することもできます。 これは、ライブラリを「外部」として宣言することで実行できます。 定義に外部ライブラリに関する情報を含めることもお勧めします。

angular.angularjs:
  remote: https://github.com/angular/angular.js
  version: 1.4.4
  license:
    name: MIT
    url: https://github.com/angular/angular.js/blob/master/LICENSE
    gpl-compatible: true
  js:
    https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js: { type: external, minified: true }

インラインJavaScript

インライン JavaScript は使用しないことを強くお勧めします。 代わりに、使用する JS をファイルにインラインで配置することをお勧めします。これにより、JavaScript をクライアント側でキャッシュできるようになります。 また、JavaScript コードをレビューして lint チェックすることもできます。 また、インライン JS は多くのサイトのコンテンツ セキュリティ ポリシーと競合し、モジュールがサイトで使用できなくなります。

マークアップを生成するインライン JavaScript

これは推奨されません。 代わりに JavaScript をファイルに配置します。 この例としては、広告、ソーシャル メディア共有ボタン、ソーシャル メディア リスト ウィジェットなどがあります。 これらはインライン JavaScript を使用します。 ただし、これらはサイトのコンテンツを装飾したり、インタラクティブにするものではなく、JavaScript を通じて外部コンテンツを取り込むものであるため、単なる特殊な種類のコンテンツ/マークアップです。

これらをカスタム ブロックに配置するか、Twig テンプレートに直接配置することもできます。

例えば:

<script type="text/javascript"><!--
ad_client_id = "some identifier"
ad_width = 160;
ad_height = 90;
//--></script>
<script type="text/javascript" src="http://adserver.com/ad.js"></script>
<a class="twitter-timeline" href="https://twitter.com/wimleers" data-widget-id="307116909013368833">Tweets by @wimleers</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

ページ全体に影響を与えるインライン JavaScript

インライン JavaScript は使用しないことを強くお勧めします。 ページ全体に影響を与えるインライン JavaScript の例としては、分析 (Google Analytics など) やホストされたフォント サービスなどがあります。 ページ全体に影響を与えるインライン JavaScript は、フロントエンド/スタイリング、または論理の 2 つのカテゴリのいずれかに分類できます。 これらのケースのほとんどは、ファイル内の JavaScript を修正し、設定を追加することで解決できます。

フロントエンド/スタイリング (ホストされたフォント サービスなど) の場合はテーマに属します。これについては、 「Drupal テーマへのスタイルシート (CSS) と JavaScript (JS) の追加」を参照してください。

もう 1 つの場合、JS はモジュールに属します。 適切なフック内 – おそらく hook_page_attachments()— 添付された HTML を定義する <HEAD>を使用してデータを 'html_head'キーを押します #attached財産:

function fluffiness_page_attachments(array &$attachments) {
  $attachments['#attached']['html_head'][] = [
    // The data.
    [
      '#type' => 'html_tag',
      // The HTML tag to add, in this case a <script> tag.
      '#tag' => 'script',
      // The value of the HTML tag, here we want to end up with
      // alert("Hello world!");.
      '#value' => 'alert("Hello world!");',
      // Set attributes like src to load a file.
      '#attributes' => ['src' => ''],

    ],
    // A key, to make it possible to recognize this HTML  element when altering.
    'hello-world',
  ];
}

動的に生成される CSS と JS

非常にまれな高度なケースでは、CSS と JS を動的に生成する必要がある場合があります。 「ダイナミクス」には 2 つのカテゴリがあります。

  1. 動的に構築されますが、複数のリクエストにわたって使用されます
  2. リクエストごとに動的に構築される

動的 CSS/JS が複数のリクエストにわたって使用される場合は、次のように使用できます。 hook_library_info_alter()ライブラリを変更して、動的/自動生成された CSS/JS を含めます。 Drupal コアの例は次のとおりです。 color_library_info_alter()。 使用するだけで hook_library_info_build()また hook_library_info_alter()ライブラリを追加しても、そのライブラリはページに自動的に表示されません。 上記のいずれかの手法を使用して、添付ファイル (ページまたは特定の要素のいずれか) として定義する必要があります。

動的 CSS/JS がリクエストごとに構築される場合、真に高度な領域に入ります。 これは難しいですが、それには十分な理由があります。リクエストごとの動的アセットは すべてのリクエストに対して構築する必要があるため、Drupal の速度が低下します。 私たちは Drupal の速度を低下させにくくしたいので、このための優れた API を提供しません。それはあなたにそれをしてほしくないからです。
それは可能ですが。 動的 JS の場合: 代わりに、構成可能な JavaScriptの使用を検討してください。ほとんどの場合、それがより良い選択です。 その後、ロジックはファイルに保存され (クライアント側で確認、リント、キャッシュが可能)、リクエストごとにそのファイル内のロジックを構成するための設定のみを生成する必要があります。 そして実際、これは動的 CSS にも使用できます。動的 CSS を次のようにアタッチします。 drupalSettingsそしてそれを JS ファイルにページに追加させます。
使用する場合 drupalSettingsさらに、JavaScript ファイルがオプションではない場合、まだ 1 つのオプションが残っています。 hook_page_attachments()に新しい値を追加します。 $page['#attached']['html_head']、次のいずれかを含みます。 <script>タグまたは <style>タグは、上記の「ページ全体に影響を与えるインライン JavaScript」セクションですでに示したとおりです。

動的ライブラリ定義用にhook_library_info_build()が追加されました

一部の高度なユースケース (手動でダウンロードする必要があるサードパーティ ライブラリを検出し、それらを Drupal アセット ライブラリ (ライブラリ API モジュールを考えてください) として公開するなど) では、追加のロジックを使用してライブラリを登録するために PHP コードを引き続き使用できるようにしたいと考えています。 。 それが理由です hook_library_info_build()追加されました

「動的」は「実行時」(つまり、すべてのリクエスト)を意味するものではないことに注意してください。これはパフォーマンスに悪影響を及ぼします。 動的に追加されたライブラリは、YML ファイルで定義されたライブラリと同様に、引き続きキャッシュされます。 つまり、上記のいずれかの手法を使用してライブラリをページまたは要素にアタッチする必要があります。 ロジックを使用してライブラリのこの接続を制御できるため、これは「動的」です。

Drupal 7 との違い

詳しくは

関連性のあるコンテンツ

*.libraries.yml を介して Drupal テーマにアセット (CSS、JS) を追加する

Drupal では、スタイルシート (CSS) と JavaScript (JS) は、モジュール (コード) とテーマ、すべての資産に対して同じシステムを通じて読み込まれます。

このサイトに関するご意見・ご質問はこちらまで

この記事またはDrupalに関するご質問がございましたら、お気軽にお問い合わせください。

タイトルとURLをコピーしました