コフス技術ブログ

Viteを用いたシンプルなWordPressテーマ開発環境の構築方法

この記事はにメンテナンスが行われています。

Viteを用いてシンプルなWordPressテーマ開発環境を構築する方法について記します。
おおよそ以下の様な構成でWordPress本体と、Viteをインストールしている時を想定しています。

.
├── .husky/
├── app
│   └── WordPress/ # WordPress本体
├── db-data/
├── dist # テーマ開発ディレクトリ
│   ├── assets
│   │   ├── main-8d0ad20e.css # ViteでビルドしたCSS
│   │   ├── main-e16e9c4f.js  # ViteでビルドしたJS
│   │   └── manifest.json    # Viteでビルド時に生成されるマニフェストファイル
│   ├── functions.php
│   ├── index.php
│   ├── screenshot.png
│   ├── single.php
│   └── style.css
├── docker/
├── docs/
├── public/
├── src
│   ├── images/
│   ├── scripts
│   │   └── main.ts # Viteでビルドするエントリーポイント
│   ├── styles
│   │   └── main.scss # Viteでビルドするエントリーポイント
│   └── vite-env.d.ts
├── vendor/
├── wp-plugins/
├── wp-uploads/
├── .editorconfig
├── .env
├── .eslintignore
├── .eslintrc.cjs
├── .gitignore
├── .markuplintrc
├── .node-version
├── .prettierignore
├── .prettierrc.cjs
├── .stylelintrc.cjs
├── Makefile
├── README.md
├── composer.json
├── composer.lock
├── docker-compose.yml
├── package.json
├── postcss.config.cjs
├── tsconfig.json
├── vite.config.ts
└── yarn.lock

vite.config.tsは以下のような設定を行います。注目するオプションはserver.corsserver.hmr.hostbuild.manifestです。
server.hmr.hostには適切なローカルIP(localhostでも良し)を指定します。

vite.config.ts
import { defineConfig,  UserConfig } from 'vite'
import FullReload from 'vite-plugin-full-reload'
import tsconfigPaths from 'vite-tsconfig-paths'

// isProduction
const isProduction = process.env.NODE_ENV === 'production'

// https://vitejs.dev/config/
const config = (): UserConfig => {
  return {
    base: isProduction ? '' : '/',
    root: '',
    server: {
      host: true,
      cors: true,
      strictPort: true,
      port: 3000,
      hmr: {
        host: '192.168.1.1'
      }
    },
    preview: {
      host: true,
      port: 3000
    },
    build: {
      outDir: './dist/assets',
      assetsDir: './',
      emptyOutDir: true,
      manifest: true,
      rollupOptions: {
        input: {
          main: './src/scripts/main.ts'
        }
      }
    },
    plugins: [tsconfigPaths(), FullReload(['./dist/**/*.php'], { root: __dirname })]
  }
}

export default defineConfig(() => config())

プラグインに指定しているvite-plugin-full-reloadはWordPressのテーマ開発時に、PHPファイルの変更を検知してブラウザをリロードするために使用しています。

エントリーポイントとなるmain.tsでは、main.scssを読み込んでいます。

main.ts
import 'path/to/main.scss'

これで基本的にはyarn buildを実行すればdist/assetsにビルドされたファイルが出力されます。

次にWordPressのテーマ開発時にHMRを有効にするために、以下のファイルを作成しfunctions.phpにて読み込みます。

inc.vite.php
<?php
/**
 * inc.vite.php
 *
 * @since 1.0.0
 */

define( 'IS_VITE_DEVELOPMENT', true );
define( 'VITE_SERVER', 'http://192.168.1.1:3000' );
define( 'VITE_ENTRY_POINT', '/src/scripts/main.ts' );
define( 'DIST_URI', get_template_directory_uri() . '/' );
define( 'DIST_PATH', get_template_directory() . '/' );
define( 'ASSETS_PATH', 'assets/' );

function add_scripts() {
  if ( defined( 'IS_VITE_DEVELOPMENT' ) && IS_VITE_DEVELOPMENT === true ) {
    //develop mode
    function cors_http_header() {
      header( 'Access-Control-Allow-Origin: *' );
    }
    add_action( 'send_headers', 'cors_http_header' );

    // add vite dev server
    wp_enqueue_script(
      'vite-script',
      VITE_SERVER . VITE_ENTRY_POINT,
      '',
      true,
      true
    );

  } else {
    // production mode, 'npm run build' must be executed in order to generate assets

    // read manifest.json to figure out what to enqueue
    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
    $manifest = json_decode( file_get_contents( esc_url_raw( DIST_PATH . ASSETS_PATH . 'manifest.json' ) ), true );

    // is ok
    if ( is_array( $manifest ) ) {

      // get first key, by default is 'main.js'
      $manifest_key = array_keys( $manifest );
      if ( isset( $manifest_key[0] ) ) {
        // enqueue CSS files
        foreach ( $manifest['src/scripts/main.css'] as $css_file ) {
          wp_enqueue_style(
            'main',
            DIST_URI . ASSETS_PATH . $css_file,
            '',
            true
          );
        }
        // enqueue main JS file
        $js_file = $manifest['src/scripts/main.ts']['file'];
        if ( ! empty( $js_file ) ) {
          wp_enqueue_script(
            'main',
            DIST_URI . ASSETS_PATH . $js_file,
            '',
            true,
            true
          );
        }
      }
    }
  }
}
add_action( 'wp_enqueue_scripts', 'add_scripts' );

※ 上記例にてmanifest.jsonを読み込む記述部分はVite v4系を想定しています。v5系の場合はmanifest.jsonの出力自体が{outDir}/.vite/manifest.jsonになっていたり、また構造が若干変わっていたりしますので適宜読み替えてください。

上記をfunctions.phpにて読み込みます。

functions.php
<?php
/**
 * Functions.php
 *
 * @since 1.0.0
 */

// Vite dev server URL
require_once 'path/to/init-vite.php';

inc.vite.phpではIS_VITE_DEVELOPMENTがtrueの時にmain.tsを読み込むようにしています。これでyarn devを実行している時には、Viteの開発サーバーからmain.tsを読み込むようになりHMRが有効になります。
またIS_VITE_DEVELOPMENTがfalseの時は、ビルドされたmanifest.jsonを参照し、main.tsmain.cssファイルをwp_enqueue_styleまたはwp_enqueue_scriptで読み込むようにしています。

IS_VITE_DEVELOPMENT.envにて定義しても良いですし、wp-config.phpにて定義しても良いです。

参考