どうも、shoheiです。
NEMウォレットアプリの完成を目指してPWAアプリの作り方を連載していきます。
今回は前回の続きからTypeScriptの導入と導入した環境で実際にTypeScriptで書いてみましょう。
開発環境
- macOS High Sierra 10.13.4
- Google Chrome
- vue-pwa-boilerplate 2.1.0
- Vue.js
- TypeScript
TypeScriptとは
TypeScriptとはマイクロソフトによって開発されたプログラミング言語であり、JavaScriptにオブジェクト指向を取り入れたプログラミング言語である(っと理解している)。TypeScriptは大規模なアプリケーション開発向きと言われている。
※オブジェクト指向
クラスや継承などの概念を取り入れて、コードを再利用できるように設計していこうぜといった考え方のこと。
なぜTypeScriptか
実はVue.jsはJavaScriptで組めます。なのでわざわざTypeScriptを導入しなくても開発できます。
じゃぁなぜわざわざTypeScriptを導入するのか?
理由は….
と言ってもPWAが普及するのはもうちょい後だから、先行投資としてエンジニアは今からかじって置くと良いと思う。
JSしかやってない人は、TSやってる人の1/10くらいしかパフォーマンス出ないと思うからちゃんとTSやった方がいい。
— nori (@1amageek) 2018年5月4日
先生 @1amageek の教えに乗っかったからですw
私自身TypeScriptはまだ疎いため、JavaScriptとの比較はできませんがとりあえずやってみようぜと思った次第です(両者の具体的な良し悪しが見えてきたら別途記事にしようと思います)。
高機能エディタVScode
エディタとしてVScode(Visual Studio Code)をお勧めします。とても使いやすく、TypeScriptのコード補完などの機能が既に搭載されています。
開発効率を上げるため、以下のライブラリをVScodeにインストールしてみてください。
- vetur
- VueHelper
- HTML Snippets
- IntelliSense for CSS class names in HTML
TypeScriptの導入
前回作った環境にTypeScriptを導入していきましょう。
ライブラリをインストール
前回作ったeasy-walletに移動し、ライブラリをインストールします。
1 |
$ npm install -D typescript ts-loader@3.5 vue-class-component |
typescript、ts-loaderはTypeScriptのコードをビルドするために必要なライブラリ、vue-class-componentはクラススタイルでVueコンポーネントを組めるようにするためのライブラリです。
なお、ts-loaderのバージョンを4以上にするとwebpack周りでビルドエラーになります。
前回vue-pwa-boilerplateで取り入れたwebpackのバージョンが古いのが原因のようですが、ここではwebpackを上げずにts-loaderのバージョンを3.5にしてインストールします。
ビルド設定
tsconfig.json
ビルド設定するため tsconfig.json を作成します。
1 |
$ ./node_modules/.bin/tsc --init |
tsconfig.jsonを以下のように変更。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "compilerOptions": { /* Basic Options */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "lib": ["dom", "es5", "es2015.promise"], /* Specify library files to be included in the compilation. */ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ "strict": true, /* Enable all strict type-checking options. */ 〜〜〜省略〜〜〜 }, "include": [ "./src/**/*.ts" ] } |
各パラメータについてこちらのサイトを参考にしてください。
webpack
ビルドできるようwebpackの設定を変更します。
build/webpack.base.conf.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
module.exports = { entry: { // 変更: main.js → main.tsに変更 app: './src/main.ts' }, output: { path: config.build.assetsRoot, filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { // 追加: '.ts' を追加 extensions: ['.js', '.vue', '.json', '.ts'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src') } }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig }, // 追加 { test: /\.ts$/, loader: 'ts-loader', include: [resolve('src'), resolve('test')], options: { appendTsSuffixTo: [/\.vue$/] } }, 〜〜〜〜省略〜〜〜〜 } |
ビルド設定は完了です。
拡張子とコードを変更する
次は既に作成されているファイルの拡張子とJavaScriptで書かれているコードを変更します。
src/main.jsとsrc/router/index.jsを以下のように変更します。
src/main.js -> src/main.ts
src/router/index.js -> src/router/index.ts
次にApp.vueとHello.vueのscriptに lang=”ts” を追加します。
main.tsとindex.ts内でimportしているvueに拡張子を追加します。
src/App.vue
1 2 3 4 5 6 7 |
<template> 〜〜〜省略〜〜〜 </template> <script lang="ts"> 〜〜〜省略〜〜〜 </script> |
src/components/Hello.vue
1 2 3 4 5 6 7 |
<template> 〜〜〜省略〜〜〜 </template> <script lang="ts"> 〜〜〜省略〜〜〜 </script> |
src/main.ts
1 2 3 4 |
import Vue from 'vue' import App from './App.vue' // 変更: .vue拡張子を追記 import router from './router' 〜〜〜省略〜〜〜 |
src/router/index.ts
1 2 3 4 |
import Vue from 'vue' import Router from 'vue-router' import Hello from '@/components/Hello.vue' // 変更: .vue拡張子を追記 〜〜〜省略〜〜〜 |
vueファイルのインポート解決
今の状態ではvueファイルをインポートしてもTypeScriptが認識できないためエラーとなります。
そこでindex.d.tsなどに型定義を置く必要があります。
src配下に以下のように記述したindex.d.tsを置いて下さい。
src/index.d.ts
1 2 3 4 |
declare module "*.vue" { import Vue from 'vue' export default Vue } |
これで完了です。
TypeScriptで書いてみる
さぁ、ようやくここまできましたのでTypeScriptを使って書いていきましょう。
コードの変更
src/App.vueと src/components/Hello.vue をそれぞれ変更していきます。
src/App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<template> <div id="app"> <header> <span>{{ title }} </span> </header> <main> <img src="./assets/logo.png" :alt="title"> <h1>{{ message }}</h1> <!-- router-viewを使ってHello.vueを表示 --> <router-view message="router-viewよりこんにちは"></router-view> <!-- componentを使ってHello.vueを表示 --> <Hello message="componentよりこんにちは"></Hello> </main> </div> </template> <script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' import Hello from './components/Hello.vue' // Helloをimportする. // コンポーネントの設定 @Component({ name: 'app', // Helloをcomponentとして定義する. components: { Hello } }) // クラス export default class App extends Vue { // 変数 privateは書いても書かなくても良い private title = 'My PWA page' private message = '' // コンストラクタのようなもの。まず初めに呼ばれるとこ mounted () { // ログ出力 Chromeブラウザのconsoleで確認できる console.log('mounted App') // 関数呼び出し this.showMsg('Hello, Vue.js and TypeScript') } // 関数 showMsg (msg: string) { this.message = msg } } </script> <style> 〜〜〜省略〜〜〜 </style> |
src/components/Hello.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<template> <div class="hello"> <h1>{{ title }}</h1> <div v-html="message"> </div> </div> </template> <script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' @Component({ name: 'hello', // propsは他のvueから値渡しされる時に使用する. props: { message: { type: String, default: 'default' } } }) export default class Hello extends Vue { private title = 'Hello class' mounted () { console.log('mounted Hello') } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style> 〜〜〜省略〜〜〜 </style> |
App.vueのページ上でHello.vueをrouter-viewとcomponentを使って表示しています。
router-viewは src/index.ts で定義されている new Router の内容に紐づきます。
src/index.tsで以下のように定義していることで、router-view のトップページが Hello.vue となります。
1 2 3 4 5 6 7 8 9 |
export default new Router({ routes: [ { path: '/', name: 'Hello', component: Hello } ] }) |
その他はコードのコメントアウトを参考にしてください。
書き終えたら npm run dev で実行。
うむ、ええ感じや。
問題なく実行できたら npm run build でビルドしてGitHubにPushしましょう!
更新されるまで少し待ってからGitHub Pagesで確認します。
ええ感じですね、ちゃんとPWA起動で反映されています。
もし反映されない場合はブラウザが古いキャッシュを見ているので、ページを更新するかキャッシュを削除するかして確認してください。
次回予告
お疲れ様でした!
前回のような感動はないと思いますがいかがでしたでしょうか。
次回からいよいよNEMウォレットアプリの開発に進みたいと思います!
GitHub
コメント