Capstone: Integrating This Into the Existing Astro Site
Romaji to Kana Converter: Angular & Express
Chapter 8 · Capstone: Integrating This Into the Existing Astro Site
Chapter 7 got the whole stack running as a real, standalone deployment. This closing chapter does what Chapter 1 always meant it to do: put it somewhere real, at a real path under the user's own existing Astro-based site, and finish the one promise that made this course's own reason for existing concrete from the very first page — tying it directly into the Japanese-language lessons and kanji pages already live there.
Three Real Ways to Mount This Behind an Existing Site
| Option | What it involves | Tradeoff |
|---|---|---|
Subdomain (romaji.existing-site.com) | A separate DNS record and its own nginx server block pointing straight at the unified Express app from Chapter 7 | Simplest possible nginx config; reads as a separate site rather than one integrated tool |
Path-mounted reverse proxy (existing-site.com/romaji/) | One nginx location block on the existing site's own domain, proxying that one path to the same Express app | Feels like part of the same site; needs two real, verified fixes this chapter builds — covered below |
| JSON-API + Astro-frontend rewrite | Keep only Chapter 5's Express route; rebuild the small UI as a new Astro page consuming it directly | The deepest real integration, and real rework of a UI that already works well — hard to justify for a tool this size |
The path-mounted option is built out in full here, matching every other Personal Multi-Technology Projects course on this site that reached this same decision.
A Real Problem: Built Assets Don't Know They're Not at the Root
Chapter 7's own ng build produces an index.html whose script and style references
assume the app is served from the domain root — correct for that chapter's own standalone deployment, and
wrong the moment this app is mounted at /romaji/ on someone else's domain.
--base-href flag exists specifically for this: it rewrites the
<base href> tag Angular injects into index.html, and the built asset
references along with it, to reflect a real sub-path deployment rather than a root one — the direct Angular
equivalent of Vite's own base config option, used for exactly this same purpose in this site's
own React-based sibling courses.
A Second Real Problem: API Calls Are Root-Relative, Not Site-Relative
Chapter 7's own environment.ts leaves apiBaseUrl empty, so every request becomes a
plain path like /api/convert — correct at the domain root, still wrong here for a genuinely
different reason than the assets above. /api/convert is an absolute path; it always resolves
against the domain's own root, regardless of which page made the request. A request from
existing-site.com/romaji/ would still be sent to existing-site.com/api/convert, not
existing-site.com/romaji/api/convert, where this app's own API actually needs to be reached once
mounted at a sub-path.
Editing environment.ts directly would fix this deployment but quietly break Chapter 7's own
root-deployment story for anyone who builds this project without mounting it under a sub-path. A third,
small environment file keeps both working:
"ng build --configuration staging,french" is the documentation's own example —
parsed left to right, with a later configuration's own settings winning if two configurations happen to
touch the same option. There's no separate extends keyword for one configuration to inherit
from another; composing two small, focused configurations together at build time is the real, documented
mechanism instead.
--base-href is a build-time setting controlling where the compiled JavaScript and CSS
files are referenced from. environment.apiBaseUrl is a value baked into the bundle at
the same build, but controlling where this app's own HTTP requests are sent. Both happen to need
the identical /romaji prefix for this deployment, but setting only one leaves either a broken
page (missing assets) or a broken app (every conversion request failing) — never both problems solved by a
single change.
Building Out the Reverse Proxy
One location block on the existing site's own nginx config, added alongside whatever configuration already serves the rest of that site:
The trailing slash on both location /romaji/ and proxy_pass http://localhost:4000/;
is what makes nginx strip the /romaji prefix before forwarding — a request for
/romaji/api/convert reaches Express as exactly /api/convert, the same route
Chapter 5 already built with no changes needed on the Express side. The same stripping applies to every
static asset request, which reaches Express's own express.static() middleware from Chapter 7
completely unaware it's being served from anywhere but its own root.
With everything mounted this way, the browser only ever sees one real domain — Chapter 7's own
ALLOWED_ORIGIN CORS setting can simply be set to https://existing-site.com, and
every request genuinely is same-origin now, exactly the scenario that chapter's own warn-box anticipated
without yet knowing which real shape it would take.
Linking It Where It's Actually Useful
Chapter 1 named the real reason this course exists — this tool's own most immediate value is sitting right
next to the Japanese-language lessons and the kanji tiles page, not off on its own. With a real, working
/romaji/ URL now live, the last piece is a real link pointing at it from exactly those pages —
the concrete payoff of a promise made eight chapters ago:
/romaji/ URL this chapter just finished standing up.
Chapter Attribution
| Piece of the finished app | Built in |
|---|---|
| The full gojūon/dakuten/yōon romaji-to-kana mapping table | Chapter 2 |
| Long vowels, sokuon, and the real は/へ/を particle exceptions | Chapter 3 |
| ConvertService, RomajiInputComponent, KanaOutputComponent — the shared-service architecture | Chapter 4 |
| The real Express /api/convert route, the ported plain-JS conversion engine | Chapter 5 |
| Debounced, race-safe, error-resilient conversion pipeline; the real styled UI | Chapter 6 |
| Single-process production deployment; environment.apiBaseUrl; PM2; nginx | Chapter 7 |
| Path-mounted reverse proxy, --base-href, the "mounted" configuration, and a real link into the site's own Japanese content | Chapter 8 (this chapter) |
What This Course Deliberately Doesn't Cover
- Kanji conversion — named out of scope in Chapter 1 for a real reason: it's a genuinely harder, dictionary-and-context-dependent problem (the same kana can map to several different kanji depending on meaning), deliberately left as its own real future project rather than bolted on here.
- A persisted conversion history — every result lives only in the current page's own signals; nothing is saved across a reload.
- UPC/EAN-style batch or file-based conversion — this tool converts one typed phrase at a time, matching the actual, narrow use case Chapter 1 scoped it around.
Hands-On Exercises
Create environment.mounted.ts and the "mounted" configuration exactly as this chapter describes, then run ng build --configuration production,mounted --base-href /romaji/. Inspect the real built index.html and confirm its asset references include the /romaji prefix, and inspect the built JavaScript bundle to confirm the string '/romaji' appears in place of Chapter 7's empty apiBaseUrl.
📄 View solutionConfigure the nginx location /romaji/ block against a real running instance of the app (a second local nginx config is fine for testing), and confirm both a page load and a real /api/convert request succeed through the proxy, with server.js completely unchanged from Chapter 7.
📄 View solutionBuild with only --base-href /romaji/ set, using just the default "production" configuration (skip "mounted" entirely, leaving apiBaseUrl empty). Serve it through the same nginx proxy from Exercise 2 and confirm the page itself loads correctly while every conversion attempt fails — demonstrating why this chapter's own warn-box treats the two fixes as genuinely separate.
📄 View solutionChapter 8 Quick Reference — Course Complete
- Three mounting options — subdomain, path-mounted reverse proxy (built here), or a full Astro-frontend rewrite
- --base-href /romaji/ — Angular's own verified flag for correcting built asset references, the real equivalent of Vite's base option
- A new "mounted" configuration — a minimal fileReplacements override, composed with "production" via Angular's own real, verified comma-separated multi-configuration syntax
- environment.mounted.ts — sets apiBaseUrl to /romaji without touching Chapter 7's own generic, empty default
- nginx's trailing-slash prefix-stripping — lets server.js stay completely unchanged from Chapter 7
- The real payoff — a live link from the existing kanji tiles page and Japanese-language lessons into a genuinely working /romaji/ tool, the exact promise Chapter 1 opened with
- This closes the course — 8/8 chapters, matching the shared Personal Multi-Technology Projects romaji-to-kana spec from Chapter 1