Environment Variables

Loading Environment Variables

Next.js는 우선 내부적으로 .env.localprocess.env 같은 환경변수를 제공해준다. 예를들어 .env.local 같은 경우에는 다음과 같이 사용한다.

DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword

해당 환경변수들은 Node.js에서 자동으로 Next.js의 데이터를 가져오는 방식으로 사용하게 된다. 예를들어 해당 환경변수를 가지고 ` getStaticProps`를 사용하는 방식을 보면 다음과 같다.

export async function getStaticProps() {
  const db = await myDB.connect({
    host: process.env.DB_HOST,
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
  });
}
서버가 민감한 정보들을 안전하게 다루기 위해 Next.js는 process.env.* 파일을 빌드 시간에 맞는 경로로 전달한다. 즉 process.env는 자바스크립트에서의 표준이 아니며, object destructuring을 사용할 수 없다는 뜻이다. 즉 환경 변수는 const { PUBLISHABLE_KEY } = process.env 처럼 사용하는 것이 아닌 process.env.PUBLISHABLE_KEY 처럼 사용해야 된다.

또한 Next.js는 ($VAR) 과 같은 변수들은 자동적으로 .env* 파일에서 연장하여 사용한다. 변수를 사용한 방법은 다음과 같다.

# .env
HOSTNAME=localhost
PORT=8080
HOST=http://$HOSTNAME:$PORT

만약 $ 를 그대로 쓰고싶다면 \$ 과 같이 백슬래쉬를 넣어 사용해야된다.

Exposing Environment Variables to the Browser

일반적인 환경변수들은 Node.js 환경에서만 사용가능하므로, 브라우저에 유출이 되진 않는다. 만약 브라우저에서 NEXT_PUBLIC 으로 시작하는 변수를 외부로 유출시키고 싶다면, 다음과 같이 사용하면 된다.

NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk

이렇게 사용하게 되면, process.env.NEXT_PUBLIC_ANALYTICS_ID가 로드되어, Node.js 환경으로 자동으로 들어가 코드 어디에서도 사용 할 수 있게 된다. 즉 NEXT_PUBLIC_과 같은 접두사를 사용하게 된다면, 자바스크립트가 브라우저에게 바로 값을 넘겨주게 된다. 이러한 인라인은 빌드시간에 일어나며, 다음과 같은 NEXT_PUBLIC_의 환경변수들은 프로젝트가 빌드가 끝난 후 사용된다. 코드에서 사용되는 예시는 다음과 같다.

// pages/index.js
import setupAnalyticsService from "../lib/my-analytics-service";

// NEXT_PUBLIC_ANALYTICS_ID can be used here as it's prefixed by NEXT_PUBLIC_
setupAnalyticsService(process.env.NEXT_PUBLIC_ANALYTICS_ID);

function HomePage() {
  return <h1>Hello World</h1>;
}

export default HomePage;

Default Envrionment Variables

일반적으로는 하나의 .env.local파일만이 필요하다. 하지만 가끔 developmentproduction에 따라 다른 환경 변수들을 사용 할 수 있다. 그래서 Next.js.env, .env.development, .env.production과 같은 환경변수 또한 지원하며 .env.local을 항상 표준으로 둔다.

주의사항으로는 .env, .env.development, .env.production 과 같은 파일들은 .env*.local에 정의되어 있어야 하고 .gitignore에 포함시켜 안전하게 보관해야된다.

Test Envrionment Variables

developmentproduction 환경변수외로, text라는 세번째 옵션이 또 존재한다. 앞선 방법들과 마찬가지로 .env.teest에서 testing 환경을 구축하여 사용 할 수 있다.

이러한 방법은 jestcypress와 같은 테스팅 툴을 사용할 때 유용하게 사용 할 수 있다. 이러한 테스트 방식은 NODE_ENVtest로 되어있다면, 테스트의 표준 환경을 사용 할 수 있다.

testdevelopmentproduction 와 다른점이 있다면, 테스트 환경은 .env.local에 로딩이 안된다는 것이다. 이러한 방식으로 실행되어야 매번 같은 환경을 사용할 수 있기 때문이다.

unit test 를 하는 동안에는 @next/env 패키지를 사용하여 loadEnvConfig를 해야함에 주의한다.

// The below can be used in a Jest global setup file or similar for your testing set-up
import { loadEnvConfig } from "@next/env";

export default async () => {
  const projectDir = process.cwd();
  loadEnvConfig(projectDir);
};

env의 우선순위는 다음과 같다.

NODE_ENV=production

  1. .env.production.local
  2. .env.local
  3. .env.production
  4. .env

NODE_ENV=development

  1. .env.development.local
  2. .env.local
  3. .env.development
  4. .env

NODE_ENV=test

  1. .env.test.local
  2. .env.test
  3. .env

Supported Browsers and Features

Script Component

Image를 NEXT 에서 제공했던것 처럼, Script같은 경우에도 따로 지정해주는걸 사용하는것이 효율과 성능면에서 더 좋다. 해당 Script 컴포넌트는 next/script에서 가져올 수 있으며 기본적인 HTML <script>의 연장선이다. 해당 next/head 밖에서 개발자들에게 로딩하는 우선순위를 지정할 수 있게 해주어 로딩 효율을 높여준다.

import Script from "next/script";

export default function Home() {
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  );
}

Overview

웹사이트는 가끔 통계, 광고, 위젯등을 사용할 때 써드파티의 스크립트를 사이트에서 사용하게 된다. 하지만 이러한 스크립트를 가져오는것이 보통 유저와 개발 입장에서 둘 다 문제를 일으키게 된다.

  • 어떠한 써드파티의 스크립트 같은경우 너무 무거워서 로딩효율이 안좋고, UX 관점에서 되게 안좋을 수 있다. 특히나, render-block 혹은 딜레이가 생길 수 있다.
  • 개발자들은 어떠한 써드파티의 스크립트를 어디에 두어야 효율적인 로딩이 될지 고민하게 된다.

이러한 문제들을 Next 에서 제공하는 Script를 사용하여 해결 할 수 있다.

Usage

이러한 Script를 사용시에, strategy란 속성을 두어서 관리를 할 수 있다. 간단한 예제를 보면 다음과 같다.

<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

속성들을 보면 다음과 같다.

beforeInteractive

beforeInteractive속성이 있는 스크립트 같은 경우에는 최초의 HTML에 들어가, 서버가 바로 실행하여 self-bundle된 Javascript가 실행되기 전에 돌아간다. 이러한 방법은 페이지가 상호작용을 하기도전에, fetch하여 실행을 해야될 경우 주로 사용된다. 이러한 방법은 메인 페이지인 _document.js에서 동작하며, 보통 모든 사이트에서 로딩이 필요한 script인 경우에 들어가서 실행된다.

이러한 beforeInteractive한 방법이 사용되는 이유는, 오직 _document.js에서만 동작하게 하여 스티리밍과 Suspense functionality를 지원하기 위함이다. 즉 _document.js 의 밖에서는 beforeInteractive의 방식이 우선순위를 잘 두어 실행된다는 보장을 할 수 없다.

// In _document.js
import { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
        <Script
          src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
          strategy="beforeInteractive"
        ></Script>
      </body>
    </Html>
  );
}

보통 이러한 속성을 띄는 예는 다음과 같다.

  • Bot detectors
  • Cookie consent managers

afterInteractive

afterInteractive 방법을 쓰는 Script같은 경우에는 클라이언트 딴에서 삽입되어, Next.js가 hydration 작업을 마친 후에 동작한다. 이러한 방식은 제일빨리 실행될 필요가 없으며 우선순위가 낮을 때 사용하게 된다.

이러한 방식의 스크립트는 다음과 같은 상황에 많이 사용된다.

  • Tag managers
  • Analytics

lazyOnload

lazyOnload의 속성을 띄는 Script 같은 경우에는, 모든 리소스들이 로딩된 후 idle 한 시간에 fetch되어 정보를 가져올 떄 사용된다. 이러한 방식은 background 나 낮은 우선순위를 가진 스크립트들이 주로 사용된다.

<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

이러한 방식을 사용하는 스크립트는 주로 다음과 같다.

  • Chat support plugins
  • Social media widgets

worker

해당 속성 같은 경우에는, 메일 쓰레드를 정해주어 효율을 높여주는 방식이지만, 아직 테스트 환경이라 안전하지 않다.