manchenkoff/nuxt-auth-sanctum

[Question][Feature] i18n Not Initialized in Server-Side Context During First Sanctum Request Interceptor Call

Closed this issue · 7 comments

Describe the bug
In a Nuxt 3 application using the nuxt-auth-sanctum and @nuxtjs/i18n modules, the $i18n object is not available in the server-side context (import.meta.server) during the first request to fetch the authenticated user when the page is loaded. This results in missing or default headers being sent, which rely on the i18n locale information.

Steps to reproduce
Set up a Nuxt 3 project with the following modules in nuxt.config.ts:

modules: [
  "@nuxt/ui",
  "@nuxt/image",
  "@nuxtjs/eslint-module",
  "@vueuse/motion/nuxt",
  "dayjs-nuxt",
  "nuxt-bugsnag",
  "@dargmuesli/nuxt-cookie-control",
  "nuxt-zod-i18n",
  "@nuxtjs/i18n",
  "nuxt-auth-sanctum",
  "@nuxtjs/seo",
  "@formkit/auto-animate/nuxt",
  "nuxt-gtag",
  "nuxt-easy-lightbox",
],

Implement the following request interceptor for the sanctum module in app.config.ts:

sanctum: {
  interceptors: {
    onRequest: (app: NuxtApp, ctx: FetchContext, _logger: ConsolaInstance) => {
      if (import.meta.server) {
        const headers = useRequestHeaders();
        ctx.options.headers = {
          ...ctx.options.headers,
          "X-Forwarded-For": headers["x-forwarded-for"],
        };
        console.log(app.$i18n?.localeProperties?.value?.code); // Undefined on server during first load
      } else {
        ctx.options.headers = {
          ...ctx.options.headers,
          "X-Language": app.$i18n.localeProperties.value.code,
        };
      }
    },
  },
},

Load the page for the first time in the browser and observe that, during the initial server-side request to fetch the user, app.$i18n is not available, resulting in undefined localeProperties in the server context.

Expected behavior
The i18n module should be initialized and available in the server context during the first page load, allowing the application to correctly set headers based on the current locale when making the request to fetch the authenticated user.

Additional context
This issue only occurs during the first server-side request to fetch the authenticated user when the page is loaded. It appears that the nuxt-auth-sanctum module may execute its interceptors before the @nuxtjs/i18n module is fully initialized on the server. Subsequent requests do not encounter this problem, as $i18n is initialized properly after the first load.

Hey @carlosvaldesweb, I'm not sure that I can change this behavior since the module initialization order cannot be controlled from the module itself. Have you tried to change the order of the modules in your nuxt.config.ts?

Thank you for the response. I have tried a few things, but I haven't been able to solve the issue. I was considering using some Nuxt hooks to ensure that i18n is fully initialized before Sanctum makes its request, but it seems like the problem is more related to the plugin loading order rather than the module loading order.

I found this note in the Nuxt 2 documentation, but I haven't been able to find anything similar for Nuxt 3:

Note: Any plugins injected by modules are added to the beginning of the plugins list. Your options are to:

Manually add your plugin to the end of the list of plugins (this.nuxt.options.plugins.push(...))
Reverse the order of the modules if it depends on another
Here is the link to the documentation I found: Nuxt 2 Modules Documentation.

@carlosvaldesweb Changing the order manually would affect other modules that depend on this one as well. For instance, I have a module that uses a sanctum client for its own plugin.
I will try to check if it is possible to expose dependencies of the plugin to the module config, I believe that should help. Otherwise, I can make the initial plugin call optional and provide a way to run it from your code instead (local plugin) once all the modules are loaded.

Thank you @manchenkoff , also maybe you can try to use:
https://nuxt.com/docs/guide/directory-structure/plugins#plugins-with-dependencies

A way to pass param or something like that.

If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the dependsOn array.

Thank you @manchenkoff , also maybe you can try to use:
https://nuxt.com/docs/guide/directory-structure/plugins#plugins-with-dependencies

A way to pass param or something like that.

If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the dependsOn array.

This is exactly what I meant by exposing plugin dependencies to the module level

The fix will be published as 0.4.12

New version has been published @carlosvaldesweb