カスタムプラグインページでの補完機能のコーディングとリファクタリングが一段落し、実際に読み込んで動作をテストしました。
ページに読み込む上でカスタムプラグインページはPC/スマートフォン/タブレットというそれぞれに対応した静的ファイルがあったので、そこでスクリプトを読み込んでいたのですが、本番環境などに移植する際極力ファイルの更新は少ないほうが良いと思ったので、まず3つのページ全てで経由しているコントローラーでスクリプトを読み込むか振り分けました。
```php
if (preg_match('/setup\/plugin/', $this->getRequest()->getRequestUri())) {
/** 読み込みの処理 */
}
```
カスタムプラグインを作成するページはブログの環境設定を行う`/setup`に属していて、`/setup`にはカスタムプラグイン以外を設定するページもあるので、`plugin`に関係するページだけでスクリプトを読み込むようにします。
これで各々の静的ファイルに直接書いていたスクリプトタグが1箇所にまとめることができます。
## スクリプトをheadで読み込む問題点
カスタムプラグインページでは追加で補完機能のスクリプトを読み込むわけですが、補完機能にはDOMの要素を取得するコードがふんだんに使われています。
通常ZendFrameworkは`$this->view->headScript()->appendFile()`といったようにheadタグ内にJavaScriptを書き加えるのですが、HTMLは上から順にDOMを構築していく上で、スクリプトファイルに到達するとJavaScriptの処理を行うため以降のDOM構築の阻害になります。
結果としてユーザには真っ白なページが数秒ほど表示されることとなり、UXの観点からしてよくない上に、スクリプトでDOMの要素を取得しようとしているのに、DOMが構築されていないためエラーが発生することにもなります。
そのため現在スクリプトタグを書くときはbody閉じタグの上(描画に関係する要素の一番下)に書くことが推奨されていますが、headタグの中に書いても`async/defer`属性をつけることでDOM構築を阻害せず読み込むことが可能です。
参考:[script タグに async / defer を付けた場合のタイミング - Qiita](https://qiita.com/phanect/items/82c85ea4b8f9c373d684)
## ZendFrameworkでdefer読み込みをする
ZendFrameworkでは以下のようにして`async/defer`属性を付与します。
```php
$this->headScript()->setAllowArbitraryAttributes(true);
$this->view->headScript()->appendFile('//js/hoge.js', null, array('defer' => 'true'));
```
参考:[javascript - Add attribute attributes while appending a js file using headscript() - Stack Overflow](https://stackoverflow.com/questions/24857569/add-attribute-attributes-while-appending-a-js-file-using-headscript)
デフォルトではスクリプトタグに属性が付与できないため、付与を可能にし、第三引数に連想配列で属性をセットします。