PHPで新しく知ったこと - try/catch、threw句、ルーティングなど

Hugoサイトのカスタマイズと同時進行でphpの勉強をしたいと思っています。

いよいよ手元にあるLaravelの本でサイトを作ろう(原点回帰)!としたところ、
それよりは基礎です!というお話を頂きました。

ごもっともです。

基本的な知識や一般的な関数・処理を知らなくては実際Laravelサイトを作っても身にならないので、ここは時間がかかっても基礎力を付けることを重視していきます。

ひとまず新しく知ったphpのことについてメモしていきます。

try/catch句とthrew句、Exceptionクラス

PHPで例外処理を使う方法【初心者向け】 | TechAcademyマガジン

PHP: Exception - Manual

こちらの記事のコードを参考にさせていただきました。

(PHP) try-catch文の使い方を解説 | hara-chan.com

function addNum($a,$b){
  try {
    // 処理
    // 例外が起こったとき、例外を投げる
    if ( is_numeric($a) == false) {
        throw new Exception('引数1が数字ではありません');
    }
    if ( is_numeric($b) == false) {
        throw new Exception ('引数2が数字ではありません');
    }
    return $a + $b;      
  } catch (Exception $e) {
    // 例外処理
    var_dump($e -> getMessage());    // 「引数1(または2)が数字ではありません」と出る
    return;
  }
}

意味は直訳で「try = 試みる」、「Exception = 例外」、「throw = 投げる」、「catch = 捕まえる」です。
投げて捕まえる、と言う表現はどこから来たのですかね。

それはさておき、
catchは例外が起こらないと処理されないことがわかりました。

catch句の最後に return があります。
改めてreturnを調べると、

関数を途中で終了する場合は、返り値を指定せずに任意の場所でreturnのみを記述することで制御が呼び出し元に戻ります。

という意味にあたるので、今回の場合は必ずしも必要ないように思います。

throw new Exception ()インスタンス化したものを投げて、catch (Exception $e) で引数としてインスタンス化したものを捕えて変数($e)に代入しています。 オブジェクト(インスタンス)名は任意ですがExceptionの「e」や「ex」がよく使われているのだと思います。

$e -> getMessage() でthrow句で投げたメッセージが取得できます。

試しに addNum() の引数に両方数字を入れた場合と、片方、両方に文字を入れた場合(例外)を入れてみました。

var_dump(addNum(1, 2));

var_dump(addNum('いち', 2));

var_dump(addNum('いち', 'に'));

両方数字の場合は「3」と出ます。

引数1つ目($a)に文字が入っている場合は「"引数1が数字ではありません"NULL」と出ます。
これは $a を検証して出た例外のメッセージと return $a + $b処理されないという意味を表しているNULLです。
この場合 '$b' を検証せずに例外が投げられています。

また、getMessage()メソッド以外にも getCode() など、クラスに応じてメソッドは色々あるみたいです。

そしてExceptionクラス以外にもInvalidArgumentException クラスなど、例外クラスは色々あるみたいです。

finally句もあります

例外が発生してもしなくても、try の下に finally のブロックを書くと、中が処理されます。

PHPでfinallyを扱う方法【初心者向け】 | TechAcademyマガジン

try,、throw、catchと併せて覚えておいたほうが良さそうです。

phpではthrow句は必要?

throw が書かれていないものを見かけたので、書かない場合はどうなるのか確かめました。

うまくロジックが書けているか疑問ですが、具体的には上のコードでtryブロックの中のif文処理を行わず、throw句を入れませんでした。
$e -> getMessage() はメッセージを設定していないのでその下に var_dump('例外です') と加えてみました。

先ほどの3パターンの addNum() を確かめた結果、順に3、2、0と出ました。

例外にならず $a + $b の処理が行われ、catchで捕まえていませんでした。

調べたところ、

【PHP入門⑫】例外処理 ~初心者でも安心!基礎から学べるプログラミング講座~ | Snome;

PHPの場合は、throwしないとcatchしてくれません。 Javaの様に勝手にthrowしてくれることは無いので、例外処理を書く場合は、ちゃんとthrowしているか確認してください。

なんと。間違っていたコードだったのでしょうか。

改めて調べました。

【PHP超入門】クラス~例外処理~PDOの基礎 - Qiita
PHPの定義済みの関数やクラスは例外を投げてくれるのか)
☆前述したExceptionクラスの種類について、catch (Exception $e) の意味についてもこちらの記事に書かれています。

定義済みの関数の多くは、エラー報告だけで例外は投げてくれないけど、エラーを例外に変換することもできるよって書いてあります。 新しい定義済みのクラスの一部は、例外を投げてくれるとも書いてあります。

throw と書かなくても例外を投げてくれる関数があるのですね。
例外を投げない関数は throw が必要なのでしょうか(これが“エラーを例外に変換”?)。

あとはtry/catch句を使う理由は、エラーで表示される内容(パスワードなど)が表に出てしまわないようにcatchする、とありました。
エラーはログに出す処理もcatch句の中に書いたりするのですね。

例外処理。読めるけど書けない類のコードだなという印象ですが、大事な部分では入れなくてはいけない処理ですね。

call_user_func_array()

コールバック関数に配列の引数を渡す場合に使う関数です。

コールバック関数とは引数の関数のことでした。

call_user_func_array(array($instance, $method), $params);
// call_user_func_array ( コールバック関数名, パラメータの配列 );

第一、第二引数ともに配列です。クラスのメソッドを指定して、そこに配列でメソッドの引数を渡して実行します。

ここでは 'array($instance, $method)' の部分をコールバック関数としています。

「【PHP】コールバック関数の使い方・サンプル(レポート出力するデータを後から差し替える)」
https://notepad-blog.com/content/95/

まだまだ根強いコールバック関数への苦手意識。早くなくしたいです。

ルーティング

ルーティングの概念を理解する【Webフレームワークの基礎知識】 | Web白熱教室

ルーティングはクライアントのリクエストとサーバーの処理をひもづける作業

phpフレームワークに限ったことではない用語でした。

既存のフレームワークで作られたサイトで新しくページを追加したときにうまく行かず(404になってしまった)、原因はルーティングが設定されていないからでした。

ルーティングではリクエストURLによってこのControllerを使う、など設定されているのですが、書き方はサイトの構造によって様々みたいです。

WordPressの場合は内部で行われているんですかね。パーマリンクの処理周りでしょうか。

そのルーティングに一役買っているのがフロントコントローラーでした!

フロントコントローラー

PHP フレームワークを理解する為のフロントコントローラとページコントローラ | h19e

フロントコントローラは、URLに関係なくすべて同一のファイルにアクセスされます。

同一のファイルにアクセスをまとめることで管理しやすいということでしょうか(未確認)。

フロントコントローラーの「コントローラー」は、MCVのコントローラー(Controller)とは別の意味で使われているそうです。

フロントコントローラー(一番上のindex.php)に転送するために.htaccessが働いているというのは盲点でした。
(普通に考えても、実体のファイルがないはずのurlでアクセスできるのは不思議なのに)

アクセスしているURLはそのままで、リダイレクトではなく転送(書き換え)しています。

例:https://example.com/hoge にアクセス
.htaccess

RewriteRule (.*)$ /index.php?r=$1

https://example.com/index.php?r=hoge に書き換え
→ GETパラメータ(r=1)によって使うクラスやControllerを決める。

というようにURLによってページ表示されています。

.htaccess mod_rewriteによる正規表現を使ったリダイレクト設定

正規表現...勉強しなくては。

GETパラメータがなくてはならないですね!

さいごに

後ろの方はボリュームが小さくなってしまいました。
大事な部分だと思うので、また復習して追記したいです。

phpの基礎力を付けるために、おなじみのTODOリストを作ってみようと思っています。
TODOリストはソースコードも用意してくださっているサイトを見ながら作るのもありですが、 今ある知識でイチからやってみるのもありかなと思っています。(あまりできる気がしない)

そういえば以前メール送信してみて深堀りするはずが頓挫しています(記事が下書きで終わっていました)。

完成まで持っていきたいです!

ドメインとサーバーを契約しました

やっと、やっと申し込みました。

お金がかかるからという単純な理由でこれまで渋っていましたが、何とか安く済ませられそうなので一念発起してドメインとサーバーを契約しました(大げさ)。

Xserverでキャンペーンがありました。

f:id:yokoyoko_115:20210503022007p:plain
Xserverのキャンペーン

キャンペーン対象のドメイン.com.net などに限られていたので迷いましたが(本当は .work にしたかった)、サーバーの契約がある限りドメインの更新料無料の言葉につられて申し込みました。

今回は、Xserverでのキャンペーンを利用したサーバー、ドメインの申し込み手順をメモします。

キャンペーンの適用は支払いが済んでから

Xserverのアカウント登録 → サーバー申し込み
の時点では「サーバーの10日間無料お試し」になり、ドメインの申し込みができませんでした。

独自ドメイン未取得で10日間特にすることがないので、支払い登録をしました。

結果内訳は下記のようになりました。

【かかった料金内訳】
サーバー初期設定:16,500 円(年間使用料1,100円x12ヶ月=13,200円含む)
ドメイン使用料: 0円 (1ドメイン無料キャンペーン)
キャンペーン:  -3,300 円(初期設定費無料キャンペーン)


支払い:     13,200円

まだお手頃価格な気がします。

支払い登録の後、ドメインを申し込みました。

サーバー・ドメイン取得後に行うこと

これで取得したドメインにアクセスしたら見れるわけではなく、ドメインの設定が必要です。

サーバーにドメイン設定をする

「サーバー管理」というボタンから「サーバーパネル」という管理画面に行きます。

ドメインの「ドメイン設定」から「ドメイン追加設定」タブを開いて独自ドメインを登録します。

f:id:yokoyoko_115:20210504000859p:plain

そしてドメインが反映されるまで待ちます(私は10〜20分でした)。

独自ドメインにアクセスすると下記のように表示されました。

f:id:yokoyoko_115:20210504001754p:plain

ファイルの構成

「ファイル管理」のボタンから、自分に割り当てられたサーバーの中身を見ることができます。

独自ドメイン設定直後の一番上の階層】
初期ドメイン
 ┗.spamassassin
 ┗autoreply
 ┗htpasswd
 ┗log
 ┗mail
 ┗public_html ←ドキュメントルート
 ┗script
 ┗xserver_php
独自ドメイン ←初期ドメインと中の構成は同じ
ssl ←中は空

ドメインごとにフォルダが用意されています。
そしてその中にはpublic_htmlを含めた各フォルダがあります。

public_html以外のフォルダについてはどう使っていくのか不明です。
空のフォルダはFTPクライアントでサーバーを見てもよく見かけるので、ここは気にしないでおきます。

さいごに

これでようやくスタート地点に立てました。

自分のサーバーがあれば、思い切ったこともできますし、壊し放題!

人様からのアクセスを気にしていないので自由にあれこれ試すことができます。

そういえばNetlifyを利用したHugoサイトで独自ドメインを充てられたと思うのでやってみます。

サブドメインも、設定してみます。

おしまい。

Hugoサイトでcssを上書きする(Theme使用)

ようやくNetlifyでHugoサイトを公開しましたが、元のThemeのままです。

少しずつカスタマイズしていこうと思います。

☆使っているテーマは「hugo-clarity」です。

sassファイルを確認してみる

デザインを変えたいのでcssを調べます。
cssファイルは見当たらず、sasファイルを見つけました。

hugo_site2021/themes/hugo-clarity/assets/sass/_custom.sass を開くと、コメントがあります。

_custom.sass

// add customs styles and general overrides here
// due to the cascading nature of css, if you try to override theme css variables in this file, those changes will not apply. Instead, override css variables in the override.sass file
// we recommend not editing this file directly. Instead, create an assets/sass/_custom.sass file at the root level of your site.
// if you edit this file directly, you will have to resolve git conflicts when and if you decide to pull changes we make on the theme

翻訳すると

カスタムスタイルと一般的なオーバーライドをここに追加します。
css のカスケードの性質上、このファイルでテーマの css 変数をオーバーライドしようとしても、その変更は適用されません。代わりに、override.sass ファイルで css 変数を上書きしてください。
このファイルを直接編集しないことをお勧めします。代わりに、サイトのルートレベルに assets/sass/_custom.sass ファイルを作成してください。
このファイルを直接編集すると、私たちがテーマに加えた変更を引き出そうとしたときに、gitコンフリクトを解決しなければならなくなります。

ということです。

override.sass ファイルとは同じ階層の _override.sass のことでしょうか。

_override.sass

// override clarity theme's _variables.sass file.
// we recommend not editing this file directly. Instead, create an assets/sass/_override.sass file at the root level of your site.
// if you edit this file directly, you will have to resolve git conflicts when and if you decide to pull changes we make on the theme

翻訳すると

クラリティテーマの _variables.sass ファイルをオーバーライドします。
このファイルを直接編集しないことをお勧めします。代わりに、サイトのルートレベルに assets/sass/_override.sass ファイルを作成してください。
このファイルを直接編集すると、私たちがテーマに加えた変更を引き出そうとしたときに、gitコンフリクトを解決しなければならなくなります。

だそうです。
んん?

ついでに _variables.sass ファイルを見てみます。

_variables.sass ファイルの中身はその名の通り変数と設定値が書かれています。

まとめると

ファイル 役割 代わりのファイル
_custom.sass カスタムスタイル(オーバーライドは適用されない) ルートディレクトリに assets/sass/_custom.sass
_override.sass _variables.sassをオーバーライド ルートディレクトリに assets/sass/_override.sass
_variables.sass 変数の設定 _override.sass

assets/sass/_custom.sass一般的なスタイルの上書き
assets/sass/_override.sass変数の設定値の変更

と考えられます。

Theme内のsassファイルに書くと、使っているテーマがGitHubで更新された時、プル(コミット?)をしたらコンフリクトするようです。
(Gitの submodule コマンド。まだ手を出さなくていいかなと思っています)

ということは、基本カスタマイズはテーマディレクトリの上のファイルを触ることになるのだと思います。

コメントに従ってassets/sass/custom.sassファイルとoverride.sassファイルを作りました。

試しにbody要素の背景色を変えてみます。

テーマ内の_variables.sass

html
  --color-mode: 'lit'
  --light: #fff
  --dark: #000
  --bg: #002538
  --haze: #f2f2f2

と書かれているので、--haze の部分を同じように書いてみます。

普段書かない書き方です。省略形でしょうか。

_override.sass

html
  --haze: linen

すると見事上書きされました!

ちなみに linen はカラーの名称です(ベージュの薄い色)。
初めて使ってみました。たくさんありますね。

cssの仕組み

デベロッパーツールを見たところ、テーマファイルの中の _base.css に変数が使われていて、その変数が _variables.sass_custom.sass で設定されていました。

そしてテーマ内のsassディレクトリ内に唯一_ の付いていない main.sass を見てみると、諸々のsassファイルを @import していました。
コンパイル不要の場合は _ を付けるはずなので、main.sass ファイルはおそらくどこかでコンパイルされているのでしょう。

図にしてみました。 ※「scss」は「sass」です。間違えました。 f:id:yokoyoko_115:20210425032542p:plain

マップファイルが使われている

デベロッパーツールで設定元のsassファイルが確認できるということは、マップファイルが使われているということです。

実際にページで読み込んでいるのは styles.css ファイルでした。
(実際は styles. の後ろに長い謎のパラメータ?が付いています)

もしかすると main.sassコンパイルされてstyles.cssになったのかもしれません (ファイル名が異なるのが気になります)

以前の記事を確認してデベロッパーツールから styles.css を見てみると、

/*# sourceMappingURL=styles.css.map */

sourceMappingURLアノテーションがありました!
しかし styles.css.map ファイルは見つかりませんでした。

さいごに

触れるcssassets/sass/_custom.sassassets/sass/_override.sass であることがわかりました。

マップファイルとcssファイルはおそらく動的に作られているのでしょう。

まだまだ謎だらけのHugoサイトですが、デザイン変更などできるところから進めていきます!

ロゴやブログ名を変えなくては。

Hugoでサイトを作り直します

すっかりご無沙汰になってしまったHugoのサイト作り、テーマを新しいものにして作り直そうと思います。

今回はこちらのテーマにしました。

f:id:yokoyoko_115:20210321005234p:plain

去年の記事を見ながらhttp://localhost:1313/で表示できるところまで進めました。

前回作ったサイトへのアクセスもhttp://localhost:1313/ですが、サイトディレクトリの中まで移動して hugo server でhugoサーバを起動させることで切り替えています。

前回の反省点

途中で作ることをやめてしまった要因は、完璧を目指してしまったからだと思います。

Hugoを理解してから記事移行しよう、など順番を決めて自らハードルを上げてしまっていました。

今回はできるところからやっていきます!

静的サイトジェネレーターのホスティングサービスを利用する

ブログのカスタマイズも行わずに、ダウンロードしたテーマをそのまま公開します。

HugoのホスティングサービスならNetlifyが良いそうなので使ってみます。

自作のサイトを公開するならサーバーを契約してドメインを作って、とお金がかかると思っていましたが無料で作れてしまうんですね!

ゆくゆくは自分のドメインでサイトを公開したいですが、ひとまず。

参考にしたい記事

いろいろと網羅されていて今後お世話になりそうです。

Hugo で静的なサイト・ブログを構築しよう - Qiita

Netlifyの使い方が書かれています。

Netlifyで静的サイトのホスティングをする - Qiita

こちらに倣ってNetlifyのアカウント登録をしました。

「Deploy site」をクリック!

Netlifyでデプロイできず

それらしきリンクを押したらこう出てきました。

f:id:yokoyoko_115:20210322010916p:plain

「 "page not found" support guide 」のページを見てみても当然のことながら英語。

さっそく挫けそうですが、同じ境遇の方はきっといると思うので日本語で調べます。

Hugoのテーマ保存方法を振り返る

GitHubのHugoテーマのリポジトリからコピーしてくるところで、

git submodule を使いましょう。

とよく見かけるので、どういうことか調べました。

今回のテーマの「Getting up and running」の方法で“recommended”と書かれていたのがgit submodule だったのでこちらを行っていました。
git clone とどう違うのでしょうか。

こちらは今後の課題として置いておいて...。

どうにもこうにも、Netlifyの英文をいくら(翻訳して)読んでも分からなかったので、サイトを一回削除して作り直しました。

Netlifyの画面

f:id:yokoyoko_115:20210326005927p:plain
1回目のときはBuild commandが空だったような。いけるかもしれない

またもや失敗。Deploy logを読んでみる

ダメもとで logを読んでみました。

ERROR 2021/03/25 15:45:25 HUGO-CLARITY theme does not support Hugo version 0.54.0. Minimum version required is 0.63.0

訳すと

ERROR 2021/03/25 15:45:25 HUGO-CLARITYテーマはHugoバージョン0.54.0をサポートしていません。最低限必要なバージョンは0.63.0です

Hugoのバージョンをアップデートしていなかったことが原因かもしれません。
Hugoを初めてインストールしたのは去年で、それきり触っていませんでした。

ローカル環境でHugoのサイトは見れましたが、デプロイ時には問題なのかもしれません。

Hugoをアップグレードする

brew upgrade hugo 

でアップデートできました。
すると、

Upgrading hugo 0.65.3 -> 0.82.0

と出てきました。

ローカルのhugoのバージョンはもとから0.63.0以上だったみたいです。
(ローカルでサイトは見れていたので当たり前といえばそうですね)

ということは、NetlifyでのHugoのバージョンを上げる必要がありそうです。

NetlifyのHugoのバージョンを設定する

Hugo 0.20以降はバージョンを設定することになるみたいです。

方法は

  • NetlifyのBuild & deploy > Environment で環境変数を設定する
  • config.toml ファイルに設定する

2つあります。

今はNetlifyへ設定する方法で進めます。

Environmentへの行き方
Sitesからサイトを選択 > 上のメニューやサイトの概要部分のSite settings > 左のメニューにBuild & deploy があります。

f:id:yokoyoko_115:20210327002923p:plain

バージョンはローカルと揃えました。

さぁうまくデプロイできるでしょうか!?

cssが読まれていない。

残念でした。

cssなどのパスや記事などへのリンクもhttps://example.com/になっていていました。
リンク先は

f:id:yokoyoko_115:20210327003746p:plain

と出てきました。

翻訳にかけると

例示ドメイン このドメインは、文書の中で例示的に使用するためのものです。このドメインは、事前の調整や許可を得ることなく、文献に使用することができます。

???

「example」の説明な気がします。

もしやと思い、config.toml ファイルの設定を見直しました。

すると

baseurl = "https://example.com/"

とありました。ここを変えれば良さそうです。
こちらもNetlifyから設定してみます。

Environmentで設定してみる

しかし、Environmentにbaseurlを設定しても変わりませんでした。

ビルドコマンドを設定してみる

そこで、ビルドコマンドを hugo -b $DEPLOY_URL にすると良い、という情報を見つけたのでやってみました。

Netlifyのプレビュー用URLに合わせてHugoのbaseURLを変更する · Issue #11 · kai2nenobu/www · GitHub

Hugoは -b, --baseURL オプションで config.toml の baesURL を上書きできる。なのでNetlifyのビルドコマンドにそれを指定してあげればいい。

フォーラムの例では netlify.toml にコマンドを指定しているが、NetlifyのWebでもできる。具体的には Settings > Build & deplooy > Continuous Deployment > Build settings の Build command に hugo -b $DEPLOY_URL を指定すればよい。

$DEPLOY_URLにはプレビュー用のURL?が入っているのでしょうか。

すると、トップページは相変わらず崩れたままで、リンク先の記事のページは、URLの頭に英数字がたくさん並んでいました。これがプレビュー用URLっぽいです!

目指している解決法とは少し違うみたいです。

config.tomlを修正する

はじめからこの方法を取ればよかったのですが、Gitが謎の状態になっていたのであまり触りたくありませんでした。遅かれ早かれ触るのですが。

Gitの謎現象は、きっとsubmoduleを使っている影響だと思います。 (リポジトリ?が2つ並んでいる)

baseurl = "https://example.com/" の部分を修正して、あたり障りなくコミットしてプッシュしました。

ようやく表示できました!

初心者には全然簡単ではありませんでした!

今度はプレビュー画面にcssが効かなくなってしまいました。

submoduleで作られたリポジトリは、今後どういう扱いをしていけばいいのかもわかりません。

ただ更新の仕方は、GitHubにプッシュ→Netlifyでビルド&デプロイ ということは分かりました。

少しずつ調べながらHugoサイトをカスタマイズしていこうと思います!

おしまい。

gulp導入の覚え書き(後編)- gulpとnpmの使い方

gulpを利用した当初は、なすがままに設定していただきました。
コマンドもほぼはじめましてだったので、黒い画面に呪文...と、何が起きているのか理解に苦しみました。

現在理解している範囲でnpm、gulpまわりで集めた情報をまとめます。

大まかな流れ

1. homebrewをインストール  
 ↓  
2. anyenvをインストール  
 ↓  
3. nodenvをインストール  
 ↓  
4. Node.js(npm)をインストール  
 ↓  
5. gulpをインストール・・・後編ここから  
 ↓  
6. gulpをつかう  
 ↓  
7. npmをつかう

前編の続きです。
gulpのインストールからnpmの使い方までまとめます。

gulpとは

gulpはNode.jsをベースとしたビルドシステムヘルパーです。Gruntと似た目的を持って作られたツールで、gulpを使えばさまざまな作業を自動化することができます。一番の特徴はファイルの処理をストリームで行う「ストリーミングビルドシステム」です。この特徴によって複雑なタスクも細かくカスタマイズして書くことができます。

(一部抜粋)

現場で使えるgulp入門 | 第1回 gulpとは何か | CodeGrid

ビルドシステムヘルパー...。
ストリーミングビルドシステム...。
まずはざっくり理解できればと思います。

gulpはNode.jsのライブラリのうちの一つであることは覚えておきます。

☆以下「ライブラリ」だったり「パッケージ」だったり、「モジュール」だったり用語が出てきますが、厳密な違いが分かっていないのでほぼ同じ認識で進めます。
(パッケージ > ライブラリ > モジュール の順の大きさだと思っています)

5. gulpをインストールする

ようやくgulpをインストールする準備ができました。
まずはNode.jsインストール時に一緒にインストールされたnpmの設定です。

プロジェクトのディレクトリに移動して行います。

npmの初期化

Node.jsのパッケージを使うにあたり最初に行います。
下記コマンドでpackage.jsonというパッケージ管理ファイルを作ります。

npm init

対話形式でpackage.jsonの設定値を入力していきますが、この時点で必ず必要ではないのでreturn(enter)キーで進めて大丈夫です。
最後にこれらの設定値でよいかyes/noで聞かれます。

詳細はこちらを参照しましょう。

初期化処理を行う!npm initの使い方【初心者向け】 | TechAcademyマガジン

また、npm init -ynpm init -yes とオプションを付けたコマンドを打つことで、対話などを省略することができます。

中には npm init --yes と、ハイフン(ダッシュ)が2つのコマンドも見掛けました。
これはLinuxの中で「UNIXスタイル」や「GNUスタイル」などのスタイルの違いから来ているそうです。複数のオプションをつけるときの書き方も異なるので注意です。

Linux引数(オプション)のハイフン-と--の違い - Qiita

なお、npm(Node Package Manager)については今のところNode.jsのパッケージ管理ツールである、とだけ認識して進めます。

package.json 中身の主な設定

"name":パッケージ名
"version":最初は"1.0.0"。パッケージの内容を変えるときに変更する
"author":作った人の名前
"dependencies":npmでインストールしたパッケージ(モジュール)
"scripts": script コマンド のプロパティ。キーがイベント、そして値がコマンド??

npmからglupをインストールする

npmコマンドでNode.jsのパッケージであるgulpをインストールします。

npm install gulp 

glupのバージョン確認

gulpのインストールが終わったら、

gulp -v

と、バージョンを確認しましょう。

npmでのパッケージのインストールについて

引っかかった部分や、覚えておきたい内容をまとめました。

パッケージのインストール

方法はオプションによって異なります。

npm install パッケージ名 -P

npm install パッケージ名 --save-prod
npm install パッケージ名 --save
npm install パッケージ名(オプションなし)と同じです。
package.jsondependencies フィールドに追加されます。

npm install パッケージ名 -D 

npm install パッケージ名 --save-dev と同じです。
package.jsondevDependencies フィールドに追加されます。

npm install -g パッケージ名

パッケージのグローバルインストールです。
パッケージのグローバルのインストールはお薦めされていません。

package.jsonに書かれているパッケージをインストールする

npm install

同じプロジェクトを複数人で開発する時に使うと便利なコマンドです。
Gitでpackage.jsonを管理しておくと、複数人の環境を npm install で揃えることができます。

上記のようにオプションなしではpackage.jsonのdependenciesとdevDependencies両方に書かれているパッケージをインストールします(npm install --production でdependenciesのパッケージのみインストール)。

dependenciesとdevDependenciesの違い

「dependencies = 依存(複数)」、「development = 開発」です。

ここではパッケージを開発用公開用に分けて考えます。

いつもプロジェクトで作るパッケージは開発用です。npm init でpackage.jsonを作ってパッケージを設定します。

これとは別に、公開用のパッケージ、すなわちインストールされるパッケージを作る場合はdependenciesとdevDependenciesを使い分ける必要があります。

【いまさらですが】package.jsonのdependenciesとdevDependencies - Qiita

パッケージを使いたい人がnpm install パッケージ名としたときにはdependenciesに書かれているパッケージのみがインストールされます。

公開パッケージを作る、というのは中々ないかなと思います。
開発のためのパッケージの使い方をどうすればいいか考えたところ、

npmのpackage.jsonと依存関係を理解しよう! - bagelee(ベーグリー)

全てdependenciesに追加してしまってもいいのですが、これらの違いはNode.jsサーバーとして動かすときやパッケージを公開するときに影響してきます。普段から、プログラムの動作には必要なく開発やテストのときのみに使うパッケージはdevDependenciesとして追加するように意識するといいでしょう。

開発やテストの時に使うパッケージとプログラムの動作に使うパッケージが異なる、というイメージがあまり持てず、そのパッケージに依存しているパッケージは全部必要に思えてしまうのですが、そういう場面に直面しなと実感できなさそうです。

なにはともあれ、開発だけのパッケージの場合はdevDependenciesに入るようにインストールする習慣をつけようと思います!

パッケージの開発、インストールまとめ

開発パッケージの場合 インストールされるパッケージの場合
パッケージに対して使うコマンド npm install npm install パッケージ名
コマンドのはたらき package.jsonに書かれているパッケージをインストールする
(他の人とパッケージの内容を共有できる)
パッケージをインストールする
インストール先のpackage.jsonへの追加(dependencies/devDependenciesはオプションで選べる)
dependenciesの
パッケージ
devDependenciesの
パッケージ

--productionをつけるとインストールしない

gulpのインストールはグローバルなのかローカルなのか、両方なのか問題

2021年現在ではローカルのみにインストールするのが主流のようです。

グローバルインストールでは、パスが通っている状態なので、gulp とコマンドを打つと、グローバルなgulpの実行になります。

なのでローカルのみのインストールでは不便なのかというと、npm-scriptnpx(後述)を使えば簡単にローカルのgulpを実行することができます。

問題の「両方」については、

gulpのインストールは通常ですとローカルとグローバルの両方にインストールする必要があります。グローバルにインストールされたgulpは、ローカルにインストールしたgulpを実行するのが役割です。

とのことで、仕組みは以下のように、

gulpのアプローチ "なぜグローバルとローカルにインストールが必要なのか" | じまぐてっく

グローバルなgulpのコマンドを叩くことで、ローカルなgulpを実行することができるのだと解釈しました。

現在のgulpのバージョン(4.0.2)では同じコードを見つけられなかったのですが、仕組みは同じではと思いました。

☆ローカルのみにgulpをインストールした環境で以下進めています

package-lock.jsonとは

まずは「ロックファイル」について調べました。

ロックファイル (lock file)
https://wa3.i-3-i.info/word12436.html

排他制御というのをするファイルなのですね。トイレの例を覚えよう。

他の言語などの場面では .lock という拡張子のロックファイルがあったりするみたいです。

そろそろlockファイルを理解するための最初のページ【composer.lock/package-lock.json】 - Qiita

ロックファイルの働きが、実際の作業の流れで見ていくとわかりやすかったです。

パッケージの公開も、こんなに簡単にできてしまうとは驚きでした。

こちらでも簡単にまとめられています。

【Node.js】package.jsonとpackage-lock.jsonについて簡単にまとめる - Qiita

買うものリストと領収書!

これらをまとめると

  • モジュールをインストール、またはアップデートする時、package.jsonにインストールするモジュールとバージョン(キャレット^やチルダ~付き)が書き込まれる→node_modulesフォルダにモジュールが入る→package-lock.jsonにインストールされたモジュールとバージョンが書き込まれる
  • package-lock.jsonはnode_modulesの中身やpackage.jsonによって自動で作成・変更される
  • npm install をする時、package-lock.jsonがあると、package-lock.jsonに書かれているバージョンのパッケージがインストールされる
  • npm install をする時、package-lock.jsonがないと、package.jsonに書かれているパッケージの新しいバージョンがインストールされる(package.json^2.0.0 と書かれていたら、2.5.0がインストールされることもある)

大体あっていると思います。

package-lock.jsonもGitで管理しましょう!

6. gulpをつかう

gulpfile.jsを作る

制作に便利なタスク(処理)をgulpfile.jsに書いて、コマンドで実行します。

2021年3月現在はgulp4が最新なので、その書き方で覚えていきます。

主に以下の記事を見ながら書きました。

Gulp4の変更点と新しい書き方 - Qiita

gulp4の設定方法 - SassやAutoprefixer、ejs、画像の圧縮などを自動化する | 夢みるゴリラ

調べるとgulp3を使っている人向けの記事ががほとんどなので、3と4の違いも分かります。同時に混乱します。

とても簡単にgulp(gulp4)の書き方をまとめると

  • task() を使わずに、タスクの関数宣言をする(無名関数を変数に入れたり、関数名を付けたり)
  • タスクの関数の中は大体 return ではじまる
  • exports.gulpタスク名 = タスク名(変数、関数) でgulpコマンドにタスクを設定する
  • gulpタスクの実行コマンドは gulp gulpタスク名(※gulpのローカルインストールでは実行できない)
  • exports.defalut とgulpタスク名を defalut にすると、実行時に gulp default と打たなくてよくなる(gulp でdefalutタスクが実行される)

という感じです。 肝心のタスクの中身は 心のタスクク中身はgulpのpipe()series()parallel()メソッドを使って、 処理をつなげたり、並行処理したりします。

何とかコードは読めはするものの、自力では書けないのでもう少しがんばりたいです。

***

ひとつ、冒頭のrequireの書き方で気になった部分があったので調べました。

const { src, dest, watch, lastRun, parallel, series } = require("gulp");

分割代入によりオブジェクトの特定のプロパティだけを単独変数に取得する (Object destructuring) | まくまくJavaScriptノート

これはES2015から使える分割代入というのですね。

gulpの中身はオブジェクトで、

const gulp = {
  'src': 'srcValue',
  'dest': 'destValue',
  'watch': watchVvalue'
}

などとなっているのかな、ーと思いましたが、ざっと見る限りそうでもありませんでした。
安直でした(笑)
実際どうrequireされているのか不明です。

const { src, ... のように書くと、gulpメソッドをつかう時に gulp.src ではなく src で済む、というものでした。

gulpコマンドでgulpタスクを実行する

ここではnpmの働きと分けるためにgulpコマンドから実行することを考えます。

先ほど「gulpタスクの実行コマンドは gulp gulpタスク名(※gulpのローカルインストールでは実行できない)」
と書きました。

gulpをローカルのみでインストールしている場合は簡単なコマンドではうまくいかないのです。

たとえば

gulpfile.js(一部)

// Sassファイルを監視し、変更があったらSassを変換するタスク
const watchSassFiles = () => watch('./scss/**/*.scss', compileSass);

// タスクの宣言
exports.watch = watchSassFiles;

と書いた場合、gulpfile.jsがある階層で
gulp watch とコマンドを叩けば実行できるかというとできません。

「command not found: gulp」(gulpコマンドが見つかりません)と返ってきます。
ローカルなgulpにはパスが通っていないのです。

なので./node_modules/.bin/gulp watch と叩けば実行できます。
これは毎回実行するのが大変です。

そこで便利なのがnpmです!

7. npmをつかう

npm コマンドからgulpのタスクを実行すると、コマンドもシンプルです。
また npx コマンドも使えるのでそれぞれ見ていきます。

npm-script

Node.jsユーザーなら押さえておきたいnpm-scriptsのタスク実行方法まとめ - ICS MEDIA

npm-scriptsとは、package.jsonファイルに記述可能なシェルスクリプトエイリアスです。エイリアスとはコマンド名を別のコマンド名に置き換えることです。

gulpfile.jsのたとえを受けてpackage.jsonが次のように書かれているとします。

package.json(一部)

 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "sass": "gulp sass",
   "start": "gulp watch"
}

echo \"Error: no test specified\" && exit 1シェルスクリプト(コマンド)で、これを test という別のコマンド(スクリプト名)に置き換えています。

実行するコマンドは

npm run test
npm run sass
npm start

になります。
npm runrunを付けます。

なおスクリプト名がstart、testの場合は run は不要です。
(↑は npm test でもOK)

runにまつわるお話も見つけました。

`npm run` は正式なコマンドじゃなかった件(NPMおれおれAdvent Calendar 2019 – 01日目) | Ginpen.com

gulpに関わらず、いろいろとコマンドを設定して使いやすくできるようです!

npx

npxはnpmのバージョン5.2.0以降に入っています。

npm 5.2.0の新機能! 「npx」でローカルパッケージを手軽に実行しよう - Qiita

ローカルにインストールしたnpmパッケージを、npxコマンドだけで実行できるようになります。

なので上記のnpmコマンドの代わりにnpxを使うと、

npx gulp sass
npx gulp watch

で実行できます。

こちらもgulp以外にもインストールしたパッケージを実行する時に、手軽にできて便利です。

さいごに

gulpとnpmのことは、ずっとまとめようと思って温め続けていました。
ようやく書けました。スッキリ!
(後々見返して意味が分かるのかは怪しい)

存在知りたての頃よりだいぶ分かってきたと思います。

私の場合はnpmの入り口がgulpでしたが、他の用途や機能の異なるパッケージも使っていけばもっと体系的に分かってくるのだろうと思います。

おしまい!

gulp導入の覚え書き(前編)- Node.jsのインストールまで

gulpを使おうとなった時に以前行った手順は記憶の彼方なので、これまでのメモをまとめました。
(特にNode.jsまでは一度入れてしまえば中々入れ直すこともないと思うので忘れてしまいます)

☆長くなるので前・後編に分けました。後編はこちら

大まかな流れ

以下に沿って進めます。

1. homebrewをインストール  
 ↓  
2. anyenvをインストール  
 ↓  
3. nodenvをインストール  
 ↓  
4. Node.js(npm)をインストール  ・・・前編ここまで
 ↓  
5. gulpをインストール

1. homebrewをインストールする

homebrewとは

App Storeで扱っていない、開発をするためのソフトウェアをインストールする際に依存関係を管理してくれるツールです。

一言でいうと、macOSのパッケージ管理ツールです。
以前調べました(記事)。

homebrew=自家醸造=ユーザー自らがビルドする」でしたね!

日本語のhomebrew公式ページ
「これをmacOSのターミナルまたはLinuxのシェルプロンプトに貼り付けて下さい。」という部分を、コピペでコマンドラインで実行します。

これでbrewコマンドが使えるようになります。

【参考】homebrewについて

【簡単】MacにHomebrewをインストールする方法と基本的な使い方|新卒エンジニアの開発日記

2. anyenvをインストールする

anyenvとは

pyenvやrbenv、phpenv、nodenvなど「〜env」と名のついた、プログラミング言語バージョン管理ツールを一元管理するツールです。
各環境(仮想環境とか、プロジェクト)ごとに各言語のどのバージョンを使っているかを管理してくれます(と解釈しました)。

anyenvのメリットです。

  • 現在のバージョンを何に設定しているか、どのバージョンが入ってるかまとめて確認できる
  • 〜env系を簡単にインストールできる
  • 新しいプログラミング言語を追加しても.bash_profileや.zprofileなど(bashzshといったシェルの設定ファイル。パスを通す時に記述する)に書き込まずに(汚さなくて)済む
  • VM (VirtualMaschine)での開発でプロジェクトを切り替えるとき、いちいち VM を立ち上げ直す手間がない
  • プロジェクトごとにバージョンを切り替えて開発できる

VMのことなど、一部まだよくわかっていないですが、便利ということは分かりました。

anyenvのインストール方法は2つあります。 ※以下シェルがzshの書き方です。

方法1:brewコマンドを使う

brew install anyenv
echo 'eval "$(anyenv init -)"' >> ~/.zshrc
exec $SHELL -l

2行目は anyenv init - を実行する処理を echo>> を使って .zshrc に記述します。

3行目でシェルを再起動させます。

シェルを再起動させる簡単な方法 - Qiita

exec $SHELL -l とは以下の意味だそうです。

環境変数 $SHELL をログインシェルから起動させることを exec するという意味となり、ターミナルが再起動できるようになります。

まだ理解するには早かったみたいです...。

方法2:gitコマンドを使う

GitHubにあるリポジトリをクローンしてインストールします。

git clone https://github.com/riywo/anyenv ~/.anyenv
echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(anyenv init -)"' >> ~/.zshrc
exec $SHELL -l

GitHubに説明がありました(英語です)。

GitHub - anyenv/anyenv: All in one for **env

【参考】anyenvについて

anyenv + macOS環境構築 - Qiita

3. nodenvをインストール する

anyenvをインストールして使えるようになったanyenvコマンドから「〜env」をインストールできるようになります。

nodenvとは

プロジェクトごとにNode.jsのバージョンを自動で切り替えてくれるツールです。

コマンドラインでnodenvをインストールします。

anyenv install nodenv

exec $SHELL -l

以降のNode.jsのインストール手順もこちらに書かれています!

Node.jsのバージョンを自動で切り替えられるnodenvが超便利 - Qiita

コマンドの使い方が丁寧に書かれています!

anyenvとnodenvでNode.jsのバージョン管理をしよう! - to-R Media

4. Node.js(npm)をインストール する

npmはNode.jsをインストールすると、もれなくインストールされます。

まずグローバルでNode.jsのインストール、バージョンの設定をします。

グローバルでNode.jsをインストールする

Node.jsはバージョンを指定してインストールします。必要なバージョンをグローバルでインストールして、全体、各プロジェクトでバージョン指定を行って使います。

インストールできるバージョンの確認

ndenv install --list

バージョンがずらっと出てくるので、安定した最新のバージョンを選びます。
新規プロジェクトの場合は最新のものでOKです。
数字だけのもののうち、一番数が大きいものが最新です。

☆ここではv13.5.0をインストールしてみます。

インストール

nodenv install 13.5.0

グローバルでNode.jsのバージョン指定をする

インストールしただけでは使えないのでバージョンの指定をします。グローバルのバージョンがデフォルトになります。

グローバルでのNode.jsのバージョン指定

nodenv global 13.5.0

プロジェクト(ローカル)ごとにNode.jsのバージョン指定をする

バージョン指定をするファイルは .node-versionです。.node-versionファイルは直接作成する方法と、コマンドで作成する方法があります。

.node-versionファイルの中身

13.5.0

ローカルのNode.jsのバージョン指定

nodenv local 13.5.0

上記のコマンドで.node-versionファイルが作られます。
プロジェクト内に .node-versionファイルがない状態、すなわちバージョンを指定しない場合はグローバルで指定されているバージョンが使われます。

インストールしただけでは使えない、バージョン指定が必要ということなので、グローバルかプロジェクト、どちらかでバージョン指定が必要であることがわかりました。

バージョンの確認

node -v

または

node --version

ちなみにanyenvでは「〜env」ごとにインストールされている言語のバージョン(ここではNode.js)のリストと、指定されているバージョンが分かります。

anyenv versions

続きは後編で

後編ではgulpのインストールとnpmの使い方についてまとめます!

レスポンシブな画像の表示を考える

投稿するコンテンツの場合、アップする画像サイズを統一させられないのが常です。
いろいろな縦横比の画像を画面いっぱいに表示させる方法を模索しています。

wordpressなどでは、リサイズさせた画像を表示させたりするので、あまり頻繁ではありませんが、たまに詰まるときがあります。

ポイントは

  • レスポンシブ(拡大縮小しても縦横比は同じ)
  • 表示枠の中央に表示
  • 表示枠いっぱいに画像を表示する(余白が出ない)

これら3つをおさえることです。

現時点でこれがベスト!という書き方をメモします。

検証の条件

サンプル画像はこちらです。

f:id:yokoyoko_115:20210306003406j:plainf:id:yokoyoko_115:20210306003439j:plain

中央がわかりやすいと思ったものにしました。
(縦は微妙かもしれない)

これらはそれぞれ
427x640px
640x427px

のサイズで約長辺3:短辺2の比です。

※横長画像はコンテンツ幅に合わせて小さくなっています。
2つの画像の比があっていないように一見見えますが同じです!(錯覚?)

これらを、幅4:縦3の枠にいっぱいに表示させることを目指します。

上記の3つのポイントを見ていきます。

htmlはこのように書いて検証しています。

html

<p class="frame">
<img class="frame_img" src="https://drive.google.com/uc?export=view&id=18asPUoAeh3QanjaSkyp_q-ETAAvc74fr" alt="縦長写真の猫">
</p>
<p class="frame">
<img class="frame_img" src="https://drive.google.com/uc?export=view&id=1_DRrKwnmc1SzcdYMp992SoCr2-EkhKCb" alt="横長写真の猫">
</p>

レスポンシブな枠の高さの作り方

レスポンシブの際にいつも悩む高さの指定ですが、height または、padding-top で考えます。

heightの場合

height で%を使うと、親要素の高さから値を取るのであまり使うことはないと思います。

一方でvwという、ビューポートの横幅を基準とした単位では、階層が深い要素だと指定が難しいです(要素のvwの数値を出す計算が大変)。

padding-topの場合

padding では%は、要素の幅から計算します。
縦:横 = 1:2 の場合は、padding-topは幅100%の半分の50%になります。

padding-topの出し方
縦 / 横 x 100%

ですね。

なのでとても使えます!

疑似要素を使うといい点

padding-top を使うときは疑似要素を使いましょう、と調べると出てきます。
ですが、例えば幅4:縦3の枠で、表示枠が width: 80% という指定だった場合

.frame {
  width: 80%;
  padding-top: 60%;    /* ←3 / 4 x 80% */
}

と、わざわざ疑似要素を作らなくても枠が作れるのです。

padding-top で高さを作る場合は、どちらにしろ表示枠の中の子要素には position: absolute を指定することになるので、必ずしも疑似要素が必要、というわけではありません。

ではなぜ疑似要素を作ることを勧められているのかというと

  • padding-top の計算がしやすい(縦 / 横 x 100% と、100%で計算できる)

ぐらいしか思い浮かびませんでした。
もっと複雑に要素を含ませたい場合に擬似要素の方が都合が良いのかもしれません。

☆ちなみに疑似要素(::before, ::after)はインライン要素なので、この場合 display: block を入れます。

画像を中央に配置する方法

中央というとまたまた position: absolute を使うか、または flexboxを使うかが考えられます。

position: absoluteの場合

.position_frame {
  position: relative;
  background-color: #000;
  padding-top: 15%;
  width: 20%;
  overflow: hidden;
}

.position_img {
  position: absolute;
  top: 0;
  bottom: 0;
  left:0;
  right: 0;
  margin: auto;
  width: auto;
  height: 100%;
}

position: absolute を使った中央配置の書き方はtop: 50%; left:50; transform: translate(-50%, -50%); transform: translateY(-50%); もありますが、私は↑の書き方のほうが好きです。 (transformを使わなくてはいけないケースがあったような)

flexboxの場合

.flex_frame {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000;
  width: 40vw;
  height: 30vw;   /* ←3 / 4 x 40vw */
  overflow: hidden;
}

.flex_img {
  width: auto;
  height: 100%;
}

paddingの部分にflexitemを置くことはできないので、flexboxでは height を使うことになります。
しかし使いづらい height を指定してまでflexboxにする意味はあまりなさそうです。

表示枠いっぱいはobject-fit: cover

imgタグを width: auto; height: 100%; とすると、画像の比率は保たれるものの、縦長画像の場合は高さが足りないことがあります。 width: 100%; height: auto; も同様です。

imgタグを使わずに枠の背景画像として background-size: cover を指定する方法もありますが、それができれば苦労しない、ということでここでは置いといて。
それ以外にある方法は、object-fit プロパティををつかう方法しかないと思います。

object-fit:cover で枠いっぱいに広げてくれます。
中央に配置する記述も不要!枠の大きさを決めるだけで良いなんて素敵です。
画像もwidth: 100%; height: 100%; でも歪む心配はありません。

こちらに詳しく書かれています!

1行追加でOK!CSSだけで画像をトリミングできる「object-fit」プロパティー | Webクリエイターボックス

object-fit プロパティは2021年3月現在ではIE以外で有効です。

Can I use... Support tables for HTML5, CSS3, etc

もう使ってもいいと思いますが、IE対応までしたいという場合は、潔くプラグイン入れたいところです。

IE11での画像のobject-fitの使用について – 東京のホームページ制作 / WEB制作会社 BRISK@22年新卒採用中

さらに前回の記事で書いたwidthとheight属性をimg要素に書けば完璧!

まとめ - 枠いっぱいのレスポンシブな画像表示の書き方

CodePenでの検証はこちらです。

See the Pen 画像のレスポンシブ表示検証 by yokoyoko (@yokoyoko_code) on CodePen.

うまくいかないときは

実際に私はうまくいきませんでした!
コードを同じようにコピーしてみても枠の高さがおかしい。
よくよく見ると親要素にdisplay: flexがかかっていました!

フレックスアイテム(flexboxの子要素)の高さはデフォルトで親要素いっぱいに広がります。なのでいくら子要素に高さを指定しても効かないようです。

そこで画像の枠である子要素に align-self: flex-start を設定することにより、高さが子要素の高さになります。

ちなみに

CodePenで画像を使っているものを見かけるのですが、方法がわかりませんでした。
調べて無料会員が画像を使う方法を会得しました!
個人でサーバーを持っていなかったらこの手があります。

CodePenの無料会員で画像を使うには | こんぷれ

最後に

自分の中ではベストな書き方がまとまった!とすがすがしさを感じていますが、人様が作ったサイトを見ることも大事ですね。
もっといい書き方があると思います。
研究しなくてはですね。

おしまい!