Capstone: Integrating This Into the Existing Astro Site
Romaji to Kana Converter: React & Next.js
Chapter 8 · Capstone: Integrating This Into the Existing Astro Site
Seven chapters have built one real, working thing: a client-side React converter that's genuinely free to call on every keystroke, a second server-comparison box proving exactly why (a real measured ~14ms round trip against a sub-microsecond direct call), and a production build that starts, runs, and survives a restart on its own. This closing chapter answers the question every prior chapter has been building toward: how does this actually reach the user's real, existing Astro-based site?
Three Real Ways to Mount This
| Option | What it looks like | Real tradeoff |
|---|---|---|
| Subdomain | romaji.example.com, a fully separate deployment |
Simplest nginx config, but needs its own DNS record and its own TLS certificate — a real second thing to keep renewed |
| Path-mounted reverse proxy | example.com/romaji/, sitting alongside the existing Astro site |
One domain, one certificate — but the app itself has to genuinely know it isn't running at the web root anymore |
| API-only, Astro-native frontend | Only /api/convert is kept; a small script embedded directly in an existing Astro page calls it |
No second React UI to maintain at all — but throws away Chapters 4-5's own real client-side box entirely, and Chapter 5's own real finding that convert() should run client-side, not through an API, in the first place |
The path-mounted option is the one worth building out in full — it keeps everything this course has already built, asks the least of the user's own existing infrastructure, and is where the single most interesting real finding in this chapter turns up.
Next.js's Own Real Tool for This: basePath
Next.js's own current, real documentation names exactly this scenario directly:
basePath "allows you to set a path prefix for the application," specifically to
"deploy a Next.js application under a sub-path of a domain."
Building a real, minimal project with NEXT_PUBLIC_BASE_PATH=/romaji set and testing
every real, relevant URL confirms exactly what basePath actually does — and what it
doesn't:
next/link and next/router get
basePath applied automatically — a <Link href="/about"> genuinely
becomes /romaji/about with zero code changes. But this course's own
ServerConverter component, built back in Chapter 5, doesn't use either of those — it
calls fetch('/api/convert', ...) directly, a plain browser API with no idea Next.js's
own basePath config even exists. The real test above proves this concretely: the exact
literal string Chapter 5's code already contains, /api/convert, is precisely the
unprefixed path that returns a genuine 404 once basePath is set — even
the official docs' own next/image component needs its src prefixed by
hand for the identical reason. Only two real, first-party helpers get this for free; a raw
fetch() call is not one of them.
The Real Fix
The community-documented pattern — confirmed by real testing — is to drive
basePath from a single NEXT_PUBLIC_ variable, then read that exact same
variable inside the component to prefix the fetch call by hand:
Re-running the same real test with this fix applied confirms it resolves cleanly:
basePath's own value "must be set at build time and cannot be changed
without re-building as the value is inlined in the client-side bundles" — the identical real
behavior Chapter 7 already verified for plain NEXT_PUBLIC_ variables, via a real
grep against a built project's own static chunk files. Running that same check here
confirms it again: the literal string "romaji" is genuinely present, baked directly
into the built client JavaScript, not read live. Moving the app under a subpath and reading an
ordinary NEXT_PUBLIC_ variable turn out to be the exact same mechanism underneath —
basePath isn't a special case, it's just one more value this course already knows gets
frozen at build time.
The nginx Side
With NEXT_PUBLIC_BASE_PATH=/romaji baked in at build time and the fixed
ServerConverter deployed, nginx's own job is simply to route requests under
/romaji/ to the same PM2-managed process Chapter 7 already set up — no separate
process, no separate port range, just one more location block alongside whatever
already serves the existing Astro site:
Because the app's own basePath is already /romaji, nginx doesn't need to
strip or rewrite anything — it forwards the request path exactly as-is, and the Next.js app itself
already expects to receive it that way.
A Real Link From the Existing Site
The whole point of this course, stated back in Chapter 1, was never "build a standalone tool" — it
was building the thing the site's own real Japanese-language lessons and kanji reference pages could
genuinely point to. With the converter now live at /romaji/, a real link from the
site's own existing kanji tiles page and from individual Japanese-language lesson pages becomes a
concrete, one-line addition rather than a hypothetical:
A learner reading through a hiragana lesson, or hovering a kanji tile on the site's own reference page, is now one real click away from a working conversion tool built specifically for this site — the exact integration this whole course existed to make possible.
Chapter Attribution
| Chapter | What it contributed to the finished, deployed tool |
|---|---|
| 1 | Next.js project setup, and the real architectural framing (one project, both UI and API) this chapter's own single-process deployment cashes in |
| 2 | The real gojūon/dakuten/handakuten/yōon KANA_MAP, and the fixed longest-to-shortest tokenizer |
| 3 | Chōon, sokuon, and particle-exception handling — three real bugs found and fixed |
| 4 | The real /api/convert route, and the measured ~14ms case for calling convert() directly instead |
| 5 | The real client-side and server-comparison boxes — including the exact fetch('/api/convert') line this chapter had to fix |
| 6 | The real, measured architecture case for a Redis kanji cache, deliberately not yet built |
| 7 | The real production build, PM2 process management, and the NEXT_PUBLIC_ build-time-freeze finding this chapter directly reused for basePath |
| 8 | Comparing three mounting options, the real basePath-plus-fetch-fix, and the nginx config that puts it all live |
Hands-On Exercises
Chapter 5 also built a client-side box that calls convert() directly, with no fetch() call at all. Explain, using this chapter's own real findings, why that box needs no basePath fix whatsoever, while the server-comparison box's own fetch call does.
📄 View solutionThis chapter's own real test showed that GET / returns a genuine 404 once basePath is set to /romaji. A teammate is confused, since the app clearly still works — just under a different path. Explain, precisely, what "the app's own root" actually means once basePath is configured, and why 404 is the honest, correct response rather than a bug.
📄 View solutionSuppose kanji conversion (Chapter 6) is eventually built, adding a new route at /api/convert-kanji that calls a real Redis instance. Explain what would need to happen for that new route to work correctly once this chapter's own basePath mounting is in place -- would the real Redis calls inside the route handler itself need any changes, or only the client-side code that calls the route?
📄 View solutionChapter 8 Quick Reference — Course Complete
- Three real mounting options compared — subdomain, path-mounted reverse proxy, and API-only; the path-mounted option built out in full
- basePath moves the whole app, API routes included — verified: the old root genuinely 404s once it's set
- A raw fetch() call is never auto-prefixed — verified: exactly the literal
/api/convertstring Chapter 5's own code uses breaks with a real 404, fixed by reading the same NEXT_PUBLIC_BASE_PATH the config itself uses - basePath is frozen at build time — the same real inlining behavior Chapter 7 already found for NEXT_PUBLIC_ variables generally, reconfirmed here
- Kanji conversion stays deliberately deferred — this course closes having built exactly what it scoped: a real, fast, working romaji-to-kana converter, genuinely integrated into the existing site