モダンJSとNext Steps
ES Modules, npm, Vite などモダンな JavaScript 開発の基礎を学び、React コースへの橋渡しをします。
このチャプターで学ぶこと
- ES Modules (import/export) を理解できる
- npm の基本的な使い方を覚える
- Vite でプロジェクトをセットアップできる
- このコースで学んだ JS 知識が React でどう活きるか理解できる
これはこのコースの最終チャプターです。
前のチャプターで、バニラ JS での状態管理の限界を体験しました。React を使えばそれらの問題を解決できると説明しましたが、React を使うには、もう少し準備が必要です。
このチャプターでは、React(そしてモダンな JavaScript 開発全般)に欠かせない3つのツールと概念を学びます。
- ES Modules: JavaScript ファイルを分割して整理する仕組み
- npm: JavaScript のパッケージマネージャー
- Vite: 現代的なフロントエンドビルドツール
これらを学んだら、いよいよ React コースへ進みます。
9.1 ES Modules
なぜモジュールが必要か
これまでのチャプターでは、すべてのコードを 1 つの JS ファイルに書いてきました。しかし、アプリが大きくなるにつれて、1 ファイルに何百・何千行ものコードを詰め込むのは維持困難になります。
PHP での解決策を思い出してください。
// PHP では namespace と use でファイルを分割する
namespace App\Services;
use App\Models\User;
use App\Helpers\FormatHelper;
class UserService {
public function getFormattedName(User $user): string {
return FormatHelper::capitalize($user->name);
}
}
JavaScript にも、同じようなファイル分割の仕組みがあります。それが ES Modules(ESM)です。
Named Export(名前付きエクスポート)
// utils.js - 便利な関数をまとめたファイル
// 関数をエクスポートする(外から使えるようにする)
export function formatPrice(price) {
// 数値を日本円形式にフォーマットする
return `¥${price.toLocaleString()}`;
}
export function formatDate(dateStr) {
// 日付文字列を読みやすい形式に変換する
const date = new Date(dateStr);
return date.toLocaleDateString("ja-JP", {
year: "numeric",
month: "long",
day: "numeric"
});
}
// 定数もエクスポートできる
export const TAX_RATE = 0.1;
export const SHIPPING_FREE_THRESHOLD = 3000;
// main.js - utils.js の関数を使うファイル
// 必要なものだけを { } で指定してインポートする
import { formatPrice, TAX_RATE } from "./utils.js";
// これで utils.js の関数が使える
const price = 1500;
const taxIncluded = price * (1 + TAX_RATE);
console.log(formatPrice(taxIncluded)); // "¥1,650"
// 使わないものはインポートしなくてよい
// formatDate は今回使わないので import しない(バンドルサイズの最適化)
// 別名でインポートすることもできる(名前が衝突する場合など)
import { formatPrice as fp, TAX_RATE as rate } from "./utils.js";
console.log(fp(1000)); // "¥1,000"
// まとめてインポートすることもできる
import * as Utils from "./utils.js";
console.log(Utils.formatPrice(1000)); // "¥1,000"
console.log(Utils.TAX_RATE); // 0.1
Default Export(デフォルトエクスポート)
1ファイルにつき1つだけ設定できる「メイン」のエクスポートです。
// User.js - User クラスを管理するファイル
export default class User {
constructor(name, email) {
this.name = name;
this.email = email;
this.createdAt = new Date();
}
getDisplayName() {
return `${this.name} <${this.email}>`;
}
isAdmin() {
return this.email.endsWith("@admin.example.com");
}
}
// main.js
// default export は { } なしでインポートする
// 名前は自由につけられる(慣習として元のファイル名と合わせることが多い)
import User from "./User.js";
const user = new User("田中太郎", "tanaka@example.com");
console.log(user.getDisplayName()); // "田中太郎 <tanaka@example.com>"
// 同じファイルに Named Export と Default Export を混在させることもできる
// api.js
export default async function fetchUser(id) {
// デフォルトエクスポート: このファイルのメインの機能
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 名前付きエクスポート: 補助的な機能
export function buildApiUrl(path) {
return `https://api.example.com${path}`;
}
export const DEFAULT_TIMEOUT = 5000;
React のコンポーネントは、基本的に「1 ファイル 1 コンポーネント」で、default export します。
// Button.jsx
export default function Button({ children, onClick }) {
return <button onClick={onClick}>{children}</button>;
}
// App.jsx
import Button from "./Button.jsx"; // default importこれは React コースで毎日書くパターンです。今のうちに import/export の感覚をつかんでおきましょう。
HTML での ES Modules の使い方
ブラウザで ES Modules を使うには、<script> タグに type="module" を追加します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ES Modules デモ</title>
</head>
<body>
<div id="output"></div>
<!-- type="module" をつけることで ES Modules が使える -->
<script type="module">
// インラインでも import できる
import { formatPrice, formatDate } from "./utils.js";
const output = document.getElementById("output");
output.textContent = formatPrice(12800);
</script>
<!-- または外部ファイルを読み込む -->
<!-- <script type="module" src="main.js"></script> -->
</body>
</html>
type="module" を使うと、ブラウザはセキュリティ上の理由から file:// プロトコルでの実行を拒否します。
file:///Users/xxx/index.html のようにファイルを直接ブラウザで開くと、CORS エラーが発生します。
開発時は必ず http://localhost:xxxx 形式のローカルサーバー経由で開いてください。VS Code の「Live Server」拡張機能や、後述の Vite を使うと便利です。
9.2 npm の基本
npm とは
npm(Node Package Manager) は、JavaScript のパッケージ(ライブラリ)を管理するツールです。世界中の開発者が作ったライブラリをインストールして使えます。
PHP の Composer とほぼ同じ役割です。
PHP Composer との比較
| Composer | npm |
|---|---|
composer.json | package.json |
composer.lock | package-lock.json |
vendor/ ディレクトリ | node_modules/ ディレクトリ |
composer install | npm install |
composer require パッケージ名 | npm install パッケージ名 |
composer require --dev | npm install --save-dev |
Packagist | npmjs.com |
Laravel を使ったことがある方は、npm をすでに使っているはずです。
# Laravel プロジェクトで見たことがありませんか?
npm install
npm run dev # Vite の開発サーバーを起動
npm run build # 本番用ビルド実は Laravel 9 以降、フロントエンドのビルドに Vite と npm が使われています。コマンドを打ったことがある方は、すでに npm ユーザーです。
プロジェクトの初期化
# 新しいフォルダを作って npm プロジェクトを初期化する
mkdir my-js-project
cd my-js-project
# package.json を自動生成する(-y で質問をすべてデフォルト回答)
npm init -y
package.json が生成されます。
{
"name": "my-js-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
パッケージのインストール
# dayjs という日付操作ライブラリをインストールする
npm install dayjs
package.json が更新され、node_modules/ ディレクトリが作成されます。
{
"name": "my-js-project",
"version": "1.0.0",
"dependencies": {
"dayjs": "^1.11.10" // 追加された!
}
}
インストールしたパッケージを使ってみましょう。
// main.js
// npm でインストールしたパッケージを import する(パスではなく名前で指定)
import dayjs from "dayjs";
const now = dayjs();
console.log(now.format("YYYY年MM月DD日")); // "2024年03月15日"
const oneWeekLater = now.add(1, "week");
console.log(oneWeekLater.format("YYYY-MM-DD")); // "2024-03-22"
// 日本語化する
import "dayjs/locale/ja";
dayjs.locale("ja");
console.log(now.format("MM月DD日 (dddd)")); // "03月15日 (金曜日)"
開発依存パッケージ
本番環境には含めない(開発時だけ使う)パッケージには --save-dev フラグをつけます。
# ESLint(コード品質チェックツール)を開発依存でインストール
npm install --save-dev eslint
# Prettier(コードフォーマッター)も開発依存
npm install --save-dev prettier
{
"dependencies": {
"dayjs": "^1.11.10" // 本番でも使う
},
"devDependencies": {
"eslint": "^8.57.0", // 開発時のみ
"prettier": "^3.2.5" // 開発時のみ
}
}
scripts の定義
package.json の scripts セクションに、よく使うコマンドを定義できます。
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src/**/*.js",
"format": "prettier --write src/"
}
}
# npm run スクリプト名 で実行できる
npm run dev # 開発サーバー起動
npm run build # 本番ビルド
npm run lint # リント実行
node_modules/ は非常に大量のファイルを含むため、git で管理しません。
.gitignore ファイルに必ず以下を追加してください。
node_modules/
dist/
.envチームメンバーが git clone したあと npm install を実行すれば、package.json と package-lock.json から同じ環境を再現できます。これは Composer の composer install と全く同じ考え方です。
9.3 Vite でプロジェクトをセットアップ
Vite とは
Vite(ヴィート) は、フランス語で「速い」を意味する、モダンなフロントエンドビルドツールです。
何ができるのかを簡単に説明します。
- 開発時: ES Modules をそのままブラウザに渡す(変換不要)。変更をすぐに反映する HMR(Hot Module Replacement)付き
- 本番時: すべてのファイルを最適化・バンドルして、高速に動作する少数のファイルを生成する
Laravel 9.19 以降、フロントエンドのビルドツールとして Laravel Mix の代わりに Vite が採用されました。
vite.config.js や npm run dev で Vite を起動する経験がある方は、その同じツールを React 開発でも使います。
React プロジェクトの作成
# Vite を使って React プロジェクトを作成する
# (npm create は npm init と同じで、プロジェクト生成ツールを実行する)
npm create vite@latest my-react-app
# 選択肢が表示される
# ✔ Select a framework: › React
# ✔ Select a variant: › TypeScript (または JavaScript)
# 作成したプロジェクトに移動
cd my-react-app
# 依存パッケージをインストール
npm install
# 開発サーバーを起動
npm run dev
ターミナルに http://localhost:5173/ と表示されたら成功です。ブラウザで開くと、React のサンプルアプリが表示されます。
生成されるファイル構造
my-react-app/
├── public/ # 静的ファイル(画像など)
│ └── vite.svg
├── src/ # ソースコード
│ ├── assets/ # CSS, 画像など
│ ├── App.tsx # メインのコンポーネント(.tsx は TypeScript + JSX)
│ ├── App.css # App のスタイル
│ ├── main.tsx # エントリーポイント
│ └── index.css # グローバルスタイル
├── index.html # HTML テンプレート
├── package.json # 依存関係の定義
├── tsconfig.json # TypeScript の設定
└── vite.config.ts # Vite の設定
HMR(Hot Module Replacement)の体験
npm run dev
開発サーバーが起動した状態で、src/App.tsx(または src/App.jsx)を編集してみましょう。保存した瞬間に、ブラウザが自動で更新されます。ページ全体のリロードではなく、変更したコンポーネントだけが更新されます。
これが HMR です。ブラウザの「更新ボタン」を押す必要がなくなり、開発体験が劇的に向上します。
本番ビルド
# 本番用ファイルを生成する
npm run build
dist/ ディレクトリに最適化されたファイルが生成されます。
dist/
├── index.html
└── assets/
├── index-AbCdEfGh.js # バンドル・ミニファイされた JS
└── index-XyZwVuTs.css # バンドル・ミニファイされた CSS
このファイルをサーバーにデプロイするだけで、本番環境で動作します。
9.4 このコースの振り返り
このコースで学んだ JavaScript の知識が、React でどのように活きるかを整理しましょう。
| JavaScript コースで学んだこと | React での使われ方 |
|---|---|
| アロー関数 | コンポーネント定義、イベントハンドラ |
| 分割代入 | Props の受け取り ({ title, onClick }) や useState の戻り値 const [count, setCount] |
| スプレッド構文 | State の更新 { ...state, newProp: value } |
.map() | JSX でリストをレンダリング posts.map(post => <Post key={post.id} {...post} />) |
.filter() | 条件に基づくリスト絞り込み |
| テンプレートリテラル | 動的な className 生成、URL 構築 |
addEventListener | React の onClick、onChange、onSubmit |
fetch + async/await | useEffect 内でのデータ取得 |
render() パターン | React の自動再レンダリング(setState で自動実行) |
| state 変数 + DOM 手動更新 | useState + 宣言的 UI(DOM 更新は React が自動化) |
| イベント委任 | React が内部で自動処理 |
localStorage | カスタムフックとして抽象化 |
| Promise / async-await | useEffect、useMutation(React Query) |
| ES Modules(このチャプター) | コンポーネントファイルの import/export |
| クロージャ | カスタムフック、コンテキスト |
すべての JavaScript の知識が React で直接活きます。
React は JavaScript の「上に」構築されたライブラリです。React 固有の概念(JSX、useState、useEffect など)を学ぶ前に、JavaScript をしっかり理解していることが、React 習得の最短ルートです。
このコースを完走したあなたは、その土台をすでに持っています。
特に重要な知識
React を書く上で、特に「毎日使う」JavaScript の知識を確認しておきましょう。
// 1. アロー関数(コンポーネントとイベントハンドラで毎日使う)
const add = (a, b) => a + b;
const greet = name => `こんにちは、${name}さん`;
// 2. 分割代入(Props の受け取りで必須)
const { name, age, email } = user;
const [count, setCount] = useState(0); // React での使い方
// 3. スプレッド構文(State 更新で必須)
const newState = { ...oldState, count: oldState.count + 1 };
const newArray = [...items, newItem];
// 4. .map() でのリストレンダリング(JSX で毎日使う)
const listItems = items.map(item => (
<li key={item.id}>{item.name}</li> // JSX の書き方(React コースで学ぶ)
));
// 5. 条件式(JSX 内での条件分岐)
const element = isLoggedIn ? <UserProfile /> : <LoginForm />;
const maybeMessage = hasError && <ErrorMessage text={errorText} />;
// 6. async/await(データ取得で毎日使う)
async function loadPosts() {
const response = await fetch("/api/posts");
const data = await response.json();
setPosts(data); // React の setState
}
9.5 React コースへ
準備は整いました。
このコースを通じて、あなたは以下を習得しました。
- JavaScript の基本構文(変数、関数、クラス)
- 配列・オブジェクト操作(map、filter、find、スプレッド)
- DOM 操作と動的な UI の構築
- イベント処理とユーザーインタラクション
- 非同期プログラミング(Promise、async/await、fetch)
- ローカルストレージとブラウザ API
- 状態管理の課題(なぜ React が必要なのか)
- ES Modules、npm、Vite
React コースでは、次のことを学びます。
| トピック | 概要 |
|---|---|
| Chapter 0: 環境構築 | Vite で React プロジェクトを作成する |
| Chapter 1: JSX | HTML のような構文で UI を書く |
| Chapter 2: コンポーネント | UI を再利用可能なパーツに分割する |
| Chapter 3: Props | 親から子へデータを渡す |
| Chapter 4: State と useState | 状態管理を React に任せる |
| Chapter 5: イベント処理 | ユーザーの操作に反応する |
| Chapter 6: useEffect | データ取得、副作用の処理 |
| Chapter 7: フォーム | 入力フォームの作り方 |
| Chapter 8: リストとキー | 動的なリストの効率的な描画 |
| Chapter 9: カスタムフック | ロジックの再利用 |
React コースの Chapter 0(環境構築)に進みましょう: Reactコース
このコースで体験した「状態管理の壁」が、React でどれほどシンプルに解決されるか、ぜひ確かめてください。Chapter 8 のミニ SNS を React で作り直したとき、「なるほど、これが React の力か」と感じるはずです。
Vite でプロジェクトを作り、ES Modules の import/export を実際に動かしてみましょう。
手順:
- Vite プロジェクトを作成する(フレームワーク: Vanilla、バリアント: JavaScript)
npm create vite@latest my-modules-practice
cd my-modules-practice
npm installsrc/utils.jsを新規作成して、以下を実装する
// src/utils.js
/**
* 価格を日本円形式にフォーマットする
* @param {number} price - 税抜き価格
* @returns {string} フォーマットされた価格文字列
*/
export function formatPrice(price) {
// toLocaleString で 3桁区切りにする
return `¥${price.toLocaleString("ja-JP")}`;
}
/**
* 日付文字列を読みやすい形式に変換する
* @param {string|Date} date - 変換する日付
* @returns {string} フォーマットされた日付文字列
*/
export function formatDate(date) {
// Date オブジェクトに変換
const d = new Date(date);
// 無効な日付の場合はエラーメッセージを返す
if (isNaN(d.getTime())) {
return "無効な日付";
}
// 日本語形式でフォーマットする
return d.toLocaleDateString("ja-JP", {
year: "numeric",
month: "long",
day: "numeric"
});
}
/**
* 文字列を指定文字数で切り詰める
* @param {string} text - 元のテキスト
* @param {number} maxLength - 最大文字数
* @returns {string} 切り詰められたテキスト
*/
export function truncateText(text, maxLength) {
if (text.length <= maxLength) return text;
return text.slice(0, maxLength) + "...";
}
// 定数もエクスポートする
export const APP_NAME = "練習アプリ";
export const VERSION = "1.0.0";src/main.jsを以下のように書き換える
// src/main.js
// utils.js から必要なものだけをインポートする
import { formatPrice, formatDate, truncateText, APP_NAME } from "./utils.js";
// ---- DOM への表示 ----
const app = document.querySelector("#app");
// 商品リスト(テストデータ)
const products = [
{
name: "React 入門書",
price: 3200,
releaseDate: "2024-01-15",
description: "React の基礎から応用まで網羅した、初心者向けの包括的な入門書です。豊富なサンプルコード付き。"
},
{
name: "TypeScript 完全ガイド",
price: 4500,
releaseDate: "2023-11-01",
description: "TypeScript の型システムを徹底解説。実践的なプロジェクトを通じて習得できます。"
},
{
name: "Next.js ハンドブック",
price: 3800,
releaseDate: "2024-03-20",
description: "Next.js 14 の App Router から Server Components まで、最新の機能を網羅的に解説します。"
}
];
// HTML を生成して表示する
app.innerHTML = `
<h1>${APP_NAME} - 書籍一覧</h1>
<ul style="list-style: none; padding: 0;">
${products.map(product => `
<li style="border: 1px solid #ddd; padding: 16px; margin-bottom: 12px; border-radius: 8px;">
<h3>${product.name}</h3>
<p>価格: <strong>${formatPrice(product.price)}</strong></p>
<p>発売日: ${formatDate(product.releaseDate)}</p>
<p>${truncateText(product.description, 50)}</p>
</li>
`).join("")}
</ul>
`;- 開発サーバーを起動して確認する
npm run dev確認ポイント:
formatPrice()が正しく「¥3,200」形式で表示されるかformatDate()が「2024年1月15日」形式で表示されるかtruncateText()が 50 文字で「…」をつけて切り詰めるか
チャレンジ:
utils.jsにcalcTaxIncluded(price, taxRate = 0.1)関数を追加して、税込み価格を計算するmain.jsからインポートして、税込み価格も表示する
9.6 まとめ
このチャプターで学んだことを振り返りましょう。
ES Modules
exportでファイルの外から使える関数・定数を公開するimport { ... } from "./ファイル.js"で名前付きインポートexport defaultでファイルのメインをエクスポートimport 名前 from "./ファイル.js"でデフォルトインポート- React コンポーネントは 1 ファイル 1 コンポーネント、基本は default export
npm
npm init -yでpackage.jsonを生成npm install パッケージ名でライブラリをインストールnode_modules/は git に含めない(.gitignoreに追加)npm run スクリプト名でコマンドを実行- Composer とほぼ同じ考え方
Vite
npm create vite@latestで React プロジェクトを作成npm run devで HMR 付きの開発サーバーを起動npm run buildで本番用ファイルを生成- Laravel でもすでに使われているツール
JavaScript コースを完走したあなたは、React を学ぶ準備が整っています。
前のチャプターで体験した「状態管理の壁」、そしてこのチャプターで学んだ ES Modules と Vite の知識を持って、React コースへ進んでください。
React コースへ進む: Chapter 0 - 環境構築
React では、バニラ JS で 200 行以上かかったミニ SNS が、はるかに少ないコードで、しかもバグなく書けるようになります。あのコメント入力の途中にいいねしても、入力が消えることはありません。ヘッダーの「総いいね数」は、自動でリアルタイムに更新されます。
JavaScript コースで学んだすべての知識が、React コースで花開きます。