Vue.jsのコンポーネントをWebComponents化してみる

きょうはVue.jsのコンポーネントをWebComponents化してみたよという話をば。

どうやって

WebComponents化しておけば、カスタム要素とJSをひとつ置けば、かんたんに任意のVue.js製コンポーネントを配置できるので便利そう~ということでお試ししてみました。

コンポーネント化には「vue-web-component-wrapper」をつかいます。 github.com

まずはインストールをば。

npm install --save-dev @vue/web-component-wrapper

あとは、コンポーネント化したいものを wrap して、カスタム要素を登録すれば完了です。

import Vue from 'vue'
import Player from 'src/player/player.vue'
import wrap from '@vue/web-component-wrapper'

const CustomElement = wrap(Vue, Player)
window.customElements.define('map-player', CustomElement)

これで、HTMLを書いてゆけば、任意のVue.jsなコンポーネントを気軽に置くことができました。Props もちゃんとカスタム要素の属性として記述できます。べんり。

<map-player mapid="1"></map-player>
<!-- スクリプトはDOMが出来上がったら読まれるようにする -->
<!-- ref: https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_custom_elements -->
<script src="/player.bundle.js"></script>

とおもいきや、なんだか思ったようにスタイルが当たらない...。これは、 vue-style-loaderhead 要素の中にビルドしたスタイルを差し込むためのようなので(WebComponents配下はShadow DOMでスタイルが分離される)、以下のようにloaderを設定し、WebComponentsのShadowDOM配下にスタイルタグが差し込まれるようにします。(Webpackでビルドされる前提)

/* webpack.config.js */

{
  // ... 省略...
  {
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
      shadowMode: true
    },
  }
 {
    test: /\.css$/,
    use: [
      {
        loader: 'vue-style-loader',
        options: {
          shadowMode: true
        }
      },
      'css-loader',
    ]
  }
}

めでたしめでたし。

(ちなみに、「vue-web-component-wrapper」をつかわずに、 HTMLElement を継承したクラスでVueインスタンスを作成し、window.customElements.define する方法も試してみましたが、どうもスタイルをShadowDOMに入れ込む周りで苦戦して、とりあえずあきらめたのでした。)

なんのために

わたしのポートフォリオサイトをつくりたい(正確にはつくりなおしたい)と思い、せっかくなので「みんなでつくるダンジョン」のマップをポートフォリオサイトに埋め込みたいなと思ったのでした。そこで、Vue.js製マップ表示+たんけんコンポーネントをWebComponents化すれば、気軽にマップを張り付けられるじゃん~と思いついてやってみたのでした。

ではでは~。