※当サイトの記事には、広告・プロモーションが含まれます。

Vue 3系ではRFCからVue Class Componentが外れたらしいが、Vue Property Decoratorを学習する

f:id:ts0818:20220129185733j:plain

www.itmedia.co.jp

 最高裁判所は1月20日、仮想通貨のマイニングツール「Coinhive」を閲覧者に無断で自身のWebサイトに設置したとして、Webデザイナーの男性が不正指令電磁的記録保管罪に問われた「Coinhive事件」について、二審の有罪判決を破棄して無罪と判断した。

Coinhive事件、無罪確定 二審の有罪判決から逆転 - ITmedia NEWS

⇧ う~ん...無断で設置したってところが心証が悪い気がするかな、閲覧者のデバイスにどれだけの負荷がかかってたのかが分からんので何と言えないけども、「広告」や「Webビーコン」の設置とかと同等の影響ってわけにはいかないように思えるし。

scam-analysis.com

Coinhiveの問題点として、以下の3点を挙げておきます。

    1. サイト閲覧者はマイニングすることを拒否できない
    2. デフォルトのコードのままだとCPU使用率が100%になる
    3. 運営者側の利益率が低い

Coinhive(コインハイブ)の問題点: サイト閲覧者から嫌われるし儲からない

⇧ 上記サイト様の説明が事実だとすると、CPU使用率が100%に成り得る可能性があるっていうのは無断設置する上でかなり大問題な気がすると思いますが...

Wikipediaさんによると、

Coinhive

Coinhiveはサイトの閲覧者にマイニングを行わせ、マイニングの利益の7割をサイトの運営者が受け取ることができるサービスであり、サイト運営者からはインターネット広告に代わる新たな収益源として注目されていた。

Coinhive事件 - Wikipedia

一方でユーザーに拒否する権限がなくページを表示した瞬間からマイニングが開始される、デフォルトのコードでは閲覧者のデバイスのCPUを100%使い切るため相当の負担になる、悪意のあるマルウェア開発者に利用され収益源になっている、など様々な物議をかもしており、一部アンチウィルスソフトでは登場して間もなくからブロックされていた

Coinhive事件 - Wikipedia

事件後もサービスは継続されていたが、マイニングしていた仮想通貨の価格暴落により2019年3月8日にサービスを終了した

Coinhive事件 - Wikipedia

⇧ 現在は、サービスが終了している模様ですが、上記の情報が真実だとするならば、尚更、無断設置は良くなかった気がするんだけど...

というわけで、例の如く冒頭からまったく関係のない話でしたが、今回は、TypeScriptとVue.jsについてです。

レッツトライ~。

Vue Class Componentとは?

GitHubで公開されてる「Vue.js」のリポジトリの情報によりますと、

github.com

ES / TypeScript decorator for class-style Vue components.

https://github.com/vuejs/vue-class-component

⇧ ということで、「Vue.js」で「TypeScript」を利用している場合に関係してくる話らしく、「Vue.js」で「TypeScript」を使っていないのであれば、関係ない話ではあるらしい。逆に言うと、「Vue Class Component」を使う場合は、必ず、「TypeScript」の利用が必要ということらしいですね。

2022年1月31日(月)追記:↓ ここから

なんか、「TypeScript」じゃなくても「Vue Class Component」は使えるみたいでした。(「ECMAScript 2015(Edition 6)」から「Class」が使えるようになっているので)

2022年1月31日(月)追記:↑ ここまで

class-component.vuejs.org

Vue Class Component is a library that lets you make your Vue components in class-style syntax. For example, below is a simple counter component written with Vue Class Component:

https://class-component.vuejs.org/

⇧ とあるように、ライブラリということで、

class-component.vuejs.org

⇧ 上記の説明にあるように、

  • Vue CLIでVue.jsのプロジェクト作成時のオプションで追加
  • npmやyarnでモジュールをインストールする

のいずれかで導入が可能ということらしい。

だが、しかし!

qiita.com

(2019/09/09 追記)
vue-class-componentはvue3のRFCから外されたようで、現在は、Composition APIRFCとなっています。

Vue.js to TypeScriptの書き方一覧 - Qiita

⇧ 上記サイト様によりますと、「Vue Class Component」については「RFC(Request For Comments)」から外れたということで、新規で機能が追加されていくことはないようなんですかね?

GitHubリポジトリを確認したところ、リリースも2020年9月17日が最新となっているので、メンテナンスだけは行っていくような状態なんかな?

「Vue.js」の「RFC(Request For Comments)」については、

github.com

RFCs for substantial changes / feature additions to Vue core

https://github.com/vuejs/rfcs

GitHubで公開されてるらしい。

話が脱線しましたが、Vue 2系で「Vue Class Component」を使う時にうために必要となる「TypeScript」を利用する場合について、「TypeScript」の話は、

jp.vuejs.org

⇧ 上記に記載があるようです。

Vue Property Decoratorとは?

「Vue Property Decorator」とは?

github.com

This library fully depends on vue-class-component, so please read its README before using this library.

https://github.com/kaorun343/vue-property-decorator

⇧ とあるように、「Vue Class Component」に完全に依存しているということで、「Vue Class Component」の「README」を読んでください、とのこと。

丸投げ感が半端ない...

ECMAScriptのクラスと関係しているということ?

改めて、「Vue Class Component」の「README」を確認してみると、

ECMAScript / TypeScript decorator for class-style Vue components.

https://github.com/kaorun343/vue-property-decorator

⇧ とあるので、「ECMAScript」または「TypeScript」の「クラス構文(class-style)」を「Vue.js」で利用できるようにするための「decorator(修飾子)」ってことで良いのかね?

ECMAScript」はと言うと、

ECMAScript(エクマスクリプト)は、Ecma Internationalのもとで標準化手続きが行われているJavaScriptの規格。ISO/IEC JTC 1はISO/IEC 16262として、日本もJIS X 3060:2000として規格を定めている。

ECMAScript - Wikipedia

ECMAScript仕様は、Ecma InternationalにてECMA-262という規格番号で標準化されている。改訂にあたっては版 (edition) が更新されている。

ECMAScript - Wikipedia

⇧「JavaScript」の規格ということで、「ECMA-262」って規格番号で標準化されてますと。

6th editionから、「ECMAScript 2015」仕様の名称に発行年が付加されることになった。以降、ECMAScriptは毎年改訂されることになり、以降特定の版を指す場合は、edition名ではなく年号つきの仕様書名で呼ばれることが推奨されている

ECMAScript - Wikipedia

⇧ ってな感じで、年号つきの仕様書名に変更になった模様、年1回、仕様の見直しが行われるという事ですかね。

Ecma International」って団体は、

Ecmaインターナショナル(エクマ・インターナショナル、英語Ecma International)は情報通信システムの分野における国際的な標準化団体である。以前は欧州電子計算機工業会(英語: European Computer Manufacturers AssociationECMA)という名称であったが、世界的な展開や活動状況を反映して、1994年に現在の名称に改められた。この結果、「ECMA」という名称はもはや略語ではなくなったため、大文字にせずに「Ecma International」と表記する。

Ecmaインターナショナル - Wikipedia

1961年にヨーロッパにおける計算機システムを標準化するために設立された。本部はスイスジュネーヴにある。

Ecmaインターナショナル - Wikipedia

⇧ 本部は、「永世中立国」である「スイス」にあるってところが、なかなか...「ECMAScriptは守護られている」と考えて良いということですかね。

話が脱線しましたが、「ECMAScript 2015(Edition 6)」において、「クラス」の仕組みが「JavaScript」に導入された模様。

つまり、2015年から「クラス」の仕組みは導入されていたんだけども、ブラウザによって「ECMAScript」の仕様に対する対応がまちまちであったので、「Babel」のような「トランスパイラ」ってツールが誕生したらしい。

トランスコンパイラ(他にトランスパイラ、ソース・トゥ・ソースコンパイラ、などとも)は、あるプログラミング言語で書かれたプログラムソースコードを入力として受け取り、別のプログラミング言語の同等のコードを目的コードとして生成する、ある種のコンパイラである。

トランスコンパイラ - Wikipedia

⇧ とあって、例えば、「JavaScript」の「Babel」の話で考えると「ECMAScript 2020(Edition 11)」の仕様でコードを生成してるけど、「IEInternet Explorer)」ってブラウザが「ECMAScript 2020(Edition 11)」に対応していない場合に、対応してる仕様に合わせたコードも生成してくれるってことらしい。

ちなみに、

support.microsoft.com

Internet Explorer 11 は廃止され、2022 年 6 月 15 日にサポートを終了します。

Internet Explorer のダウンロード

atmarkit.itmedia.co.jp

 上記の図や表の「ブラウザとしてのIE」は、単体で動作するWebブラウザアプリとしてのIE11を指している。そのサポートは2022年6月15日に終了する(以前は2025年10月終了だったのが前倒しされた)。

いよいよ完全終了へ。Internet Explorer(IE)サポート終了スケジュール:Tech TIPS - @IT

⇧ ということで、これまで何かとWeb界隈の開発者の手を煩わせてきた「IEInternet Explorer)」が完全にサポート終了するらしい、「クロスブラウザ」対応の作業とかも多少は軽減されるのかな。

度々、話が脱線して申し訳ない。「ECMAScript」の仕様については、

262.ecma-international.org

About this Specification

The document at https://tc39.es/ecma262/ is the most accurate and up-to-date ECMAScript specification. It contains the content of the most recent yearly snapshot plus any finished proposals (those that have reached Stage 4 in the proposal process and thus are implemented in several implementations and will be in the next practical revision) since that snapshot was taken.

https://262.ecma-international.org/

Contributing to this Specification

This specification is developed on GitHub with the help of the ECMAScript community. There are a number of ways to contribute to the development of this specification:

https://262.ecma-international.org/

⇧ 上記のページで管理されてる模様。

ちなみに、「Ecma International」の「TC39」ってのは、

tc39.es

TC39

Ecma International's TC39 is a group of JavaScript developers, implementers, academics, and more, collaborating with the community to maintain and evolve the definition of JavaScript. 

https://tc39.es/ 

⇧ ということらしく、「JavaScript」の仕様とかをメンテナンスしてるグループってことみたいね。

www.ecma-international.org

www.ecma-international.org

Scope:

Standardization of the general purpose, cross platform, vendor-neutral programming language ECMAScript®. This includes the language syntax, semantics, and libraries and complementary technologies that support the language. This work intends not to use patents or if so then only royalty free patents. To aid in achieving that objective, this TC is using the Royalty-Free Patent Policy.

https://262.ecma-international.org/

⇧ 目的としては、「クロスプラットフォーム」や「ベンダー依存の無い」あたりを目指してるみたい。

「Published Standards」タブを確認すると、

www.ecma-international.org

f:id:ts0818:20220129143127p:plain

⇧「ECMA-262」以外にも管理してるようだけど、「ECMAScript」の言語の仕様としては「ECMA-262」で管理してますよ、ってことみたいね。

過去の仕様のアーカイブとかも公開してくれてるみたいです。

www.ecma-international.org

なんか、URL的には、

https://262.ecma-international.org/{ECMAScriptのEdition}/    

って感じになってるらしく、例えば、「ECMAScript 2020(Edition 11)」の仕様書のURLだと、

https://262.ecma-international.org/11/    

ってことになるみたい。

ちなみに、最新版の仕様書のリンクURLには、何もEditionが付かないみたいです。

仕様書の「Introduction」には、各Editionの時にどんな変化があったかをザックリ説明してくれていて、「ECMAScript 2015(Edition 6)」の部分を抜粋すると、

Introduction

In a very real sense, the completion of the sixth edition is the culmination of a fifteen year effort. The goals for this edition included providing better support for large applications, library creation, and for use of ECMAScript as a compilation target for other languages. Some of its major enhancements included modules, class declarations, lexical block scoping, iterators and generators, promises for asynchronous programming, destructuring patterns, and proper tail calls.

https://262.ecma-international.org/

⇧ ということで、「class declarations」が追加されたということらしく、日本語だと「クラス宣言」ということで、「クラス」が利用できることになったらしいですと。

で、「ECMAScript」におけるクラスがどんなものなのかってのが、「ECMAScript Specification」を見れば分かるかと思いきや、サッパリ分かりませんでしたと。

というか、「クラス」を追加したって言うのに、その説明を避けてる感じがしてなりませんと、何故かというと、

4.3 ECMAScript Overview

4.3.1 Objects

Even though ECMAScript includes syntax for class definitions, ECMAScript objects are not fundamentally class-based such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initializes all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named "prototype" that is used to implement prototype-based inheritance and shared properties.

https://262.ecma-international.org/

f:id:ts0818:20220129153138p:plain

In a class-based object-oriented language, in general, state is carried by instances, methods are carried by classes, and inheritance is only of structure and behaviour. In ECMAScript, the state and methods are carried by objects, while structure, behaviour, and state are all inherited.

https://262.ecma-international.org/

⇧ ってな感じで、「ECMAScript」ってのは「Java」などのような「クラスベースのオブジェクト指向言語」とは異なりますよと言っているのですが、

Beginning with ECMAScript 2015, the ECMAScript language includes syntactic class definitions that permit programmers to concisely define objects that conform to the same class-like abstraction pattern used by the built-in objects.

https://262.ecma-international.org/

⇧ 肝心の「クラス」については曖昧にボヤかしてるところが甚だ納得がいきませんと。そこはちゃんと説明して欲しいんですがね...、「ECMAScript 2015(Edition 6)」で『Some of its major enhancements』って謳い文句を掲げてた中の1機能だったんだから図解してやってくれても良い気はするんだが...

そもそも、「Objects」って『Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initializes all or part of them by assigning initial values to their properties.』って説明からして、

  • via a literal notation
  • via constructors

のどっちかで作るとは言ってるけども、

  • object
  • ordinary object
  • exotic object
  • standard object
  • built-in object

このあたりの違いってのがよう分からん...

timothygu.me

⇧ 上記サイト様によりますと、「object」「ordinary object」「exotic object」の関係性は何となくイメージできたけど、「standard object」「build-in object」が結局よく分からんですな...

ECMAScriptのクラスとは?

まぁ、今回は、「class」の話ということで、「object」の話は一旦おいておいて、

googlechrome.github.io

ES6 Classes formalize the common JavaScript pattern of simulating class-like inheritance hierarchies using functions and prototypes. They are effectively simple sugaring over prototype-based OO, offering a convenient declarative form for class patterns which encourage interoperability.

https://googlechrome.github.io/samples/classes-es6/

Google Chromeだと、上記のような説明になっていて、

  • functions
  • prototypes

を使えば「Class」を実現できるって言っていて、「ECMAScript Specification」の「4.3.1 Objetcs」の説明で、

Each constructor is a function that has a property named "prototype" that is used to implement prototype-based inheritance and shared properties.

ってなっていたところを見ると、「Class」も「object」と作り方は変わらないような感じなのかね?

う~ん...結局、「ECMAScript」における「Class」ってものが何なのかいまいちよく分からん...

ECMAScriptとTypeScriptとAtScriptと

ECMAScript」と「TypeScript」の関係を調べていて、「AtScript」なるものも出てきたんだが、それぞれの関係は、

medium.com

⇧ となると言ってるのだけど、Wikipediaさんによると、

AtScriptは、マイクロソフトTypeScriptを拡張してJavaScriptへのトランスコンパイルを行い提案されたJavaScriptベースのスクリプト言語である。

AtScript - Wikipedia

これは2014年10月にGoogleAngularJS Web開発フレームワークの開発者によって ng-Europe 会議で導入され、今後のAngular 2.0の構築に使用される言語として導入された

AtScript - Wikipedia

AtScriptはもともとTypeScript上で実行することを目的としていたが、Dartの機能もいくつか含まれていた。 2014年10月、GoogleはAngular 2.0がAtScriptで書かれると発表した2015年3月、マイクロソフトはAtScriptの機能の多くがTypeScript 1.5リリースで実装されること、そしてAngular 2.0が純粋なTypeScript上に構築されることを発表した。

AtScript - Wikipedia

「AtScript」という名前は、多くの言語で注釈に使用される@「at」記号に由来。

AtScript - Wikipedia

⇧ ということで、「AtScript」使われてない説が大きい気がするのだが...

まぁ、「AtScript」はおいておくとして、「TypeScript」のドキュメントで「Classes」のページを確認してみると、

www.typescriptlang.org

TypeScript offers full support for the class keyword introduced in ES2015.

https://www.typescriptlang.org/docs/handbook/2/classes.html

⇧「ECMAScript 2015(Edition 6)」の「class keyword」を完全にサポートしてますってことらしいんだけど、怖いのは「TypeScript」側で独自の仕様を追加してたりしてないかってことね、つまり余計なことしてくれてなければ良いんだけどね...

 

Vue Property Decoratorを使ってみる、その前に「Vue CLI」で「Vue.js」のプロジェクト作成

長々と脱線してきましたが、Vue.jsで「ECMAScript」の「Class」や「TypeScript」の「Classes」を利用してみようというわけで、Vue 2系を使ってる場合は、「Vue Property Decorator」を使ってる場合があり得るということで、

qiita.com

⇧ 上記サイト様を参考に学習してみる。

「TypeScript」を使うには「Node.js」が必要なので、インストールされているか確認。(自分は「nvm-windows」というツールをインストールして「Node.js」のインストールを行っています。)

f:id:ts0818:20220123143940p:plain

で、「Vue.js」のプロジェクト用に適当なフォルダを作成しておきます。

f:id:ts0818:20220123144415p:plain

そしたらば、コマンドプロンプトで、上記のフォルダに移動し、「Vue CLI」をnpmでインストールしていきますが、インストール可能な「Vue CLI」バージョンを確認。

f:id:ts0818:20220123144840p:plain

とりあえず、最新版の「Vue CLI」をインストール。

f:id:ts0818:20220123145243p:plain

f:id:ts0818:20220123145343p:plain

「node_modules」フォルダがインストールされました。

f:id:ts0818:20220123145502p:plain

「Vue CLI」で「Vue.js」のプロジェクトを作成していきます。「Vue CLI」をグローバルにインストールしない場合は、一時的にパスを追加するか、「Vue CLI」までのフルパスでコマンド実行する必要があるようです。今回は、一時的にパスを追加で。

「Vue CLI」のコマンドが実行でき、選択肢が表示されたら、

f:id:ts0818:20220123145951p:plain

「Manually select features」を選択して「Enterキー」を押下。

f:id:ts0818:20220123150025p:plain

そしたらば、「TypeScript」にカーソルを移動し、

f:id:ts0818:20220123150424p:plain

「Spaceキー」を押下。「*」が付いた機能が「Vue.js」のプロジェクトで利用できるようになるようです。もし、ここでチェックを付けなかった場合でも、「Vue.js」のプロジェクト作成後に、npmでインストールなどは可能のようです。

とりあえず、「TypeScript」のみ追加で「Enterキー」を押下。

f:id:ts0818:20220123150532p:plain

「Vue.js」のバージョンです。今回は「2.x」にしてます。「Enterキー」押下。

f:id:ts0818:20220123150847p:plain

「Vue Class Component」を利用するかの選択肢では、「Y」を入力し、「Enterキー」押下。

f:id:ts0818:20220123151018p:plain

「Babel」は「ECMAScript」の最新の仕様に対応していないブラウザに対応したJavaScriptコードに変換してくれるもののようですが、今回は利用しない方向で。「IEInternet Explorer)」もサポート終了するって言ってるし、他のブラウザはきっと最新の「ECMAScript」に対応してくれてると信じて。

f:id:ts0818:20220123151515p:plain

「ESLint + Prettier」が主流らしいので、選択しました。

f:id:ts0818:20220123152031p:plain

「Lint on save」を選択しました。

f:id:ts0818:20220123152142p:plain

f:id:ts0818:20220123152311p:plain

f:id:ts0818:20220123152420p:plain

f:id:ts0818:20220123153142p:plain

f:id:ts0818:20220123153529p:plain

f:id:ts0818:20220123153656p:plain

作成されたプロジェクトには、npmのモジュールがいろいろインストールされてますと。

f:id:ts0818:20220123154245p:plain

⇧「TypeScript」「vue-class-component」「vue-property-decorator」などなど、今回必要なものはインストールされてますね。

Vue Property Decoratorを使ってみる、その前に「VS CodeVisual Studio Code)」の設定

Vue 2系の「TypeScript」の使用に関するドキュメントを確認すると、

jp.vuejs.org

各エディタによるサポート

TypeScript による Vue アプリケーションを開発するために、すぐに利用できる TypeScript のサポートを提供する Visual Studio Code を使用することを強く勧めます。単一ファイルコンポーネント (SFC) を使用している場合、SFC 内部で TypeScript インターフェイスと他の多くの優れた機能を提供する素晴らしい Vetur 拡張 を入手してください。

https://jp.vuejs.org/v2/guide/typescript.html

⇧「VS CodeVisual Studio Code)」を使用することを強く勧めます、ということなのですが、「VS CodeVisual Studio Code)」での設定については一切言及がないというね...

VS CodeVisual Studio Code)」をインストールしていない場合は、インストールしておきます。

VS CodeVisual Studio Code)」を起動し、「ファイル(F)」>「フォルダーを開く...」を選択し、

f:id:ts0818:20220123155455p:plain

f:id:ts0818:20220123155759p:plain

f:id:ts0818:20220123155852p:plain

VS CodeVisual Studio Code)」には、「ワークスペース」という概念があり、

ts0818.hatenablog.com

⇧ 手前味噌で恐縮ですが、上記記事でまとめております。

今回、新しくプロジェクトを作成したので、「VS CodeVisual Studio Code)」の「ワークスペース」を新しく設定します。

f:id:ts0818:20220123155958p:plain

f:id:ts0818:20220123160122p:plain

「.vscode」というフォルダと「settings.json」というファイルが作成されます。

f:id:ts0818:20220123160159p:plain

「settings.json」に設定を追記。

{
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "eslint.format.enable": false,
      "editor.formatOnSave": true,
      "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[json]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[typescript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "editor.lineNumbers": "on",
      "editor.rulers": [80],
      "editor.wordWrap": "on",
      "eslint.packageManager": "yarn",
      "files.insertFinalNewline": true,
      "files.trimTrailingWhitespace": true,
      "npm.packageManager": "yarn",
      "typescript.enablePromptUseWorkspaceTsdk": true,
    //   // 拡張機能で「Code Runner」入れてる場合の設定
    //   // ts-node、esbuild-registerはnpmなどでインストールが必要
    //   "code-runner.executorMap": {
    //     "javascript": "node",
    //     "typescript": "node --require esbuild-register"
    //     //"typescript": "node -r ts-node/register"
    //   }
}

あとは、「VS CodeVisual Studio Code)」の「拡張機能」を追加しておいたほうが良いものとしては、

pokuwagata.hatenablog.com

⇧ 上記サイト様が参考になるかと。

自分は、「TypeScript」関連の「VS CodeVisual Studio Code)」の「拡張機能」としては、

  • ESLint
  • TypeScript Importer
  • TypeScript Import Sorter
  • Move TS
  • Prettier

を追加しています。「拡張機能」は以下のアイコンを押下して表示されるページですが、「インストール済み」と表示されていればOK。インストールして無い場合は、検索してインストールしておきます。

f:id:ts0818:20220123164242p:plain

「Vue.js」関連の「拡張機能」としては、

  • Vetur

ってものをインストールしています。

 

Vue Property Decoratorを使ってみる

というわけで、ようやっと、「VS CodeVisual Studio Code)」でコーディングする準備ができたので、「.vue」ファイルを作成で。

f:id:ts0818:20220123173930p:plain

ファイルを編集。

■vue-property-decorator-work\my-typescript-project\src\components\Deco.vue

<script lang="ts">
/* eslint-disable no-console */
import {Component, Vue} from 'vue-property-decorator';
console.log("■Deco class■")

@Component
export default class Deco extends Vue {

}
</script>    

■vue-property-decorator-work\my-typescript-project\src\App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
import Deco from "./components/Deco.vue";

@Component({
  components: {
    HelloWorld,
    Deco
  },
})
export default class App extends Vue {}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

⇧ で、保存して、「コマンドプロンプト」で、「npm run serve」を実行。

f:id:ts0818:20220123174634p:plain

f:id:ts0818:20220123174701p:plain

で、ブラウザで「http://localhost:8080」にアクセス。

f:id:ts0818:20220123174820p:plain

⇧「デベロッパーツール」の「console」タブを確認すると、「Deco.vue」が読み込まれてることが確認できます。

いまいち、よう分からんのは、

jp.vuejs.org

プレーンな JavaScript オブジェクトを data オプションとして Vue インスタンスに渡すとき、Vue はその全てのプロパティを渡り歩いて、それらを Object.defineProperty を使用して getter/setter に変換します。これは ES5 だけの、シム (shim) ができない機能で、Vue が IE8 以下をサポートしないのはこのためです。

https://jp.vuejs.org/v2/guide/reactivity.html

getter/setter はユーザーには見えませんが、内部では、Vue が依存性を追跡したり、プロパティがアクセスまたは変更されたときに変更を通知したりすることを可能にしています。ひとつ注意点を挙げると、変換されたデータオブジェクトをログ出力するとき、各ブラウザコンソールで getter/setter のフォーマットが異なるため、より調査に適したインターフェイスの vue-devtools をインストールしたほうがいいかもしれません。

https://jp.vuejs.org/v2/guide/reactivity.html

全てのコンポーネントインスタンスは対応する ウォッチャ (watcher) インスタンスを持っていて、これはコンポーネントを描画する間に “触れた (touched)” プロパティを全て依存性として記録しています。その後、依存性の setter がトリガされると、ウォッチャに通知してコンポーネントの再描画が起動します。

https://jp.vuejs.org/v2/guide/reactivity.html

⇧ getter/setterはデフォルトで用意されてるってことなんかね?

なんか、

qiita.com

親から受け取るvalue を直接v-model に指定できないので、get、setプロパティを間に挟んで、set時にEmit してあげるわけですね。

Vue.js+TypeScriptでコンポーネントをv-modelでつなげてみる - Qiita

⇧ 別コンポーネントにしてる場合、トリッキーな書き方をせざるを得ないらしい...

qiita.com

こちらのコア開発メンバーによる質問回答を見るに、複数のプロパティをv-modelのような使い方をしたいという要望に答えて.syncが足されたという経緯のようで、本質的には同じもののようです。

Vue.js:v-modelと$emitを使ってデータを読み書きする子コンポーネントをつくる (2019/10/13追記) - Qiita

⇧そして、悲報は続く...

Vue 2系だと、複数のプロパティでv-model使えない説が...

で何やかんやで制約がめちゃくちゃ多いっぽいのだが、

■my-typescript-project\src\components\Deco.vue

<template>
  <div>
      <p><label>{{value}}</label></p>
      <p><input type="text" v-model="localValue"/></p>
      <!--
      <input type="text" v-model="localAge"/>
      -->
  </div>
</template>

<script lang="ts">
/* eslint-disable no-console */
import {Component, Emit, Prop,  Vue, Watch} from 'vue-property-decorator';
console.log("■Deco class■")

@Component
export default class Deco extends Vue {
//   @Prop() public name!: string;
@Prop() public value!: string;
// @Prop() public age!: number;

@Emit()
public input(value: string) {/* */}

// @Emit()
// public inputAge(age: number) {/* */}

// getterは、@Emit()の付いたメソッドの後に記述する必要がある
private get localValue(): string {
  return this.value;
}

private set localValue(value: string){
    this.input(value);
}

// private get localAge(): number {
//   return this.age;
// }

// private set localAge(age: number){
//     this.inputAge(age);
// }

  // created() {
  //   //   this.name = "";
  //   //   this.age = 0;
  // }

//   public get valueName(): string {
//       return this.name;
//   }

//   public set valueName(name: string) {
//       this.name = name;
//   }

//   public get valueAge(): number {
//       return this.age;
//   }

//   public set valueAge(age: number) {
//       this.age = age;
//   }

  @Watch('value')
  propertyNameWatcher() {
      console.log("@Watch('value')【this.value】" + this.value)
  }

//   @Watch('name')
//   propertyNameWatcher() {
//       console.log("@Watch('name')【this.name】" + this.name)
//   }

//   @Watch('age')
//   propertyAgeWatcher() {
//       console.log("@Watch('age')【this.age】" + this.age)
//   }

//   updated() {
//       console.log("【this.name】" + this.name)
//       console.log("【this.age】" + this.age)
//   }

}
</script>

■my-typescript-project\src\App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
    <!--{{parentName}}{{parentAge}}-->
    <!--
    <deco
    :name.sync="parentName" @name="name = $event"
    :age.sync="parentAge" @age="age = $event" />
    -->
    <deco v-model="msg" />
    <deco v-model="parentAge" />
  </div>
</template>

<script lang="ts">
/* eslint-disable no-console */
import { Component, Vue, Watch } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
import Deco from "./components/Deco.vue";

@Component({
  components: {
    HelloWorld,
    Deco,
  },
})
export default class App extends Vue {

  // private msg!: string = "";
  // private parentAge!: number = 0;
  private msg = "hoge";
  private parentAge = 9999;

  // beforeCreate() {
  //   this.parentName = "";
  //   // this.parentAge = 0;
  // }
  @Watch('msg')
  propertyNameWatcher() {
      console.log("@Watch(msg)【this.msg】" + this.msg)
  }

  @Watch('parentAge')
  propertyAgeWatcher() {
      console.log("@Watch('parentAge')【this.parentAge】" + this.parentAge)
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

という感じでファイルを編集して、

f:id:ts0818:20220129182108p:plain

f:id:ts0818:20220129182133p:plain

ブラウザから「http://localhost:8080」にアクセスすると、「input」タグが表示されており、「デベロッパーツール」の「コンソール」を表示しておいて、

f:id:ts0818:20220129182249p:plain

適当に値を変えてみると、リアルタイムで値が変更されるので、リアクティブな値の変更ができているので、「双方向バインディング」が実現できていることが確認できました。

f:id:ts0818:20220129182515p:plain

何て言うか、Vue 2.xとTypeScriptの相性が悪すぎるだけなのか、妙にコーディング上の制約がてんこ盛りな気がしていて、Vue.jsのメリットがまだまだ実感できないのですが、慣れれば納得できる良さが見えてくるのか期待したいところですかね。

ちなみに、

www.ykrods.net

公式には(2018年以降) event bus の利用は非推奨で、グローバルな状態管理には Vuex を使いましょうということで良いと思います。

  • 例えばログインユーザのセッションなどはグローバルな状態だと思われるので、基本的には SPA を Vue で作るなら Vuex を利用することになると思います。

Vue.js の event bus (あるいは event hub) 、非推奨になっていた — ykrods note

⇧ 上記サイト様によりますと、Vue.jsのドキュメントから知らない間に削除されてるとかあるらしい...何と言うか、ドキュメントから黙って削除するのはやったらアカンでしょ...

既に利用されてるケースでメンテナンスしなきゃならん場合に参照できる情報は残しておいてもらわないと現場が困りますな...

zenn.dev

使ってわかる、Vueへの恨み、つらつらと(随時更新)

2021年現在Vueを選択すべきでないと思う理由

⇧ というような情報もあり、暗澹たる気持ちでいっぱいですが、引き続き学習を進めていきたいところです。

Vue.jsって利用してる人が多いって割には、TypeScriptと絡んだ時の情報がネットであんまり引っかかってこないというね...

フロントエンド界隈の有識者の方が、どしどし発信してくれるのを期待ですかね。

毎度モヤモヤ感が半端ない...

今回はこのへんで。