簡単なwebアプリ作成、もはやClaudeに全部やってもらえる説

# はじめに
こんにちは！みっきーです！
この記事を見つけてくださりありがとうございます。

今回はまたClaudeを使ってwebアプリを作っていこうと思います。いや、Claudeにwebアプリを作ってもらいます。

# もう要件定義だけすればいいのでは...?
前回、Pythonで作った「モンハンのクエスト同行メンバーをランダムで決めるプログラム」をClaudeを使ってwebアプリ化させることに成功しました。

https://qiita.com/mickey_mh/items/2de82d01d4506fa8cfa4

この時は元となるPythonのプログラムがありましたが、今回は**要件定義だけやって**あとはClaudeに丸投げしてみます。これで本当にwebアプリが作れるのか検証していきます。
# 文字数カウントアプリを作りたい
前まで大学の授業等のレポート課題をやる際によく使っていた「文字数をカウントしてくれるサイト」がありました...でもいつの間にか閉鎖されてました(涙)
広告もなくシンプルな設計ですごく使いやすかったのに残念。これのほかにも文字数をカウントしてくれるサイトはありますが、広告(特にアニメーション付きの広告)が厄介で作業の邪魔になっていました。
前回のwebアプリ作成でClaudeのすごさを知ったので、「もうClaudeに作ってもらえばいいじゃん」と思い立ちました。それではやっていきましょう。

# 作成したアプリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493131/3374ac9a-1def-4ba9-a3d1-4d0810d94649.png)
試してみたい方は[こちら](https://script.google.com/macros/s/AKfycbx82Jw8ZQlAEjPrJ24tpARM-7QOd4zzkq4ys60t0fOuQuNBJ5ktvcT-BUrVTISha2GS/exec)

# 作成手順
まずは要件定義を行います。
使用したプロンプトはこちら
```
文字数カウントwebアプリを作りたいです。 
以下に要件を指定するので作成手順を教えてください。 
・大きなテキストボックス 
・テキストボックス内にはフィードフォワードで「カウントしたい文字列を入力」と表示 
・文字数はリアルタイムでカウント 
・カウントする内容は「文字数」　「改行を除いた文字数」　「改行、空白を除いた文字数」　「行数」　「バイト数」　 
・カウントする文字列は日本語と英語を想定 
・英語の場合のみ単語数をカウント 
・テキストボックス内の文字列を一括で削除する「リセットボタン」の実装
編集
・Google Apps Scriptを使用
```
前回同様、GASでのデプロイ手順、htmlファイル、gsファイルを出力してくれました。
出力されたhtmlファイル、gsファイルを以下に提示します。
### HTML
```html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <meta charset="UTF-8">
    <title>文字数カウンター</title>
    <style>
      body {
        font-family: 'Helvetica Neue', Arial, 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif;
        max-width: 800px;
        margin: 0 auto;
        padding: 20px;
        background-color: #f5f5f5;
      }
      h1 {
        color: #333;
        text-align: center;
        margin-bottom: 20px;
      }
      .container {
        background-color: white;
        border-radius: 10px;
        padding: 20px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      }
      .text-area-container {
        position: relative;
        margin-bottom: 20px;
      }
      textarea {
        width: 100%;
        height: 300px;
        padding: 15px;
        border: 1px solid #ddd;
        border-radius: 5px;
        resize: vertical;
        font-size: 16px;
        box-sizing: border-box;
      }
      textarea:focus {
        outline: none;
        border-color: #4A90E2;
      }
      .placeholder {
        position: absolute;
        top: 15px;
        left: 15px;
        color: #aaa;
        pointer-events: none;
        transition: opacity 0.2s;
      }
      .counter-container {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 15px;
        margin-bottom: 20px;
      }
      .counter {
        background-color: #f9f9f9;
        padding: 15px;
        border-radius: 5px;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
      }
      .counter h3 {
        margin-top: 0;
        margin-bottom: 10px;
        color: #333;
      }
      .counter p {
        margin: 0;
        font-size: 24px;
        font-weight: bold;
        color: #4A90E2;
      }
      button {
        background-color: #4A90E2;
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 5px;
        font-size: 16px;
        cursor: pointer;
        transition: background-color 0.3s;
      }
      button:hover {
        background-color: #3A80D2;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>文字数カウンター</h1>
      
      <div class="text-area-container">
        <textarea id="textInput" oninput="countText()"></textarea>
        <div id="placeholder" class="placeholder">カウントしたい文字列を入力</div>
      </div>
      
      <div class="counter-container">
        <div class="counter">
          <h3>文字数</h3>
          <p id="charCount">0</p>
        </div>
        <div class="counter">
          <h3>改行を除いた文字数</h3>
          <p id="charNoLineBreaks">0</p>
        </div>
        <div class="counter">
          <h3>改行・空白を除いた文字数</h3>
          <p id="charNoSpaces">0</p>
        </div>
        <div class="counter">
          <h3>行数</h3>
          <p id="lineCount">0</p>
        </div>
        <div class="counter">
          <h3>バイト数</h3>
          <p id="byteCount">0</p>
        </div>
        <div class="counter">
          <h3>単語数 (英語のみ)</h3>
          <p id="wordCount">0</p>
        </div>
      </div>
      
      <button id="resetButton" onclick="resetText()">リセット</button>
    </div>

    <script>
      // プレースホルダーの表示/非表示を管理
      document.getElementById('textInput').addEventListener('focus', function() {
        document.getElementById('placeholder').style.opacity = '0';
      });
      
      document.getElementById('textInput').addEventListener('blur', function() {
        if (this.value === '') {
          document.getElementById('placeholder').style.opacity = '1';
        }
      });
      
      // テキストカウント機能
      function countText() {
        const text = document.getElementById('textInput').value;
        
        // 文字数 (全体)
        document.getElementById('charCount').textContent = text.length;
        
        // 改行を除いた文字数
        const noLineBreaks = text.replace(/\n/g, '');
        document.getElementById('charNoLineBreaks').textContent = noLineBreaks.length;
        
        // 改行と空白を除いた文字数
        const noSpaces = text.replace(/[\n\s]/g, '');
        document.getElementById('charNoSpaces').textContent = noSpaces.length;
        
        // 行数
        const lines = text === '' ? 0 : text.split('\n').length;
        document.getElementById('lineCount').textContent = lines;
        
        // バイト数 (UTF-8エンコーディングを想定)
        let byteCount = 0;
        for (let i = 0; i < text.length; i++) {
          const c = text.charCodeAt(i);
          if (c >= 0x0000 && c <= 0x007F) {
            byteCount += 1;
          } else if (c > 0x07FF) {
            byteCount += 3;
          } else {
            byteCount += 2;
          }
        }
        document.getElementById('byteCount').textContent = byteCount;
        
        // 単語数 (英語のみ)
        // 日本語が含まれない場合のみカウント
        const hasJapanese = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/.test(text);
        if (!hasJapanese && text.trim() !== '') {
          const words = text.trim().split(/\s+/).length;
          document.getElementById('wordCount').textContent = words;
        } else {
          document.getElementById('wordCount').textContent = hasJapanese ? '日本語テキスト' : '0';
        }
      }
      
      // リセット機能
      function resetText() {
        document.getElementById('textInput').value = '';
        document.getElementById('placeholder').style.opacity = '1';
        countText();
      }
    </script>
  </body>
</html>
```
### gs
```gs
// Google Apps Script のコードファイル (Code.gs)

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index')
    .setTitle('文字数カウンター')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

// 必要に応じてサーバーサイドの関数を追加できます
// 例: ログ機能や保存機能など
```

# いざ、デプロイ！
アプリのUI等は[作成したアプリ](#作成したアプリ)でお見せした通りなので、実際に動かしてみます。
### まずは日本語入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493131/9140f0b8-7229-47bd-b8ed-dd5bb1592024.png)
**ちゃんとできてる！！！！**
指示通りリアルタイムでカウントしてくれます。
そして、指示していないのに日本語入力している場合は単語数の部分に「日本語テキスト」と書かれています。賢すぎ

### 英語入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493131/c0141bc2-6852-4164-a99a-232c711a5f02.png)
英語でもしっかりとカウントしてくれてます。

```html
// 単語数 (英語のみ)
// 日本語が含まれない場合のみカウント
const hasJapanese = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/.test(text);
if (!hasJapanese && text.trim() !== '') {
  const words = text.trim().split(/\s+/).length;
  document.getElementById('wordCount').textContent = words;
} else {
  document.getElementById('wordCount').textContent = hasJapanese ? '日本語テキスト' : '0';
}
```
HTMLのこの部分を見る限り、単語数はスペースで区切ってカウントしているようです。また、日本語の有無に関しては正規表現を用いて絞っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493131/b81827a7-bcad-41b3-affc-b91cc50aed82.png)
文字列に日本語が混ざると単語のカウントは止まります。そもそも単語数を数える条件が日本語が含まれていないときなので当然ですね。(全角文字を入力しても単語数のカウントは止まります。)
# さいごに
まさか本当に要件定義だけで完結するとは思ってませんでした。生成AIの進歩を身をもって感じることができました。「作業中にあったら便利だな」と思うようなwebアプリをノーコードで作ることができるのは、作業効率化に大きく寄与してくれると思います。
### 検証結果
「簡単なwebアプリ作成、もはやClaudeに全部やってもらえる説」立証！！