目次
1.はじめに
この記事は、note記事のマガジン: DakotaRed流:Vibe Codingへの道 と連動しています。
今回は、 独学『バイブコーディングをやってみよう#2』 で作成した『デスクトップ上ファイルのレポート』アプリの解析記事です。
この記事の内容を理解することで、以下の基礎が身につきます:
✅ Electronの役割理解
✅ モダンな開発環境の知識
✅ Reactの基礎
✅ データ可視化(Chart.js)
✅ Node.jsのファイル操作
✅ CSS アニメーション
2.プロジェクトの概要
目的: デスクトップにあるファイルを分析し、どの種類のファイルがいくつあるか、いつ作られたかなどをグラフで可視化するアプリケーションです。
使われている技術:
- Electron: Web サイトを作る技術(HTML/CSS/JavaScript)で、Windows や Mac で動くデスクトップアプリを作るためのツール。
- React: 画面の表示や動き(ボタンを押した時の反応など)を作るための人気のライブラリ。
- Vite (ヴィート): 開発をスムーズにするための、高速なビルドツール(準備ツール)。
- Chart.js: 棒グラフや円グラフなどのグラフを簡単に描画するためのライブラリ。
3.ファイル構成
holographic-comet/
├── package.json # プロジェクトの「設計図」。必要なライブラリや起動コマンドが書いてあります。
├── electron/
│ └── main.cjs # アプリの「裏方」。ウィンドウを作ったり、OSとやり取りをするメインプロセスです。
├── src/ # アプリの「表舞台」。画面の見た目や動きを作るコードが入っています。
│ ├── App.jsx # アプリのメイン画面のロジック(計算やグラフ表示)がここに集まっています。
│ ├── App.css # 画面のデザイン(色や配置など)を決めるスタイルシートです。
│ └── main.jsx # Reactアプリの「入り口」。ここから `App.jsx` が読み込まれます。
└── vite.config.js # Viteの設定ファイル。
4.主要ファイルの詳細説明
1. electron/main.cjs (アプリの管理者)
このファイルは、Electron アプリが起動したときに最初に実行される「メインプロセス」です。
-
ウィンドウを作る (
createWindow): 幅 1200px、高さ 800px の画面を作成します。 -
Node.js の機能を許可:
nodeIntegration: trueという設定で、普通の Web サイトではできない「パソコンのファイルを見る」などの強力な機能を許可しています。 -
読み込み: 開発中は
http://localhost:5173(Vite の開発サーバー) を読み込み、本番用アプリとしてパッケージされた後はindex.htmlファイルを読み込みます。
補足:
Electronで nodeIntegration: true にすると、画面のコード(JavaScript)から以下のようなNode.js の機能を直接呼び出せるようになります。
- ファイルの読み書き: fs モジュールを使って、パソコン上の任意のファイルを操作する。
- OS情報の取得: os モジュールを使って、ホームディレクトリの場所やネットワーク情報などを知る。
- 外部プロセスの実行: child_process を使って、コマンドラインの操作を行う。
2. src/App.jsx (アプリの主役)
このファイルに、アプリの実際の機能がすべて書かれています。
🛠️ パソコンのファイルを読む仕組み
普通の Web サイトはパソコンの中身を勝手に見ることはできませんが、このアプリは Electron なので特別なことができます。
// window.requireを使って、パソコンを操作する道具(モジュール)を取り出しています
const fs = window.require("fs"); // ファイルシステム(File System):ファイルの読み書き
const path = window.require("path"); // パス:ファイルやフォルダの場所を扱う
const os = window.require("os"); // OSの情報:ホームディレクトリの場所などを知る
コード内の fetchData 関数でこれらを使い、デスクトップ上のすべてのファイルを見つけ出し(スキャン)、数を数えています。
📊 データの集計
スキャンしたデータは以下の 3 つの視点で集計されます:
- 合計ファイル数: 単純に見つかったファイルの数。
-
拡張子ごとの集計:
.txtや.pngなど、ファイルの種類ごとに数を数えます(円グラフ用)。 -
週間作成トレンド: ファイルが作られた日 (
birthtime) を調べ、週ごとに何個作られたかを集計します(棒グラフ用)。
🖼️ 画面の自動調整 (ズーム機能)
ウィンドウのサイズを変えたときに、中の文字やグラフが崩れないように自動で拡大縮小(ズーム)する工夫がされています。
// ウィンドウの幅に合わせて、アプリ全体の倍率(Zoom)を調整しています
const zoom = Math.max(0.5, Math.min(ratio, 2.0));
webFrame.setZoomFactor(zoom);
3. src/App.css (デザイン)
App.jsx で作られた画面の「見た目」を指定しています。
chart-container や stats-card といったクラス名に対して、カードのような枠線をつけたり、影をつけたりして、見やすくモダンなデザインに整えています。
5.アプリケーションの動作フロー
ここではどのような流れで画面を表示しているのか、順序を追って見てみましょう。
-
アプリ起動 (Mount)
-
Appコンポーネントが最初に実行されます。 - 最初は
stats(データ) が空なので、画面には「Loading...」と表示されます。
補足:
マウント(Mount)=Reactのコンポーネント(このプロジェクトでは App.jsx など)が、仮想DOM(メモリ上の表現)から実際のWebページ(DOM)に追加され、画面に初めて表示されるプロセスのこと。つまり、初期設定が完了するタイミングを指します。
アンマウント(Unmount)=そのコンポーネントが画面から削除される(破棄される)プロセスのこと。 -
-
データ取得開始 (
useEffect)- 画面が表示された直後に、このフックの中にある
fetchData関数が 1 回だけ呼び出されます。
- 画面が表示された直後に、このフックの中にある
-
スキャン処理 (
scanDir)-
fetchDataの中でscanDirという関数が定義されます。 - これは再帰関数(自分自身を呼び出す関数)になっており、デスクトップにあるフォルダの中にさらにフォルダがあれば、その中まで自動で潜って調査を続けます。
- ファイルを見つけるたびに、「拡張子は何か?」「作成日はいつか?」を調べて集計用データ (
newStats) に追加していきます。
for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { await scanDir(fullPath); } else if (entry.isFile()) { newStats.totalFiles++; const ext = path.extname(entry.name).toLowerCase() || "(no extension)"; newStats.extensions[ext] = (newStats.extensions[ext] || 0) + 1; } } -
-
状態の更新 (State Update)
- 全てのスキャンが終わると、
setStats(newStats)を実行して集計結果を保存します。 - 続いて
setLoading(false)を実行し、読み込み中モードを終了します。
- 全てのスキャンが終わると、
-
画面の再描画 (Re-render)
- データ (
stats) が更新されたことを React が検知し、画面を作り直します。 - 今度はデータがあるため、「Loading...」ではなく、集計結果のグラフや表が表示されます。
- データ (
6.押さえておくべきポイント
このプログラムコードの中で利用されている重要なポイントをあげておきます。
1. 非同期処理 (async/await)
async(エイシンク)と await(アウェイト)というキーワードは、「時間がかかる処理」を扱うために使われます。
ファイルアクセスは一瞬で終わることもあれば、ファイル数が多いと数秒かかることもあります。
-
await: 「処理が終わるまで、ここで待ってね」という命令です。 -
async:awaitを使う関数には、必ずこのマークをつけるルールがあります。
これを使うことで、「まだデータを読み込んでいる途中なのに、グラフを表示しようとしてエラーになる」といった事故を防いでいます。
2. 再帰関数 (Recursion)
scanDir 関数の中で、また scanDir 関数を呼んでいる部分があります。これを**再帰(さいき)**と呼びます。
「フォルダの中にフォルダがあったら、その中のフォルダに対しても同じ調査を行う」という処理を実現するのに非常に便利なテクニックです。
これのおかげで、フォルダが何重になっていても全てのファイルを漏らさず見つけることができます。
3. State (状態管理)
React における useState は、「変数の値が変わったら、画面も自動で書き換える」ための仕組みです。
普通の let x = 0; 変数だと、計算で値が変わっても画面上の数字は古いままですが、useState を使うと値の変化に連動して画面が更新されます。
今回は「集計データ (stats)」や「読み込み中かどうか (loading)」を管理するために使っています。
4. 副作用 (useEffect)
useEffect は、「画面が表示されたタイミング」や「何かのデータが変わったタイミング」で実行したい処理を書く場所です。
今回は [] (空の配列) を指定しているので、「アプリが最初に表示された時だけ」中の処理(ファイルスキャン)が実行されます。
これがないと、画面が更新されるたびに何度も何度もファイルスキャンが走ってしまい、パソコンが重くなってしまいます。