簡易ブラウザゲームなど、HTML + 画像 + CSS + (クライアントサイド)JavaScript のみで作成できる静的ページの公開手段として Github ページを使っている人は少なくないと思っています。かくいう自分もその一人で、例えば以下のページはすべて自作した上で Github ページを使って公開している例です:
ブラウザ移植版 "MOLEMOLE"
マッチ棒を1本だけ動かして正しい式にする(を自動解答)
JavaScript + CSS + HTML オンラインプレビューワー


あらためて Github ページを簡単に紹介します。

ベースとなっている Github は無料で(も)使えるソースコードのオンラインバージョン管理システムです。個人的には 10 年前は全く別の Subversion というバージョン管理システムを自分で自宅サーバーにインストールして使っていました(一応まだ残ってますが、ほぼ使わなくなりました)が、この 10 年で状況ががらりと変わり、今ではほぼ Github (というか、Git を使ったシステム)がバージョン管理の主流となりました。 Github ページはこの Github の機能の1つとして提供されているもので、Git プロジェクト(の一部)のフォルダをまるごと HTML のドキュメントルートとして公開するというものです。いわば「Github の安定した HTTP サーバーを使って公開する無料のウェブページ」とも言えるものです。あくまで静的コンテンツしか公開できないため、データベースにデータを登録する機能などは使えませんが、CORS の設定や REST API 、AJAX などを併用することで外部ファイルや外部データベースからデータを取得して表示する、といった程度であれば実現できます。自分自身は上述のような簡易アプリケーションに加えて、ドキュメント類やランディングページを公開する際にも便利に使っています。


このように便利な Github ページですが、Github に登録した後は便利なのですが、登録前のコンテンツ作成時にちょっと使いにくいと感じることもありました。例えば以下のようなケースを考えてみます:
2021042901


↑リポジトリの説明に必要な README.md と、Github ページで表示する index.html を同じフォルダに配置しています(このルートフォルダを Github ページで公開する、という想定です)。

index.html 内では imgs/icon.png ファイルを参照しています。また外部 JavaScript である jQuery(https://code.jquery.com/jquery-2.2.4.min.js)の URL を指定して利用しています:
2021042902


ちなみに img/icon.png は「いらすとや」さまの「静かにしてください」のマークを使わせていただきました:
icon


index.html 自体は上述のように比較的シンプルな内容です。(ローカルファイルをフルパス指定して)ブラウザで表示すると以下のような内容が表示されるものです:
2021042903


ちなみに <body> 部はこれだけ:
<body>

<h1>GHP(GitHub Pages) サンプル</h1>

<img src="./imgs/icon.png"/>

</body>

このプロジェクトを(深く考えずに)Github ページで公開する場合の手順を紹介します。そんなに複雑な話ではなく、まず単純に Github にパブリックなプロジェクトを作り、このフォルダ内の全ファイルを同プロジェクトに git push します(以下は自分のリポジトリに push した際の例です):
$ git init

$ git add .

$ git commit -m 'first commit'

$ git branch -M main

$ git remote add origin https://github.com/dotnsf/ghp.git (ここは実際の URL を指定してください)

$ git push -u origin main


2021042904

 
これでプロジェクトのバージョン管理を Github で行えるようになりましたが、今回の目的はバージョン管理というよりも Github ページによるコンテンツ公開なので、もう1ステップ必要になります。同プロジェクトの "Settings" メニューから "Pages" を選び、公開方法(どのブランチのどのフォルダ以下をページとして公開するか)を指定します。今回の場合は main ブランチのルートディレクトリをそのまま公開するだけなので、以下のように指定して "Save" します:
2021042905


すると以下のような画面になり、このコンテンツが Github ページで公開されます(実際にインターネットからアクセスできるようになるまで1分弱かかるようです):
2021042906


表示されている URL にアクセスすると、ちゃんとコンテンツとして公開できていることを確認できます。(オリジナルドメインで GitHub ページを使う設定をしていなければ)HTTPS にも自動的に対応されていて、非常に便利な機能です:
2021042907


ここまでが Github ページの概要および使い方です。index.html の内容を更新したり、新しいファイル(ページ)を追加した場合でも同様にしてプロジェクトの更新ファイルを Github に登録(git push)するだけで公開されるコンテンツの内容も更新されます。静的コンテンツの公開目的には非常に便利なサービスですが、一方で細かな点ではありますが、この方法だと少し非効率に感じる点がないわけではありません。自分の場合は以下の2点で少し不便に感じています。

まず一点目として、ローカルでの動作確認時にブラウザでローカルファイルを開く必要がある、という点があります。上述でもローカルファイルの内容を参照する際には file:/// から始まる URL で(つまりブラウザのメニューや Ctrl + O で「ファイルを開く」を選択してから、目的のフォルダを探し、その中の index.html を指定して)開いていました。自分の場合は普段 Node.js を使ってウェブアプリケーションを作るのですが、その際の動作確認時は http://localhost:8080/ といったシンプルな URL でアプリケーションを開けるようにしています。この差もあって、動作確認するたびにこの「ファイルを開く」オペレーションをするのは少し面倒に感じてしまいます:
2021042903


もう一点は「外部ファイルのプロトコル」についてです。例えば index.html 内で jQuery を呼び出す部分は以下のように記載しています:
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>

気になるのは赤字の部分、つまり目的のファイルを https 指定で呼び出しています。現実問題として https で指定できるファイルを https で呼び出すことにはセキュリティ面での問題はないとも言えます。

一方で、これまで Node.js でウェブアプリケーションを開発している中でこのような外部 JavaScript の呼び出しを行う必要がある際、http か https かを指定せずに記述することがあります。つまり普段は以下のように指定しています:
<script type="text/javascript" src="//code.jquery.com/jquery-2.2.4.min.js"></script>

この記述方法だと表示するページ(今回の例だと index.html)を呼び出す際に使うプロトコルと同じプロトコルで jquery ファイルを呼び出すことになります。つまりローカルでの動作確認時など http://localhost:8080/ で呼び出している場合は http プロトコルで、実際に Github ページとして https://dotnsf.github.io/ghp/ で呼び出している場合は https プロトコルで、それぞれ呼び出すことになり、外部ファイル呼び出しもアクセス時のセキュリティレベルに合わせて行うことができるようになっています。

ただこの方法はローカルファイルを直接呼び出す際の file プロトコルでアクセスした場合は正しく読み込むことができません(file:///code.jquery.com/jquery-2.2.4.min.js は存在しないため)。ローカルファイルを呼び出す場合はプロトコルを省略せずに明記する必要があり、http か https のいずれかを指定して記述する必要があるのでした。

つまり、Github ページで運用する際には index.html 内の外部ファイル呼び出し部でプロトコルまで指定せずに記述することができるのに、動作確認時はプロトコルを指定して呼び出す必要がある。ということになります。これは非常に面倒な話で動作確認が終わったらプロトコル記述を削除する(Github ページを更新した後に、更にまた手元のファイルを変更する必要が生じた場合はもとに戻す)という運用は面倒だし、だからといってそのためだけにプロトコルを固定して記述しなければならないのだとしたら筋の違う話だと思っています。ローカルで常に HTTP サーバーを動かして、対象フォルダをドキュメントルートにしておけば、動作確認時も http://localhost:8080/ のようにアクセスできるようにはなりますが、それも本末転倒な話です。なんとかして Github ページを作る際もローカル動作確認時だけ HTTP サーバーを使って動作させることができないものか・・・


・・・と、長い前振りでしたが、ここからが本題です。アプリケーション・サーバーや HTTP サーバーを併用しないと解決が難しそうで、かつ Github ページ利用時に余計なコードが公開されないようにしたい、という上述の問題を解決する方法を紹介します。以下に紹介する方法は Node.js + Express を使った方法で、どちらかというとサーバーサイド JavaScript のアプリケーションエンジニア向けですが、言語環境によっては同様のことができる別方法(というか別言語環境)があるかもしれません。

答としてはプロジェクトを以下のようなファイル構成に変更します:
2021043001


Github ページで公開していたコンテンツ関連ファイル(今回の例では index.html と imgs/icon.png)を新たに作成した docs/ フォルダ内に移動しました。プロジェクトのルートフォルダには README.md を残した上で、新たに .gitignore, app.js, package.json ファイルを追加しています。以下、追加したファイルの内容を紹介します。

.gitignore ファイルは一般的なもので、Node.js では node_modules/ フォルダを Git 連携の対象外フォルダとすることが一般的です。というわけで、今回は以下の内容の .gitignore ファイルを使います:
node_modules/
package-lock.json
!.gitkeep

package.json ファイルも特殊なものではなく普通の package.json ファイルです。後述の app.js が express パッケージのみ利用するものなので、このような内容にしました:
{
    "name": "ghp",
    "version": "0.0.1",
    "scripts": {
        "start": "node app.js"
    },
    "dependencies": {
        "express": "^4.17.1"
    },
    "repository": {},
    "engines": {
        "node": "10.x"
    }
}

そして Node.js のメインファイルとも言える app.js 、これも実はごくシンプルな内容のものです:
//. app.js
var express = require( 'express' ),
    app = express();

app.use( express.static( __dirname + '/docs' ) );

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

特筆というほどのことはないのですが、肝といえるのは赤字部分です。Express を使ってウェブアプリケーション内のスタティックコンテンツが含まれるフォルダを docs/ フォルダに指定しています。これにより docs/ フォルダ以下にあるファイルはアプリケーションのルートパスから相対パスで表示できるようになります。つまりブラウザなどのクライアントから ./index.html と指定すると ./docs/index.html ファイルが、./imgs/icon.png と指定すると ./docs/imgs/icon.png ファイルを参照することができるようになります。つまり Github ページで公開するのとほぼ同じ状態をローカルホストで作ることができるようになります。

実際にローカルホストで動作確認用に動かす場合は、Node.js インストール後に以下のコマンドを実行します。特にオプションを指定しない場合は 8080 番ポートで HTTP サーバーが起動します:
$ npm install

$ node app
server starting on 8080 ...

8080 番以外の番号で待ち受けたい場合は起動時に環境変数 PORT に待受ポート番号を指定します(以下は 8081 番で待ち受ける場合):
$ PORT=8081 node app
server starting on 8081 ...

起動後、localhost の待受ポート番号を指定してブラウザでアクセスすれば(Ctrl + O で index.html ファイルを指定して開かなくても)目的のページを開くことができます:
2021050101


この状態であれば file プロトコルではなく http(s) プロトコルを使っているので、 docs/index.html 内の外部 JavaScript 参照部分でのプロトコルも明示する必要がなく、以下のような記述でも(ローカルでの動作確認時も、Github ページでの利用時も)動作するようになります。ローカルでの開発時と Github ページで公開する時の差を意識する必要もなくなりました:
<script type="text/javascript" src="//code.jquery.com/jquery-2.2.4.min.js"></script>

最後にこの変更を Github ページでも反映する必要があります(ルートディレクトリを Github ページとして公開している設定だと index.html ファイルが開かないので)。まずは更新した内容を Github リポジトリにもコミット&プッシュして反映させます:
$ git add . -A

$ git commit -m 'node.js 対応'

$ git push origin main

次に Github ページの設定を変更し、/(ルートフォルダ)ではなく /docs/ フォルダ以下を Github ページとして公開するように変更して Save します:
2021050102


少し待つとこの変更が Github ページにも反映され、先程と同じ URL で同様のページを参照することができるようになります:
2021042907


この状態ができてしまえば、手元でページを編集するときは docs/ フォルダ以下のファイルを対象に変更を加えて、必要に応じて `$ node app` でローカルの HTTP サーバーでコンテンツの出来を確認し、Github にコミット&プッシュすれば自動的に Github ページにも更新が反映されるようになります。

もうちょっとスマートなやり方があるのかもしれませんが、Node.js + Express であればこのように「Express の静的コンテンツフォルダを docs/ にする」+「Github ページの対象フォルダを docs/ 以下にする」という設定を組み合わせることで面倒からの開放は実現できそうでした。