wordpressのローカル作業をwebpack(proxyとかHMR?)でやる

25/02/2020

ここ何年かやってるwordpressの更新案件で、手つけ始めた時から使ってたgulpでずっと作業してたんだけども、
無駄にgulp使ってるとそろそろおじさん扱いされそうな風潮なので
ローカル作業の環境周りをnpm scriptとwebpackベースに乗り換えてみた。

・css/jsの出力とか監視はwebpack
・ローカルサーバーとその他のphpファイルとか画像の監視はbrowserSyncで

って感じになってます。

できるとこは全部webpackでまとめた方がいいかなーと思って色々頑張ったんだけども
結果で言うとwordpressの場合webpack dev serverだとproxy周りで少し不便な気がするので
browserSyncも使った方がいいような気がする、
なんか方法あるかもだけど、

ってなると別にgulpでもいいんじゃないのって気もするけど
まぁ折角頑張って何となく落ち着いたので記事にしてみます。

config.js

configです。適宜環境に合わせてください。

module.exports = {
  public: "public/",
  proxy: "http://×××.×××.×××.×××:8000",
  assets: "public/wp/wp-content/themes/themename/assets/",
  publicPath: "/wp/wp-content/themes/themename/assets/"
};

proxyにmampなりdockerなりのurl入れます

webpack.config.js

webpack.configです。

const config = require("./config");

const webpack = require("webpack");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");

module.exports = {
  mode: "development",
  entry: {
    main: [
      "webpack/hot/dev-server",
      "webpack-hot-middleware/client?reload=true",
      "jquery",
      "./src/js/main.js"
    ]
  },
  output: {
    path: path.join(__dirname, config.assets),
    filename: "js/[name].js",
    publicPath: config.publicPath
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"]
            }
          }
        ]
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          "css-hot-loader",
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              url: false
            }
          },
          "sass-loader"
        ]
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loader: "url-loader"
      }
    ]
  },
  devtool: "inline-source-map",
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/style.css"
    }),
    new FixStyleOnlyEntriesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    // これもwebpackdevServerだといらない?かも
    new webpack.ProvidePlugin({
      jQuery: "jquery",
      $: "jquery",
      jquery: "jquery",
      "window.jQuery": "jquery"
    })
  ]
};

entry周りとかHMR


entry: {
  main: [
    "webpack/hot/dev-server",
    "webpack-hot-middleware/client?reload=true",
    "jquery",
    "./src/js/main.js"
  ];
  // "css/style": [
  //   "webpack/hot/dev-server",
  //   "webpack-hot-middleware/client",
  //   "./src/css/style.scss"
  // ]
  // cssはエントリ分けてもいいかなと思ったけど
  // webpackdevServerだとrealod効くけど
  // browserSync経由するとcss-hot-loaderとかの動作が微妙かも、
  // のでmain.js側からimportする
}

webpack/hot/dev-server
webpack-hot-middleware/client?reload=true

webpackdevServer使う時は上2つは勝手に読まれる?のか不要っぽい。
けどbrowserSyncとかでwebpack-dev-middleware使う場合はいる、と思う。多分
ちなみにclient?reload=trueを外すと

The following modules couldn’t be hot updated: (Full reload needed)

js変更した際にこんなエラーがでる。

で何となく気づいたけど、
ブラウザのログに
[HMR] connectedとかってでてたから
HMRってimportしてるjsファイル別に勝手にreplaceしてくれる物かと思ってたけど、

どうも違うっぽいかも、
対応してるモジュールがある場合は(react-hot-loaderとか)使えばいいけど、
素のjsとかjqueryの場合は、

if (module.hot) {
   module.hot.dispose(() => {});
   module.hot.accept(() => {});
}

とかってそれに対応した書き方しないと動作しない様子かも、

でもわざわざ対応するのは面倒なので
今回はclient?reload=true
で落ち着きました。

って事はただのオートリロードなのかな?
HMRよくわかってない

CSSは個別で出力

wordpressでjquery使ってるいわゆる普通のサイトで
個別にcss読み込む(js in cssとかで無く)ため
別出ししたいなと調べてたら
エントリーで分けてoutputしてもいいのかなと思ったけども、
browserSync中継するとauto relaodが効かなかったりしたりして
色々試して結果としてMiniCssExtractPlugin使ってます。

webpack dev serverでWPのProxy

あとwebpack dev serverで下記みたいな感じなんとか
ならんかなと思ったけども

devServer: {
  open: true,
  hotOnly: true,
  contentBase: "public",
  watchContentBase: true,
  publicPath: config.assets,
  proxy: {
    "/": {
      target: config.proxy,
      changeOrigin: true,
      autoRewrite: true
    }
  }
}


普通のWordpressみたいなMPA(って最近は言うの?)だと微妙な気がした。

一応起動した時点では問題ないけど、

なんて呼べばいいのか不明だけど、siteurlとかhome等の
ページ内のリンクとをproxyのIPとかPORTに適宜書き換えてくれる処理
(多分browserSyncのproxyの処理?)、というか何というかが
webpack dev serverには無い(のかな?多分。)
のが非常に不便に感じた。

server.js

のでserver.jsでbrowserSync使う事にしました。

const config = require("./config");

const webpack = require("webpack");
const bundler = webpack(require("./webpack.config"));
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const browserSync = require("browser-sync");

browserSync.use({
  plugin: function() {},
  hooks: {
    "client:js":
      '(function (bs) {bs.socket.on("disconnect", function (client) { window.close(); });})(___browserSync___);'
  }
});
browserSync({
  proxy: {
    target: config.proxy
  },
  middleware: [
    webpackDevMiddleware(bundler, {
      publicPath: config.publicPath
    }),
    webpackHotMiddleware(bundler, {
      log: () => {}
    })
  ],
  files: [
    `${config.public}**/*.{php,html,twig}`,
    `${config.public}**/*.{jpg,png,gif,svg}`
  ],
  open: "external"
});

publicPath

なんとなくWP側のcss/jsのパスをローカル用にwebpackのpublicPathに合わせないとなーと思ってたけど

<script src="<?php echo get_template_directory_uri(); ?>/assets/js/main.js" defer></script>

なんか普通にそのまま上記のような感じでリロード動いた。
browserSyncがうまい事やってくれてるのかも

npm script

で、あとは
package.jsonにscripts書いて

yarn serve

とかで、起動する感じで一応無事に
gulpからnpm scriptへの乗り換え完了できました。

まとめ

webpack自体がもしかしたらSPA向きのモジュールなのかな?
と言う印象もあるかもな感じですがこんな感じで落ち着きました。

時間かかった割に
別にgulpに比べて何かが便利になったとかは特に無いので
特におすすめはしませんが、参考になりましたら幸いでございます。