🤷‍♂️

リアルタイム反映!Dockerを使ったWordPressの効率的な開発環境構築

2024/07/23に公開

はじめに

WordPressの開発環境を効率的に管理するために、Dockerを利用した環境構築方法を紹介します。このガイドでは、ファイルの編集、SCSSやTypeScriptのバンドル、データベースの同期、デプロイの手順を詳しく説明します。

https://github.com/daisukemaki1003/wordpress-docker-setup/tree/main

目的

1. FTPでファイルを一つずつ編集する非効率さを解消

FTPでファイルを手動でアップロードして編集するのは時間がかかります。
この環境を使えば、もっと簡単にファイル管理ができます。

2. SCSSやimg、TSファイルをバンドル

スタイルや画像、TypeScriptファイルを効率よくまとめて管理します。
Gulpを使って、これらを自動的にバンドルします。

3. バンドルされたデータをリアルタイムで反映

変更した内容が即座にバンドルされます。
生成したデータはブラウザの再読み込みを介さずリアルタイムで反映されます。
この環境では、Gulpを使って、ファイルの変更を監視します。

4. WordPressの開発効率を向上

開発環境を整えることで、WordPressのテーマやプラグインの開発がスムーズになります。

5. 開発環境で編集したデータベースを本番環境に反映

開発環境で作業したデータベースの内容を本番環境に同期します。
本番環境と開発環境のデータベース同期を容易にします。

6. 本番環境を直接操作せず、Nodeやnpmのバージョン管理を簡素化

本番環境を直接触らずに、Dockerを使って環境を管理します。
Nodeやnpmのバージョン管理もDockerで一元管理するため、ローカルの開発環境に依存したバグを防ぐことができます。

開発環境の構成

.
├── .cz-config.cjs
├── .env
├── .env.example
├── .github
│   └── workflows
├── .gitignore
├── .husky
├── Makefile
├── README.md
├── build
├── docker
│   ├── app
│   ├── browsersync
│   └── mysql
├── docker-compose.init.yml
├── docker-compose.yml
├── package.json
├── pnpm-lock.yaml
├── scripts
│   ├── export_all.sh
│   ├── export_db.sh
│   ├── export_src.sh
│   └── functions.sh
├── src
│   ├── assets
│   ├── gulpfile.js
│   ├── package.json
│   ├── plugins
│   ├── rollup.config.js
│   ├── themes
│   ├── tsconfig.json
│   └── uploads
└── wordpress

使用ツールと技術

  • Docker
  • WordPress
  • Gulp
  • PHP
  • Apache
  • Node.js
  • MariaDB
  • Husky
  • phpMyAdmin
  • SCSS
  • TypeScript
  • Github actions

環境構築手順

1. 環境変数の設定

env.exampleを基に.envファイルを作成します。

# -------------------------------------------
# Wordpress
# -------------------------------------------
WP_VERSION=

# -------------------------------------------
# Mysql
# -------------------------------------------
MYSQL_DATABASE=
MYSQL_USER=
MYSQL_PASSWORD=
MYSQL_ROOT_PASSWORD=
MYSQL_HOST=

2. 初期セットアップ

初めて環境を構築する場合は、以下の手順を実行します。

make init

http://localhost にアクセスし、WordPressの初期設定を行います。完了後、コンテナを停止します。

make down

3. 既存プロジェクトの移行

srcフォルダに既存のWordPress関連ファイルを配置します。
データベースを本番環境と同期させる場合は、ダンプファイルをdocker/mysql/initdbに配置します。

make prepare

再びコンテナを起動します。

make down

了解しました。それでは、「デプロイについて」セクションを手動と自動で分け、開発環境構築の手順と処理の内容を分けて説明します。

4. デプロイについて

手動デプロイ

手動でデプロイを行う場合の手順です。

  1. scripts/export_all.shを実行し、buildフォルダにデプロイ情報を生成します。
    scripts/export_all.sh
    
  2. WordPressのみデプロイする場合は、scripts/export_src.shを実行します。
    scripts/export_src.sh
    
  3. データベースのみデプロイする場合は、scripts/export_db.shを実行します。
    scripts/export_db.sh
    

処理内容

  • export_all.sh: データベースとWordPressのファイルをエクスポートします。
    #!/bin/bash
    current_path="`dirname \"$0\"`"
    
    sh "$current_path/export_db.sh"
    sh "$current_path/export_src.sh"
    
  • export_src.sh: WordPressのファイルをエクスポートします。
    #!/bin/bash
    current_path="$(dirname "$0")"
    source "$current_path/functions.sh"
    
    # .envファイルを読み込む
    if [ -f "$current_path/../.env" ]; then
        export $(cat "$current_path/../.env" | grep -v '#' | awk '/=/ {print $1}')
    fi
    
    # コンテナが手動で起動されたかどうか
    container_manually_started=false 
    
    # 環境変数からWordPressのイメージバージョンを取得
    WP_VERSION=${WP_VERSION:-latest}
    image_name="wordpress:$WP_VERSION"
    service_name="wordpress"
    
    # ビルドディレクトリが存在することを確認
    create_build_directory
    
    echo "WordPressファイルをエクスポート中"
    
    # コンテナが起動していない場合は起動
    start_container_if_not_started "$service_name"
    
    # 指定されたイメージからコンテナ名を取得
    container_id=$(get_container_id $service_name)
    
    # デバッグ用のログを追加
    echo "デバッグ情報:"
    echo "コンテナID: $container_id"
    echo "サービス名: $service_name"
    
    if [ -z "$container_id" ]; then
        echo "コンテナが見つかりません。コピーをスキップします。"
        exit 1
    fi
    
    echo "Building src files..."
    
    # Browsersyncサービスを起動し、最適化設定でGulpビルドを実行
    docker-compose run -e NODE_ENV=production browsersync node_modules/.bin/gulp build
    
    # DockerのCOPYメソッドを使用して、WordPressコンテナ内のファイルをホストマシンにコピー
    docker cp $container_id:/var/www/html/ ./build
    
    # ファイルのエクスポートが成功したことを通知
    echo "ファイルのエクスポートに成功"
    
    # コンテナが手動で起動された場合、コンテナを停止
    if [ "$container_manually_started" = true ] ; then
        docker-compose stop "$service_name" > /dev/null
        docker-compose stop db > /dev/null
    fi
    
  • export_db.sh: データベースをエクスポートします。
    #!/bin/bash
    current_path="$(dirname "$0")"
    source "$current_path/functions.sh"
    
    # .envファイルを読み込む
    if [ -f "$current_path/../.env" ]; then
        export $(cat "$current_path/../.env" | grep -v '#' | awk '/=/ {print $1}')
    fi
    
    # コンテナが手動で起動されたか、すでに起動されていたかどうか
    container_manually_started=false 
    service_name="db"
    
    # ビルドディレクトリが存在することを確認
    create_build_directory
    
    echo "データベースのエクスポートが完了するまでお待ちください...";
    
    # コンテナが起動していない場合は起動
    start_container_if_not_started "$service_name"
    
    # コンテナ名を取得
    container_id=$(get_container_id $service_name)
    
    # MYSQLデータベースをエクスポートするコマンドを実行し、ホストマシンにコピー
    docker exec "$container_id" bash -c "mysqldump -h'$MYSQL_HOST' -u'$MYSQL_USER' -p'$MYSQL_PASSWORD' '$MYSQL_DATABASE' > /db.sql" || {
        echo "データベースのエクスポート中にエラーが発生しました"
        exit 1
    }
    docker cp $container_id:/db.sql ./build/db.sql
    
    echo "データベースが正常にコピーされました。"
    
    # コンテナが手動で起動された場合は停止
    if [ "$container_manually_started" = true ] ; then
        docker-compose stop "$service_name" > /dev/null
    fi
    

自動デプロイ

自動でデプロイを行う場合の手順です。

  1. GitHub Actionsを使用して、自動デプロイを設定します。
  2. mainブランチが更新されると自動でデプロイされます。

処理内容

  • .github/workflows/deploy.yml:
    ## .github/workflows/deploy.yml
    name: Deploy to FTP
    on:
      workflow_dispatch:
      push:
        branches:
          - main
    
    jobs:
      deploy:
        name: DeployCoreServer
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2
          - name: Sync files
            uses: SamKirkland/FTP-Deploy-Action@v4.3.5
            with:
              server: ${{ secrets.FTP_SERVER }}
              username: ${{ secrets.FTP_USERNAME }}
              password: ${{ secrets.FTP_PASSWORD }}
              server-dir: ${{ secrets.FTP_SERVER_DIR }}
              local-dir: ./src/
    

Makefileのコマンド

  • init: 初期セットアップ
  • prepare: コンテナのビルドと起動
  • down: コンテナの停止
  • build: コンテナのビルド
  • up: コンテナの起動
  • ps: コンテナのステータス確認
  • clear: Dockerシステムのクリア
  • logs: 全てのコンテナのログを確認
  • logs-app: アプリケーションコンテナのログを確認
  • logs-db: データベースコンテナのログを確認

Gulpの設定

Gulpを使用してSCSS、img、TSファイルをバンドルします。以下はgulpfile.jsの内容です。

import browserSync from 'browser-sync';
import pkg from 'gulp';
const { src, dest, watch, series, parallel } = pkg;
import gulpif from 'gulp-if';
import plumber from 'gulp-plumber';
import notify from 'gulp-notify';
import imagemin from 'gulp-imagemin';
import mozjpeg from 'imagemin-mozjpeg';
import changed from 'gulp-changed';
import postcss from 'gulp-postcss';
import mqpacker from 'css-mqpacker';
import sortCSSmq from 'sort-css-media-queries';
import dartSass from 'sass';
import bulkSass from 'gulp-sass-glob-use-forward';
import gulpSass from 'gulp-sass';
const sass = gulpSass(dartSass);
import cleanCSS from 'gulp-clean-css';
import autoprefixer from 'autoprefixer';
import { rollup } from 'rollup';
import { deleteAsync } from 'del';
import path from 'path';
import minmax from 'postcss-media-minmax';

// Rollupの設定ファイル
import deploy from './rollup.config.js';

const paths = {
    rootDir: 'dist',
    styles: {
        src: 'src/css/**/*.scss',
        dest: 'dist/css',
    },
    scripts: {
        src: 'src/js/**/*.{js,jsx,ts,tsx}',
        dest: 'dist/js',
    },
    images: {
        src: 'src/img/**/*.{jpg,jpeg,png,svg,gif}',
        dest: 'dist/img',
    },
    dist: {},
};

// Browsersync <- Browsersyncによる再表示とローカルサーバー起動の設定
const server = browserSync.create();
const serve = (done) => {
    server.init({
        proxy: "wordpress",
        port: 3000,
        open: true,
        notify: true
    });
    done();
};
const reload = (done) => {
    server.reload();
    done();
};

// Clean
const clean = () => {
    return deleteAsync(['dist/**', '!dist']);
};

// SCSS
const styles = (done) => {
    src(paths.styles.src)
        .pipe(plumber({ errorHandler: notify.onError('Error: <%= error.message %>') }))
        .pipe(bulkSass())
        .pipe(sass.sync({ outputStyle: 'expanded' }))
        .pipe(postcss([minmax(), autoprefixer(), mqpacker({ sort: sortCSSmq })]))
        .pipe(gulpif(process.env.NODE_ENV === 'production', cleanCSS()))
        .pipe(dest(paths.styles.dest))
        .pipe(server.stream());  // CSSのホットリロード
    done();
};

// Script
let rollupCache = null;
const scripts = async (done) => {
    const bundle = await rollup({ ...deploy, cache: rollupCache });
    rollupCache = bundle.cache;
    await bundle.write(deploy.output);
    done();
};

// Image
const Imagemin = (done) => {
    src(paths.images.src)
        .pipe(changed(paths.images.dest))
        .pipe(imagemin([mozjpeg({ quality: 90 })]))
        .pipe(dest(paths.images.dest));
    done();
};

const watchFiles = () => {
    watch(paths.scripts.src, series(scripts, reload)); // JavaScriptのホットリロード
    watch(paths.styles.src, styles); // CSSのホットリロード
    watch(paths.images.src, Imagemin); // 画像の変更を監視

    watch(paths.styles.src).on('unlink', (filePath) => {
        if (!/^_/.test(path.parse(filePath).name))


            deleteAsync(filePath.replace(/src\/css/, paths.styles.dest).replace(/.scss$/, '.css'));
    });

    watch(paths.images.src).on('unlink', (filePath) => deleteAsync(filePath.replace(/src\/img/, paths.images.dest)));
    watch(paths.images.src).on('change', (filePath) => deleteAsync(filePath.replace(/src\/img/, paths.images.dest)));
};

export const dist = series(parallel(styles, scripts, Imagemin));
export const dev = series(dist, serve, watchFiles);
export const production = series(dist, serve, watchFiles);
export const build = series(clean, dist);
export default dev;

デバッグとログ管理

デプロイに失敗した場合は、GitHub Secretのデータが正しく登録されているか確認します。ログの確認には以下のMakefileコマンドを使用します。

make logs
make logs-app
make logs-db

BrowserSyncの設定

開発環境で使用しているBrowserSyncの設定やホットリロードを実現するための手順は以下の通りです:

  • データをバンドルし、バンドルしたデータはvolumeに保存される。
  • volumeデータはWordPressのコンテナに同期される。
  • BrowserSyncはファイルの変更を監視する。
  • BrowserSyncのproxyにWordPressを設定する。

docker/browsersync/Dockerfile

FROM node:14

WORKDIR /var/www/html

# Copying our package.json containing all the necessary dependencies
COPY package.json /var/www/html/package.json

# Installing Gulp, BrowserSync and other necessary packages
RUN npm i

# Copy all the Gulp related files
COPY ./gulpfile.js ./gulpfile.js
COPY ./rollup.config.js ./rollup.config.js
COPY ./tsconfig.json ./tsconfig.json

# Exposing port 3000 for the page to be served via BrowserSync
EXPOSE 3000

# Exposing port 3001 for the admin console for BrowserSync
EXPOSE 3001

CMD ["npm run dev"]

まとめ

サーバー環境に合わせてDockerをセットアップするのは手間ですが、
編集のたびにFTPで接続する必要がなくなるのはいいですね!

Discussion