Unleash / unleash-client-nextjs

Unleash SDK for Next.js
28 stars 9 forks source link

Middleware cause Error : Initial locale argument was not passed into serverSideTranslations #54

Closed geryfauzi closed 1 year ago

geryfauzi commented 1 year ago

Describe the bug

When i'm using next-i18next with middleware, it work fine in development mode (e.g yarn dev). But when i test it in production mode (e.g yarn build then yarn start), its not working anymore. It gave an error saying "Error: Initial locale argument was not passed into serverSideTranslations". Fyi my nextjs version is 13.0.2 and my next-i18next version is 12.1.0.

P.S : If i'm changing the middleware (change it into anything beside using unleash) it work fine. It's only error when i'm using unleash.

Steps to reproduce the bug

I'm adding middleware to my nextjs Project. Here it's the code :

import { NextRequest, NextResponse } from "next/server";
import { evaluateFlags, randomSessionId } from "@unleash/nextjs";
import { addBasePath } from "next/dist/client/add-base-path";

export default async function middleware(req: NextRequest) {
  let cookies: any = req.cookies.get("flags");
  const newUrl = req.nextUrl.clone();
  const res = NextResponse.rewrite(newUrl);
  if (cookies) {
    return res;
  } else {
    const sessionId = req.cookies.get("flags")?.value || randomSessionId();
    const context = { sessionId };
    let flagCookies = null;

    // Grab definitions from an endpoint cached on the edge
    const protocol = req.url.startsWith("https") ? "https://" : "http://";
    const host = req.headers.get("host");
    const endpoint = addBasePath("/api/proxy-definitions");
    const token = process.env.UNLEASH_SERVER_INSTANCE_ID || "";
    const definitionsUrl = `${protocol}${host}${endpoint}?token=${token}`;

    // Make a request to the edge-cached endpoint
    const definitions = await fetch(definitionsUrl, { method: "GET" }).then(
      (res) => res.json()
    );

    // Evaluate based on provided context
    const evaluated = await evaluateFlags(definitions, context);
    flagCookies = JSON.stringify(evaluated);
    // Redirect to variant
    if (flagCookies)
      res.cookies.set("flags", flagCookies, {
        expires: new Date(new Date().getTime() + 1 * 60 * 1000)
      });
    return res;
  }
}

export const config = {
  matcher: ["/:path*"]
};

My next-i18next configuration :

// used for SSR (getServerSideProps)
// const path = require('path')
// const localePath = path.resolve('./public/locales')

module.exports = {
  // https://www.i18next.com/overview/configuration-options#logging
  debug: process.env.NODE_ENV === "production",
  i18n: {
    defaultLocale: "id",
    locales: ["id"]
  },
  // localePath,
  reloadOnPrerender: process.env.NODE_ENV === "production"
};

Expected behavior

The app should working fine as its work fine in developmen mode

Logs, error output, etc.

Error [TypeError]: fetch failed
    at Object.processResponse (evalmachine.<anonymous>:7941:27)
    at <unknown> (evalmachine.<anonymous>:8271:42)
    at <unknown> (node:internal/process/task_queues:140:7)
    at AsyncResource.runInAsyncScope (node:async_hooks:204:9)
    at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Error: Initial locale argument was not passed into serverSideTranslations
    at _callee$ (C:\xampp\htdocs\parent-app\node_modules\next-i18next\dist\commonjs\serverSideTranslations.js:116:19)
    at tryCatch (C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:133:17)
    at Generator.next (C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:24)
    at _next (C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\asyncToGenerator.js:22:9)
    at C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at C:\xampp\htdocs\parent-app\node_modules\@babel\runtime\helpers\asyncToGenerator.js:19:12
    at serverSideTranslations (C:\xampp\htdocs\parent-app\node_modules\next-i18next\dist\commonjs\serverSideTranslations.js:217:17)

Screenshots

No response

Additional context

No response

Unleash version

1.2.0

Subscription type

None

Hosting type

Self-hosted

SDK information (language and version)

No response

Tymek commented 1 year ago

Look into adding catch on errors when fetching definitions. Probably something isn't working with another part required for this approach (/api/proxy-definitions file).

I noticed is you're sending all flags to the client in a cookie, and this has a significant overhead. If you're not making decisions related to flags in middleware, maybe client-side approach will be a better match for this.