React アプリを Github Pages にデプロイする方法

はじめに

React アプリを Github Pages にデプロイする方法を備忘録としてまとめます。

以下の記事を大いに参考にさせていただきました。 https://qiita.com/tat_mae084/items/745761eee6cd1d42949d

前提条件

  • Node.js v18.18.0
  • npm v9.8.1
  • react v18.2.0

手順

アプリのひな形作成

  • 以下のコマンドにより React アプリのひな形を作成します。
$ npx create-react-app my-app

package.json を編集する

  • my-app配下にpackage.jsonがあるので、以下を追記します。
  • 注意点
{
~ 省略 ~
//homepageのURLはGithubPagesを公開した際に自動生成されるURLを入力します。
"homepage":   "homepage": "https://<GitHubアカウント名>.github.io/<GitHubリポジトリ名>/",
~ 省略 ~
  "scripts": {
    ~ 略 ~
    "rm": "rm -rf ./docs", //docディレクトリがリポジトリのroot配下になるようにパスを適宜調整してください。
    "mv": "mv build ./docs", //docディレクトリがリポジトリのroot配下になるようにパスを適宜調整してください。
    "github-build": "npm run rm && npm run build && npm run mv"
  },
}

Git に push する

  • docsの中に build された資材が格納されているので、ブランチに commit します。今回は main ブランチに直接 push する形を想定して記載します。
  • この作業が初回の push で、remote に origin を追加していない場合 remote add してから行ってください。
$ git add .
$ git commit -m 'コミットメッセージ'
$ git push origin main

GitHub Pages の設定を変更する

  • GitHub Pages の設定ページから以下を選択してください。
    • [Settings]→[Pages]→[GitHub Pages]→[Build and Deployment]の Branch で以下を選択し Save します。
    • [main], [/docs]
  • GitHub Pages の URL が自動生成され、Deploy 完了です。

JavaScript Primer - 迷わないための入門書 (jsprimer)を読んで

はじめに

JavaScript Primer - 迷わないための入門書 (jsprimer)の感想を記載いたします。

良かったところ

  • JS は、暗黙的な型変換についてかなりアバウトであることを学ぶことができました。
  • 特に NaN は一度発生すると挙動的にもデバッグ的にもかなり厄介なため、NaN の防止がとりわけ重要であることを学べてよかったです。

難しかったこと

  • this の扱いや、非同期処理、アロー関数の定義等一度読んだだけでは理解しきれない内容が多かったです。JS のコーディングをしていく中で辞書的に都度確認していこうと思います。

学んだこと

第一部:基本文法

  • JavaScriptECMAScript の使用によって動作が決められている。ECMAScript は毎年更新される。
  • 変数宣言時にvarを使用するのは現在非推奨。ECMAScript では機能を追加する際にも後方互換性を重視しているため、var自体の挙動は変更されなかった。
  • REPL(Read-Eval-Print-Loop)
    • コードを評価しその結果を表示する機能のこと。Chromeデベロッパーツールで叩けるコンソールもその一つ

データ型とリテラル

  • typeof null"object"となるのは、歴史的経緯のある仕様のバグ。
  • テンプレートリテラル内で${変数名}と書いた場合に、その変数の値を埋め込むことができる。
const str = "文字列";
console.log(`これは${str}です`); // => "これは文字列です"
  • undefinedリテラルではない。undefinedはただのグローバル変数で、undefinedという値を持っているだけ。
  • JS において、ラッパーオブジェクトを明示的に作成する必要はない。ラッパーオブジェクトを使わずとも、ラッパーオブジェクトのプロパティを使用できる。常にリテラルでプリミティブ型のデータを表現すること推奨。

演算子

  • NaN
    • 数値ではないが Number 型。
    • NaN はどの値とも(NaN 自身に対しても)一致しない特性がある。Number.isNaNメソッドを使うことで NaN の判定を行える。
// 自分自身とも一致しない
console.log(NaN === NaN); // => false
// Number型である
console.log(typeof NaN); // => "number"
// Number.isNaNでNaNかどうかを判定
console.log(Number.isNaN(NaN)); // => true
  • 厳密等価演算子
    • 意図しない挙動となることがあるため、暗黙的な型変換が行われる等価演算子(==)を使うべきではない。
    • 代わりに、厳密等価演算子(===)を使い、異なる型を比較したい場合は明示的に型を合わせるべき。
    • 例外的に、等価演算子(==)が使われるケースとして、null と undefined の比較がある。
 const value = undefined; /* または null */
// === では2つの値と比較しないといけない
if (value === null || value === undefined) {
    console.log("valueがnullまたはundefinedである場合の処理");
}
// == では null と比較するだけでよい
if (value == null) {
    console.log("valueがnullまたはundefinedである場合の処理");
}
  • 分割代入
const obj = {
    "key": "value"
};
// プロパティ名`key`の値を、変数`key`として定義する
const { key } = obj;
console.log(key); // => "value"
  • falsy な値
    • 以下は全て暗黙的な型変換でfalseに変換される。これらをfalsyな値という。
      • false
      • undefined
      • null
      • 0
      • 0n
      • NaN
      • ""(空文字列)
  • Nullish coalescing 演算子(??)
    • Nullish coalescing 演算子(??)は、左辺の値が nullish であるならば、右辺の評価結果を返す。
    • nullish とは、評価結果が null または undefined となる値のこと。
    • 0が falsy のため||では扱えない。この問題を解決するため??演算子が導入された。
const inputValue = 任意の値または未定義;

// ||を使った場合
// `inputValue`がfalsyの場合は、`value`には`42`が入る
// `inputValue`が`0`の場合は、`value`に`42`が入ってしまう
const value = inputValue || 42;

// ??を使った場合
// `inputValue`がnullishの場合は、`value`には42が入る
// `inputValue`が`0`の場合は、`value`に`0`が入る
const value = inputValue ?? 42;

console.log(value);

暗黙的な型変換

  • JS は、型エラーに対して暗黙的な型変換をしてしまうなど、驚くほど曖昧さを許容している。
  • そのため、大きなアプリケーションを書く場合は、このような検出しにくいバグを見つけられるように書くことが重要となる。
  • 真偽値の true が数値の 1 へと暗黙的に変換されてから加算処理
// 暗黙的な型変換が行われ、数値の加算として計算される
1 + true; // => 2
  • JS では、エラーが発生するのではなく、暗黙的な型変換が行われてしまうケースが多くある。
  • 暗黙的に変換が行われた場合、プログラムは例外を投げずに処理が進むため、バグの発見が難しくなる。
  • 暗黙的な型変換はできる限り避けるべき挙動です。
Boolean への型変換
  • 真偽値については、暗黙的な型変換のルールが少ないため、明示的に変換せずに扱われることも多い。
String への型変換
  • 配列には join メソッド、オブジェクトには JSON.stringify メソッドなど、より適切な方法がある。
  • そのため、String コンストラクタ関数での変換は、あくまでプリミティブ型に対してのみに留めるべき。
  • シンボル →String への型変換
    • ES2015 で追加されたプリミティブ型であるシンボルは暗黙的に型変換できない。
    • 文字列結合演算子をシンボルに対して利用すると例外 TypeError を投げるようになっている。
    • そのため、片方が文字列であるからといってプラス演算子の結果は必ず文字列になるとは限らない。
"文字列と" + Symbol("シンボルの説明"); // => TypeError: can't convert symbol to string
数値への型変換(主に NaN について)
  • Number コンストラクタ関数、Number.parseIntNumber.parseFloatは、 数字以外の文字列を渡すと NaN を返す。
// 数字ではないため、数値へは変換できない
Number("文字列"); // => NaN
// 未定義の値はNaNになる
Number(undefined); // => NaN
  • 任意の値から数値へ変換した場合には、NaN になってしまった場合の処理を書く必要がある。
  • 変換した結果が NaN であるかはNumber.isNaN(x)メソッドで判定可能。
const userInput = "任意の文字列";
const num = Number.parseInt(userInput, 10);
if (Number.isNaN(num)) {
  console.log("パースした結果NaNになった", num);
}
  • NaN は何と演算しても結果は NaN になる特殊な値。次のように、計算の途中で値が NaN になると、最終的な結果も NaN となる。
const x = 10;
const y = x + NaN;
const z = y + 20;
console.log(x); // => 10
console.log(y); // => NaN
console.log(z); // => NaN
  • NaN しか持っていない特殊な性質として、自分自身と一致しないというものがある。
  • 実際に値が NaN かを判定する際には、Number.isNaN(x)メソッドを利用するとよい。
  • NaN は暗黙的な型変換の中でももっとも避けたい値となる。

    • 理由として、先ほど紹介したように NaN は何と演算しても結果が NaN となってしまうため。
    • これにより、計算していた値がどこで NaN となったのかがわかりにくく、デバッグが難しくなる。
  • 意図しない NaN への変換を避ける方法として、大きく分けて2つの方法がある。

    • 関数側(呼ばれる側)で、Number 型の値以外を受けつけなくする
    • 関数を呼び出す側で、Number 型の値のみを渡すようにする
  • つまり、呼び出す側または呼び出される側で対処するということ。どちらも行うことによってより安全なコードとなる。
    • 上記の方法を行うためには、定義した関数が数値のみを受けつけるということを明示する必要がある。
  • 明示する方法として以下の方法がある。
    • 関数のドキュメント(コメント)として記述する。
    • 引数に数値以外の値がある場合は例外を投げるという処理を追加する。
/**
 * 数値を合計した値を返します。
 * 1つ以上の数値と共に呼び出す必要があります。
 * @param {...number} values
 * @returns {number}
 **/
function sum(...values) {
    return values.reduce((total, value) => {
        // 値がNumber型ではない場合に、例外を投げる
        if (typeof value !== "number") {
            throw new Error(`${value}はNumber型ではありません`);
        }
        return total + Number(value);
    }, 0);
}
明示的な変換でも解決しないこと
  • あらゆるケースが明示的な変換で解決できるわけではない。
    • Number 型と互換性がない値を数値にしても、NaNとなってしまう。
    • 一度、NaNになってしまうとNumber.isNaN(x)で判定して処理を終えるしかない。
  • JS の型変換は基本的に情報が減る方向へしか変換できない。
  • そのため、明示的な変換をする前に、まず変換がそもそも必要なのかを考える必要がある。
空文字列判定について
  • 以下のように Boolean で明示的な型変換をすると、falsy である0も空文字列となってしまい意図しない挙動になる。
// 空文字列かどうかを判定
function isEmptyString(str) {
    // `str`がfalsyな値なら、`isEmptyString`関数は`true`を返す
    return !Boolean(str);
}
  • 文字列とは「String 型で文字長が 0 の値」であると定義することで、空文字判定の関数をより正確に書くことができる。
  • 次のように実装することで、値が空文字列であるかを正しく判定できるようになる。
// 空文字列かどうかを判定
function isEmptyString(str) {
    // String型でlengthが0の値の場合はtrueを返す
    return typeof str === "string" && str.length === 0;
}
console.log(isEmptyString("")); // => true
// falsyな値でも正しく判定できる
console.log(isEmptyString(0)); // => false
console.log(isEmptyString()); // => false
関数と宣言
  • 定義した関数の仮引数よりも呼び出し時の引数が少ない場合、余った仮引数には undefined という値が代入される。
  • デフォルト引数を使わないで||を使って初期化するとバグにつながるので、デフォルト引数を使うべき。
文と式
  • JS は、文(Statement)と式(Expression)から構成される。
オブジェクト
  • プロパティの存在を確認するには in 演算子か Object.hasOwn 静的メソッドを使う
プロトタイプオブジェクト
  • Object.hasOwn 静的メソッドは、指定したオブジェクト自体が指定したプロパティを持っているかを判定する。
  • 一方、in 演算子はオブジェクト自身が持っていなければ、そのオブジェクトの継承元である prototype オブジェクトまで探索して持っているかを判定する。
関数と this
  • this はオブジェクト指向プログラミングの文脈で JavaScript に導入された。
  • メソッド以外においても this は評価できるが、実行コンテキストや strict mode などによって結果が異なり、混乱の元となる。
  • そのため、メソッドではない通常の関数においては this を使うべきではない。
  • コールバック関数における this は Arrow Function を使うことでわかりやすく解決できる。

Everyday Rails - RSpec による Rails テスト入門を読んで

はじめに

Everyday Rails - RSpec による Rails テスト入門の感想を記載いたします。

良かったところ

  • RailsRSpec をメインにした書籍はあまり多くないと考えられるので、本書の内容は Rails を軸におく開発者にとってとても有益のものだと感じた。
  • RSpec というテスト技法一つとってもその根底には思想があり、ベストプラクティス的な RSpec の書き方があることを知ることができた。
  • テストをする際の方法は必ずしも 1 つではなく、普通のコーディングと同じように様々なテストアプローチを持っておくことが効果的な RSpec を書けるようになるコツであることを学んだ。

難しかったこと

  • RSpec は普通の RubyRails の構文とも少し毛色が違うので、構文を覚えるのがとても大変に感じた。システムテストで使う Capybara は RSpec ともまた違う記法を使ったりもするので、RSpec をマスターするのは予想以上にコストが高そうに感じた。
  • 一方で、マスターすれば効果的かつ自在なテストを書くことができる印象を受けたので、Rails を軸とする開発に携わった際には是非マスターしたいと感じた。

学んだこと

3.モデルスペック

  • 期待する結果は能動形で明示的に記述すること。example の結果がどうなるかを動詞を使って説明するようにする。チェックする結果は example 一つに付き一個だけにする。
  • 起きてほしいことと、起きてほしくない両方をテストすること。example を書くときは両方のパスを考えてテストを書く。
  • 境界値テストをすること。もしパスワードのバリデーションが 4 文字以上 10 文字以下なら、4 文字と 10 文字、3 文字と 11 文字もテストするのが良いテストケース。
  • テストを書くことは、アプリケーションの要件について見返すのに良い機会でもある。
  • 可読性を上げるためにスペックを整理する。
    • describe と context によりよく似た example を分類してアウトライン化する。
    • before ブロックと after ブロックにより重複を除去する。
  • テストの場合は DRY であることよりも読みやすいことの方が重要。
    • スペックファイルのあちこちを参照しなければならない場合、ちょっとぐらいリピートしても問題ない。

4.意味のあるテストデータの作成

  • Factory Bot を使うことで、データを作成する際の柔軟性を上げたり、リアルなシナリオをテストしやすくなる

5.コントローラスペック

  • コントローラのテストは RailsRSpec から完全にはなくなっていないものの、最近では時代遅れのテストになっている。コントローラのテストに限界があるためである。
  • そのため、筆者が開発しているアプリケーションでは、コントローラのテストはアクセス制御が正しく機能しているか確認するテストに限定している。
  • コントローラのテストは対象となる機能の単体テストとして最低限活用できるときだけ使うのがよい。使いすぎないように注意。

6.システムスペックで UI をテストする

  • システムスペックは受入テスト、統合テストとも呼ばれる。
  • システムスペックではたくさんの異なる部品が統合されて、一つのアプリケーションになっ ていることをテストする。

8.スペックを DRY に保つ

  • テスト内や複数のテストファイルにまたがるコードの重複を減らし、テストコードを DRY にすることも重要。長い目で見たときに保守しやすいテストコードを作ることができる。

9.速くテストを書き、速いテストを書く

  • モック、スタブ、ファクトリを使う等でテストをする際に様々な方法がある。これらの方法を適切に選ぶことでスペックを明快なものにすることができる。

10.その他のテスト

  • メールやファイルアップロード、web サービス、バックグラウンドプロセスといった機能もテストできる。

11.テスト駆動開発に向けて

Linux基本コマンド集

Linux基本コマンド集

  • Linuxで基本となるコマンドについて簡単にまとめました。

  • cd

    • change directoryの略
    • cd <移動先のパス>で移動先のパスをカレントディレクトリとして移動する。
  • pwd
  • ls
  • mkdir
  • rmdir
  • cat
    • concatenateの略
    • ファイルの中身を確認できる。一度にすべて表示する。
  • less
    • ファイルの中身を確認できる。ファイルの中身を一部のみ表示する。
  • tail
    • ファイルの中身を確認できる。ファイルの中身の最後の部分を表示する。
  • touch
    • 存在しないファイルを指定するとファイルを新規作成できる。
    • 存在しているファイルを指定しても上書きしないので安全。タイムスタンプを更新するのみ。
  • rm
    • removeの略
    • rmコマンドを実行すると、ゴミ箱を経由せずに削除される。
    • -r(recrusion)オプション:ディレクトリの中のファイルもまとめて削除する。
    • -f:ファイル削除の際に警告文を表示しない。
    • -i:削除前に確認してくれる。
  • mv
    • moveの略
    • 移動先をファイル名とするか、ディレクトリのとするかで動きが変わる。
      • mv file flie1:ファイル名をfile1に変更する。
      • mv file dir/:dirにファイルを移動する。
      • -i:変更前に確認する。
  • cp
    • copyの略
    • ファイルのコピーができる。
    • コピー先のファイルがすでにあると上書きされるので注意。
    • -r:ディレクトリをコピーする。
    • -i:上書き前に確認する。
  • ln
    • linkの略
    • リンクを作成することができる。
    • ln -s hoge.txt ln_hoge.txtシンボリックリンクを作る。
    • 何もつけないとハードリンクになる。
    • ハードリンクとシンボリックリンク
      • ハードリンク:1つのファイルの実体に複数の名前をつける。元のファイルを削除しても消えない。
      • シンボリックリンク:リンク先のパス名が書かれた特殊なファイル。リンク先がファイルの実体となる。 元のファイルを削除・移動するとファイルを参照できなくなる。
      • シンボリックを使うことの方が多い。ハードリンクは制約(ディレクトリに対して使えない等)が多いため。
  • find
    • 検索する。
    • 例)find . -name README.md -print
    • 検索条件で使われるもの
      • -name:大文字小文字を区別する。ワイルドカードが使える。
        • 例)find . -name '*.html' -print
        • ワイルドカードを使う際はシングルクォートで囲む必要あり。
      • -iname:大文字小文字を区別する。
      • -type:ファイルの種類
      • -a:複数の条件を指定する。-aは省略可能
  • chmod
    • change modeの略
    • ファイルやディレクトリのパーミッションを設定する
    • chmod [ugoa] [+-=] [rwx] <ファイル名>で特定ユーザーの権限を設定できる。
    • 8進数を使ってchmod <8進数の数値> <ファイル名>でも指定可能。全パーミッションを指定したい時に便利でchmod 755 fileはよく使われる。
  • chown
    • change ownerの略
    • ファイルの所有者を変更できる。
  • ps
    • process statusの略
    • PIDにプロセスID、CMDに実行中のコマンドが表示される。
    • aux:全ユーザーのプロセスを表示する。オプションだけどハイフン不要。
      • aが全てのユーザー、uが詳細情報を含める、xがpsコマンドを実行したユーザの全てのプロセスという意味。
  • kill
    • ジョブやプロセスを終了させる。
      • 正確にはkillコマンドはシグナルを送信するもの。
    • シグナル
      • kill 4965kill -TERM 4965が省略されたもの。TERMのシグナルは終了を指示する。
      • TERMが効かないプロセスがある場合はSIGKILLという強制終了のシグナルがある。安全に終了させず強制終了させるので最終手段のとして使う。
    • ジョブを修了させる場合kill %1、プロセスを終了させる場合kill 4965のように書く。

Vimの基本操作について

Vimの基本操作について

Vimについて

Linux系OSで、いわゆる黒い画面で使用できるエディタのことです。 マウスが使えないOSでテキストの編集を行う際には使用するのがマストになります。 一方で慣れるとコーディング作業もとても速くできるようになる(らしい)です。 ※筆者はVimを使い始めたばかりで、まだ全然慣れていません。

Vimには以下の表の4つのモード(操作の方式)があります。

モード 説明 他モードからの開始キー
ノーマルモード 最初にVimを起動した際にはこのモード。
カーソルの移動やコピペを行うモードで、普通に文字を入力しても画面に何も入力できません。
Esc
インサートモード テキストの入力や編集を行うモード i,I,a,A,o,O等
ビジュアルモード テキストの範囲選択を行えるモード。
矩形選択が強力。
v, Shift + v, Ctrl + v
コマンドラインモード vim内でコマンドを使用したり、外部のコマンドを呼び出す際に使用するモード。検索や変更、外部ファイルの操作も可能。 vim内のコマンドは「:"コマンド"」
外部コマンドは「:!"コマンド"」

基本のコマンドについて

  • 英単語の頭文字で解釈できるコマンドも多いですが、そうでないものも多いです。
  • Shiftを押しながらの操作は、「真逆の操作になる」か「小文字の操作よりも大袈裟な操作になる」と解釈すると覚えやすいです。

ノーマルモード

カーソル操作

コマンド 動作
h, j, k, l 左、下、上、右の1文字に移動
gj, gk 下、上に1行移動
w 次の単語の先頭に移動
e 単語の末尾に移動
b 前の単語の先頭に移動
0 行頭に移動
$ 行末に移動
gg ファイルの先頭へ移動
G ファイルの末尾へ移動

編集操作

コマンド 動作 何の略か
y 行のコピー yank
x カーソルの文字を削除
dd カーソル行の削除 delete
p カーソルの下の行にペースト paste
P カーソルの上の行にペースト
u 操作の取り消し undo
. 直前操作の繰り返し

インサートモードへの移行

コマンド 動作 何の略か
i カーソル位置から入力モードに移行 insert
I 行頭から入力モードに移行
a カーソル位置の右から入力モードに移行
A 行末から入力モードに移行
o カーソルの下に行を挿入し、その行から入力モードに移行
O カーソルの上に行を挿入し、その行から入力モードに移行

ビジュアルモードへの移行

コマンド 動作
v ビジュアルモードへ移行
V カーソルがある行を選択してビジュアルモードへ移行
Ctrl + v 矩形選択のビジュアルモードへ移行

コマンドラインモードへの移行

コマンド 動作
:wq テキストを保存しVimを終了
:q! テキストを保存せずにVImを終了
:w テキストの保存
:s/old/new/g カーソル行全てのoldをnewに変換する

最後に

Vimのコマンドをまとめ直すと、ここに書いたものだけでも全コマンドを使えているわけではないことを自覚しました。 普段からVimを使う→時折使用可能コマンドを振り返る、ということを繰り返すことで徐々にコマンドを覚えていくのだと感じました。

web技術の基本的な用語について

web技術の基本的な単語についてまとめました。

リクエスト、レスポンス

Webアプリケーションをパソコン上で使用するためには、パソコン(クライアント)に対して サーバから情報を取得する必要があります。 クライアント→サーバに対する要求を「リクエスト」、サーバ→クライアントの応答を「レスポンス」と呼びます。

プロトコル

プロトコルとは直訳すると規約のことです。 Webアプリケーションの通信においてのプロトコルは、通信を行う際のルール(規約)のことを指します。 プロトコルがないと、通信をやり取りした際にその通信が何を意味しているのかを互いに読み取ることができません。 そのため、ルールとしてプロトコルを決めて通信を行なっています。 プロトコルの例としては、HTTP、IP、TCP等があります。

ステートフル、ステートレス

ステート(state)は状態という意味を表す英単語です。 Webアプリケーションの通信において以前の通信の状態を保持している場合ステートフル(state+ful)、 保持していない場合ステートレス(state+less)と言います。 FTPはステートフルなプロトコル、HTTPはステートレスなプロトコルです。 ステートフルであると、オーバーヘッド(本来の処理を行うため付随する処理のこと)が大きくなるデメリットがあります。

クッキー

HTTPは、通信手順が簡単でオーバーヘッドが少ないステートレスなプロトコルが必要になっため考案されました。 しかし、HTTP通信を使用した今日のアプリケーションでは状態を保持する必要がある場面が多いです。(ログインの認証など) そこで使用されているのがクッキー(Cookie)です。 HTTPのレスポンスヘッダやリクエストヘッダに「名前=値」の組み合わせの情報を入れて通信を行うことで、 ログイン認証などの状態を管理しています。

ポート番号

通信を受信した際に、通信の中身を見ただけではどのプロトコルで送られてきたものか判別することができません。 そこで、「ポート(直訳すると、港の桟橋)」という考え方を受信時に使うことでプロトコルを判別しています。 プロトコルごとにどのポートで通信を受け取るかを決める、というのがポートの考え方です。 受信時のポート番号をあらかじめ決めておくことで、ポート番号からプロトコルを判断できます。 特に、HTTP等の代表的なプロトコルでは使用するポートを80番にするという取り決めがあります。 この取り決めで決められたポートは「ウェルノウンポート(wel-known ports)」と呼ばれます。 well-known portsがあることで、HTTP等の代表的なプロトコルではの通信ではポート番号を意識することが不要となります。