Project Overview & Next.js Setup

Romaji to Kana Converter: React & Next.js

Chapter 1 · Project Overview & Next.js Setup

This is the third of three real, working variants of the same converter — a web tool that takes typed romaji (Latin-alphabet Japanese) and converts it live to hiragana and katakana. The Astro variant, completed first, is the site's own current framework and the most direct "could genuinely ship tomorrow" story. The Angular & Express variant committed, from its own Chapter 1, to a real, dedicated Express backend paired with a framework this site had no other home for. This course's own real reason for existing is different again — and it's worth naming precisely before writing a single line of the conversion logic itself.

The Shared Spec

The core feature is unchanged from both sibling courses: a real, verified gojūon-plus-yōon romaji-to-kana mapping table, real handling for long vowels, sokuon (small っ), and the は/へ/を particle exceptions, and a live input box producing both a hiragana and a katakana output as the user types. Full kanji conversion is explicitly out of scope for this course — a genuinely bigger, dictionary-and-context-dependent problem, honestly flagged in this project's own tracking (project_issues.md P2) as a real future sub-project in its own right, not a missing feature of this one.

This Variant's Own Real Angle

Both sibling courses had to make an explicit architectural choice about where the frontend and backend actually live. Astro's own default is a single project that can serve both static pages and, once opted in per route, real on-demand server code — but Chapter 1 of that course deliberately left the question of whether this specific feature should use that capability open until its own Chapter 5. Angular has no server story of its own at all, so that course committed to a real, separate Express backend from the very first chapter, specifically because pairing Angular with a purpose-built backend was that course's own stated reason to exist.

Next.js's own real, defining feature sits between those two positions, and it's the reason this variant is worth building at all: a single Next.js project can hold both the React UI and real server-side API endpoints — Route Handlers, covered properly in Chapter 4 — without ever needing a second framework, a second process, or a second deployment target the way the Angular course's Express backend does. There's still a genuine architectural decision to make about where the conversion logic should actually run — that question isn't pre-answered here either, and Chapter 4 addresses it directly, informed by the real, measured verdict Chapter 5 of the Astro course already reached for the identical feature. What's already decided, and what this chapter's own setup reflects, is that whichever way that decision goes, it never requires leaving this one project.

VariantFrontend/backend relationshipClient-vs-server decision
Astro One project; on-demand server routes are opt-in per page Left open in Ch.1, resolved with a real measured benchmark in Ch.5
Angular & Express Two separate projects, two separate processes Committed to a real server from Ch.1 — that pairing is the course's own reason to exist
React & Next.js One project; UI and API routes are both native to it Left open in this chapter, resolved directly in Ch.4

A Real, Current Next.js Setup

Scaffolding a fresh project with the real, current CLI (verified directly against Next.js's own documentation, current release 16.3.5):

# scaffold a new Next.js project npx create-next-app@latest romaji-converter-nextjs \ --typescript --app --eslint --no-tailwind --src-dir \ --import-alias "@/*" --use-npm

TypeScript, ESLint, and the App Router are all real current defaults — the flags above just make that explicit rather than relying on an interactive prompt. Tailwind is deliberately declined (--no-tailwind): both sibling courses style this converter with plain CSS matching the site's own established dark-tool palette, and Chapter 5's own UI work keeps that convention rather than introducing a styling system neither variant otherwise uses. Turbopack ships enabled by default and is left as-is.

romaji-converter-nextjs/
├── src/
│   └── app/
│       ├── layout.tsx
│       ├── page.tsx
│       ├── globals.css
│       └── api/
│           └── ping/
│               └── route.ts   ← added below, the first real Route Handler
├── public/
├── package.json
├── tsconfig.json
└── next.config.ts

A Real, Working Placeholder Route

Before Chapter 2's own conversion engine exists to call, it's worth confirming the Route Handler mechanism itself actually works end to end — the same discipline both sibling courses already applied to their own first real server call. A Route Handler lives at app/api/<path>/route.ts, exporting an async function named after the HTTP method it handles:

// src/app/api/ping/route.ts export async function GET() { return Response.json({ status: 'ok', service: 'romaji-converter-nextjs' }); }

Verified with a real request against the local dev server:

$ npm run dev $ curl http://localhost:3000/api/ping {"status":"ok","service":"romaji-converter-nextjs"}
Verified Directly Against Next.js's Own Documentation
Since Next.js 15, a GET Route Handler with no explicit caching configuration is dynamic by default — it genuinely re-runs on every request rather than being statically cached the way it was before that change. That matters here: a future kanji/vocabulary lookup route (the natural home for Chapter 6's own Redis caching idea, once kanji conversion is picked up as a real future project) would need to know its own responses aren't silently frozen at build time without opting in explicitly via a revalidate export — this variant's plain conversion route in Chapter 4 benefits from the identical default, with zero extra configuration needed to keep it live.

Route Handlers use the real Web Request/Response APIs directly — request.json() to read a JSON body, Response.json(...) to return one — rather than a framework-specific request/response object the way Express's own req/res pair works. That's the exact shape Chapter 4's own POST /api/convert route will use once the conversion engine exists to call.

Hands-On Exercises

Exercise 1

Scaffold the project exactly as shown above, run npm run dev, and confirm the placeholder /api/ping route responds correctly both from a browser tab and from a real curl request.

📄 View solution
Exercise 2

Add a second placeholder route, POST /api/echo, that reads a JSON body of the shape {"message": "..."} and returns it back unchanged. Confirm it with a real POST request, and explain why this route needs request.json() where /api/ping needed nothing from the request at all.

📄 View solution
Exercise 3

Using this chapter's own compare-table, explain in your own words why the Angular & Express course genuinely needed two separate projects while this course doesn't — and why that difference is a real structural one, not just a stylistic preference.

📄 View solution

Chapter 1 Quick Reference

  • Shared spec unchanged — real romaji-to-kana conversion, kanji explicitly deferred (project_issues.md P2)
  • This variant's own angle — one Next.js project holds both the UI and real server-side API routes, with no second process required either way the Ch.4 decision goes
  • Setup — TypeScript, App Router, ESLint, plain CSS (no Tailwind), verified against Next.js 16.3.5's own current create-next-app defaults
  • A real, working placeholder route — GET /api/ping, using the real Web Request/Response APIs directly
  • Verified finding — GET Route Handlers are dynamic by default since Next.js 15, with no extra config needed to keep them live