expatfile / next-runtime-env

Next.js Runtime Environment Configuration - Populates your environment at runtime rather than build time.
https://www.npmjs.com/package/next-runtime-env
MIT License
403 stars 14 forks source link

Doesn't work when a page.tsx throws an unhandled exception. #106

Open carlos-dubon opened 7 months ago

carlos-dubon commented 7 months ago

The library stops working when a page.tsx throws an unhandled error. This results in a cascade of issues in my app.

Expected behaviour: read env vars even tho there is an unhandled exception in a page/layout..

// app/page.tsx
import { env } from 'next-runtime-env';
const NETWORKING_ENVIRONMENT = env('NEXT_PUBLIC_NETWORKING_ENVIRONMENT')

async function getData(): Promise<number> {
    throw new Error('This is a test error');
    return 1;
}

export default async function Home() {
    const pageData = await getData();

    return (
       <div>
home page
<div>ENV: {NETWORKING_ENVIRONMENT}</div> This stops reading/working...
</div>
    );
}
ccxdev commented 6 months ago

I think I have similar issue. When navigating to non-existing page.

NextJS throw error:

Failed prop type: The prop href expects a string or object in <Link>, but got undefined instead.`

Because of appUrl and window['__ENV'] are undefined.

# .env

NEXT_PUBLIC_APP_URL=http://localhost:3000
// config.ts

import { env } from "next-runtime-env"

export const appUrl = env("NEXT_PUBLIC_APP_URL")
// not-found.tsx

'use client'

import Link from "next/link"
import { appUrl } from "./config.ts"

export default function NotFound() {
  console.log(window['__ENV']) // undefined
  console.log(appUrl) // undefined

  return <Link href={appUrl}>Back home</Link>
}
carlos-dubon commented 6 months ago

@nekotoriy I found a workaround, and it is using the provider aproach: https://github.com/expatfile/next-runtime-env/tree/main/examples/with-app-router-context This works for my use case.

NOTE: This is NOT a solution, so please don't close the issue!!

HofmannZ commented 5 months ago

Thanks for reporting this issue.

@carlos-dubon the env utility in the server is just a wrapper around process.env[key]. Can you confirm that `process.env.NEXT_PUBLIC_NETWORKING_ENVIRONMENT' does provide the correct variable in the server component.

@nekotoriy - I don't think this issue is related, as you are using the env utility in a client component. The question here is if Next.js wraps the not found page with the root layout which would expose the environment variables in the client.

emreakdas commented 5 months ago

@HofmannZ

 Error: Environment variable 'blablabla' is not public and cannot be accessed in the browser

I'm getting an error.

<PublicEnvScript />

installation.

HofmannZ commented 5 months ago

@emreakdas - Can you please provide some additional context?

emreakdas commented 5 months ago

@HofmannZ NextJS 14

I use it normally with this usage, there is nothing extra I do, but it gives the above error in the console

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}
gregorybolkenstijn commented 5 months ago

@HofmannZ NextJS 14

I use it normally with this usage, there is nothing extra I do, but it gives the above error in the console

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}

The env vars stop working once it hits a 404 page, a not-found.tsx in the root of the app directory. The root layout has the <PublicEnvScript /> component and is rendered, but window.__ENV is empty.

emreakdas commented 5 months ago

@HofmannZ NextJS 14 I use it normally with this usage, there is nothing extra I do, but it gives the above error in the console

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}

The env vars stop working once it hits a 404 page, a not-found.tsx in the root of the app directory. The root layout has the <PublicEnvScript /> component and is rendered, but window.__ENV is empty.

unfortunately I have given up using this package, but what is the solution? isn't this a package problem?

HofmannZ commented 5 months ago

@HofmannZ NextJS 14 I use it normally with this usage, there is nothing extra I do, but it gives the above error in the console

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}

The env vars stop working once it hits a 404 page, a not-found.tsx in the root of the app directory. The root layout has the <PublicEnvScript /> component and is rendered, but window.__ENV is empty.

@gregorybolkenstijn I will add an example to try and replicate.

HofmannZ commented 5 months ago

I was able to replicate the initial issue reported by @carlos-dubon. The problem appears to be that Next.js does not include the scripts from the top-level layout when a server error occurs. I attempted to address this by adding an error.tsx file to handle the error, but it didn't have any impact. I also tried switching from an HTML script tag to using Script from next/script, but the result was the same.

This seems to be a problem with Next.js itself, rather than with our package, and I've opened an issue on their GitHub repository. If you'd like to keep track of its progress, please give it an upvote: https://github.com/vercel/next.js/issues/63980

However, I did confirm that everything works fine on the not-found page. (@gregorybolkenstijn, I can't reproduce your issue.)

gregorybolkenstijn commented 4 months ago

This comment in the. related Next.js issue gave us an idea of how to tackle this issue: https://github.com/vercel/next.js/issues/63980#issuecomment-2056307152

The solution of adding a loading.tsx fixed it, but it also led to an unnecessary and intrusive loading state between pages. This other remark led us to another solution though:

If an error occurs on the server, react will skip SSR up to the nearest suspense boundary

So we wrapped the children in a <Suspense> in the root layout to allow that component to be partially rendered on the server correctly:

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        <Suspense>{children}</Suspense>
      </body>
    </html>
  );
}

It has worked well for us, we have not experienced any issues.

lightrow commented 4 months ago

This comment in the. related Next.js issue gave us an idea of how to tackle this issue: vercel/next.js#63980 (comment)

The solution of adding a loading.tsx fixed it, but it also led to an unnecessary and intrusive loading state between pages. This other remark led us to another solution though:

If an error occurs on the server, react will skip SSR up to the nearest suspense boundary

So we wrapped the children in a <Suspense> in the root layout to allow that component to be partially rendered on the server correctly:

// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        <Suspense>{children}</Suspense>
      </body>
    </html>
  );
}

It has worked well for us, we have not experienced any issues.

that's bad for UX though, user just sees a blank page until everything is loaded.

A better solution is to set up an /error/page.tsx and /not-found/page.tsx and redirect to those pages on 500 or 404, that way the scripts will load.