Saltar a contenido

architecture-it/react-env

Librería que contiene el estándar de manejar variables de entorno necesarias para las aplicaciones frontend (CRA, NextJS, Microfrontend).

Variables accesibles en el navegador

Para que realmente sean disponibles en el navegador deben contener el prefijo REACT_APP_ o NEXT_PUBLIC_ en el caso de NextJS Dicho prefijo se puede configurar (caso microfrontends)

La razón de está librería es para mantener el estandar de Dockerización que se tiene en la empresa, actualmente el build se hace en Azure, y luego la misma imagen se utiliza en qa y producción, por defecto webpack inyecta las variables cuando hace el build, por lo que el manejo de las variables dentro de nuestro estandar no es posible de este modo (necesitaríamos un build para cada entorno), por lo que está librería se encarga de resolver este punto.

react-env-why


Este fork contiene mejoras con respecto al testing y a la sobreescritura (caso microfrontend)


Toma las variables en tiempo de ejecucion en vez de en tiempo de construccion de la aplicación (webpack), para darle soporte al principio de dockerización de CICD de la empresa.

  • Soporta SSR y CSR.
  • Soporta multiples .env.

Instalación

Configuración necesaria

Si aún no has configurado npm para traer paquetes internos de andreani por favor volver a [configuración](../../Architecture_Packages/index.md#npm)
    pnpm i @architecture-it/react-env

Ejemplo

.env
REACT_APP_API_URL=https://localhost:5800/api/
REACT_APP_ANOTHER=ejemplo

# Protegidas y no devueltas en el wrapper, no contienen el prefijo
API_TOKEN=1234
App.tsx
import env from "@architecture-it/react-env";

export default function App(props) {

    return (
        <div>
            <small>
                Funciona en el navegador: <b>{env("API_URL")}</b>.
            </small>
            <small>
                Funciona también en SSR: <b>{env("ANOTHER")}</b>.
            </small>
            <small>
                Solo obtienes las que contienen en el prefijo por seguridad (no contiene API_TOKEN):
            <pre>
                <code>{{JSON.stringify(env())}}</code>
            </pre>
            </small>
        </div>
    )
};

Excepción

En el caso de variables que modifican el comportamiento de nuestra app según el modo de levantarla NODE_ENV (que en modo desarrollo tiene el valor "development" y en cuando se hace build de la aplicación siempre tiene el valor "production") debemos seguir usando process.env

Ejemplo

if(process.env.NODE_ENV !== "production"){
    console.log("Información solo relevante en modo de desarrollo")
}

NextJs SSR

En el caso de NextJs en las funciones getServerSideProps, getStaticProps o en cualquier endpoint generado se debe seguir utilizando el process.env


Implementacion

.gitignore
# ...Otras propiedades ignoradas por brevedad

# Solo debería ser autogenerado
/public/__ENV.js

# ...Otras propiedades ignoradas por brevedad

_app.tsx
import Script from "next/script";

//omitido por brevedad

//en el componente principal
    <Script src="/__ENV.js" strategy="beforeInteractive" />
package.json
{
    //..otras opciones ignoradas
    "scripts":{
        //..otros scripts ignorados
        "predev": "react-env --prefix NEXT_PUBLIC --",
        //..otros scripts ignorados
    },
    //..otras opciones ignoradas
}

public/index.html
    <script src="%PUBLIC_URL%/__ENV.js"></script>
package.json
{
    //..otras opciones ignoradas
    "scripts":{
        //..otros scripts ignorados
        "prestart": "react-env --",

        //..otros scripts ignorados
    },
    //..otras opciones ignoradas
}


.env file orden de prioridad

Se establecen ciertos ordenes de prioridad segun parametros y/o archivos encontrados

  1. {path-to-file} // from the --path, -p argument
  2. .env.{key} // from the --env, -e argument
  3. .env.local
  4. .env

Tu configuración esta disponible en el navegador (siempre y cuando cuente con el prefijo), y process.env en el caso del servidor.

Buena practica

Se establece que el .env.local esté agregado al .gitignore ( que nunca se suba al repositorio)

Especificando el .env

package.json
{
  ...
  "scripts": {
    "start": "react-env --path .env.example -- next start"
  }
  ...
}

Especificando prefijos

En el caso de NextJS para mantenernos con el estandar del framework se recomienda hacer lo siguiente:

package.json
{
  ...
  "scripts": {
    "start": "react-env --prefix NEXT_PUBLIC -- next start"
  }
  ...
}
# .env
NEXT_PUBLIC_NEXT=Next.js
NEXT_PUBLIC_CRA=Create React App
NEXT_PUBLIC_NOT_SECRET_CODE=1234
SECRET_CODE=super-secret-token
Uso con testing

Necesitas agregar REACT_ENV_PREFIXcomo variable de entorno antes de usar jest si usas la utilidad env() durante tus tests:

package.json
{
  ...
  "scripts": {
    "test": "REACT_ENV_PREFIX=NEXT_PUBLIC jest --maxWorkers=3"
  }
  ...
}

Uso con Docker

Dockerfile
# ...Omitido por brevedad...

FROM ghcr.io/architecture-it/nextjs:latest AS runner

COPY --from=builder /app/next.config.js ./
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/package.json ./package.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

# WORKAROUND si se tiene problemas con permisos, (Evitar)
# RUN chmod -R 777 ./public/__ENV.js

CMD ["/bin/sh", "-c", "react-env --prefix NEXT_PUBLIC -- && node server.js"]
Dockerfile
# ...Omitido por brevedad...

FROM ghcr.io/architecture-it/nginx:latest
COPY --from=builder /app/build .

# WORKAROUND si se tiene problemas con permisos, (Evitar)
# RUN chmod -R 777 ./__ENV.js

CMD ["/bin/sh", "-c", "react-env -d ./ -- && nginx -g \"daemon off;\""]

Deprecated runtime-env-cra

7- En caso de que estemos usando Typescript debemos configurar a window para que entienda que tiene la propiedad __RUNTIME_CONFIG__. Para esto en el archivo src/types/global.ts debemos agregar lo siguiente.

src/types/global.ts
export { };
declare global {
    interface Window {
        /**
         * environment variables available on runtime
         */
        __RUNTIME_CONFIG__: {
            // its posible define your env file
            REACT_APP_URL_API: string;
            [key: string]: string,
        };
    }
}
8- Para que Typescript reconozca este objeto global hay que configurarlo además en nuestro tsconfig.json específicamente en include json title="tsconfig.json" { "compilerOptions": { //... Omitido para brevedad }, "include": [ "src", "src/types" // Para que reconozca el globals.ts ] }

##### Testing

Para hacer uso de las variables y que los test en jest funcionen hay que declarar la propiedad `__RUNTIME_CONFIG__` en el objeto window ( con cuantas variables tengamos declaradas en el archivo .env), por lo que debemos agregar al archivo `setupTests.ts` o `setupTests.js` lo siguiente.

```js title="setupTests.ts" hl_lines="2"
// resto de las imports y configuraciones ...
import "../public/runtime-env";
```