クロコめも2。

ただのめもー

TypeScriptでvue-class-componentを使ってみる

追記:書き直した->

http://kurokokoruru.hatenablog.com/entry/2015/11/14/131304

以下のこと書くメモ

  • Vue.jsでコンポーネントベースで開発する
  • TypeScriptでvue-class-componentを使ってみる
  • sass使う
  • gulpなしwebpackのみ

環境構築手順(mac) 2015/11/4

  1. ディレクトリを用意する
  2. npmの初期化&必要なものをインストール
  3. ビルドの設定
  4. ヘッダーコンポーネント定義&設置
  5. todoAppをクラスベースに書き換えると

vue-class-componentについて

ES7/TypeScript向けにクラスベースでコンポーネントを定義するためのもの
https://github.com/vuejs/vue-class-component

TypeScriptの1.5.0-alphaから利用可能になったDecoratorを利用している。

環境構築手順詳細(mac)2015/11/4

ディレクトリを用意する

mkdir プロジェクトのフォルダ
cd プロジェクトのフォルダ
mkdir build
mkdir -p  src/{components,views,assets,directives,filters}
mkdir src/assets/js

npmの初期化&必要なものをインストール

npm init
npm i -g webpack webpack-dev-server mocha typescript tsd tslint
npm i -S vue vue-class-component
npm i -D webpack style-loader css-loader sass-loader ts-loader html-loader typescript tsd tslint-loader mocha mocha-loader chai
cp ./node_modules/tslint-loader/node_modules/tslint/docs/sample.tslint.json ./tslint.json
// ターミナルで定義ファイルのインストール
tsd init
tsd install vue --save
tsd query require -so -a install

ビルドの設定

webpack.config.js

module.exports = {
    entry: {
        app: "./src/assets/js/entry.js"
    },
    output: {
        path: './build/js',
        publicPath: '/js/',
        filename: "[name].js"
    },
    devtool: "source-map", // source-mapを生成する
    module: {
        preloaders: [
            {
                test: /\.ts$/,
                loader: "tslint"
            }
        ],
        loaders: [
            {
                test: /\.scss$/,
                loader: "style!css!sass"
            },
            {
                test: /\.html$/,
                loader: "html"
            },
            {
                test: /\.ts$/,
                loader: "ts-loader"
            }
        ]
    },
    resolve: {
        // require()するときに拡張子を省略可能にします
        extensions: ['', '.js', '.scss']
    }
};

src/assets/js/にentry.tsを作成

console.log("hello");

/build/index.htmlを作成

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>sample</title>
</head>
<body>
    <div id="app">this is app</div>
    <script type="text/javascript" src="js/app.js" charset="utf-8"></script>
</body>
</html>

webpack-dev-serverを起動してプレビュー
http://localhost:8080/webpack-dev-server/

// コンソールで"hello"の文字が出力されてればここまでOK

ヘッダーコンポーネント定義&設置

src/assets/js/entry.tsを書き換え

/// <reference path="../../../typings/tsd.d.ts" />    
import Vue = require('vue');
require('../sass/main');
new Vue(require('../../views/app'));

src/assets/sass/main.scss作成(てきとー)

body {
  margin: 0px;
  padding: 0px;
}
.main-header {
  margin: 0px;
  padding: 3px;
  background-color: #fafafa;
  border-bottom: 1px solid #CCCCCC;
  text-align: center;
}

.main-footer {
  position: fixed;
  width: 100%;
  margin: 0px;
  padding: 3px;
  background-color: #fafafa;
  border-top: 1px solid #CCCCCC;
  bottom: 0px;
}

src/views/app/index.tsを作成

/// <reference path="../../../typings/tsd.d.ts" />
import Vue = require('vue');
var app = new Vue({
    el: "#app",
    template: require('./template.html'),
    components: {
        'app-header': require('../../components/header').Header
    }
});

src/views/app/template.htmlを作成

<app-header></app-header>

src/components/header/index.tsを作成

/// <reference path="../../../typings/tsd.d.ts" />
import VueComponent = require('vue-class-component');

@VueComponent
export class Header {
    static template = require("./template.html");

    ready() {
        console.log('hogehoge');
    }
}

src/component/header/template.html

<div class="main-header">
    <h3>TypeScript & Vue.js sample</h3>
</div>

ここでプレビュー画面にヘッダーが表示されてればOK.

あとのコンポーネント追加は同じことの繰り返しなので割愛。

todoAppをクラスベースで書き換えると

先日エントリのTodoアプリのコンポーネントかつクラスベース版

/// <reference path="../../../typings/tsd.d.ts" />
import VueComponent = require('vue-class-component');


interface ITask {
    body: string;
    done: boolean;
}

@VueComponent
export class TodoApp {
    tasks:ITask[];

    newTaskBody = '';

    static template = require('./template.html');

    data() {
        return {
            tasks: this.tasks,
            newTaskBody: this.newTaskBody
        }
    }

    get computedDoneCount() {
        return this.getDoneCount();
    }

    created () {
        this.tasks = [
            {body: 'do this 1', done: false},
            {body: 'do this 2', done: false},
            {body: 'do this 3', done: false},
            {body: 'do this 4', done: false}
        ]
    }

    addNew():void {
        console.log("addNew");
        var task:string = this.newTaskBody && this.newTaskBody.trim();
        if (!task) {
            return;
        }
        this.tasks.push({body: task, done: false});
        this.newTaskBody = '';
    }

    deleteTask(delIndex:number):void {
        console.log("deleteTask");
        this.tasks.splice(delIndex, 1);
    }

    deleteDone():void {
        console.log("deleteDone");
        var oldTasks = this.tasks;
        this.tasks = [];

        oldTasks.forEach(task => {
            if (!task.done) this.tasks.push(task);
        });
    }

    getDoneCount():number {
        var count = 0;
        this.tasks.forEach(task => {
            count += task.done ? 1 : 0;
        });
        return count;
    }
}

うーん。良い。

定義ファイル(d.ts)について

d.tsファイルの作り方がよくわからない。

declare module "vue-class-component" {
    var VueComponent:ClassDecorator;
    export default VueComponent;
}

このようなものを用意したが、export defaultはES6の書き方だ。。
他にもTypeScriptがらみでintellij上で怒られるのを回避しないと行けないので課題多し。

あと、実際にやってから一週間ほど経っているのでもうすでに情報が古いかも。。

追記

  • そのままやるとbabelの6が入ってしまって動かない
  • tsのコンパイルIntelliJがやっててそれで動いてたみたい。ほかのエディタじゃ動かないはず
  • tsconfig.jsonとか用意しないとね!
  • 一応拡張子はtsだけど、とくにTypeScriptの利点が生かされてない

ってことで近いうちに書き直す