🖇️

Vite の vanilla-ts テンプレートで生成したプロジェクトで vite-plugin-handlebars を利用する

2023/03/08に公開

https://zenn.dev/key_luvless/scraps/c5931340e06862

上記スクラップを記事としてリライト

状況

npm create vite@latest ${PROJECT_NAME} -- --template vanilla-ts
という感じで vanilla, vanilla-ts で生成したプロジェクトにて。

テンプレートを使って値を埋め込みたい、とかは不要で、長大になってしまった index.html を別ファイルに分割し、index.html で include したい、といったことへの対応したい。また、できるだけプラグインの設定などもシンプルなものが良い、という観点で調べてみた。

調査

vite import partial html でググった最初に出てきた Stack Overflow

https://stackoverflow.com/questions/70818545/how-to-include-html-partials-using-vite

そうそう。そーゆーことがしたい。
回答にあったのは以下 2 点。

  • vite-plugin-handlebars
  • vite-plugin-html

上記で紹介されていたプラグインは Awesome Vite.js の Plugins > Transformers にも記載あり。

https://github.com/vitejs/awesome-vite#transformers

せっかくなのでほかもざっと眺めてみて、結果、以下の 3 つが良いかなー、という感じになった。

  • vite-plugin-handlebars
  • vite-plugin-html
  • vite-plugin-html-inject

比較

プラグイン同士の比較と、、、

vite-plugin-handlebars vite-plugin-html
source https://github.com/alexlafroscia/vite-plugin-handlebars https://github.com/vbenjs/vite-plugin-html
npm https://www.npmjs.com/package/vite-plugin-handlebars https://www.npmjs.com/package/vite-plugin-html
Weekly Downloads 2,492 142,397
Version 1.6.0 3.2.0
License MIT MIT
Unpacked Size 50.8 kB 25.4 kB
Total Files 10 5
Issues 8 47
Pull Requests 6 13
Last publish 2 years ago a year ago

プラグインで利用しているテンプレートエンジンの利用状況など、、、

https://handlebarsjs.com https://ejs.co
source https://github.com/handlebars-lang/handlebars.js https://github.com/mde/ejs
npm https://www.npmjs.com/package/handlebars https://www.npmjs.com/package/ejs
Weekly Downloads 11,700,707 11,666,499
Version 4.7.7 3.1.8
License MIT Apache-2.0
Unpacked Size 2.72 MB 140 kB
Total Files 118 13
Issues 66 90
Pull Requests 18 11
Last publish 2 years ago 10 months ago

あと vite-plugin-html-inject で、こちらは依存なしのためプラグイン自体の数値のみ。

vite-plugin-html-inject
source https://github.com/donnikitos/vite-plugin-html-inject
npm https://www.npmjs.com/package/vite-plugin-html-inject
Weekly Downloads 3,016
Version 1.0.1
License MIT
Unpacked Size 9.77 kB
Total Files 6
Issues 1
Pull Requests 0
Last publish 3 months ago

検証・結果

./index.html./src/partials/header.html がある想定で試してみる。

vite-plugin-html-inject

Plugin 設定したら ./index.html に以下のように記載するのみ。

index.html
<load ="src/partials/header.html" />

なのだが、やはり属性名が無い感じの記述がすごく気になる。
実装としては <load> タグを置換しているだけなので、

index.html
<load foo="src/partials/header.html" />

という感じに、適当な属性名(上記では foo )を設定しても動くが、それもそれでなんとなく気になる感じではある。結果、以下の点などから採用を見送った。

  • <load> というタグ名が汎用にすぎないか
    => たとえばカスタム要素みたいに <load-partials> とかになっててもよいのではないか
  • 属性名無しで値あり、みたいな記述が構文的に気になる
    => src とかじゃだめだったのだろうか
  • 閉じタグ </load> を書いてしまうとそれ以後の他のタグの表示がおかしくなる
    => エディタで自動補完とかされちゃうといきなり表示崩れたりするのが少しイヤ

しかし今回の要件は満たしてくれるし、ミニマムで個人的にはかなり好き。
残念。

vite-plugin-html

利用数は今回の 3 つで一番多そうで、できることも多そうな印象なんだけど、逆に設定がなんだか面倒そうだな、と思っていた。

結果 <%- include('/src/partials/header.html'); %> と書いても
ENOENT: no such file or directory, open '/src/partials/header.html' と、なんかうまく行かず、設定いじったりパス変えて試してみたけど途中で面倒になって、んじゃもう 1 つの vite-plugin-handlebars を試すか、となって検証やめた。

vite-plugin-handlebars

結局 Stack Overflow で最初に見たものを採用することとした。
プラグインの設定が不要だった vite-plugin-html-inject に比べて設定が必要になる、とはいえ実際は以下の記述だけだし。

vite.config.js
// vite.config.js
import { resolve } from 'path';
import handlebars from 'vite-plugin-handlebars';

export default {
  plugins: [
    handlebars({
      partialDirectory: resolve(__dirname, 'src/partials'),
    }),
  ],
};

https://github.com/alexlafroscia/vite-plugin-handlebars#partials

というわけで今回は vite-plugin-handlebars を採用することとした。

注意点

ただし以下の箇所に記載の内容に注意が必要。

https://github.com/alexlafroscia/vite-plugin-handlebars#quirks

Assets included in a partial using a relative path will probably not work how you would first expect; the relative path is left alone, making it relative to the output file, not the partial itself. It's recommended that you use the resolve-from-root helper to ensure paths are resolved from the project root, rather than relative to a particular file.

相対パスを使ってパーシャルに含まれるアセットは、おそらく最初に期待したようには動作しません。相対パスは放置され、パーシャル自体ではなく、出力ファイルに対する相対パスとなります。相対パスはそのままで、パーシャル自体ではなく出力ファイルへの相対パスとなります。特定のファイルへの相対パスではなく、プロジェクトルートからのパスを確実に解決するために resolve-from-root ヘルパーを使用することをお勧めします。

というわけで resolve-from-root を使ってみたが、うまくいく場合とうまく行かずにローカル環境のフルパスが展開されてしまうパターンがあったため、結果としては、

相対パスはそのままで、パーシャル自体ではなく出力ファイルへの相対パスとなります。

という形で対応とすることとする。
つまり以下のような構成の場合、

.
├── index.html
└── src
    ├── logo.jpg
    └── partials
        └── header.html
  • ./index.html./src/partials/header.html をインクルード
  • ./src/partials/header.html 内に <img> タグを配置
  • <img> タグには ./src/logo.jpg を表示したい

といった場合、 src の値は
./src/partials/header.html からの相対パス ../logo.jpg ではなく、
./index.html からの相対パス ./src/logo.jpg となる。

Discussion