Vue.js が予想以上に良かったので、既存WordPressに導入。Vue.js (vue-class-component) + TypeScript + WordPress で作る、記事読み込み component 「環境構築編」
2017.02.21
この記事は最終更新日から1年以上が経過しています。
どもです。
タイトル長めになりました。
かれこれ、6、7年放置気味のWordPressのサイトを サーバー移転に伴い色々と整理しています。
既存のWordPressは、がっつりプラグインに依存しているしjQueryも7年前ぐらいに入れっぱなし。。
という事で、外せるプラグインは外して、これを機にjQueryも外そうと。
したところ、よくある「さらに記事を読み込む」ボタンの実装がどうやら必要だ。

このボタンを押すと、Ajaxで記事を取得してきて、表示する。と言った機能。
今まで、プラグインを利用してきたのですが、外せるなら外して自作したいですよね。
そこで、どうせなら新しめのフレームワークを入れちゃおうかなと、どれを入れようか20秒ほど考えました。
Angular2を入れるにはちょっと大げさすぎるし、気軽な感じでMVVMしたいからReactはちょっと違うかなと。
という事で最近、話題の「Vue JS」の出番ですよ!!
バージョンが2.0になったということで何やら、評判も上々。
かなりの人気を博しておりますね。
公式ページ

基本的な使い方は公式ページを参照ください ><
で、使って行きたいのですが、やはりTypeScriptで書いていきたい。。。
かれこれ、3年ほど書いてきましたがやはり型があるのは良いですよね。
型が必要ということも徐々に浸透しだしておりますね。
ということで、TypeScriptを使うならこれを使えと、公式も推奨している
「vue-class-component」を使うことにしました。
github
https://github.com/vuejs/vue-class-component
サンプルを見てわかるように、Compornent ディレクティブを利用することができ、Angular Likeに記述していくことができます。
(なんとなく書いていて、結果 Angularみたくなってなってしまったがw
ビルド環境はこんな感じ
Dependencies
・ Vue.js
・ vue-class-component
Dev Dependencies
・ TypeScript
・ Webpack
・ ts-loader
・ html-loader
では、早速インストール
インストール
npm install
$ npm install vue $ npm install vue-class-component $ npm install html-loader $ npm install ts-loader
TypeScriptなので、Typingsで型定義ファイルをインストールしたいのですが、嬉しいことにVueはTypeScriptにも対応していて特に別途インストールする必要もありません。
それでは、webpackのconfigを作成していきます。
webpack
webpack.config.js
"use strict";
var webpack = require('webpack');
module.exports = {
entry: "./ts/index.ts",
output: {
filename: "bundle.js",
path: "./js"
},
module: {
loaders: [
{ test: /\.tsx?$/, loader: "ts-loader" },
{ test: /\.html$/, loader: "html-loader?minimize=false" }
]
},
resolve: {
extensions: ["", ".ts", ".tsx", ".js"],
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
なんともない、ほぼwebpackのデフォルトの設定なのですが、気をつけないといけない所として、
resolve の aliiasとして「vue$ : vue/dist/vue.common.js」を定義しないといけないところですね。 ><
これがないとコンパイルが通らず、少々苦労しました orz
余り、日本語のドキュメントもないという。。
package.json
"scripts": {
"webpack": "webpack",
"webpack:w": "webpack --progress --colors --watch"
},
なるべく最小限で行きたいので、 npm scriptsでwebpackを実行できるようにと。
tsファイル作成
エントリーポイントをindex.ts としましたので、index.tsを作成。
とその前にざっと、ディレクトリ構成を
ts/ ├──components/ ├──service/ ├──store/ ├──bus.ts ├──components.ts └──index.ts
シンプルにこのような感じとなりました。なんとなくAngular寄りなディレクトリ構造。
では、一応説明を。
「components」は、コンポーネントのtsとそれに対となるhtmlが格納されるディレクトリです。
「service」ディレクトリは、古来Angular等のアーキテクチャでもそうですが、Ajax等による通信周りの処理を格納するディレクトリです。
「store」は、Flux等とはちょっと異なりモデル層を格納するディレクトリです。
「bus.ts」は、公式でも書かれているようにpubsubの責務を持つファイルとなります。(追って詳細を)
「components.ts」は、各componentsを集約させるファイル。
「index.ts」はエントリーポイントとなるファイルとなります。
それでは、index.tsを作成していきます。
index.ts
"use strict";
import Vue = require('vue');
import {
PostMoreBtn,
PostList
} from './components';
const app = new Vue({
el: '#app',
components: {
PostMoreBtn,
PostList
}
});
今回は、「さらに記事を読み込む」ボタンの実装を行いたいので、componentsは「PostMoreBtn」と「PostList」にしました。
Vueをrequireして、各componentsをimport。
Vueオブジェクトにcomponentsを定義し、作成。変数appに代入。
components.ts
export * from './components/post-more-btn'; export * from './components/post-list';
componentsファイル側はこんな感じですね。
components作成と共に追加していく感じですね。
ま。この辺、Angularをやっている方だと、特に変わりない感じですかね。
storeの方も作成していきましょう。
store/post.ts
interface Category {
readonly name: string;
readonly url: string;
}
interface Tag {
readonly name: string;
readonly url: string;
}
export default class Post {
public title: string;
public date: string;
public imageUrl: string;
public postDetail: string;
public categoryList: Category[];
public tagList: Tag[];
}
WordPressの記事をモデルとして扱いたいので、上記のような感じにしました。
(TypeScriptの詳細等は割愛させていただきます。
Service層でWordPress側のAPIと、Ajax通信して型付けしていくイメージですね。
それでは、componentsの作成を。
components/post-list.ts
import Vue = require('vue');
import Component from 'vue-class-component';
import bus from '../bus'
import Post from '../store/post';
@Component({
template: require('./post-list.html')
})
export class PostList extends Vue {
private posts: Post[];
data(): any {
return {
posts: []
}
}
created() {
bus.$on('update-post', this.onUpdatePost)
}
destroyed() {
bus.$off('update-post', this.onUpdatePost)
}
onUpdatePost(posts: any): void {
posts.forEach((post: any) => {
this.posts.push(post);
});
}
}
ここで、vue-class-componentを利用するので、vue-class-componentをimportして利用します。
また、html-loaderを利用すると、componentをhtmlとして読み込み使用できますので、テンプレートは別にファイルを作成します。
busに関しては、次回追って詳細を><
なので、「created」、「destroyed」関数は飛ばして、「onUpdatePost」関数を。
といっても説明するほどでもないのですが、Ajax通信したあと、onUpdatePost関数を経てpostを保持します。
components/post-list.html
<div>
<div class="post section" v-for="post in posts">
<h2 class="post-title"><a :href="post.postUrl">{{ post.title }}</a></h2>
<ul>
<li v-for="category in post.categoryList"><a :href="category.url" rel="category">{{ category.name }}</a></li></ul>
<p>{{ post.date }}</p>
<p><img :src="post.imageUrl" :alt="post.title"></p>
<p>{{ post.postDetail }}</p>
<p><a :href="post.postUrl"><b class="icon next"></b>続きを読む</a></p>
<div class="postTag">
<p><a :href="tag.url" rel="tag">{{ tag.name }}</a><span v-if="post.tagList.length > (index + 1)">,</span></p>
</div>
</div>
WordPressの記事のリストとなる部分です。
ざっと、こんな感じでしょうか。。この辺は任意で。vueJSのバインドの記述などは割愛させていただきます。
ちょっと気をつける点として、ファイルの最初にvueJSのバインドを記述しているとうまく行かず、空divを囲うことで避けました。。
(この辺、どうにかならないのか。。)
それでは、「さらに記事を読み込む」ボタンの箇所を実装していきましょう。
components/post-more-btn.ts
import Vue = require('vue');
import Component from 'vue-class-component';
import PostMoreService from '../service/post-more.service';
import bus from '../bus'
@Component({
props: ['nowPostNum'],
template: require('./post-more-btn.html')
})
export class PostMoreBtn extends Vue {
private nowPostNum: number;
private postMoreService: PostMoreService = new PostMoreService();
onClick (): void {
this.postMoreService.fetchData(this.nowPostNum)
.then((response: any) => {
bus.$emit('update-post', response.data);
this.nowPostNum += 10;
}, (error: any) => {
console.log(error);
});
}
}
このボタンを押すと、非同期でWordPress側のAPIと、Ajax通信したいので、PostMoreServiceのサービス層を読み込んで利用します。
props [‘nowPostNum’] で、外から記事を今何件表示しているかを受け取ります。
postMoreServiceで記事データをfetchできたら、busに通知するため bus.$emit update-postを行い、現在の記事表示「nowPostNum」を加算していきます。
components/post-more-btn.html
<div class="moreBtnBox"> <a @click="onClick">他の記事を読み込む</a> </div>
ボタン側のテンプレートとなります。
こちらはシンプルで、クリックされたら先程のonClick関数を実行します。
と、一旦はここまでで、
(この辺でもう、Angularぽくなって来てるのが、わかるかとw
意外に長くなりそうなので、次回は WordPressのAPIと連携して、PostMoreServiceで受取り 記事を更新していく箇所を書いていければと思いますー
ではでは。




















