WordPress + Vue.js 3.2 + TypeScript の開発環境を Docker Compose を使って用意する
Vue.js を使っていると Firebase のような BaaS だったり Serverless な環境ばかりになっていて、バックエンドの環境構築をする機会がしばらくありませんでした。
久しぶりに WordPress を扱うことになり、せっかくなので利用機会の少ない Docker Compose を使って環境構築をしようかなと。
WordPress で構築したサイト内で JavaScript で実装したい機能がいくつかあるので Vue.js 3.2 を動かすところまでやってみましたので一連の流れを記録しておきます。
環境構築の全体的な流れ
WordPress は Docker Compose で
WordPress は PHP, MySQL で動作しているため、普段使いの Mac に 少なくとも MySQL を入れる必要があります。また PHP が入っていることは知っていますが、バージョン等がどうなっているか分かりません。
以前 PHP で開発していたころから随分と時間が経ち、いまやほとんどは Docker のような閉じた開発環境を効率的に用意するというのが一般的だろうということで、利用頻度の著しく低かった Docker について軽く調べたところ Docker Compose というので良さそうです。
docker-compose.yml
という GitHub Actions と同じようなものがあればすぐに立ち上げられそうだということが分かり、これを利用することにしました。
Vue.js は、まずは CDN 版で
自分で Vue.js の環境を用意するときは Nuxt を利用するため npx nuxi init
のような始め方しかしていません。WordPress に載せるというときに、はたと「どうやって動かすのだろう🤔」と疑問に思いました。
なんとかなるとは思っていますが、まずは直接 index.php
などに <script>
タグで読み込んでしまい、最低限の動作を確認するところを一旦のゴールにします。
結局使いませんでしたが petite-vue という軽量 Vue.js もありますしね。
Vue.js + TypeScript の環境をいつもどおりに用意
結論から言うと CDN 版があっさり動きました。となると今度は TypeScript で書きたいという思いが湧いてきます。
そうなると当然にトランスパイルすることになるので、いつもどおりに node.js を使って動かすことになるでしょう。というわけで結果的にいつもどおりに利用できるようにしました。
WordPress を Docker Compose で
どうやら Docker Compose というのは複数の Docker 環境で用意されたアプリケーションを扱うためのツールのようです。
なるほど docker-compose.yml
に記述した内容を docker-compose up
してあげればすべて整うと。便利すぎる。
docker-compose.yml
公式の Docker WordPress
で検索すると Docker 公式サイトの クィックスタート: Compose と WordPress が見つかりました。
これをターミナルで docker-compose up -d
とコマンドを実行すれば OK なのでしょう。
(すでに Docker for Mac 等がインストールされている前提で話を進めます。まだの方は、公式サイトよりダウンロードしインストールしておいてください)
-d
オプションはデタッチモードのことで「コンテナはバックグラウンドで起動し、そのまま実行し続けます」とのこと。毎回つけて良さそうです。
cd ~/.gitrepos/samples # いつもお試しするときに利用しているフォルダへ移動
mkdir wordpress # WordPress 用のフォルダを作成
cd wordpress
docker-compose.yml
を作成する
プロジェクト用のフォルダ内に 今回は wp-docker-sample
というフォルダ名にしたいと思います。
mkdir wp-docker-sample
code wp-docker-sample # VS Code を起動
関係ないですが code
コマンドで VS Code が起動するのは本当に便利ですね。
以降の操作は VS Code 内でターミナルで行えば「どのタブだっけ?」ということがなくなります。
フォルダ内に docker-compose.yml
というファイルを作成し、上述の クィックスタート: Compose と WordPress 内のコードをそのまま貼り付けて保存します。
docker-compose up -d
はじめての VS Code 内に新しいターミナルを開き、次のコマンドを実行します。
docker-compose up -d
とくにエラー表示がなく Started
のようになれば起動したようです。あっさり。
ブラウザで http://localhost:8000
を開くと WordPress の言語選択画面が表示されましたね! 🎉
いやあ、驚きの簡単さです。
さて、つづいては…
まずはコードを見てみましょう。
Docker アプリが起動していると思いますので Containers / Apps
タブを開き、プロジェクト名を確認します(ここでは wp-docker-sample
です)
▼ wp-docker-sample
wp-docker-sample-db-1 # mysql:5.7
wp-docker-sample-wordpress-1 # wordpress:latest
のようになっていると思います。
wp-docker-sample-wordpress-1
にカーソルを合わせると CLI
のアイコンが表示されますのでクリックしターミナルを立ち上げます。
すると Docker 内の /var/www/html
フォルダが表示され ls
して WordPress の各ファイルがあることが確認できます。
このあとの工程としては VS Code から編集できるよう、フォルダをマウントするのでしょう。
しかし、想像するに、誰かがもっと開発しやすいように準備してくれていると思います。
慣れてない僕が試行錯誤するより、公開してくれていると思われるそれを活用したいですね。
docker-compose.yml
今回ありがたく使わせていただいた WordPress 開発環境 Docker ssh
で検索したところ次の記事が見つかりました。
TypeScript や Vue.js の記事でもよく拝見する @KawamataRyo さんの記事です。
.env
に記述した内容に従い環境構築してくれるため管理しやすそうです。
さらにデプロイするための Wordmove というツールもあり、そもそも存在を知らなかったのでとても助かります。
というわけで同じように docker-compose up -d
します。
リポジトリはQuick-start-wordpress-dockerです。
cd ~/.gitrepos/samples/wordpress
git clone git@github.com:kawamataryo/quick-start-wordpress-docker.git quick-start-wordpress-docker-sample
code quick-start-wordpress-docker-sample
VS Code が開いたら .env
の内容を編集しますが、その前に git のリポジトリを混同しないように origin を変更しておきます。
git remote rename origin template # origin → template に変更
gh repo create # 自分の GitHub リポジトリを作成
git branch -M main # 主ブランチを main に変更
git push -u origin main # main ブランチをプッシュ
これで template:master
がclone元のリモートブランチで origin:main
が自分の GitHub アカウント上のリモートリポジトリのブランチになりました。
gh
は GitHub CLI のコマンドです
.env
の編集ですが、まだ本番環境については分からないので先頭のみ編集します( PRODUCTION_NAME
以外はデフォルトで良いでしょう)
# -------------------------------------------
# wordpress・mysqlコンテナの設定
# -------------------------------------------
# プロダクトの名前 作成されるcontainer名の接頭語として使用
PRODUCTION_NAME=coedo
# local wordpressを紐付けるPort名(ex: 8080)
LOCAL_SERVER_PORT=8080
# localのmysqlを紐付けるPort名(ex: 3306)
LOCAL_DB_PORT=3306
保存したら docker-compose up -d
し、ブラウザで http://localhost:8080
を開くと、動作していることが確認できますね! 🎉
初期設定後、管理画面を開けば見慣れた管理画面が表れます。
このあたりで一度 git commit
しておきましょう。
子テーマの作成
WordPress での開発をする際は、テーマを直接編集するのではなく、一般的に子テーマを使いますね。
といっても、子テーマの作成をするのも1億年ぶりくらいなので、手順を確認しつつ進めます。
(自分自身の備忘録を兼ねているので趣旨とずれるので遠慮なく読み飛ばしてくださいませ)
Vue.js を入れるのも、簡易的に CDN 版を読み込むことにするので、まずはデフォルトのテーマ Twenty Twenty-One
の子テーマを作成します。
概ね次のステップでした。
- 子テーマフォルダを
wp-content/themes
内に作成 -
style.css
のコメントで子テーマの情報を記述 -
functions.php
で子テーマの読み込み - 管理画面で作成した子テーマを選択
wp-content/themes
内に作成
子テーマフォルダを 子テーマのフォルダ名は、親テーマのフォルダ名に -child
をつけるのがベストプラクティスとあります。(どのテーマの子テーマかというのがフォルダ名だけで分かるのと、一覧したときに親テーマと子テーマでフォルダが並ぶからですかね🤔)
というわけで今回は twentytwentyone-child
としました。
style.css
のコメントで子テーマの情報を記述
style.css
の先頭にコメントで子テーマの情報を記述します。
今回の子テーマの名称は Co-Edo
としました。
/*
Theme Name: Co-Edo
Version: 1.6
Template: twentytwentyone
*/
Template
は親テーマのフォルダ名です。ここ試験に出ます。(僕は最初ここを間違えてうまく表示されずに困りました)
functions.php
で子テーマの読み込み
WordPress といえば functions.php
ですね。
古い記憶とは作業内容が変わっていました。どうやら @import
で読み込む方式より変更になったようです。
<?php
function theme_enqueue_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}
add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' );
ここまでの作業に問題がなければ、管理画面で作成した子テーマを選択できるようになっているはずです。
(表示されない場合は、上記の何らかの箇所に問題があります)
といっても、今のままだと親テーマとまったく同一ですので index.php
を作成し、子テーマが読み込まれていることを確認しましょう。
cp wp-content/themes/twentytwentyone/index.php wp-content/themes/twentytwentyone-child/
// 17行目付近の get_header() した直後に挿入
get_header(); ?>
<div id="app" style="text-align: center;">
<p>
テスト
</p>
</div>
ヘッダーの下に テスト
とセンタリングして表示されれば子テーマの読み込み確認は無事終了です。
id="app"
は Vue.js で使うので、今のうちに記述してます。
CDN の Vue.js を利用する
一般的に Vue.js のような宣言的UIでリアクティブな値を扱うライブラリは npm
等のパッケージ管理ソフトを使ってインストールし利用するはずです。
Vue.js も React も CDN にホストされている js ファイルを直接 <script>
タグに入れてそのまま利用することもできます。
基本的には次のように html
ファイルのなかに <script>
タグを記述し利用できます。
<script src="https://unpkg.com/vue@next"></script>
Vue.
をつける
利用する箇所では 注意点としてはおなじみのメソッド等の前には Vue.
をつけるということです。
Vue 3 であれば Composition API や setup()
も利用可能です。
<script>
Vue.createApp({
setup() {
const message = Vue.ref('WordPress に Vue.js')
return { message }
},
}).mount("#app")
</script>
もちろん利用する場所では通常通りマスタッシュ記法で {{ message }}
のように記述します。
<script>
を記述する
WordPress で 子テーマ作成時に style.css
を functions.php
で設定したように <script>
も同様に行います。
functions.php
の末尾で読み込みましょう。
// Vue.js 3
function add_vuejs() {
wp_enqueue_script('vue', 'https://unpkg.com/vue@next');
}
add_action( 'wp_enqueue_scripts', 'add_vuejs' );
さきほどと同様に index.php
を編集します。
get_header(); ?>
<div id="app" style="text-align: center;">
<p>
テスト
</p>
<p style="min-height: 2em; line-height: 2em;">
{{ message }}
</p>
<div>
<input type="text" v-model="message" />
</div>
</div>
<script>
const app = Vue.createApp({
setup() {
const message = Vue.ref('WordPress に Vue.js 3 を入れました。')
return { message }
},
}).mount("#app")
</script>
<input>
の v-model
にもリアクティブな変数 message
を入れましたので、入力欄を書き換えると、そのすぐ上の {{ message }}
の箇所も同じ値に書き換わるでしょう。
無事 CDN 版の Vue.js 3.2 を入れることができました! 🎉
WordPress で Vue.js + TypeScript
ここまで予想以上にすんなりいったので、欲張って TypeScript で書けないかと思い調べました。
まずはJavaScript ビルド環境のセットアップのページが見つかりました。
node.js や npm / yarn は利用済みとして説明をします
以下npm
のコマンドで記述
まず npm init
をするわけですが、はたと困ったことが、これはどこでやれば良いのでしょうね。
node_modules
は .gitignore
に追記するとしても、開発経験が浅すぎてどこで実行すればよいかが分かりません。
いろいろ試行錯誤しようと、思いきって子テーマのフォルダのなかで実行することにしました。
cd wp-content/themes/twentytwentyone-child/
npm init
package.json
を編集後、開発環境で @wordpress/scripts
を利用します。
npm install --save-dev --save-exact @wordpress/scripts
Vue.js と TypeScript のトランスパイラをインストールします。
(このふたつとも -D で良かったかも…)
npm install vue@next ts-loader
package.json
, tsconfig.json
, webpack.config.js
はおそらくこんな感じ。
{
"main": "build/index.js",
"scripts": {
"start": "wp-scripts start",
"build": "wp-scripts build",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@wordpress/scripts": "19.0.0"
},
"dependencies": {
"ts-loader": "^9.2.6",
"vue": "^3.2.20"
}
}
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5",
"outDir": "./build/"
},
"include": [
"src/**/*"
]
}
const path = require('path')
module.exports = {
mode: 'development', // "production" | "development" | "none"
// ローカル開発用環境を立ち上げる
// 実行時にブラウザが自動的に localhost を開く
// devServer: {
// contentBase: "build",
// open: true
// },
// メインとなるJavaScriptファイル(エントリーポイント)
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, "build"),
filename: "index.js",
},
module: {
rules: [{
// 拡張子 .ts の場合
test: /\.ts$/,
// TypeScriptをコンパイルする
use: 'ts-loader',
}]
},
// import文で .tsファイルを解決するため
resolve: {
modules: [
"node_modules", // node_modules内も対象とする
],
extensions: [
'.ts',
'.js', // node_modulesのライブラリの読み込みに必要
],
},
}
webpack.config.js
はTypeScriptを用いたWEBサイトをWebpackを用いて構築するを参考にさせていただきました m(_ _)m
まずは JavaScript で確認します。
(webpack.config.js
の entry
を一旦 './src/index.js'
にしてください)
mkdir src
functions.php
を書き換え
// add_action( 'wp_enqueue_scripts', 'add_vuejs' );
// npm
function add_npm() {
wp_enqueue_script( 'npm', get_theme_file_uri('/build/index.js') );
}
add_action( 'wp_enqueue_scripts', 'add_npm');
index.php
に書いていたものを src/index.js
に移動します。
import { createApp, ref } from 'vue'
// window.onload が必要?
window.onload = () => {
const app = createApp({
setup() {
console.log('テスト npm Vue.js 3.2! at setup')
const message = ref('WordPress に npm で Vue.js 3.2 を入れました。')
return {
message,
}
},
}).mount('#app')
}
ビルドし、
npm run build
動作することを確認します。
npm run start
うまく動作することを確認できたら、拡張子を .ts
に変更し src/index.ts
が build/index.js
に書き出されることを確認しましょう。
console.log()
がうまく動いていたら無事 Vue.js 3.2 の動作確認が完了です! 🎉
TypeScript での開発を楽しみましょう🙂
SFC(単一ファイルコンポーネント)を利用する設定を追加する
だんだんと欲は出てくるもので、なるべくいつもと変わらない開発ができると良いなあと思いますね。
というわけで .vue
ファイルを使用する記述を追加することにします。
webpack がビルド時に .vue
ファイルを適切にコンパイルしてくれればよいので、基本的には webpack.config.js
の設定ということになります。
まずは必要なものをインストールします。
npm i -D @vue/compiler-sfc vue-loader@next
つづいて webpack の設定を追記します。
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader') // 追加
module.exports = {
mode: 'development', // "production" | "development" | "none"
// メインとなるJavaScriptファイル(エントリーポイント)
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, "build"),
filename: "index.js",
},
module: {
rules: [{
// 拡張子 .ts の場合
test: /\.ts$/,
// TypeScriptをコンパイルする(変更)
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
},
// 追加
}, {
test: /\.vue$/,
loader: 'vue-loader',
}]
},
// 追加
plugins: [
new VueLoaderPlugin(),
],
// import文で .tsファイルを解決するため
resolve: {
modules: [
"node_modules", // node_modules内も対象とする
],
extensions: [
'.ts',
'.js', // node_modulesのライブラリの読み込みに必要
],
},
}
型定義ファイルを作成する
declare module "*.vue" {
import { defineComponent } from "vue"
const component: ReturnType<typeof defineComponent>
export default component
}
通常通り Component を利用する
<script setup lang="ts">
const msg = '子コンポーネント at setup'
console.log(msg)
</script>
<template>
<div>{{ msg }}</div>
</template>
<script setup>
も使えます。
import { createApp } from 'vue'
import TheTest from './components/TheTest.vue'
window.addEventListener('load', () => {
const app = createApp({
components: {
TheTest,
},
setup() {
console.log('親コンポーネント at setup')
},
}).mount('#app')
})
<the-test />
のように子コンポーネントを読み込んで、コンソールや画面の表示で確認できたら完了です🎉
その他
SFC 内に style
タグを使う場合は vue-style-loader
も追加します。
npm install -D vue-style-loader
webpack.config.js
の module.rules
に次の記述も追記します。
}, {
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
上述の設定のいずれかがうまくできていない場合は、おそらく次のようなエラーメッセージのどれかが表示されるはずです。
Vue packages version mismatch: vue-template-compiler
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file
PHP のデータを JavaScript に引き渡す
WordPress が提供しているデータを JavaScript で使用したい場合があります。
wp_localize_script()
を使用することでとても簡単に利用することが可能です。
functions.php
にて、利用したい変数を渡す
function add_npm() {
wp_enqueue_script( 'npm', get_theme_file_uri('/build/index.js') );
global $post;
wp_localize_script('npm', 'serverProps', [
'currentUser' => wp_get_current_user(),
'postData' => get_post($post->ID),
'postOptions' => get_post_custom($post->ID),
]);
}
add_action( 'wp_enqueue_scripts', 'add_npm');
関数内で $post
を使用するため global
で呼び出します。
第一引数にはコードを差し込むスクリプトを指定します(通常は wp_enqueue_script()
するときと同じものとなります)
第二引数には JavaScript 側のオブジェクト名を指定します(上記の場合は console.log(serverProps.currentUser)
のように使用できます)
第三引数には、JavaScript 側でオブジェクトとして利用したい連想配列を渡します。
型定義ファイルを作成する
利用時に型の補完がされるようにします。
interface ServerProps {
currentUser?: {
ID: number
caps: {
administrator: boolean
}
data: {
ID: number
display_name: string
user_email: string
user_login: string
user_nickname: string
user_registered: string // "2021-12-23 04:54:48"
user_status: string
user_url: string
}
roles: Array<string> // "administrator"
// 以下略
}
postData?: {
ID: number // 29404
post_author: string // "1"
post_date: string // "2020-09-27 09:52:16"
post_date_gmt: string // "2020-09-27 00:52:16"
post_content: string
post_title: string
// 以下略
}
postOptions?: {
original_custom_field: Array<string> // [ "1" ],
}
}
declare const serverProps: ServerProps
利用する
const { currentUser } = serverProps
console.log(currentUser)
オブジェクトはグローバルに読み込まれるようです。
ブラウザの Dev Tools でも確認可能です。
誰でも簡単に確認できるということですので、ユーザーがアクセスしてはいけないデータを渡すことのないようにしましょう。
(wp_get_current_user()
ではuser_pass
も見れますが、ハッシュ化されているためパスワードそのものを取得することはできません)
セキュリティ上、引き渡すべきではないデータがありましたら、コメント等で教えてくださいませ。
Discussion