@include
を利用して呼び出せるコンポーネントを作成する際、JSとCSSの記述方法について迷ったのでどのような方法が良いのか検討してみました。
最初に作成したコンポーネント
最初は以下のようなコンポーネントを作成しました。
<div>
<button type="button"></button>
<div>ポップアップ</div>
</div>
<script>
jsの処理
</script>
<style>
cssの記述
</style>
上記コンポーネントを以下のように@include
を利用して特定ページのbladeファイルに設置します。
~ 省略 ~
<div>
<p>投稿内容を記述してください</p>
</div>
@include('popup-component')
<div>
<textarea></textarea>
</div>
~ 省略 ~
上記のようにすると、HTMLが生成された際にscriptタグやstyleタグがbodyの途中に存在することとなりパフォーマンスや可読性的にもあまり良くないのかなと思いました。
そこで、popup-componentにて@section
を利用することで、レイアウトファイルの@yield
で設定したbodyの閉じタグ前に設置できるか試みました。しかし、@section
の使用上、ページファイルのJSがコンポーネントのJSで上書きされてしまいました。
改善したコンポーネント
上記を踏まえてコンポーネントはHTMLのみに変更しました。
<div>
<button type="button"></button>
<div>ポップアップ</div>
</div>
上記コンポーネントを以下のように@include
を利用して特定ページのbladeファイルに設置します。JSやCSSをそれぞれ用意して呼び出します。
@extends('layouts')
~ 省略 ~
@section('style')
<link href="{{ asset('css/popup-component.css')}}" rel="stylesheet">
@endsection
~ 省略 ~
<div>
<p>投稿内容を記述してください</p>
</div>
@include('popup-component')
<div>
<textarea></textarea>
</div>
~ 省略 ~
@section('script')
<script src="{{ asset('js/popup-component.js') }}"></script>
@endsection
~ 省略 ~
JSやCSSの読み込み位置としては問題ないが、「ポップアップを出す」という要件のために複数ファイルを読み込まないといけないのは残念だなと感じました。
@stack
と@push
を利用
@stack
と@push
を利用することで上記問題点を解決できました。@push
はsectionと異なり何度でも追加できるとのことで複数のコンポーネントを読み込む場合も柔軟性がありそうです。
<div>
<button type="button"></button>
<div>ポップアップ</div>
</div>
@push('component-css')
<script>
jsの処理
</script>
@endpush
@push('component-js')
<style>
cssの記述
</style>
@endpush
@extends('layouts')
~ 省略 ~
<div>
<p>投稿内容を記述してください</p>
</div>
@include('popup-component')
<div>
<textarea></textarea>
</div>
~ 省略 ~
~ 省略 ~
@yield('style')
@stack('component-css')
</head>
~ 省略 ~
<div>
<p>レイアウト</p>
</div>
~ 省略 ~
@yield('script')
@stack('component-js')
</body>
~ 省略 ~
現状、同一処理の記述が複数箇所に散らばっているので、今後やってくるNext.jsへの移行に備えて、関連するHTML、CSS、JSをまとめていい感じにコンポーネント化できないかと考えていました。@stack
と@push
を利用したコンポーネント化は相性が良さそうです。
参考文献