nuit

ローカルで動くのになぜbuildが必要?初学者向けに解説

ローカルで動くのになぜbuildが必要?初学者向けに解説

はじめに、、、プログラミングを始めたばかりの頃、こんな疑問を持ったことはありませんか?「npm run devでローカルでは動いてるのに、なんでnpm run buildが必要なの?」私も最初は同じ疑問を持っていました。この記事では、開発環境と本番環境の違い、そしてbuildが必要な理由について、初学者向けにわかりやすく解説します。開発環境で動いている"正体"ローカルでnpm run devやnpm startを実行しているとき、実は裏側で様々な開発支援機能が動いています。開発環境の特徴ファイル監視とホットリロード: ファイルを保存すると自動でブラウザがリロードされる詳細なエラーメッセージ: エラーが起きたときに、どこで何が起きたかを親切に教えてくれるソースマップ: 元のコードを確認できるようにする開発用サーバー: 常に監視しながら動き続けるサーバーこれらは開発体験を良くするための機能で、実はかなり重い処理なんです。buildが必要な理由開発環境は便利ですが、そのまま本番環境に持っていくことはできません。理由は大きく分けて3つあります。1. パフォーマンス最適化本番環境では、ユーザーにできるだけ速くアプリを表示する必要があります。buildプロセスでは以下のような最適化が行われます:コードの圧縮(minify): 空白や改行を削除し、変数名を短くするTree shaking: 使われていないコードを削除するバンドル: 複数のファイルを1つにまとめて、リクエスト数を減らすコード分割: 必要な部分だけを最初に読み込む例: コードの圧縮// 開発環境 (読みやすい) function calculateTotal(price, taxRate) { const tax = price * taxRate; const total = price + tax; return total; } // build後 (圧縮された) function calculateTotal(p,t){return p+p*t} ファイルサイズが大幅に削減され、ユーザーのダウンロード時間が短縮されます。2. ブラウザ互換性の確保現代のJavaScript(ES6+)やTypeScript、Sassなどは、古いブラウザでは動作しません。buildプロセスでは:トランスパイル: 最新の文法を古いブラウザでも動く形に変換ポリフィル: 古いブラウザに足りない機能を補完CSS プリプロセッサの変換: SassやLessを通常のCSSに変換例: アロー関数の変換// 開発環境 (ES6) const greet = (name) => `Hello, ${name}!`; // build後 (ES5 - 古いブラウザ対応) var greet = function(name) { return "Hello, " + name + "!"; }; 3. セキュリティとクリーンアップ開発環境には、本番環境に含めるべきでない情報が含まれています:開発用のデバッグ情報: コンソールログや詳細なエラーメッセージソースマップ: 元のコード構造が見える(設定次第)環境変数の適切な処理: APIキーなどの機密情報の管理buildプロセスでこれらを適切に処理・削除します。buildで警告が出る理由buildを実行すると、こんな警告を見たことはありませんか?Warning: 'unusedFunction' is defined but never used Warning: Module 'lodash' imported but not used これはbuildツールが最適化のために教えてくれているんです。警告の意味import { Button, Modal, Dropdown, Tooltip } from 'heavy-ui-library'; // 10MB function App() { return <Button>Click me</Button>; // Modal、Dropdown、Tooltipは使ってない! } この場合:開発環境では問題なく動作しますしかしbuildすると「Modal、Dropdown、Tooltip使ってないよ!」と警告が出ますこれらを削除すれば、10MBが2MBになる可能性がありますなぜ開発時には気づかないのか?開発環境では「全部読み込んで動かす」ので、無駄があっても動作します。 buildで初めて「本番に出すには無駄が多いよ!」と可視化されるんです。つまり、buildは最適化のための"健康診断"のようなものです。開発環境と本番環境の比較開発環境 (npm run dev)本番環境 (npm run build)目的開発体験の向上パフォーマンスの最適化ファイルサイズ大きい(読みやすさ優先)小さい(圧縮・最適化済み)エラー表示詳細でわかりやすい最小限リロード自動(ホットリロード)なし(静的ファイル)処理速度遅め(監視処理あり)速い(最適化済み)デバッグしやすいしにくい(圧縮済み)まとめ開発環境は、開発者の作業効率を上げるための環境本番環境は、エンドユーザーに最高の体験を提供するための環境buildプロセスは、開発環境のコードを本番環境用に最適化する作業ローカルで動いているからといって、それがそのまま本番で使えるわけではありません。buildは、ユーザーに快適な体験を届けるための重要なステップなんです。「なんでbuildが必要なの?」という疑問が、少しでも解消されたら嬉しいです!参考Vite - Why Bundle for Productionwebpack - Production

Next.js × socket.io で学ぶ「WebSocket」/ SSE との違いは?

Next.js × socket.io で学ぶ「WebSocket」/ SSE との違いは?

突然ですが、上記のようなチャット、、、リアルタイムで取り交わされていますが、どんな実装イメージがつきますか?「リアルタイム通信」と一言で言っても、実装にはいくつか選択肢があり、特に WebSocket と SSE(Server-Sent Events)が代表的です。勉強中に両者の違いをざっくり眺めていたら少し混乱したので、整理して記事にまとめました。今回は Next.js + Socket.io を使ったシンプルなチャットアプリを例に、WebSocket の基本的な使い方を解説します。※ Next.js・tailwindcss・shadcnの構築部分は省略します…ドキュメントご覧くださいNextじゃなくて全然OKです〜〜1. WebSocket とは?💡WebSocket は クライアントとサーバー間で双方向通信を常時確立する技術 です。特徴双方向通信:クライアントもサーバーも自由にメッセージを送れる常時接続:HTTP のようにリクエストごとに接続する必要がないリアルタイム性が高い:チャットや位置情報共有、ゲームなどに最適SSE との違い項目WebSocketSSE通信方向双方向サーバー → クライアントのみデータ形式バイナリ・テキスト両方テキストのみ接続方法常時接続HTTP ベースで常時接続(受信専用)適した用途チャット、ゲーム、位置情報共有ニュース配信、株価、ログ表示つまり、「クライアントからサーバーに情報を送る必要がある」場合は WebSocket が必須です。SSE は「サーバーから通知を送るだけ」の用途に向いています。2. Socket.io を使う理由Socket.io は WebSocket をラップして、開発しやすくしたライブラリです。接続管理や再接続処理が自動化されているブラウザ間の互換性が担保されているemit/on で簡単にメッセージ送受信できる生の WebSocket を使う場合、セキュリティー問題や接続失敗時のリトライやブラウザ互換性の考慮が必要ですが、Socket.io はそれを内部で処理してくれます。3. チャットアプリの通信フロー今回作るチャットアプリでは、次のフローで通信します。ユーザーA ------> サーバー ------> ユーザーB <------ <------ユーザーがメッセージを送信 → サーバーに送信サーバーが接続中の他のクライアントに転送他のユーザーの画面にリアルタイムで表示されるここで「双方向通信が必要」なため、WebSocket が適しています。4. サーバー側の実装(Node.js + Socket.io)必要なパッケージをインストールします💫# Express と HTTP サーバー npm install express # Socket.io npm install socket.io # 開発時に自動再起動 npm install -D nodemonnodemon を使うとサーバーコードを変更したときに自動で再起動されます(便利すぎ〜〜)package.jsonの中も変更します!これで npm start でサーバーが起動可能! "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon index.js" },// 必要なモジュールを読み込む const express = require('express'); const http = require('http'); const { Server } = require('socket.io'); const app = express(); const server = http.createServer(app); // Socket.ioサーバーを作成 // CORS設定でフロントエンド(localhost:3000)からのアクセスを許可 const io = new Server(server, { cors: { origin: 'http://localhost:3000', }, }); const PORT = 5000; // クライアントが接続してきたときの処理 io.on('connection', (socket) => { console.log('クライアントと接続しました'); // クライアントから送信されたメッセージを受信 socket.on('send_message', (data) => { console.log('受信メッセージ:', data); // 送信者以外の全クライアントにメッセージを送信 socket.broadcast.emit('receive_message', { message: data.message, sender: 'other', // 他人のメッセージとして扱う timestamp: Date.now(), // 受信時刻を追加 }); }); // クライアントが切断したときの処理 socket.on('disconnect', () => { console.log('クライアントが切断しました'); }); }); // サーバーを起動 server.listen(PORT, () => console.log(`Server running on port ${PORT}`));socket.broadcast.emit は「送信者以外に送る」ために便利CORS 設定でフロントエンドからの接続を許可5. クライアント側の実装(Next.js + TypeScript)必要なパッケージをインストール# Socket.io クライアント npm install socket.io-client'use client'; import { useState, useEffect, useRef } from 'react'; import io, { Socket } from 'socket.io-client'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; // チャットメッセージの型を定義 interface Chat { message: string; // メッセージ本文 sender: 'me' | 'other'; // 送信者 timestamp?: number; // メッセージの送信時刻 } export default function Home() { // メッセージ入力値 const [message, setMessage] = useState(''); // チャットメッセージリスト const [list, setList] = useState<Chat[]>([]); // socket.ioの接続を保持するref const socketRef = useRef<Socket | null>(null); // コンポーネントがマウントされた時に一度だけ実行される useEffect(() => { // サーバーに接続 const socket = io('http://localhost:5000'); socketRef.current = socket; // サーバーから受信したメッセージをリストに追加 socket.on('receive_message', (data: { message: string }) => { setList((prev) => [ ...prev, { message: data.message, sender: 'other', timestamp: Date.now() }, ]); }); // コンポーネントがアンマウントされる時に接続を切断 return () => { socket.disconnect(); }; }, []); // 空配列なので初回レンダリング時のみ実行 // メッセージ送信処理 const handleSendMessage = () => { // 空メッセージや未接続の場合は送信しない if (!message.trim() || !socketRef.current) return; // サーバーにメッセージ送信 socketRef.current.emit('send_message', { message }); // 自分のメッセージをローカルリストに追加 setList((prev) => [ ...prev, { message, sender: 'me', timestamp: Date.now() }, ]); // 入力欄を空にする setMessage(''); }; return ( <div className='min-h-screen flex flex-col'> {/* メッセージリスト表示エリア */} <div className='flex-1 overflow-y-auto p-4 space-y-2'> {list.map((chat, index) => ( <div key={index} className={`flex items-end ${ chat.sender === 'me' ? 'justify-end' : 'justify-start' }`} > {chat.sender === 'other' && ( <Avatar className='w-8 h-8 mr-2'> <AvatarFallback>👤</AvatarFallback> </Avatar> )} {/* メッセージの内容 */} <div className={`px-4 py-2 rounded-lg max-w-xs wrap-break-word ${ chat.sender === 'me' ? 'bg-primary text-primary-foreground' : 'bg-secondary text-secondary-foreground' }`} > {chat.message} <div className='text-xs mt-1 text-right text-muted-foreground'> {new Date(chat.timestamp!).toLocaleTimeString('ja-JP')} </div> </div> {chat.sender === 'me' && ( <Avatar className='w-8 h-8 ml-2'> <AvatarFallback>👤</AvatarFallback> </Avatar> )} </div> ))} </div> {/* 入力エリア */} <div className='fixed bottom-0 left-0 w-full p-4 bg-white border-t flex gap-2 max-w-sm mx-auto'> <Input type='text' placeholder='message...' value={message} onChange={(e) => setMessage(e.target.value)} // 入力値をstateに反映 className='flex-1' /> <Button type='button' variant='outline' onClick={handleSendMessage}> Send </Button> </div> </div> ); }これで記事の冒頭にあったチャットアプリが完成します🥳6. まとめWebSocket は双方向通信が必要なリアルタイムアプリに最適SSE は「サーバーから通知するだけ」の用途に向くSocket.io は WebSocket をラップし、再接続やブラウザ互換性を自動で処理Next.js のクライアントコンポーネントでは useEffect と useRef で Socket を管理7. もうすぐ冬休み ㊗️今年もお疲れ様でした〜〜年末はゆっくり休みましょうね!

【完全保存版】Next.js × Google Fonts のベストプラクティス

【完全保存版】Next.js × Google Fonts のベストプラクティス

Next.js で開発を進めていると、「どのように Google Fonts を適切に利用すべきか?」という疑問をお持ちの方も多いのではないでしょうか。本記事では、Next.js の next/font/google を使ったモダンで最適な Google Fonts の活用方法を、初心者の方にも分かりやすくまとめました。プロジェクト全体でフォントを設定したいある特定のコンポーネントだけ別フォントにしたいTailwind CSS との連携方法を知りたいsubsets や display など、各オプションの意味が曖昧そのようなお悩みを、この記事ひとつで整理していただけます。1. Next.js でのフォント利用は next/font が最適解Next.js 13 以降、Google Fonts を利用する際には next/font/google を使う方法が推奨されています。理由は以下のとおりです。フォントがビルド時に最適化され高速使わない字形を除外して軽量化(自動サブセット化)CSS や <link> を使った手動管理が不要FOUT(表示の遅れ)発生を抑えられるこれらの理由から、Next.js では CSS の @import や <link> は推奨されません。2. Google Fonts の確認方法Google Fonts の一覧は下記の公式サイトから確認できます。https://fonts.google.com/フォント名太さ(Weight)スタイル対応文字セット(subset)サンプル表示Next.js の next/font/google で使えるフォントは基本的にここから確認できます。3. next/font/google のオプションを理解するGoogle Fonts を読み込む際には、次のようなオプション(パラメータ)を指定できます。ここでは 重要度の高い順に、分かりやすく解説していきます。3-1. subsets(文字セット)どの文字セットを読み込むかを指定します。例:subsets: ['latin', 'japanese'] 主な subsets の種類:値内容latin英語圏の基本ラテン文字latin-ext拡張ラテン文字japanese日本語cyrillicキリル文字greekギリシャ文字vietnameseベトナム語※ フォントごとに対応している subsets が異なるため、Google Fonts で要確認。3-2. weight(フォントの太さ)使用するウエイトを指定します。weight: ['400', '700'] 一般的な値:100:Thin200:Extra Light300:Light400:Regular500:Medium600:Semi Bold700:Bold800:Extra Bold900:Black※ 対応していないウエイトは読み込めません。3-3. style(スタイル)フォントの種類(normal / italic)を指定します。style: ['normal', 'italic'] 3-4. display(表示方法)フォント読み込み中の表示挙動を制御します。【特に重要】最も推奨されているのは swap です。値意味swap(推奨)先に代替フォントを表示し、読み込み後に本フォントへ切替blockフォント読み込みまでテキストを非表示fallback小さな時間だけ待ち、読み込めなければ代替表示optionalネット環境が悪い場合は読み込まないこともNext.js では swap 一択と考えて良いでしょう。3-5. variable(CSS 変数として利用)Tailwind と組み合わせる際に便利です。variable: '--font-roboto' CSS や className で柔軟に適用できます。3-6. fallback(フォールバックフォント)読み込み中に表示する代替フォントを指定できます。fallback: ['Helvetica', 'Arial', 'sans-serif'] 3-7. preload(事前読み込み)必要に応じてプリロードを無効にできます。preload: false 通常は true のままで問題ありません。4. よくある利用方法4-1. プロジェクト全体のフォントを指定する(layout.tsx)import { Noto_Sans_JP } from 'next/font/google'; const noto = Noto_Sans_JP({ subsets: ['japanese'], weight: ['400', '700'], display: 'swap', }); export default function RootLayout({ children }) { return ( <html lang="ja" className={noto.className}> <body>{children}</body> </html> ); } 4-2. 特定のコンポーネントだけ別のフォントを使うimport { Noto_Serif_JP } from 'next/font/google'; const serif = Noto_Serif_JP({ subsets: ['japanese'], weight: ['700'], }); export const Title = () => { return <h1 className={serif.className}>ここだけセリフ体</h1>; }; 4-3. Tailwind と組み合わせる(実務で非常に便利)layout.tsx:const inter = Inter({ subsets: ['latin'], variable: '--font-inter', }); tailwind.config.js:extend: { fontFamily: { inter: ['var(--font-inter)'], } } 5. まとめ本記事では、Next.js で Google Fonts を利用する際のポイントを整理いたしました。最適解は next/font/google を利用することsubsets / weight / display(swap)が特に重要プロジェクト全体でも、部分適用でも柔軟に使えるTailwind との連携も非常に強力適切に設定することで、読み込みが速く、美しい文字表示を実現できます。Next.js での UI 品質向上にお役立ていただければ幸いです。