Troubleshooting Docusaurus i18n: A Case Study on Routing and Deployment Issues
This article chronicles the journey of identifying and resolving two tricky problems encountered after adding internationalization (i18n) to a Docusaurus v3 site: "client-side routing collapse" and "container startup failure on Cloud Run."
- Site Generator: Docusaurus v3
- Hosting: Google Cloud Run
- Development & Deployment: Docker, GitHub Actions
- Package Manager: pnpm
Sources
- https://docusaurus.io/docs/i18n/tutorial#start-your-site
- https://github.com/facebook/docusaurus/issues/11112
1. The Problems Encountered
After configuring i18n, two critical issues emerged consecutively during local production build verification (pnpm build
+ pnpm serve
) and after deploying to Cloud Run.
Problem 1: Client-Side Routing Collapse
When accessing the site and switching languages using the language switcher, the following symptoms appeared:
- Incorrect URL Accumulation: Every time the language was switched, the locale prefix was repeatedly appended to the URL, resulting in paths like
/en/en/en/...
. - React Hydration Errors: The browser console was flooded with errors like
Warning: Expected server HTML to contain a matching ...
. This is a serious error in SPAs, indicating a mismatch between the server-generated HTML and the client's DOM structure. - Eventual 404: The attempt to access the malformed URL ultimately led to the site's 404 page.
Problem 2: Container Startup Failure on Cloud Run
After implementing a fix for Problem 1 and redeploying, a new issue arose: the container itself failed to start on Cloud Run.
-
Container Startup Timeout: The Cloud Run logs showed the following error:
The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.
This meant that the deployed Docker container could not successfully start the web server on the port specified by Cloud Run (8080).
2. Identifying Causes and Solutions
I tackled each problem by isolating and identifying its root cause.
2.1. Resolving Problem 1 (Routing Collapse)
-
Cause: The root cause was the lack of SPA (Single Page Application) support in the local verification server. The default configuration of the
serve
package I was using at the time could not correctly handle "pretty URLs" like/docs/intro/
generated by Docusaurus. It failed to fall back requests to.../index.html
internally. As a result, the server returned a 404 before the client-side React Router could interpret the URL, causing the entire routing system to collapse. -
Solution: I switched the local verification server to
http-server
, which supports SPA mode out of the box.-
Install
http-server
# Install as a development dependency
pnpm add -D http-server -
Update the
serve
script inpackage.json
I added the--single
option to make all unresolved path requests fall back to the rootindex.html
. This ensures that URL resolution is correctly delegated to the client-side React Router.package.json"scripts": {
"serve": "http-server ./build --single"
}
-
2.2. Resolving Problem 2 (Container Startup Failure)
-
Cause: Ironically,
http-server
, which was introduced to fix Problem 1, was the direct cause of this new problem. The fundamental issue was improper classification of dependencies.Since
http-server
was installed as adevDependency
(development-only dependency), it was removed by thepnpm prune --prod
command executed inside the productionDockerfile
. Consequently,http-server
did not exist in the final production container, causing the startup commandpnpm run serve
to fail and the container to exit immediately. -
Solution: I moved
http-server
todependencies
(production dependency) to make it available in the production environment.- Reclassify the dependency
# Remove from devDependencies
pnpm remove -D http-server
# Re-install as a dependency
pnpm add http-server - Remove the unnecessary package
The old
serve
package was no longer needed, so I removed it completely from the project.pnpm remove serve
- Reclassify the dependency
With these fixes, the container started correctly on port 8080, and the Cloud Run deployment completed successfully.
3. Improved Development and Deployment Flow
Based on this experience, I standardized the development process as follows.
3.1. Development Commands
- Daily Development (Hot Reload):
# Docker environment
docker-compose up
# Local environment
pnpm start - Development for a Specific Language (e.g., English):
# Docker environment
docker-compose run --rm --service-ports app pnpm start --locale en --host 0.0.0.0
# Local environment
pnpm start --locale en
3.2. Final Check Before Deployment
Before any deployment, I always verify the production build using the following command flow:
# 1. Build the static files for production
pnpm build
# 2. Serve the build artifacts with an SPA-aware server
pnpm serve
3.3. Content Management
When adding a new page, I enforce the practice of also adding its translated version to the appropriate location within the i18n/[locale]/...
directory. Pages without a translation will result in a 404 error for that language, so keeping content in sync is crucial.
4. Summary
This series of issues was a compound problem stemming from a poor choice of local development server and a dependency management mistake in the Docker build process. By systematically isolating the cause at each layer and applying the right tools and configurations, I was able to re-establish a robust development and deployment foundation for reliably operating the i18n-enabled site.