ha6_6ruブログ

主にフロントエンドの技術ネタを中心にしていく予定です。

Vue 3 Auth Guard(未認証の場合にログインページにリダイレクト)

はじめに

次のような振る舞いを実現する場合、Vue.js(Vue Router)ではナビゲーションガードを利用します。

  • ECサイトで購入手続きに入ろうとしたときにログインページに飛ばされる
  • 最初にログインが必要なサイトで、ログイン以降に表示されるページにアクセスしたときにログインページに飛ばされる

ナビゲーションガード

ナビゲーションガードには、グローバルやルートごとの設定、コンポーネント内の設定と種類が分かれますが、サイト全体の認証を制御するのでグローバルナビゲーションガードを使います。グローバルナビゲーションガードは、Vue Routerのインスタンスに対して設定を行います。
まずは、未認証のときにログインページにリダイレクトするナビゲーションガードの実装を紹介します。

ナビゲーションガードの実装サンプル

  • auth-guard.ts
import type { Router } from 'vue-router';
import { useAuthenticationStore } from '@/stores/authentication';
import { useRoutingStore } from '@/stores/routing';

export const authenticationGuard = (router: Router) => {
  const authenticationStore = useAuthenticationStore();
  const routingStore = useRoutingStore();

  router.beforeEach((to) => {
    // 既に認証されていれば何もしない
    if (authenticationStore.isAuthenticated) {
      return true;
    }

    // 未認証状態で遷移を許可するルート
    if (['login', 'home'].includes(to.name)) {
      return true;
    }

    // 認証後のリダイレクトで使う。必要に応じてパラメーターも保存しておく。
    routingStore.setRedirectFrom(to.name);

    return { name: 'login' };
  });
};

認証状態はストアで扱うことを前提とした実装になっています。メモリやストレージなど、実際の保存先はストア内で決定します。
遷移しようとしたページに移動させずにログインページにリダイレクトしたいので、beforeEachを使います。beforeEachはVue Routerによるナビゲーションが確定する前のフックです。
ログイン後に元々アクセスしようとしていたページに移動して手続きを続行したいので、アクセスしようとしていたページの情報と必要に応じて遷移時のパラメーターを保存しておき、ログイン後にそれらの情報を使ってアクセスしようとしていたページに遷移します。ECサイトの例では、ログイン後には購入手続きに自動的に遷移します。
この実装サンプルでは次のような条件判定を行っています。

  • 認証されていれば何もせずに遷移しようとしたページに移動
  • 未認証状態で表示してもよいページに対しては何もせず、遷移しようとしたページに移動
  • 上記以外はログインページにリダイレクト

グローバルナビゲーションガードの登録

先ほど作った関数にcreateRouterで生成したVue Routerのインスタンスを渡すことで、グローバルナビゲーションガードとして動作します。

authenticationGuard(router);

PiniaのactionからVue Routerを使ってルーティング

はじめに

ストアのactionでルーティングを行うにはどうすればよいかを解説します。

準備

piniaのストアインスタンスにプロパティを追加し、Vue Routerのインスタンスを設定しておくことで、ストアからVue Routerを使うことができます。
公式ドキュメントの説明はこちら。
https://pinia.vuejs.org/core-concepts/plugins.html#adding-new-external-properties

実装サンプル

  • main.ts
import { createApp, markRaw } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';

const app = createApp(App);
const pinia = createPinia();

pinia.use(({ store }) => {
  store.router = markRaw(router);
});

app.use(pinia);
app.use(router);

app.mount('#app');

公式ドキュメントに記載がありますが、アプリケーションで扱うデータのようにリアクティブオブジェクトとして扱うもの以外、例えばVue Routerのようなライブラリのインスタンスやユーティリティーについては、markRawを使ってラップすることで非リアクティブオブジェクトとして扱うことができます。

actionでのルーティング

actionでは、ストアインスタンスに追加されたプロパティを経由してVue Routerのインスタンスにアクセスすることでき、ルーティングが可能になります。

実装サンプル

import { defineStore } from 'pinia';

export const useRoutingStore = defineStore({
  id: 'routing',
  actions: {
    push() {
      this.router.push('/');
    },
  },
});

this.routerでVue Routerのインスタンスにアクセスしています。

axiosの脆弱性解析事例(JVNDB-2020-013151)

はじめに

この記事では、axiosの脆弱性(JVNDB-2020-013151)を題材に、エンタープライズ系案件の脆弱性対応について紹介したいと思います。
この記事で題材にするエンタープライズ系案件の特徴としては、例えば大規模で自動テストも無く、簡単にはバージョンアップが出来ないような案件ということにしましょう。
そんな状況あるの?と思う方も居るかもしれませんが、これ、SIerの受託開発案件ではよくある状況といっても過言ではありません。
おおまかな流れとしては、脆弱性がシステムに与える影響を調査して、その後対応方針を検討し、対策を行います。
最初に、脆弱性がシステムに与える影響の調査から始めましょう。

影響調査

脆弱性の検知と脆弱性対策情報データベース

GitHubソースコードを運用していれば、GitHub Advisory Database脆弱性が通知されることでしょう。 この記事で題材にしている脆弱性こちらです。共通脆弱性識別子(CVE)をキーワードに情報収集も出来ますが、JVN iPedia - 脆弱性対策情報データベースで情報公開されているようであれば、脆弱性対策情報データベースを参照するのが日本語で情報がまとまっていることもあり、とっつきやすいでしょう。
脆弱性対策情報データベースで公開されている情報はこちらです。早速、内容を確認してみましょう。

CVSS による深刻度

まずは CVSS による深刻度 を確認します。これは脆弱性の深刻度を示す指標です。深刻度を示す項目ごとにそのレベルや影響などが示されていますね。
この脆弱性では 攻撃元区分ネットワーク であり、機密性への影響 になっていますが、これは例えば、インターネット経由で攻撃されて機密情報が流出してしまう可能性がある、と読み取ることができる内容になっています。

影響を受けるシステム

次に 影響を受けるシステム には axios 0.21.0脆弱性が確認されたライブラリとそのバージョンが記載されていますね。 この段階で対象バージョンに該当しなければ脆弱性の影響を受けないと判断できますが、ここでは対象のバージョンを使っていると想定して、具体的な脆弱性の影響について、確認していきましょう。
この項目では脆弱性の影響を受ける具体的な条件までは記載されていないので、次の項目に読み進めていきます。

想定される影響

「情報を取得される可能性があります。」としか記載されていません。CVSS による深刻度 を読み解いた情報から追加の情報がないので諦めて読み進めましょう。

対策

「ベンダより正式な対策が公開されています。ベンダ情報を参照して適切な対策を実施してください。」とのことです。
端的に言えば、今回脆弱性対策情報データベースから得られる情報としては、ベンダーの提供情報を参照してね、ということだけです。 対策は ベンダ情報 に記載されているリンクを元に検討を行いましょう。

脆弱性対策情報データベースについてのまとめ

脆弱性対策情報データベースで脆弱性の深刻度から優先度を確認、さらに対象ライブラリとそのバージョンから該当判定を行う、という流れは理解いただけたのではと思います。
ここまでの流れでお気付きと思いますが、脆弱性を検知した多くの場合、影響調査も対応方針検討も、脆弱性対策情報データベースとは別に、別途情報を集めて作業を進めていく必要があります。なかなか大変な作業ですよね。バージョンアップが簡単ならさっさとバージョンアップして終わらせたいものです。
ここでは、情報を集めてさらに影響調査や対応方針検討を進めていく流れを見ていきましょう。

GitHub Issue から影響調査を再開

GitHub Issue を読む

ここからは GitHub Issue から脆弱性の情報を読み解いていきます。対象の Issue はこちらです。投稿された Issue の次の部分を読めば、リダイレクトを受けた後にプロキシサーバーを経由しないことが問題であることがわかります。

The following code spawns a proxy server that always responds with a 302 redirect, so requests should never reach the target url, however, axios is only reaching the proxy once, and bypassing the proxy after the redirect response.

脆弱性によって影響を受けるケース

読み解いた情報から、対象システムが以下のケースに該当する場合に脆弱性の影響がありそうです。

  1. Web API を呼び出す際にプロキシサーバーを使う(axios の proxy オプションを使用する)
  2. Web API を呼び出した結果、リダイレクトされるケースが存在する

修正内容の確認による裏付け調査

ここで、修正内容から裏付け調査を行います。GitHub Issue に紐付けられたコミットログ*1から、修正内容を確認します。コミットログから修正内容を見ると、proxy オプションが有効な場合にしか作用しないことがわかります。

if (proxy) {
  // If a proxy is used any redirects must also pass through the proxy

また、確かにリダイレクト時にプロキシサーバーを向くように設定されていますね。

if (proxy) {
  // If a proxy is used any redirects must also pass through the proxy
  options.beforeRedirect = function beforeRedirect(redirection) {
    var location = redirection.href;
    redirection.hostname = proxy.host;
    redirection.host = proxy.host;
    redirection.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : '');
    redirection.port = proxy.port;
    redirection.path = location;
  };
}

調査方針

裏付けがとれたので、これで調査方針が固まりました。

1. Web APIを呼び出す際にプロキシサーバーを使う(axiosのproxyオプションを使用する)

上記を確認するには、クライアントアプリケーションのソースコードproxy で検索すれば良さそうです。ここで、該当しなければ影響なしで調査完了です。
今回のケースでは、proxy オプションを利用していたということにしておきましょう。

2. Web API を呼び出した結果、リダイレクトされるケースが存在する

もう一つの条件については、外部の API を呼び出している場合は、リダイレクトが発生する可能性は考慮しておく必要がありますし、 今後の改修でリダイレクトを扱うことも考慮しておいた方がよいでしょう。現時点でリダイレクトのケースが無いことを理由に対応を見送ったとして、リダイレクトのケースが出てきたときに、この脆弱性対応をセットで反映させられる保証が無いからです。
今回のケースでは、今後も見据えて該当する可能性があると判断したことにしておきます。 これで影響調査は完了とし、次に脆弱性の対応方針を検討していきましょう。

対応方針検討

対応方針の大まかなパターン

まずは、影響調査結果を元に、対応するかしないかを判断します。次に、大まかに以下のパターンです。

  1. 影響調査の結果脆弱性に該当しないので、対応を見送る
  2. 影響調査の結果脆弱性に該当しないが、今後を見据えて対応する
  3. 影響調査の結果脆弱性に該当するので、対応する

対応方針には次のようないくつかのパターンがあり、プロジェクトのコンディションに応じて対応を検討することになります。

  1. バージョンアップに対するシステムへの影響が大きいので、アプリケーションで回避する
  2. 脆弱性が対応されたバージョンにアップデートする
    当然ながら、バージョン間の非互換に伴い、アプリケーションの改修が必要になるケースがあります。

対応方針を選択

今回は今後を見据えて脆弱性の対応を行うこととし、対応方針は axiosのバージョンアップを行う選択をした想定とします。
それでは、具体的な対策について見ていきましょう。

脆弱性の対策

コミットログから修正内容を確認した結果、アプリケーションの改修は不要であること、proxy オプションを使うケースのみ処理が追加されているのでテストバリエーションは少なく済む、ということがわかっています。
結果として、axios のバージョンを脆弱性対応が行われた v0.21.1 以降にバージョンにアップデートし、確認テストを実施するということで方針が定まりました。

まとめ

ここまで、脆弱性の検知から対策までの流れの一例を紹介しました。
自動テストが整備されていればさっさとバージョンあげた方が早いのは言うまでもないですが、そうもいかないケースでは、なかなか大変な作業になります。そうでなくても、社会的影響の高いシステムでは、攻撃の有無などインシデント調査に多くの時間をとられます。 所謂塩漬けと呼ばれるバージョンアップが行われないシステムが多い、エンタープライズ系案件の脆弱性対応について紹介しました。

*1:実際にはこの後リファクタリングが行われていますが、修正意図がわかりやすいのでこちらのコミットから引用しました。

Vue.jsをベースにしたWebフロントエンドのアーキテクチャとその実行環境

はじめに

この記事は Vue Advent Calendar 2020 の 25 日目の記事です。
Vue.jsを使ったアプリケーション開発とは少し趣旨を変えて、Vue.jsをベースにしたWebフロントエンドのアーキテクチャとその実行環境について整理します。
スクエア free セミナー 第118回 Webサイト構築の新潮流 - YouTube で話した内容を整理してまとめたものです。

Webフロントエンドのアーキテクチャ

f:id:ha6_6ru:20201225001324p:plain

Webフロントエンドのアーキテクチャとしては、Single Page Application、Server Side Rendering、Static Site Generation(Static Site Generator)の3つが主流ですね。ここではそれぞれのアーキテクチャについては解説しません。

WebフロントエンドアーキテクチャのVue.jsベースの実装技術

f:id:ha6_6ru:20201225001649p:plain

SPAとSSRについては改めて解説することもないと思うので、説明は省略します。SSGで人気のツールには、Hugoのように所謂3大JavaScriptフレームワークに依存しないものもあります。Vue PressやNuxtJSは、Vue.jsのコンポーネントを活用することができるので、Vue.jsの開発者にはおススメです。

Webフロントエンドのアーキテクチャとその用途

f:id:ha6_6ru:20201225002946p:plain

企業内で使う業務システムを代表とするエンタープライズWebアプリケーションでは、高速なイントラネットが用意されていることやSEO対策が不要ということもあり、SPAが適しています。 ​
コンシューマー向けのWebアプリケーションになると、パフォーマンスやSEO対策の必要性に応じてSSRが優位になることがありますが、 サーバーリソースの効率性やスケールのしやすさ、開発の容易性から、多くの場合はSPAが適しています。SSRを適用すべきなのは、静的サイトではないWebアプリケーションにおいて、First Meaningful Paintを高速化したい場合や動的にOGPを設定したいケースがあげられます。 SSGは、ブログやニュースなどの投稿、外部リソースの更新をトリガーに更新するWebサイト、ランディングページのように従来から静的サイトとして作られていたものが適しています。

Webフロントエンドのアーキテクチャとその実行環境

Webフロントエンドのアーキテクチャに対して、クラウドサービスをフル活用した実行環境について紹介します。

SPAコンテンツ配信

f:id:ha6_6ru:20201225004326p:plain

Azureでは前段にCDNを構え、ビルドで生成した静的コンテンツはAzureのストレージサービスであるBlob Storageを使ってホスティングします。​Azureでは、Static Web AppsというサーバーレスのFaaSをセットにした静的コンテンツ配信用のサービスがプレビュー公開中で、今後はStatic Web Appsが主流になっていくと思います。 ​ AWSでは前段にCloudFrontを構え、ビルドで生成した静的コンテンツはAWSのストレージサービスであるS3を使ってホスティングします。​
CDNまたはCloudFrontでは、キャッシュやファイル圧縮の機能など、図に記載した機能を利用します。また、SPAの場合はクライアントサイドルーティング用の設定を忘れないようにしましょう。
​ここで紹介したストレージサービスではなく、Webサーバーでコンテンツを配信することもできますが、静的コンテンツのホスティング環境を使うことで、非常にお手軽でハイパフォーマンスな構成を実現できます。​

API

f:id:ha6_6ru:20201225004432p:plain

SPAとSSR、SSG(Jamstack)で使うAPIはサーバレス(FaaS)で構成することができます。AzureではFunctions、AWSではLambdaです。
また、Open ID Connectを使い、別に用意したOpen IDプロバイダー兼認可サーバーに認証認可を移譲する形で認証認可をサポートすることもできます。​認証認可はAzureではAPI Managementで、AWSではAPI Gatewayで構成します。​

SSRコンテンツ配信

f:id:ha6_6ru:20201225004453p:plain

SSRの場合は、サーバー側でHTMLを生成するためのWebサーバー機能が必要ですので、Webサーバーとして、Node.jsが動作する環境を用意しましょう。
Azureでは、Node.jsをランタイムとして利用できるAzure App Serviceが手軽に利用できます。
AWSではFargateを使い、Docker上でNode.jsをセットアップして使うのがおススメです。制約はあるものの、Lambdaで動作させることもできます。

SSG(Jamstack)

f:id:ha6_6ru:20201225004517p:plain

SSGのコンテンツの配信方法はSPAと同じ構成で実現できます。​SSGはJamstackで使われるケースが増えていますので、Jamstackの構成についても紹介します。
Azure PipelineまたはAWS Amplifyを使ってGitHubにプッシュされたことをトリガーに、静的サイトをビルド、デプロイします。ビルドに使うのは、実装技術で出てきたVuePress、NuxtJSですね。

おわりに

2020年はVue.js 3.0がリリースされましたが、VuetifyなどのUIコンポーネントライブラリやその他周辺ライブラリのVue.js 3対応は現時点でまだ揃っていません。2021年はVue.js 3を使った本格的な開発に取り組みたいですね。
Vue.js 3.0に向けた準備には、是非こちらの著書もよろしくお願いします。

f:id:ha6_6ru:20201225012239j:plain:w250

amzn.to

コード値(区分値)選択用フィールドの作り方

概要

コード値(区分値)の選択用フィールドを、Vuetifyを使って実装する方法について解説します。 これだけだったらVuetifyの公式ドキュメントで十分な内容なのですが、今回は業務利用を想定したコード値選択用フィールドの実装について解説します。

業務用アプリケーションによくあるコード値の選択用フィールド

窓口業務で使うアプリケーションでは、オペレーターさんが直接コード値を入力するケースがあります。 これは、コード値がわかっていればドロップダウン式やスクロール式のリスト選択よりも入力が速くなるからだと思います*1

作り方

Vuetifyのv-autocomplete Autocomplete component — Vuetify を使って、入力を補完できるようにしてみます。 題材は銀行コードにします。銀行コードは馴染みがあると思いますが、こちら 金融機関コード・銀行コード検索 のコードです。

コード値選択フィールドの外観

これから作成するコード値選択フィールドの外観はこちらです。

コード値選択フィールド
コード値選択フィールド
選択フィールドには、選択肢としてコード値と名称の両方を表示します。

コード値選択フィールドの入力補助
コード値選択フィールドの入力補助

オートコンプリート機能は、コード値と名称の両方を扱えるようにします。

Vuetifyを使った実装指針

コード値と名称の両方を表示し、選択された値にコード値を扱えるようにするには*2、Vue.jsの実装としては表示(v-bind)と入力(v-on)を分ければよいですね。Vuetifyは最初からこれらを分離することができるように設計されており、専用のプロパティが用意されています。それでは実装方法を見ていきましょう。

その1 コード値をキャッシュする

選択肢が少ない場合は、クライアント上にキャッシュしてしまいましょう。

template

<v-autocomplete
  v-model="selectedBankCode"
  outlined
  dense
  :items="bankList"
  :item-text="formatBankCode"
  item-value="code"
  label="銀行コード"
/>

プロパティの解説です。

  • v-model: 選択したコード値を格納するプロパティを指定します。
  • outlined: フォームを線で囲まれたスタイルにします。
  • dense: フォームの高さを下げます。
  • items: 選択候補のリストを格納したプロパティ指定します。
  • item-text: コード値の表示をカスタマイズするためのメソッドを指定します。
  • item-value: 選択されたコード値のキーとして扱う値を、リストのプロパティから指定します。
  • label: フィールドの項目を示すラベルです。

script

script部は今回は@vue/composition-apiを使って記述します。

<script>
import { defineComponent, reactive, toRefs } from '@vue/composition-api';

export default defineComponent({
  setup() {
    const state = reactive({
      selectedBankCode: null,
      bankList: [
        { name: 'みずほ銀行', code: '0001' },
        { name: '三菱UFJ銀行', code: '0005' },
        { name: '三井住友銀行', code: '0009' },
        { name: 'りそな銀行', code: '0010' },
        { name: '埼玉りそな銀行', code: '0017' },
      ],
    });

    const formatBankCode = value => {
      return `${value.code}: ${value.name}`;
    };

    return {
      ...toRefs(state),
      formatBankCode,
    };
  },
});
</script>

bankListを固定のオブジェクトにしていますが、実際にはMVVMモデルでいうところのModelに格納し、値が空であればWebAPIを経由して取得するといった、キャッシュとして扱う形で実装します。
formatBankCodeでコード値と名称の両方を組み合わせた、リスト表示用の文字列を組み立てています。 コード値選択フィールドでコード値を選択すれば、selectedBankCodeにコード値(埼玉りそな銀行であれば0017)が格納されます。 ほぼほぼv-autocompleteの機能で実現できてしまうので簡単ですね。

その2 コード値を都度WebAPI経由で取得する

選択肢が多い場合は、クライアント上には大きなデータを保持しないようにするといいでしょう。 WebAPIで絞り込みを行い、該当するコード値のみを選択肢として表示する形を想定して実装し ます。

template

<v-autocomplete
  v-model="selectedBankCode"
  outlined
  dense
  no-filter
  :loading="isLoading"
  :search-input.sync="keyword"
  :items="bankList"
  :item-text="formatBankCode"
  item-value="code"
  label="銀行コード"
/>

その1のキャッシュ方式から追加したプロパティの解説です。

  • no-filter: ブラウザー上のフィルタリングを無効にします。有効にするとWebAPI経由での取得タイミングのずれによって、少し動作に違和感があったので無効にしています。
  • loading: リストの読み込み中であることを表現するプロパティを指定します。このプロパティを使うと、フィールド下部にプログレスバーが表示できます。
  • search-input: フィールドに入力した文字列を格納するプロパティを指定します。

script

<script>
import { defineComponent, reactive, toRefs, watch } from '@vue/composition-api';
import axios from 'axios';

const fetchBankCodes = async value => {
  const response = await axios.get('bank-codes');
  return response.data;
};

export default defineComponent({
  setup() {
    const state = reactive({
      isLoading: false,
      keyword: null,
      selectedBankCode: null,
      bankList: [],
    });

    watch(
      () => state.keyword,
      async () => {
        state.isLoading = true;
        state.bankList = await fetchBankCodes(state.keyword);
        state.isLoading = false;
      },
    );

    const formatBankCode = value => {
      return `${value.code}: ${value.name}`;
    };

    return {
      ...toRefs(state),
      formatBankCode,
    };
  },
});
</script>

search-inputで指定したプロパティkeywordをウォッチし、値が変更されたらWebAPIを呼び出して選択候補のコード値リストを取得し、プロパティに設定します。WebAPIの呼び出しはModelに実装することをおすすめしますが、ここでは単純化するめコンポーネント内に関数を配置しました。
WebAPIの呼び出し中にプログレスバーを表示するために、WebAPIの呼び出し前後でisLoadingプロパティを設定しています。

終わりに

実際にはここからさらにスタイルを変更したり、細かい動作の修正を行うことになると思いますが、Vuetifyを使うことでとても簡単に実装できました。
コード値と名称の両方でオートコンプリート機能を使うことができること、コード値と名称がセットで表示されるので入力誤りを防止する効果も期待できることがポイントです。コード値を選択するUIの候補として参考にしてもらえると嬉しいです。

書籍の紹介

宣伝となり恐縮ですが、こちらの書籍でVue.jsとVuetifyを扱っていますので、参考にしていただければ幸いです。


書籍の情報サイト

紹介

人気のJavaScriptフレームワークVue.jsにフォーカスし、フロントエンド開発の基礎から本格的なSPAの開発まで、ハンズオン形式で一歩ずつ、無理なく着実にステップアップしていきます。 さらに、2020年リリース予定のVue.js 3.0をいち早くキャッチアップ。Vue CLI 4に対応しつつ、Vue.js 2.xとの差分として新しい記述スタイル(Composition API)を併記するなど、バージョン移行を強力に支援します。

基本情報

*1:実際に窓口業務で使うアプリケーションの入力作業を見せてもらったことがあるのですが、オペレーターさんは私からすると異常な速さで入力していきます。

*2:コード値のデータ構造に依存するので、選択された値にIDを使用するケースもあるでしょう。

Vue3の始め方

はじめに

Vue.js 3.0リリースに併せて、Vue.jsをハンズオン形式で学習する書籍を出版しました。 書籍では、Vue3への移行情報や新機能の中心になっているComposition APIを解説しています。 書籍の宣伝を兼ねて、2020年10月時点のVue3の取り組み方について解説します。 多大に宣伝を含みますが、ご了承ください。
最初に結論を。しばらくは公式ライブラリとUIコンポーネントライブラリの対応状況をウォッチし、Vue3の本格的な採用は様子見することを個人的におススメします。

Vue3の新機能

https://v3.vuejs.org/guide/migration/introduction.html#notable-new-features

Vue3の新機能をいくつか取り上げて紹介します。

Composition API

https://v3.vuejs.org/guide/composition-api-introduction.html

新しく導入されたコンポーネントの記述スタイルです。 次のプラグインを使うことで、Vue2でも一部の機能を除いて利用可能です。

書籍ではComposition APIを中心に解説しています。 Vue3と言えばComposition API、という感じでネット上にも情報が溢れていますのでここでは紹介を割愛します。

Teleport

https://v3.vuejs.org/guide/teleport.html#teleport

teleportタグで囲まれたコンテンツを、toで指定した場所に描画させることができる機能です。 公式ドキュメントのサンプルは次のとおりです。記述方法を確認してみてください。

template: `
  <button @click="modalOpen = true">
    Open full screen modal! (With teleport!)
  </button>

  <teleport to="body">
    <div v-if="modalOpen" class="modal">
      <div>
        I'm a teleported modal! 
        (My parent is "body")
        <button @click="modalOpen = false">
          Close
        </button>
      </div>
    </div>
  </teleport>
`,
template: `
  <h2>This is a parent component</h2>
  <teleport to="#endofbody">
    <child-component name="John" />
  </teleport>
`

Fragments

https://v3.vuejs.org/guide/migration/fragments.html

公式ドキュメントのサンプルを見ればわかると思いますが、templateタグ直下に複数のタグを並べることができるようになりました。

<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>

Breaking Changes

https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes

Vue3のBreaking Changesをいくつか取り上げて紹介します。

Global API

インスタンスの生成やグローバルコンポーネントの登録など、グローバルAPIインスタンスAPIに変更されています。 また、Vue.nextTickは次のようにインポートして使うなど、APIの見直しが行われています。

import { nextTick } from 'vue'

v-modelの変更

:value:modelValueに、@input@update:modelValueに変更されました。 v-bindディレクティブの.sync修飾子が廃止され、v-modelを使う形になります。 また、次の公式ドキュメントのサンプルのように、複数のv-modelを設定できるようになりました。

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

フィルターの廃止

メソッドで代用が効くため、Vue3で廃止されました。

$listenersの廃止

Vue3では、イベントリスナーは$attrsにマージされたため、$listenersはVue3で廃止されました。

.native修飾子の廃止

v-onディレクティブの.native修飾子が廃止されました。

Events API

$on$off$onceが廃止されました。

実験的な機能

次の機能が試験的に実装されています。

ライブラリの対応状況

https://github.com/vuejs/vue-next

Vue RouterがRCになりましたが、Vuexやその他周辺ライブラリはβの状態です。

UIコンポーネントライブラリの対応状況

UIコンポーネントライブラリのVue3対応は、もうしばらく待つことになりそうです。Vue3への移行は、実質UIコンポーネントライブラリの対応待ちになるでしょうね。 メジャーなライブラリのVue3への対応が言及されているIssueを示しておきます。

クラススタイルにどう向き合うか

主流はComposition APIを使った記述スタイルになっていくことが予想されますが、サーバーサイドエンジニアに馴染みの深い、オブジェクト指向言語に似た記述スタイルを捨てがたい人も居るのではないでしょうか。 Vue.jsの公式リポジトリ内では、Vue3へのクラススタイルの導入は一旦見送られていますが、クラススタイルをサポートするライブラリはそうとも限りません。次のモジュールを使っている場合は、ライブラリの対応をウォッチしておくのが良さそうです。

  • vue-property-decorator
  • vuex-module-decorators

Vue3への対応について言及しているIssueはこちらです。

まとめ

公式ライブラリやUIコンポーネントライブラリなどの対応状況をウォッチしながら、Vue3の学習をしつつ準備を進めるのが良さそうです。
既存のアプリケーションを移行するにもそれなりの作業量が予想されるため、少しずつ準備を進めましょう。プラグイン@vue/composition-apiを使った段階的な移行を検討するのもよいかもしれません。

書籍の紹介


書籍の情報サイト

紹介

人気のJavaScriptフレームワークVue.jsにフォーカスし、フロントエンド開発の基礎から本格的なSPAの開発まで、ハンズオン形式で一歩ずつ、無理なく着実にステップアップしていきます。 さらに、2020年リリース予定のVue.js 3.0をいち早くキャッチアップ。Vue CLI 4に対応しつつ、Vue.js 2.xとの差分として新しい記述スタイル(Composition API)を併記するなど、バージョン移行を強力に支援します。

基本情報