jig.jp サマーインターンシップ 選考課題(Webコース、Claude Code で学ぶ実践開発)

はじめに

今回のインターンシップの選考課題では、Webブラウザ上で動作する「しりとりアプリ」を実装して提出していただきます。
使用言語やフレームワークに制限はありませんので、得意な環境で取り組んでください。

また、AIの活用について制限はありません、積極的に活用してください。 ただし、後述の通り、使用した場合は「どの部分にどのように活用したか」を README に記入してください。

課題内容

Webブラウザ上で動作する「しりとりアプリ」を実装して提出してください。詳細を以下に示します。

提出方法について

ソースコードとREADMEを掲載したGitHubリポジトリのリンクを以下のGoogleフォームから提出してください。
このとき、必ずどこかにデプロイし、動作が確認できるURLを用意してください。

README.mdは以下の仕様を満たすよう作成してください。 これ以外の内容が含まれていても問題ありません。

課題提出用Googleフォーム
https://forms.gle/v2rkvJUsamCrWWvS7

仕様

まず、以下の仕様を満たすように実装してください。

追加で、便利・面白いと思う任意の機能を考えて、最低2つ以上実装してください。以下に例を示します。

実装環境

使用する言語やフレームワークの指定は、特にありません。得意なものや、気になっているものを使用して実装してください。
特に環境に拘りの無い方は、以下にDenoを使用して途中まで実装した例を示しますので、Denoを使用して実装してみてください。

Step 0. GitHubアカウントの作成

GitHubアカウント作成後、数日経過しなければ使用できない機能もあるため、早めに登録することをおすすめします。

作成したWebアプリケーションの提出等に必要なため、GitHubアカウントを作成しましょう。
以下のWebサイトからアカウント登録を行ってください。

既にアカウントをお持ちの方は、そちらのアカウントを使用していただいて構いません

https://github.com/

Step 1. VSCodeのインストール

Visual Studio Codeとは

Microsoftが提供しているソースコードエディタです。VSCodeとも呼ばれます。
開発に必要な機能の多くを搭載しており、プラグインの開発も企業・個人問わず行われているので、特に拘りが無ければインストールをおすすめします。

既にお気に入りのエディタがある場合は、インストールせずに進めていただいても構いません。

Visual Studio Codeのインストール

公式サイトの説明に従い、Visual Studio Codeをインストールしてみましょう。

https://code.visualstudio.com/

ご自身のOSに合わせたものをダウンロードして、インストールしましょう。

ターミナルの準備

VSCode上で、Ctrl(Macの場合はCmd)とJを押すことで、下部のパネルを表示を切り替えることができます。
パネル内にある「ターミナル」からコマンドを実行することができるため、コマンドの実行はこちらを使用してください。

WindowsのPowerShellやMacのターミナルを使用しても構いません。

Step 2. Denoのインストール

Deno (ディーノ) とは

Denoは、JavaScript/TypeScriptの実行環境(ランタイム)です。これらの言語でサーバーの処理を実装できます。
ここでは、入門者向けとしてJavaScriptを使用します。TypeScriptの使用方法が分かる方は、そちらを使用していただいても問題ありません。

Webフロントエンドで多く用いられるJavaScriptを使用するため、フロントエンドとバックエンドを同一言語で実装できます。
DenoはNode.jsの作者であるライアン・ダール氏によって実装されたランタイムで、Node.jsをブラッシュアップしたものとなっています。

Denoという名前は、Nodeのアナグラムだそうですよ!

Denoのインストール

公式サイトの説明に従い、Denoをインストールしてみましょう。

https://docs.deno.com/runtime/getting_started/installation/

Download and install の項目に記載されたコマンドをご自身のOSに合わせて実行するだけで、インストールが可能です。
インストールが完了したら、以下のコマンドを実行してみましょう。バージョン情報が表示されればOKです!

バージョン情報は資料作成時のものです。
これと同じか、より新しいバージョンになっていることを確認してください。

# 入力
deno --version

# 出力
deno 2.8.0 (stable, release, aarch64-apple-darwin)
v8 14.9.207.2-rusty
typescript 6.0.3

DenoでHello World

Hello Worldを出力するプログラムを作って実行してみましょう。
空のフォルダを作り、中に server.js を作成して、以下のプログラムを書き込んでください。

console.log("Hello World!");

保存が完了したら、Denoで実行してみましょう!

deno run server.js

# Hello World!

Step 3. VSCodeのセットアップ

Denoの拡張機能をインストール

VS CodeにDenoの拡張機能をインストールしましょう。画面左側の「Extensions」アイコンから拡張機能の画面を開き、「Deno」で検索して、インストールしてください。

Denoの拡張機能をセットアップ

server.jsを作成したフォルダで、Denoの拡張機能の設定を行いましょう。「Control+Shift+P」でコマンドパレットを開き、「Deno: Initialize Workspace Configuration」を実行します。
.vscode/settings.jsonが作成され、Deno関連の補完が効くようになったらOKです。

設定の追記(任意)

追加で、保存時にコードのフォーマットを行うように設定しましょう。
Denoでは、deno fmt コマンドでコードのフォーマットを行うことができますが、VSCode上でファイルを変更し、保存した際に自動で実行されるようにします。

先ほど作成された、.vscode/settings.jsonに以下の内容を追記します。

  {
-     "deno.enable": true
+     "deno.enable": true,
+     "deno.lint": true,
+     "editor.formatOnSave": true,
+     "editor.defaultFormatter": "denoland.vscode-deno",
+     "[html]": {
+         "editor.defaultFormatter": "vscode.html-language-features",
+         "editor.tabSize": 2,
+     }
  }

各設定項目について、簡単に説明しておくと以下のようになります。

Step 4. DenoでHTTPサーバーを立ててみよう

DenoでHTTPサーバーを立ち上げてみましょう。

HTTPサーバーとは、HTTP (HyperText Transfer Protocol) に則って通信するサーバーです。
HTTPサーバー上に処理やデザイン等を記述することで、様々なWebアプリを動作させられます。
Denoが提供しているserve関数を利用することで、簡単にHTTPサーバーを立ち上げることができます。

以下に実装と作動の手順を示します。

  1. server.jsの内容を以下のように書き換えて保存してください。
// server.js

// localhostにDenoのHTTPサーバーを展開
Deno.serve((_req) => new Response("Hello Deno!"));
  1. --allow-netオプションをつけてserver.jsを起動してください。このオプションがない場合、Denoがネットワークにアクセスできません。
deno run --allow-net server.js
  1. ブラウザでhttp://localhost:8000にアクセスしてみましょう。

  2. ブラウザにHello Deno!と表示されればOKです!

  1. 動作が確認できたら、「Control+C」でプログラムを終了します。

Step 5. サーバーに変数を定義してみよう

HTTPサーバー上にアクセス数をカウントする変数を追加して、アクセス数を確認してみましょう。

  1. server.jsファイルを以下の内容に書き換えます。
// server.js
// アクセス数を保持する変数をグローバル領域に定義
let count = 0;


// localhostにDenoのHTTPサーバーを展開
Deno.serve((_req) => {
    count++;
    return new Response(`Hello World! ${count}`);
});
  1. --allow-netに加えて、--watchオプションを追加してserver.jsを起動してください。このオプションを指定すると、Denoがファイルの変更を自動でサーバーに反映してくれます。
deno run --allow-net --watch server.js
  1. ブラウザでhttp://localhost:8000にアクセスしてみましょう。

  2. 何回かアクセスして、ブラウザにアクセス回数が表示されればOKです!尚、ブラウザが自動で/favicon.icoを取得しようとするため、カウントが2つずつカウントアップすることがあります。

Step 6. HTMLを表示してみよう

ブラウザにHTMLを表示させてみましょう。レスポンスをHTML形式に変更し、ヘッダ情報にContent-Typeを指定します。

Content-Typetext/htmlを指定して、ブラウザにHTML形式のデータを返すことを通知します。Content-Typeには様々なものがあり、例として以下のようなものが挙げられます。

Content-Type データ
text/html HTML
text/css CSS
text/javascript JavaScript
application/json JSON形式
image/jpeg 画像(JPEG)ファイル
image/png 画像(PNG)ファイル
  1. server.jsファイルを以下の内容で置き換えます。
// server.js

// localhostにDenoのHTTPサーバーを展開
Deno.serve((_req) => {
    return new Response(
        // Responseの第一引数にレスポンスのbodyを設置
        "<h1>H1見出しです</h1>",
        // Responseの第二引数にヘッダ情報等の付加情報を設置
        {
            // レスポンスにヘッダ情報を付加
            headers: {
                // text/html形式のデータで、文字コードはUTF-8であること
                "Content-Type": "text/html; charset=utf-8"
            }
        }
    );
});

  1. ブラウザを再読み込みして、H1見出しですと大きく表示されればOKです!

Step 7. ファイルサーバーを実装してみよう

HTMLファイルを読み込んでみよう

前のステップではHTMLを文字列として直接記述しましたが、別のファイルとして保存しておいたHTMLを読み込むようにしてみます

また、ファイルの読み込みが完了するまではレスポンスを返さないように、処理にasync-awaitを追加します。JavaScriptでは非同期処理が採用されているため、async-awaitを記載しなければファイルがうまく表示できない場合があります。

非同期処理について、詳しく解説はしません。気になる方はMDNなどを参考にしてください。 https://developer.mozilla.org/ja/docs/Learn_web_development/Extensions/Async_JS

  1. publicフォルダを作成し、中にindex.htmlを作成します。フォルダ構成は以下のようになります。
├─ .vscode/
│  └─ settings.json
├─ public/
│  └─ index.html
└─ server.js
  1. index.htmlファイルに以下の内容を記述します。
<!DOCTYPE html>
<html lang="ja">

<head>
    <!-- headタグの中にはメタデータ等を記載する -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- bodyタグの中には実際に表示するものなどを書く -->
    <h1>H1見出しですよ</h1>
</body>

</html>
  1. server.jsファイルを以下の内容で置き換えます。
// server.js

// localhostにDenoのHTTPサーバーを展開
Deno.serve(async (_req) => {
    const htmlText = await Deno.readTextFile("./public/index.html");

    return new Response(
        // Responseの第一引数にレスポンスのbodyを設置
        htmlText,
        // Responseの第二引数にヘッダ情報等の付加情報を設置
        {
            // レスポンスにヘッダ情報を付加
            headers: {
                // text/html形式のデータで、文字コードはUTF-8であること
                "Content-Type": "text/html; charset=utf-8"
            }
        }
    );
});

  1. このプログラムではファイルの読み込みが発生するので、--allow-netに加えて、--allow-readが必要になります。しかし、一つずつ許可するのは大変なので、開発時は全てを許可するようにして再度実行します。
deno run -A --watch server.js
  1. ブラウザを再読み込みして、H1見出しですよと大きく表示されればOKです!

CSSファイルを読み込んでみよう

CSSファイルを作成して、読み込めるようにしてみましょう。index.htmlとは別にstyles.cssを作成し、このファイルを読み込めるようにします。

  1. publicフォルダの中に、styles.cssを作成します。
├─ .vscode/
│  ├─ settings.json
├─ public/
│  ├─ index.html
│  └─ styles.css
└─ server.js
  1. 各ファイルを、以下のように編集します。
/* public/styles.css */

body {
    background: skyblue;
}
  <!-- public/index.html -->
  ...(省略)
  <head>
    <!-- headタグの中にはメタデータ等を記載する -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
+   <link rel="stylesheet" href="styles.css">
  </head>
  ...(省略)
// server.js

// localhostにDenoのHTTPサーバーを展開
Deno.serve(async (_req) => {
    // パス名を取得する
    // http://localhost:8000/hoge に接続した場合"/hoge"が取得できる
    const pathname = new URL(_req.url).pathname;
    console.log(`pathname: ${pathname}`);

    // http://localhost:8000/styles.css へのアクセス時、"./public/styles.css"を返す
    if (pathname === "/styles.css") {
        const cssText = await Deno.readTextFile("./public/styles.css");
        return new Response(
            cssText,
            {
                headers: {
                    // text/css形式のデータで、文字コードはUTF-8であること
                    "Content-Type": "text/css; charset=utf-8"
                }
            }
        );
    }

    // http://localhost:8000/ へのアクセス時、"./public/index.html"を返す
    const htmlText = await Deno.readTextFile("./public/index.html");
    return new Response(
        // Responseの第一引数にレスポンスのbodyを設置
        htmlText,
        // Responseの第二引数にヘッダ情報等の付加情報を設置
        {
            // レスポンスにヘッダ情報を付加
            headers: {
                // text/html形式のデータで、文字コードはUTF-8であること
                "Content-Type": "text/html; charset=utf-8"
            }
        }
    );
});
  1. ブラウザを再読み込みして、背景が青くなっていればOKです!

publicフォルダ全体を公開してみよう

1つずつ返すファイルを指定する実装では、ページ数が増えた場合に手間がかかります。
そこで、public以下を静的ファイルサーバーとして公開し、ここに入れたファイルは自動で公開されるようにしてみましょう。

  1. server.jsファイルを以下の内容で置き換えます。
// server.js
import { serveDir } from "jsr:@std/http/file-server";

// localhostにDenoのHTTPサーバーを展開
Deno.serve(async (_req) => {
    // ./public以下のファイルを公開
    return serveDir(
        _req,
        {
            /*
            - fsRoot: 公開するフォルダを指定
            - urlRoot: フォルダを展開するURLを指定。今回はlocalhost:8000/に直に展開する
            - enableCors: CORSの設定を付加するか
            */
            fsRoot: "./public/",
            urlRoot: "",
            enableCors: true,
        }
    );
});
  1. ブラウザを再読み込みして、先程と同じ内容が表示されればOKです!

Step 8. ブラウザでJavaScriptを実行してみよう

ブラウザでJavaScriptを実行してみましょう。alert関数を使用して、ブラウザ上でアラートを出力します。
今回は簡単のため、HTMLファイルに直に処理を記述します。

  1. public/index.htmlのbodyに以下のように追記します。
  <body>
    <!-- bodyタグの中には実際に表示するものなどを書く -->
    <h1>H1見出しですよ</h1>
+
+   <!-- JavaScriptを実行 -->
+   <script>
+     alert("Hello JavaScript!");
+   </script>
  </body>
  1. ブラウザを再読み込みして、アラートが表示されればOKです!

Step 9. しりとりの実装: サーバーの処理を実装してみよう

ここからは、実際に「しりとり」をするWebアプリを実装します。 実装するアプリは、以下の仕様を満たしたものとします。

  1. 直前の単語が表示できる。
  2. 次の単語を入力できる。
  3. 直前の単語の末尾と入力した単語の先頭が同一であれば、単語を更新。同一でなければ、エラーを表示する。

このセクションでは、サーバー側の処理を実装します。前セクションまでで実装した内容をベースにして実装を進めましょう。

GET /shiritoriを実装しよう

仕様1を満たすため、サーバーに保存されている直前の単語を取得できるようにしましょう。

GET /shiritoriからデータを取得できるようにします。

  1. server.jsファイルを以下の内容で編集します。
  // server.js
  import { serveDir } from "jsr:@std/http/file-server";

+ // 直前の単語を保持しておく
+ let previousWord = "しりとり";

  // localhostにDenoのHTTPサーバーを展開
  Deno.serve(async (_req) => {
+     // パス名を取得する
+     // http://localhost:8000/hoge に接続した場合"/hoge"が取得できる
+     const pathname = new URL(_req.url).pathname
+     console.log(`pathname: ${pathname}`);
+ 
+     // GET /shiritori: 直前の単語を返す
+     if (_req.method === "GET" && pathname === "/shiritori") {
+         return new Response(previousWord);
+     }
+ 
      // ./public以下のファイルを公開
  ...
  1. ブラウザでhttp://localhost:8000/shiritoriにアクセスして、「しりとり」と表示されればOKです!

POST /shiritoriを実装しよう

仕様2を満たすため、サーバーに保存されている単語を、受け取ったデータで更新できるようにしましょう。

POST /shiritoriでデータを更新できるようにします。

  1. server.jsファイルを以下の内容で編集します。
      // GET /shiritori: 直前の単語を返す
      if (_req.method === "GET" && pathname === "/shiritori") {
          return new Response(previousWord);
      }
  
+     // POST /shiritori: 次の単語を受け取って保存する
+     if (_req.method === "POST" && pathname === "/shiritori") {
+         // リクエストのペイロードを取得
+         const requestJson = await _req.json();
+         // JSONの中からnextWordを取得
+         const nextWord = requestJson["nextWord"];
+ 
+         // previousWordの末尾とnextWordの先頭が同一か確認
+         if (previousWord.slice(-1) === nextWord.slice(0, 1)) {
+             // 同一であれば、previousWordを更新
+             previousWord = nextWord;
+         }
+ 
+         // 現在の単語を返す
+         return new Response(previousWord);
+     }
+ 
      // ./public以下のファイルを公開
      return serveDir(
          _req,
  1. POSTのリクエストの送信は専用のツールやOSによって異なるコマンドが必要なので、動作確認はスキップして、次のセクションに進みましょう。もし動作確認の方法が分かるようであれば、動作確認してみてください。

Step 10. しりとりの実装: Webの処理を実装してみよう

前セクションの内容を踏まえて、Web側の処理を実装しましょう。

GET /shiritoriの結果を表示する

GET /shiritoriにアクセスして、直前の単語を取得します。以下のようにして実装してみましょう。

  1. public/index.htmlファイルを以下の内容で編集します。fetchを利用してGET /shiritoriにリクエストを送信し、受信したデータをpタグに挿入します。
  <body>
    <!-- bodyタグの中には実際に表示するものなどを書く -->
-   <h1>H1見出しですよ</h1>
+   <h1>しりとり</h1>
+   <!-- 現在の単語を表示する場所 -->
+   <p id="previousWord"></p>

    <!-- JavaScriptを実行 -->
    <script>
-     alert("Hello JavaScript!");
+     window.onload = async (event) => {
+       // GET /shiritoriを実行
+       const response = await fetch("/shiritori", { method: "GET" });
+       // responseの中からレスポンスのテキストデータを取得
+       const previousWord = await response.text();
+       // id: previousWordのタグを取得
+       const paragraph = document.querySelector("#previousWord");
+       // 取得したタグの中身を書き換える
+       paragraph.innerHTML = `前の単語: ${previousWord}`;
+     }
    </script>
  </body>
  1. ブラウザをhttp://localhost:8000で再読み込みして、「しりとり」と表示されればOKです!

Topic: サーバー側のpreviousWordを書き換えて、反映されるか確認してみましょう。

(起動時に)POST /shiritoriに次の単語を送信してみよう

POST /shiritoriにアクセスして、次の単語を入力してみましょう。ここでは、ブラウザの起動時に勝手に「りんご」と送信されるようにしてみます。

  1. public/index.htmlファイルを以下の内容で編集します。GET同様、fetchを使用してPOST /shiritoriにリクエストを送信します。
    <!-- JavaScriptを実行 -->
    <script>
      window.onload = async (event) => {
+       // 試しでPOST /shiritoriを実行してみる
+       // りんごと入力……
+       await fetch(
+         "/shiritori",
+         {
+           method: "POST",
+           headers: { "Content-Type": "application/json" },
+           body: JSON.stringify({ nextWord: "りんご" })
+         }
+       );
+ 
        // GET /shiritoriを実行
        const response = await fetch("/shiritori", { method: "GET" });
        // responseの中からレスポンスのテキストデータを取得
  1. ブラウザを再読み込みして、「りんご」と表示されればOKです!

Topic: サーバー側のpreviousWordやWeb側のnextWordを書き換えて、反映されるか確認してみましょう。しりとりとして単語が繋がっていなければ、更新されないようになっていることも確認しましょう。

POST /shiritoriに任意の単語を送信してみよう

起動時にサーバーの値を書き換えることができました。次に、任意の単語を送信できるようにしてみましょう。

  1. public/index.htmlファイルを以下の内容で編集します。送信ボタンが押下された時にinputタグの中身を取得して、POST /shiritoriに送信します。
  <body>
    <!-- bodyタグの中には実際に表示するものなどを書く -->
    <h1>しりとり</h1>
    <!-- 現在の単語を表示する場所 -->
    <p id="previousWord"></p>
+   <!-- 次の文字を入力するフォーム -->
+   <input id="nextWordInput" type="text" />
+   <button id="nextWordSendButton">送信</button>

    <!-- JavaScriptを実行 -->
    <script>
      window.onload = async (event) => {
-       // 試しでPOST /shiritoriを実行してみる
-       // りんごと入力……
-       await fetch(
-         "/shiritori",
-         {
-           method: "POST",
-           headers: { "Content-Type": "application/json" },
-           body: JSON.stringify({ nextWord: "りんご" })
-         }
-       );
-
        // GET /shiritoriを実行
        const response = await fetch("/shiritori", { method: "GET" });
        // responseの中からレスポンスのテキストデータを取得
        const previousWord = await response.text();
        // id: previousWordのタグを取得
        const paragraph = document.querySelector("#previousWord");
        // 取得したタグの中身を書き換える
        paragraph.innerHTML = `前の単語: ${previousWord}`;
      }
 
+     // 送信ボタンの押下時に実行
+     document.querySelector("#nextWordSendButton").onclick = async(event) => {
+       // inputタグを取得
+       const nextWordInput = document.querySelector("#nextWordInput");
+       // inputの中身を取得
+       const nextWordInputText = nextWordInput.value;
+       // POST /shiritoriを実行
+       // 次の単語をresponseに格納
+       const response = await fetch(
+         "/shiritori",
+         {
+           method: "POST",
+           headers: { "Content-Type": "application/json" },
+           body: JSON.stringify({ nextWord: nextWordInputText })
+         }
+       );
+
+       const previousWord = await response.text();
+ 
+       // id: previousWordのタグを取得
+       const paragraph = document.querySelector("#previousWord");
+       // 取得したタグの中身を書き換える
+       paragraph.innerHTML = `前の単語: ${previousWord}`;
+       // inputタグの中身を消去する
+       nextWordInput.value = "";
+     }
    </script>
  </body>
  1. ブラウザを読み込み直して、入力フォームが表示されていればOKです!

Topic: 単語を色々入力して、しりとりとして成立しているか確認してみましょう。

Step 11. しりとりの実装: エラーを実装してみよう

「りんご」の次に「らっぱ」などの続かない単語が入力された時に、エラーを表示できるようにしてみましょう。ここでは、application/json形式のデータを返すようにしてみます。Webとサーバーを以下のように書き換えてください。

  1. server.jsファイルを以下の内容で編集します。
      // POST /shiritori: 次の単語を受け取って保存する
      if (_req.method === "POST" && pathname === "/shiritori") {
          // リクエストのペイロードを取得
          const requestJson = await _req.json();
          // JSONの中からnextWordを取得
          const nextWord = requestJson["nextWord"];

          // previousWordの末尾とnextWordの先頭が同一か確認
          if (previousWord.slice(-1) === nextWord.slice(0, 1)) {
              // 同一であれば、previousWordを更新
              previousWord = nextWord;
          }
+         // 同一でない単語の入力時に、エラーを返す
+         else {
+             return new Response(
+                 JSON.stringify({
+                     "errorMessage": "前の単語に続いていません",
+                     "errorCode": "10001"
+                 }),
+                 {
+                     status: 400,
+                     headers: { "Content-Type": "application/json; charset=utf-8" },
+                 }
+             );
+         }

          // 現在の単語を返す
          return new Response(previousWord);
      }
  1. public/index.htmlファイルを以下の内容で編集します。
      // 送信ボタンの押下時に実行
      document.querySelector("#nextWordSendButton").onclick = async(event) => {
        // inputタグを取得
        const nextWordInput = document.querySelector("#nextWordInput");
        // inputの中身を取得
        const nextWordInputText = nextWordInput.value;
        // POST /shiritoriを実行
        // 次の単語をresponseに格納
        const response = await fetch(
          "/shiritori",
          {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ nextWord: nextWordInputText })
          }
        );
+ 
+       // status: 200以外が返ってきた場合にエラーを表示
+       if (response.status !== 200) {
+         const errorJson = await response.text();
+         const errorObj = JSON.parse(errorJson);
+         alert(errorObj["errorMessage"]);
+         return;
+       }
  
        const previousWord = await response.text();
  1. ブラウザを再読み込みして、不正な単語を入力してみましょう。アラートが表示されればOKです!

Step 12. GitHubのリポジトリを作ろう

作成したWebアプリをGitHubリポジトリに保存し、コードを公開しましょう。

GitHubは、Gitのリポジトリをインターネット上で管理するためのサービスです。リポジトリをアップロードしておくことで、複数人での開発時のソースコードの共有、ソースコードのバックアップ、ご自身の実績の公開の場として、などの効果を期待できます。

GitHubアカウントでログインしてリポジトリを作成し、成果物をアップロードしてみましょう。

  1. GitHubの新規リポジトリを作りましょう。https://github.com/newにアクセスして、任意のリポジトリ名を入力、公開状態は「Public」としてください。他の設定は触らなくて大丈夫です。

  1. 以下のような画面になれば、リポジトリの完成です。任意の方法で、GitHubにソースコードをプッシュしてみましょう。CUIで操作する場合は、GitHubの画面に表示されているコマンドを実行すればOKです。

Topic: コミット、プッシュなど、Gitの操作について軽く調べてみましょう。

  1. 以下の例では、README.mdも一緒にプッシュしてみました。GitHubでは、README.mdに記述した内容が画面下部に表示されます。ここに環境構築手順やリポジトリの説明等を記載すると分かりやすいです。

Step 13. Deno Deployにデプロイしてみよう

注意 GitHubアカウントの作成後、一週間程はDeno Deployの登録ができません。登録できない場合は、Step 12はスキップしてStep 13を先に終わらせてください。

Deno Deployのアカウント登録をしよう

Deno Deployでアカウント登録しましょう。Deno DeployのアカウントはGitHubアカウントと連携する形で作成できるので、先に作成したGitHubアカウントを使用してください。

https://deno.com/deploy

Organizationを作成しよう

アカウント作成後、Organizationを作成します。
nameとslugにはこだわりがなければ自分のGitHubのユーザー名をセットしておくのがいいでしょう。
入力後、Create organizationを押して作成します。

Deno Deployのプロジェクトを作成しよう

早速、Deno Deployのプロジェクトを作ってみましょう。
GitHubのリポジトリを元に、Deno Deployのプロジェクトを作成します。

  1. Deno DeployのOrganizationのトップを開きます

  1. 「New App」をクリックして、新規プロジェクトの作成画面を開きましょう。

  1. 「Select User or Organization」から順に作成したしりとりアプリのリポジトリを指定します。

  1. 「Edit app config」を選択し、下記の設定画面を開きます

  1. 「Runntime Configuration」を「Static Site」から「Dynamic App」に切り替えて、「Entrypoint」に server.js を指定します。

Topic: Entrypointに指定したDenoファイルが、サーバー起動時に自動で実行されます。

  1. 設定を閉じて、末尾の「Create App」を押します。

  2. しばらくするとデプロイが完了します。画像のようにBuildの各ステップにチェックが入れば完了です。画面右上に表示されているリンクをクリックしてWebサイトを開いてみましょう!

Step14. おわりに

ここまでで、Deno DeployにWebアプリケーションをデプロイして動作させることができました。Deno DeployはGitHubと連携していますので、GitHubを更新すれば自動で修正された内容がデプロイされるようになっています。

以降はご自身で実装を進めていただきます。
次セクションに実装のヒントを記載していますので、参考にしてみてください。

提出は資料冒頭に記載のGoogle フォームからお願いします。
必ず、仕様を満たしていることを確認し、READMEを記載しましょう!

Step 15. 実装のヒント

ここでは、必須仕様を満たすための実装のヒントを掲載します。

実装の例

以下のWebサイトに必須仕様を満たすWebアプリケーションをデプロイしました。実装の参考にしてみてください。 尚、課題に記載していなかった詳細な仕様については自身で検討して実装していますが、以下に示すのはあくまでも一例ですので、従う必要はありません。

https://dice-deno-shirit-93.deno.dev/

"末尾が「ん」で終わる単語が入力されたら、ゲームを終了する"

Hint1: 処理を追加する場所

POST /shiritoriを実行した際の処理を修正して、以下の部分に処理を追加するとよさそうです。

// server.js
  ...
          // previousWordの末尾とnextWordの先頭が同一か確認
          if (previousWord.slice(-1) === nextWord.slice(0, 1)) {
+             // 末尾が「ん」になっている場合
+             // ifの中に入力された単語の末尾が「ん」になっていることを確認する条件式を追加
+             if (...) {
+                 // エラーを返す処理を追加
+                 // errorCodeを固有のものにして、末尾が「ん」の時に発生したエラーだとWeb側に通知できるようにする
+             }
+ 
              // 同一であれば、previousWordを更新
              previousWord = nextWord;
          }
  ...
// index.html
  ...
        if (response.status !== 200) {
          const errorJson = await response.text();
          const errorObj = JSON.parse(errorJson);
+         // errorObj["errorCode"]ごとに処理を分岐する
+         // errorCodeが、末尾が「ん」の時のエラーだったら、ゲームを終了する
          return;
        }
  ...

Hint2: ゲーム終了時のWeb画面表示

ゲームの終了時には、ゲームが終了したことを画面に表示するとよさそうです。

ゲームの終了を画面に表示する方法として、以下のものが考えられます。

  1. 表示文言を修正して、入力フォームを削除する。
  2. 終了用の画面に遷移する。

1の場合は、HTMLタグの操作や削除など、ここまでに実装した内容の応用で実装が可能です。
2の場合は、HTMLファイルを新しく作成し、ゲーム終了時にゲーム終了画面に遷移するようにすれば実装可能です。

"過去に使用した単語が入力されたら、ゲームを終了する"

Hint1: 処理を追加する場所

処理を追加する場所は、末尾が「ん」の場合の処理と殆ど変わりません。新しいエラーの処理を実装しましょう。 また、直前より前の単語を保存しておく必要がありますので、その点の処理を追記しましょう。

Hint2: 直前より前の単語を保存する

今までは、直前の単語のみを保存して入力した単語と比較していました。しかし、入力した単語が既に使われているかを確認するには、今までの単語を全て記録しておく必要があります。

そこで、JavaScriptのリストを使用して今までの単語を保存しておきましょう。以下のようにして、単語の保存用の変数をリストにしておき、単語の更新時に逐次保存するようにしておけばよさそうです。

- let previousWord = "しりとり";
+ let wordHistories = ["しりとり"];

また、もし余裕があれば、新しくサーバーを作ったりSaaSを使ったりして、データベース等を使用してみるのも良いかもしれません。

"ゲーム中や終了後に、最初からやり直せるリセット機能をつける"

Hint1: 処理を追加する場所

サーバーに、POST /reset等の新しいPOSTメソッドを追加しましょう。また、追加したPOSTメソッドを実行するためのボタンをWebに追加しましょう。

// server.js
  ...
          return new Response(previousWord);
      }

+     // POST /reset: リセットする
+     // _req.methodとpathnameを確認
+     if (...) {
+         // 既存の単語の履歴を初期化する
+         // 初期化した単語を返す
+     }
+ 
      // ./public以下のファイルを公開
      return serveDir(
          _req,
  ...
// index.html
  ...
    <!-- 次の文字を入力するフォーム -->
    <input id="nextWordInput" type="text" />
    <button id="nextWordSendButton">送信</button>
+   <button id="resetSendButton">リセット</button>
  ...
        // inputタグの中身を消去する
        nextWordInput.value = "";
      }

+     // 送信ボタンの押下時に実行
+     document.querySelector("#resetSendButton").onclick = async(event) => {
+       // POST /resetを実行
+       // ページをリロードする
+     }
    </script>
  ...

Hint2: ページをリロードする

リセット処理後、必要であればページをリロードして、Webサイトの表示をリセットしましょう。ゲーム終了時に要素を削除していた場合は、リロードの処理が必要になるかと思います。

JavaScriptの関数を検索して、処理を追記してみましょう。