はじめに
自分の音楽活動用の公式サイトとして、7g3.net を作っています。
最初はかなりシンプルに、HTMLとCSSだけで作っていました。
作品へのリンク、プロフィール、活動履歴、SNSリンクなどを置く場所としては、それで十分でした。
ただ、活動が増えていくにつれて、
- 作品が増える
- リンクが増える
- 活動履歴が増える
- 表示したいセクションが増える
- 同じようなHTMLを何度も書く
- 修正するたびに全体の整合性を見る必要がある
という状態になってきました。
静的なHTML/CSSだけでも作れます。
でも、自分のサイトを今後も更新していくことを考えると、だんだん「書き足す」よりも「管理する」ことの方が重要になってきました。
そこで、HTMLとCSSだけだったサイトを、React + TypeScriptでリファクタリングしました。
もともとの構成
最初のサイトは、かなり素朴な構成でした。
index.html
style.css
assets/
HTMLにセクションを書いて、CSSで見た目を整えるだけです。
小さいサイトなら、この構成はかなり強いです。
- ビルド環境がいらない
- すぐ公開できる
- 仕組みが単純
- Cloudflare PagesやGitHub Pagesに置きやすい
- 壊れにくい
実際、最初に公式サイトを作るだけなら、HTMLとCSSだけで十分でした。
ただ、自分のサイトは単なる名刺ページではなく、音楽活動の変化を置いていく場所にしたかったので、だんだんHTML直書きがつらくなってきました。
HTML/CSSだけでつらくなったところ
同じような記述が増える
作品一覧や活動履歴は、構造が似ています。
たとえば作品カードなら、
<article>
<h3>作品名</h3>
<p>説明文</p>
<a href="...">Listen</a>
</article>
のような形が何度も出てきます。
HTMLだけで書いていると、カードが増えるたびに同じような構造をコピーして編集することになります。
最初は問題ありません。
でも、数が増えると、
- クラス名の付け忘れ
- リンクの修正漏れ
- 表記ゆれ
- セクションごとの構造のズレ
が起きやすくなります。
データと見た目が混ざる
HTML直書きだと、作品情報とマークアップが同じ場所にあります。
<h3>Architecture of Afterglow</h3>
<p>Ambient / Glitch / Shoegaze...</p>
<a href="...">Bandcamp</a>
これは分かりやすい反面、作品が増えるほど編集が重くなります。
本当は、
const works = [
{
title: 'Architecture of Afterglow',
description: 'Ambient / Glitch / Shoegaze...',
url: '...',
},
]
のように、情報はデータとして持ちたい。
そして表示はコンポーネントに任せたい。
そう思うようになりました。
活動履歴が増えるほど管理しづらい
音楽活動のサイトでは、Timelineのようなセクションも重要です。
たとえば、
- リリース
- レーベル参加
- コレクティブ参加
- サイト公開
- 新しいプロジェクト開始
などが増えていきます。
HTML直書きだと、時系列を並び替えたり、文章を整えたりするたびに、DOM構造ごと触ることになります。
活動履歴は今後も増えていくので、ここはデータ化した方が管理しやすいと感じました。
React + TypeScriptにした理由
今回の目的は、サイトを無駄に大きくすることではありません。
むしろ、見た目はできるだけ軽く、シンプルなままにしたかったです。
React + TypeScriptにした理由は、主に以下です。
- セクションをコンポーネント化したい
- 作品や活動履歴をデータとして管理したい
- 表記ゆれや修正漏れを減らしたい
- 今後の更新に強くしたい
- 型を使ってデータ構造を固定したい
- サイト全体の見通しを良くしたい
つまり、派手なSPAを作りたかったというより、更新し続けるための土台にしたかったという感じです。
リファクタリング後の考え方
リファクタリング後は、ざっくり以下のような考え方にしました。
ページ全体
↓
セクション
↓
コンポーネント
↓
データ
たとえば、Worksセクションなら、
WorksSection
↓
WorkCard
↓
works data
Timelineセクションなら、
TimelineSection
↓
TimelineItem
↓
timeline data
のように分けます。
これによって、HTMLに全部を書き込むのではなく、情報と表示を分けられるようになります。
データを分ける
たとえば作品一覧は、以下のような形にできます。
type Work = {
title: string
description: string
url: string
category: 'release' | 'single' | 'prototype'
}
const works: Work[] = [
{
title: 'Architecture of Afterglow',
description: 'Ambient / Glitch / Shoegazeを中心にしたアルバム。',
url: 'https://7g3n.bandcamp.com/album/architecture-of-afterglow',
category: 'release',
},
]
表示側では、この配列を map します。
function WorksSection() {
return (
<section>
<h2>Works</h2>
<div>
{works.map((work) => (
<WorkCard key={work.title} work={work} />
))}
</div>
</section>
)
}
カード側はこうです。
type WorkCardProps = {
work: Work
}
function WorkCard({ work }: WorkCardProps) {
return (
<article>
<p>{work.category}</p>
<h3>{work.title}</h3>
<p>{work.description}</p>
<a href={work.url}>Listen</a>
</article>
)
}
この形にすると、新しい作品を追加するときは works に1件追加するだけで済みます。
HTMLの構造を毎回コピーする必要がありません。
Timelineもデータ化する
活動履歴も同じです。
type TimelineItem = {
year: string
title: string
description: string
}
const timeline: TimelineItem[] = [
{
year: '2025-2026',
title: 'NEON RAVE DANCE / PEARL ORIGIN ∞',
description: '音楽活動とレーベル関連の動きが広がった時期。',
},
{
year: '2026',
title: 'DirtyCrazyZ',
description: '新しいコミュニティ・活動への参加。',
},
]
表示側では同じように map します。
function TimelineSection() {
return (
<section>
<h2>Timeline</h2>
<div>
{timeline.map((item) => (
<article key={`${item.year}-${item.title}`}>
<span>{item.year}</span>
<h3>{item.title}</h3>
<p>{item.description}</p>
</article>
))}
</div>
</section>
)
}
HTML直書きよりも、後から並び替えたり、追加したり、削除したりしやすくなります。
TypeScriptを入れてよかったところ
小さいサイトでも、TypeScriptを入れる意味はありました。
特によかったのは、データ構造を固定できることです。
たとえば作品データで url を入れ忘れたり、category に想定外の文字列を入れたりすると、型で気づけます。
type WorkCategory = 'release' | 'single' | 'prototype'
こうしておくと、
category: 'album'
のような値を入れたときにエラーになります。
小さいサイトでは「型なんていらない」と思うこともあります。
でも、活動履歴や作品情報のように今後増えていくデータがある場合、TypeScriptはかなり便利でした。
CSSはどうしたか
React化したからといって、CSSの考え方を大きく変えたわけではありません。
今回のサイトでは、見た目を派手に作り込みすぎるよりも、余白や文字の見え方を大事にしました。
最近のWebサイトは、綺麗に整えすぎると、逆にその人らしさが薄く見えてしまうことがあります。
特にアーティストの個人サイトでは、完成されたテンプレート感よりも、その人の活動や温度が見えることの方が大事だと思っています。
なので、React化しても、デザインの方向性はできるだけ変えすぎないようにしました。
- 余白を残す
- 情報を詰め込みすぎない
- 色を使いすぎない
- アニメーションを入れすぎない
- 読めることを優先する
- アーティストサイトとしての空気感を残す
Reactにすると、ついコンポーネントを増やしたり、動きを足したくなります。
でも今回は、技術を見せるためのサイトではなく、音楽活動の置き場所としてのサイトなので、そこは意識しました。
コンポーネント化してよかったところ
修正範囲が小さくなった
HTML直書きのときは、同じようなカードが複数あると、見た目を変えるだけでも複数箇所を触る必要がありました。
React化した後は、WorkCard を修正すれば、すべての作品カードに反映されます。
これはかなり楽でした。
情報追加が怖くなくなった
新しい作品や活動履歴を追加するときに、HTML構造を壊す心配が減りました。
データを追加するだけで表示されるので、更新のハードルが下がります。
個人サイトは、作ったあとに更新しなくなることが多いです。
その原因のひとつは、更新が面倒になることだと思っています。
React化したことで、自分にとって更新しやすい形にできました。
セクション単位で考えられるようになった
HTMLだけで作っていたときは、ページ全体をひとつの大きなファイルとして見ていました。
React化したことで、
- Header
- Hero
- About
- Works
- Timeline
- Now Playing
- Footer
のように、セクション単位で考えられるようになりました。
これは設計としてかなり見通しが良くなります。
逆にReact化しなくてもよかった部分
正直、全部をReact化する必要があったかというと、そうではありません。
個人サイトで、内容がほとんど変わらないなら、HTMLとCSSだけで十分です。
むしろ、その方が軽くて壊れにくいです。
今回React化したのは、サイトの内容が今後も増えていく前提だったからです。
- Worksを追加していく
- Timelineを更新していく
- リンクを差し替える
- セクションを増やす
- デザインを少しずつ調整する
こういう更新が続くなら、React + TypeScriptのメリットが出てきます。
逆に、1ページだけの固定プロフィールなら、無理にReactを使わなくてもいいと思います。
個人サイトを作るときに大事だと思ったこと
今回作ってみて、個人サイトで大事なのは「技術的にすごいこと」よりも、「更新できること」だと思いました。
最初から完璧な設計にする必要はありません。
でも、自分が更新するたびに疲れる構成だと、だんだん触らなくなります。
個人サイトは、作って終わりではなく、活動と一緒に少しずつ変わっていくものです。
だからこそ、
- 追加しやすい
- 消しやすい
- 並び替えやすい
- 壊れにくい
- 自分の温度感を残せる
ことが大事だと思います。
React + TypeScript化してよかったこと
今回のリファクタリングでよかったことをまとめると、以下です。
- 作品情報をデータとして管理できるようになった
- Timelineを更新しやすくなった
- カードやセクションをコンポーネント化できた
- 同じHTMLを何度も書かなくてよくなった
- TypeScriptでデータの形を守れるようになった
- 今後の更新に強くなった
- デザインの方向性を保ったまま、内部構造を整理できた
見た目を大きく変えるためのリファクタリングではなく、これからもサイトを育てていくためのリファクタリングでした。
まとめ
もともと 7g3.net は、HTMLとCSSだけで作っていました。
最初はそれで十分でした。
ただ、音楽活動が増えていくにつれて、作品、リンク、活動履歴、告知など、更新したい情報も増えていきました。
そこで、React + TypeScriptでリファクタリングしました。
今回やったことは、技術的に派手なことではありません。
でも、
HTMLに直接書いていた情報をデータ化する
同じ構造をコンポーネント化する
型でデータの形を守る
更新しやすいサイトにする
という意味では、かなり効果がありました。
個人サイトは、活動の変化がそのまま出る場所だと思います。
だからこそ、見た目だけでなく、自分が更新し続けられる構造にしておくことが大事だと感じました。
これからも、作品や活動が増えるたびに、少しずつ育てていけるサイトにしていきたいです。