Jan 26, 2025
4 min read
Nuxt3,
Cloudflare,

Recording the 'Pitfalls' of Nuxt 3 on Cloudflare Pages

Be cautious, you might encounter them too.

Recently, while developing some interesting personal projects using Nuxt3 and deploying them on Cloudflare Pages, I encountered several frustrating issues. Here’s a record of those.

Node.js Issues on Cloudflare Pages

Despite Cloudflare’s claim to be all-encompassing, even they have their limitations.

In reality, the Node.js environment on Cloudflare Pages is not a full version and is fixed without any options for customization. This means certain JavaScript libraries cannot be used. A notable example is when trying to use aws-sdk-js to interact with AWS S3 via Cloudflare’s R2 storage, which results in a cryptic error t is not a function. This error does not occur during local development but fails at build time.

The reason is that aws-sdk-js depends on @aws-sdk/s3-request-presigner, which in turn relies on @smithy, requiring the node:fs module. Clearly, Cloudflare’s Node.js environment does not provide node:fs. As an alternative, Cloudflare Pages recommends using the more primitive SDK aws4fetch.

Many similar issues can arise, often due to unsupported modules in Cloudflare’s Node.js environment.

Some Routes Work Fine in Development but Return 404 in Production?

We know that if a project has static files that need to be accessed, placing them in the public directory is standard practice. Typically, frameworks are designed to look for corresponding files if a route is undefined or return a 404 if the file doesn’t exist.

Recently, I encountered a peculiar issue where some static files in the public directory could be accessed normally, while others returned a 404 Not Found error. In development mode, all addresses worked fine.

Checking the console revealed an error [nuxt] error caught during app initialization Wa: Page not found: /content/xxxx. This clearly indicated that the routing logic was being handled internally by the application, even though these were supposed to be static files.

Based on previous experience, this issue was likely related to Cloudflare Pages. Checking the deployment information, I found that Cloudflare Pages has its own routing mechanism for determining when to execute Functions scripts. This routing configuration is generated based on files in the /functions directory.

To control when functions are called, one can write custom functions. However, Nuxt does not provide relevant configurations or documentation for this.

_routes.json

Another solution is to create a _routes.json file to control which routes call functions. This file should be placed in the project’s output directory.

Reviewing the deployment details, I noticed that the routing content listed was from _routes.json.

{
  "version": 1,
  "include": [
    "/*"
  ],
  "exclude": [
    "/_nuxt/*",
    "/_robots.txt",
    "/favicon.ico",
    "/images/pvz.jpg",
    "/js/jquery.js",
    "/content"
    //...
  ]
}

By comparing the errors, I identified the root cause: the 404 Not Found pages were not listed in the exclude list.

This issue was very subtle; _routes.json only excluded some static files, so the missing ones were treated as application routes, leading to the error [nuxt] error caught during app initialization Wa: Page not found: /content/xxxx.

The solution was straightforward—manually control the content generation of _routes.json.

Unfortunately, there is no documentation in Nuxt3 for this. Since Nuxt3 uses nitro for the backend, I looked into nitro’s documentation regarding Cloudflare Pages.

Nitro automatically generates a _routes.json file to control which routes are served by files and which by Worker scripts. You can override the auto-generated routing file using the cloudflare.pages.routes configuration option.

Thus, we can configure it directly in nuxt.config.ts:

export default defineNuxtConfig({
    nitro: {
        modules: [nitroPublic()],
        preset: 'cloudflare_pages',
        prerender: {
            autoSubfolderIndex: false
        },
        cloudflare: {
            pages: {
                routes: {
                    "version": 1,
                    "include": [
                        "/*"
                    ],
                    "exclude": [
                        "/_nuxt/*",
                        "/_robots.txt",
                        "/favicon.ico",
                        "/fonts/FUTRSTI.TTF",
                        "/images/bg.jpg",
                        "/images/logo.jpg",
                        "/js/jquery.js",
                        "/js/jquery.mobile-1.4.5.min.js",
                        "/content/*"
                    ]
                }
            }
        }
    },

})

Thoughts on the Nuxt 3 Framework

My impression of Nuxt3 is that it has no major problems but plenty of minor ones. For instance, it starts slowly, and the server-side performance is also slow. Error debugging messages are often unhelpful. Some routing behaviors work as expected sometimes but not others.

In the Vue ecosystem, the closest equivalent to Next.js that I know of is Nuxt.

Recently, I came across a framework called Tuono, which implements SSR full-stack with Rust on the backend. It would be interesting to see if someone develops a Vue version.