morishitaです。
先日、Web Componentついて書きました。
多くのブラウザで動作できるようになってきていることは確認できました。
ただ、実装方法についてはもっと良い方法がないものかと思いました。
と思っていたら、Vue.jsが Web Components もサポートしているではないですか!
で、やってみました。
環境準備
手っ取り早く試すためにVue CLIを使います。 次のコマンドでインストールできます。
$ yarn global add @vue/cli
インストールできたらプロジェクトを作ります。
このエントリではvue-web-componentsという名前で作りますが、
なんでも構いません。
次のコマンドを実行するといろいろ質問されます。
$ vue create vue-web-components
今回は次の様に答えました。
? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, CSS Pre-processors, Linter ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass) ? Pick a linter / formatter config: Airbnb ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No
見ての通りTypescript で、class-style のコンポーネント実装を選択しました。
VueによるWeb Componentsのお試しなので、テスト系は選択しませんでした。そのあたりは必要に応じて選択してください。
ということで本エントリで示すコードはTypescriptとなります。
モジュールのインストール等が走るので終わるまで待ちます。
次のメッセージが表示されたら完了です。
🎉 Successfully created project vue-web-components. 👉 Get started with the following commands: $ cd vue-web-components $ yarn serve
指示に従って、yarn serve
でローカルサーバを立ち上げてみます。
Vue.jsを触ったことがあればおなじみのページが表示されればOKです。
出来上がったファイル群は次の通りです。
上のページは、src/App.vueが表示された結果です。
public/index.htmlでsrc/main.tsが読み込まれてsrc/App.vueがVueアプリケーションとして起動されます1。
Vueアプリケーションを起動するは src/main.ts のようなVueインスタンスを生成するコード(次のnew Vue(...)
の部分)が必要です。
import Vue from 'vue'; import App from './App.vue'; Vue.config.productionTip = false; new Vue({ render: h => h(App), }).$mount('#app');
VueアプリケーションをWeb Components化してみる
Vue CLIのドキュメントWeb ComponentにVueの単一ファイルコンポーネント(*.vue)を Web Component としてビルドする方法が記述されています。
それに従って、src/App.vue をWeb Component化してみます。
といっても次のコマンドを実行するだけです。
$ vue-cli-service build --target wc --name vue-app src/App.vue
この結果、次のファイル群が生成されます。
dist ├── demo.html ├── img │ └── logo.82b9c7a5.png ├── vue-app.js ├── vue-app.js.map ├── vue-app.min.js └── vue-app.min.js.map
dist/demo.html は次のとおりです。
<meta charset="utf-8"> <title>vue-app demo</title> <script src="https://unpkg.com/vue"></script> <script src="./vue-app.js"></script> <vue-app></vue-app>
とてもシンプルです。
先程、ビルドしたWeb Componentのコードであるvue-app.js を読み込み、カスタム要素<vue-app>
を表示しているだけです。
でこれをブラウザで表示してみると次の通りです。
さっきと同じ画像を再掲載しているのかと思うかもしれませんが、URLバーを見るとdist/demo.htmlを表示していることがわかると思います。
すぐ試せるようにvue-app demoにも置いておきます。
実は、src/App.vue はその中でコンポーネントsrc/components/HelloWorld.vueを利用しています。ということは複数のVueコンポーネントで構成されたVueアプリケーションをまるごとWeb Component化できるということです。
また、通常のVueアプリケーションは前述のsrc/main.tsの様に起動処理が必要でした。一方、Web Component化すると表示したい場所でカスタム要素を書くだけです。
ビルドも、その利用もとても簡単です!
PopupをVueで実装してWeb Component化してみる
先日のエントリ「Web Componentsを試してみた」で作ったPopupと同等のものをVueコンポーネントとして実装してみます。
Pugを使いたいので次のコマンドで必要なモジュールを追加します。
$ yarn add -D pug pug-plain-loader
これだけで特に追加の設定なしで使えるようになります。vue-loaderバンザイ!!
で、Popupのコードsrc/components/Popup.vueは次のとおりです。
<template lang="pug"> div #popup(v-if="isOpen" @click="close") .dialog .title {{title}} .content {{content}} button(@click="open") OPEN </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class Popup extends Vue { @Prop() private title!: string; @Prop() private content!: string; private isOpen = false; private open() { this.isOpen = true; } private close() { this.isOpen = false; } } </script> <style lang="sass"> #popup position: fixed background-color: rgba(0,0,0,0.3) width: 100vw height: 100vh top: 0 left: 0 .dialog background-color: white width: 80vw margin: 100px auto 0 auto padding: 10px border-radius: 5px .title font-weight: bold </style>
次のコマンドでサクッとWeb Componentとしてビルドできます。
vue-cli-service build --target wc --name vue-popup src/components/Popup.vue
実行後 dist/ を見るとトランスパイルされたファイルが出力されています。
で動かしてみた様子が次のとおりです。 当たり前ですが、先日のエントリのものと同じ動作をします。
ここから試せます。 => Web Components - Vue Popup
@vue/web-component-wrapper
Vueコンポーネントは@vue/web-component-wrapperによってWeb Component化されています。
Requires ES2015 classesとのことですが、Can I use... で確認するとIE以外の主要なブラウザでは使えるようです。
Web Componentsの仕様に未対応ブラウザではwebcomponents.jsを使えば動くようです。
Vue CLIを使っていないプロダクトでもこのラッパーを使えばWeb ComponentsとしてVueコンポーネントを利用できそうです。
まとめ
すでに単一ファイル形式のVueコンポーネントがあるなら簡単にWeb Component化できます2。個人的にはVueの単一ファイル形式は、コンポーネントの要素すべてが1ファイルにまとまるのでポータブルでメンテナンス性もいいと思っています3。なのでWeb Componentを作る方法としてもおすすめな方法だと思います。
ただ、ビルドされたスクリプトにはVue本体を含まないので、HTMLには<script src="https://unpkg.com/vue"></script>
を挿入する必要があります。これはCDNからVueのランタイムライブラリを読み込みます。これがVue
クラスをページのコンテキストに晒してしまうのですでにVueを導入しているなら、バージョンには注意が必要でしょう4。
使い所としては、モダンフレームワークを使っていない既存のWebアプリケーションに部分的にVue.jsを導入したいというケースにはうってつけだと思います。
メインコンテンツは普通にレンダリングして、どのページにも置くサイドコンテンツを遅延させたり動的に表示したいケースっていうのは結構あるんじゃないでしょうか。
最後に
アクトインディではエンジニアを募集しています。
-
ソースコードを見てもわかりにくいと思いますが、
yarn build
でビルドしてみればわかります。public/index.htmlを雛形にdist/index.htmlが出力されます。その中でsrc/main.tsをトランスパイルしたものを読み込む<script>
タグが挿入されています。↩ -
ReactのドキュメントにもWeb Componentsの記述があります。また、adobe/react-webcomponent(Adobe !!)でReactコンポーネントをWeb Component化できそうです。↩
-
ポータブルと言っても他のスクリプトをimportしていればそれらも必要になりますが…。↩
-
https://unpkg.com/vue@2.6
のようにバージョンを指定することもできます。 ↩