gulpのアップロードタスクの書き方について

gulpを使うようになって設定するものの1つとして「ファイルアップロード」があります。

具体的には「vinyl-ftp」というプラグインを使っています。

vinyl-ftp - npm

最新の更新も4年前(2021年10月現在)と、更新が滞っているプラグインですが、FTPクライアントを使って1つ1つファイルを上げていた身としては、今でも重宝しています。

セキュリティ上SFTPで上げた方がいいのでは、と思うのですが、SFTPでしか上げられない場合とFTPでしか上げられない場合があり、
その違いや仕組みをまだ理解していません。

むしろFTP/SFTPでデプロイする方法を改めた方がいいのでしょうが、こちらも残念ながら勉強不足です。
GitHubからnetlifyを使ってHugoブログを作るような方法が現在はメジャーなのかと考えています)

今回は何回もうまくいったりいかなかったりしている「vinyl-ftp」の設定についてメモします。

ファイルの構成は以下のようになっています。
(フォルダには「/」を入れました)

***

/www
┗/テストドメイン
 ┗/res ←imgやcss、jsフォルダに各ファイルが入る
 ┗/wp
  ┗/wp-admin
  ┗/wp-content
  ┗/wp-includes
  ┗/src ←ローカルリポジトリにのみある
   ┗/scss ←scssファイルが入る
   ┗/node_modules
   ┗package.json
   ┗deploy-config.json
   ┗gulpfile.js ←ここに書くコードの話

***

最終的にうまくいったgulpは以下のように書きました。

gulpfile.js

const fs = require('fs');
const ftp = require('vinyl-ftp');
const { src, dest } = require('gulp');
// ↑const src = gulp.src; const dest = gulp.dest;

// サイトへアップロード
const config = JSON.parse(fs.readFileSync('./deploy-config.json', 'utf8'));
const conn = ftp.create(config['production']['ftp']);
const srcList = [
  '../../res/**/*',
  '../../' + THEME_PATH + '**/*',
  '!../wp-config.php',
  '!../src/',
  '!../wp-content/uploads/',
  '!../wp-content/plugins/'
];
const uploadProduction = () => {
  return src(srcList, { base: '../../', buffer: false })
    .pipe(conn.newer(FTP_UPLOAD_PATH))
    .pipe(conn.dest(FTP_UPLOAD_PATH))
};

// タスクの宣言
exports.up_prod = uploadProduction;

つまづき1:パーミッションエラー - newerとdestの部分

conn.newer

「vinyl-ftp」のドキュメントぺージの説明

Returns a transform stream which filters the input for files which are newer than their remote counterpart.

リモート側のファイルよりも新しいファイルの入力をフィルタリングする変換ストリームを返します。

gulp.dest

公式

dest() | gulp.js

Creates a stream for writing Vinyl objects to the file system.

意味はこちらのほうがわかりやすかったです。

gulp.dest | gulp 日本語リファレンス | js STUDIO

pipeされたものを、ファイルに書き出します。 渡された全てのデータが再度選択されるため、複数のフォルダに書き出すことが可能です。 フォルダが存在しない場合、自動的に生成されます。

conn.newerconn.dest の引数は接続先のパスを書きます。 conn.newer でリモートと比較してローカルで新しく更新があったものをチェックします。
その結果を受けて conn.dest で配置しています。

FTP_UPLOAD_PATH は定数にしています。

直した所は、この定数を /home などルートディレクトリから書くということです。

接続したディレクトリから相対的に(途中から)書いてしまうとエラーが出ます。
この例では /www と間違えて

Error: /www: Permission denied

とエラーが出ました。

試しにFTPのパスワードを変更してみると別のエラー(認証エラー)が出ました。接続はできているみたいです。

パーミッションで書き込み権限がないというのは、サーバー側の問題の場合もあるし、クライアント側の問題の場合もある。
と調べたら出てきました。

サーバー側はディレクトリのパーミッションを変えてみましたが元から書き込み権限があてられていたため当然変わらず。
クライアント側は、FTPクライアントでも同じアカウント情報で接続しているのに権限とは??という状態でした。

設定のパスをいろいろ試してみて解決しました。これでとりあえずファイルをアップロードすることはできました。

つまづき2:アップロード先がおかしい - srcのオプションbase

アップロードができるようになったものの、今度は対象のアップするファイルがすべて FTP_UPLOAD_PATHディレクトリ にアップされるようになってしまいました。

cssディレクトリもなく、cssファイルがサイトトップのディレクトリに配置されてしまいました。

const srcList = [] の書き方か、glob形式の書き方が間違っているのではと調べましたが、なかなか望む内容の記事に出会えず。

こちらの記事が頼りになりました。

gulpでFTPサーバにデプロイする - なおしむ論

そこで gulp.src のbaseオプションに着目しました。

「vinyl-ftp」のドキュメントには

base: Set as file.base, default is glob beginning. This is used to determine the file names when saving in .dest().

base:file.baseとして設定され、デフォルトはglob beginningです。.dest()で保存する際のファイル名の決定に使用されます。

さっぱり分からない...。

実はこの時点まで、何を思ったのか、不要だったbaseオプションを省いていました。

../../ は、このgulpfile.jsからサイトトップのディレクトリまでの相対パスを書いています。

過去に携わったサイトのgulpfile.jsを見てみるとbaseオプションが書かれていたので、真似て入れてみました。

すると、うまくアップロードされたのです。

道理がわからないのですが、ひとまず解決です☆

gulp.src

こちらも調べてみました。

gulp.src | gulp 日本語リファレンス | js STUDIO

アップロードに指定されたglob、またはglobの配列にマッチしたファイルを選択します。 プラグインとpipe可能なVinylファイルのストリームが返されます。

配列で書けます。こちらもgulpfile.jsからの相対パスで書きます。

glob形式の指定の書き方が何となくでしか理解できないのですが、いつかまとめられた記事が見つかるといいいです。

さいごに

なんとも後味の悪い終わり方ですが、うまくいったのです。

Vinylファイル、ストリームとは??
理解していないのでまたつまづく可能性がありますが、そのときはまた唸ることにします。

おしまい。