ローカルWebアプリの作り方(はじめての人向け)

## はじめに
この記事では、ローカルで（インターネットに接続せずに）動くWebアプリの作り方について説明します。windowsを想定していますが、たぶんMacでもだいたい同じだと思います。

ChatGPTなどのLLMを用いることで、簡単に素人でもコードを用意することが可能になりました。しかし、初心者にとっては、(コードよりも)環境構築などの部分で苦戦するのではないかと思います。ローカルで動くWebアプリなら、環境構築も必要ないので、初めてのアプリ開発としておすすめです。

## 作り方

### 1.メモ帳アプリを開く
Windowsマークをクリックして「メモ帳」で検索するとでてくると思います。

### 2.コードをかく
自力でかいてもいいですし、LLMにかかせてもいいです。
とりあえず作ってみたいという方は以下のコードをコピペしてください。ChatGPTに以下のようにいってかかせたものです。
>「1つのhtmlファイルで動くストップウォッチアプリを作って。デザインはおしゃれな感じで。あと、わかりやすいようにコード中にコメントも入れてください。」


<details><summary>サンプルコード（ストップウォッチアプリ）</summary>

```html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>おしゃれストップウォッチ</title>
  <style>
    /* 全体のスタイル設定 */
    body {
      margin: 0;
      padding: 0;
      display: flex;
      height: 100vh;
      align-items: center;
      justify-content: center;
      background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }
    /* ストップウォッチ本体のカード風デザイン */
    .stopwatch {
      background: rgba(255, 255, 255, 0.85);
      backdrop-filter: blur(10px);
      border-radius: 16px;
      box-shadow: 0 8px 24px rgba(0,0,0,0.2);
      padding: 2rem;
      text-align: center;
      width: 300px;
    }
    /* 時間表示部分 */
    .display {
      font-size: 3rem;
      letter-spacing: 0.1em;
      margin-bottom: 1.5rem;
      color: #333;
    }
    /* ボタン群を横並びに */
    .buttons {
      display: flex;
      justify-content: space-around;
    }
    /* 各ボタンの共通スタイル */
    .btn {
      border: none;
      padding: 0.75rem 1.5rem;
      border-radius: 8px;
      font-size: 1rem;
      cursor: pointer;
      transition: transform 0.1s ease-in-out;
    }
    .btn:active {
      transform: scale(0.95);
    }
    /* スタート／ストップボタン */
    .btn--start {
      background: #6a11cb;
      color: #fff;
    }
    /* リセットボタン */
    .btn--reset {
      background: #f76262;
      color: #fff;
    }
  </style>
</head>
<body>

  <div class="stopwatch">
    <!-- 時間表示エリア -->
    <div id="display" class="display">00:00:00.000</div>

    <!-- 操作ボタン -->
    <div class="buttons">
      <button id="startStopBtn" class="btn btn--start">Start</button>
      <button id="resetBtn" class="btn btn--reset">Reset</button>
    </div>
  </div>

  <script>
    // 開始時間や経過時間を管理する変数
    let startTime = 0;        // ストップウォッチ開始の基準時間
    let elapsedTime = 0;      // 経過時間（ミリ秒）
    let timerInterval = null; // setInterval の戻り値

    // ディスプレイ要素
    const display = document.getElementById('display');
    // スタート／ストップボタン要素
    const startStopBtn = document.getElementById('startStopBtn');
    // リセットボタン要素
    const resetBtn = document.getElementById('resetBtn');

    // 時間をフォーマットして表示する関数
    function updateDisplay(time) {
      const ms = time % 1000;
      const totalSeconds = Math.floor(time / 1000);
      const seconds = totalSeconds % 60;
      const minutes = Math.floor(totalSeconds / 60) % 60;
      const hours = Math.floor(totalSeconds / 3600);

      // ゼロパディングして表示
      const formatted =
        String(hours).padStart(2, '0') + ':' +
        String(minutes).padStart(2, '0') + ':' +
        String(seconds).padStart(2, '0') + '.' +
        String(ms).padStart(3, '0');
      display.textContent = formatted;
    }

    // ストップウォッチを開始または停止する処理
    startStopBtn.addEventListener('click', () => {
      if (timerInterval) {
        // 既に動作中なら停止
        clearInterval(timerInterval);
        timerInterval = null;
        startStopBtn.textContent = 'Start';
      } else {
        // 停止中なら開始
        startTime = Date.now() - elapsedTime; // 経過時間を引いた時点から再開
        timerInterval = setInterval(() => {
          elapsedTime = Date.now() - startTime;
          updateDisplay(elapsedTime);
        }, 10); // 10ms ごとに更新
        startStopBtn.textContent = 'Stop';
      }
    });

    // リセット処理
    resetBtn.addEventListener('click', () => {
      clearInterval(timerInterval); // タイマー停止
      timerInterval = null;
      elapsedTime = 0;             // 経過時間リセット
      updateDisplay(0);            // 表示リセット
      startStopBtn.textContent = 'Start';
    });

    // ページ読み込み時に初期表示
    updateDisplay(0);
  </script>

</body>
</html>

```
</details>

### 3.HTMLファイルとして保存する
ここが初心者にとって難しいかもしれません。画像つきで説明します。

まず、「名前を付けて保存」を選択します。すると、保存先、ファイル名、ファイルの種類、を選択する画面になります。保存先は、デスクトップなどわかりやすい場所にしておきましょう。

ファイル名とファイルの種類は以下のようにします。

初期状態では以下のようになっていると思います。

![スクリーンショット 2025-04-23 105529.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900848/58c04a1e-76d7-4de6-b08b-a710016bb4f2.png)

これを以下のように変更します。
・ファイル名の **「.txt」** の部分を **「.html」**  (「test」の部分は任意)にかきかえる
・ファイルの種類を **「すべてのファイル」**  にする 

![2png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900848/feae299a-b93b-4bf8-9713-52e27e035656.png)

変更したのち、保存。

:::note 
（拡張子が表示してある状態なら）保存後に「名前の変更」で、「.txt」から「.html」への書き替えを行ってもいいです
**（ ※ この注意書きが何言ってるのかわからない場合は無視してください）**
:::


### 4.アプリを開く
「手順3」で保存したファイルを**開き直して**ください。ブラウザが起動するはずです。
私のコードをコピペした場合はストップウォッチアプリが起動します。

### 5.編集する
もし、作成したアプリに編集を加えたい場合は、「手順3」で保存したファイルを右クリックします。
「プログラムから開く」→「メモ帳」とするとメモ帳で開かれてコードが編集できます。今度は「名前を付けて保存」ではなく、上書き保存で十分です。変更を確認したい場合は、再度「手順4」のように開いてください。

もし、LLMのかいたコードが気に入らない場合は再度指示しましょう。「追加の指示」＋「現在のコード」(メモ帳で開いたコードを全てコピペして貼り付ける)でやってくれます。


## おわりに
htmlで用意したアプリは(GitHubPagesなどで)インターネットに公開することもできます。今回は完全に初学者向けということでメモ帳で編集しましたが、ある程度やりたいならVisual Studio Codeなどを導入したほう編集がしやすやすくなります。