프론트 공부/웹과 API, 네트워크

리액트 프로젝트 하나로 두 개 이상의 파이어베이스 사이트에 호스팅하는 법

홍구리당당 2025. 2. 1. 20:35

0. 배경

나는 웹 호스팅할 때 파이어베이스를 쓴다.

근데 한 프로젝트에다가 하나의 파이어베이스 웹 콘텐츠를 연결해서 호스팅하는 건 쉬운데, 두 개 이상의 사이트에 호스팅해야 할 일이 생겼다.

단순히 하나의 build 파일을 두 개의 사이트 각각에 똑같이 배포하는 게 아니라, (1) .env.development 가 적용된 dev 용 build 파일을 만들고 이걸 dev-website 에 배포하기, (2) .env.production 이 적용된 prod 용 build 파일을 만들고 이걸 production-website에 배포하기. -> 이렇게 dev용, prod용 환경을 따로따로 만들고 각 사이트에 배포해야 하는 것이다.

따라서 이번 포스팅에선

  1. .env.development, .env.production 각 환경변수 파일을 가지고 dist/development, dist/production 이라는 빌드 파일을 만드는 방법
  2. .firebaserc, firebase.json 파일을 수정해 두 개 이상의 파이어베이스 웹 콘텐츠와 연결하는 방법

이렇게 두 개를 작성할 것이다.

1. .env.development, .env.production 파일 각각 build 파일을 만들고 빌드파일 위치 수정하기.

(1) npm i env-cmd 를 통해 라이브러리를 설치한다.

리액트는 npm run build할 때 적용될 .env 파일 우선순위를 강제하기 때문에, .env.development 파일을 .env.production 보다 먼저 적용되게끔 커스텀할 수 없다. npm run build하면 무조건 env 우선순위에 따라 환경 변수를 적용한다.

따라서 env-cmd 패키지를 통해 어떤 env 파일을 적용할지 커스텀해줘야 한다. (어떻게 env-cmd 패키지는 이걸 가능케 하냐면... 나중에 따로 포스팅해보겠음.)

(2) package.json의 scripts 명령어를 원하는대로 작성한다.

package.json 에 가보면 "scripts" 가 아마

"scripts":{
  "start": "react-scripts start",
  ...
}

이런 식으로 되어있을텐데, react-scripts를 쓴다면 아마 build 파일은 ./build 경로에 생성된다. (vite 를 쓴다면 아마 /dist 를 쓰던 걸로 기억함...) 참고로 나는 타입스크립트 import 문 절대경로때문에 craco를 쓰는데, craco 로 build해도 ./build 경로에 빌드 파일이 생성된다.
이제 여기에 원하는 스크립트를 추가하면 된다.

예를 들어 .env.development 를 사용해 npm start가 되게 하고 싶으니까, 대충 start:dev 라는 명령어를 만들어보겠다.

"scripts":{
  "start": "craco start",
  ...
  "start:dev": "env-cmd -f .env.development craco start"
}

이렇게 추가하면 된다.

내가 원하는 건 .env.development 로 시작하는 거 하나, .env.production으로 시작하는 거 하나 이렇게 2개 만드는 거니까 아래처럼 작성하면 될 것. (.env.development, .env.production 두 개의 env 파일밖에 없다면 그냥 npm run start 를 해도 바로 .env.development가 적용될테지만, 난 뭔가 명시적으로 dev, prod 명령어를 나누고 싶었기 때문에 굳이 start:dev 명령어를 만들어줬다.)

"scripts":{
  "start": "craco start",
  ...
  "start:dev": "env-cmd -f .env.development craco start",
  "start:prod": "env-cmd -f .env.production craco start",
}

마찬가지로 dev 환경 build 파일 만들기, prod 환경 build 파일 만들기 이렇게 2 개의 명령어를 만들고 싶다면 아래처럼 작성하면 된다. 참고로 빌드할 때 빌드 파일 위치를 변경하기 위해 명령어를 조금 더 추가해줬다.
중요한 건, BUILD_PATH 를 설정할 때 윈도우랑 맥에서의 명령어가 조금 다르다는 거다!

"scripts":{
    ....
    "build:dev:window": "set \"BUILD_PATH=.\\dist\\development\" && env-cmd -f .env.development craco build",
    "build:prod:window": "set \"BUILD_PATH=.\\dist\\production\" && env-cmd -f .env.production craco build",
    "build:dev:mac": "BUILD_PATH='./dist/development' && env-cmd -f .env.development craco build",
    "build:prod:mac": "BUILD_PATH='./dist/production' && env-cmd -f .env.production craco build",
}

이제 cmd에서 npm run build:dev:window 혹은 npm run build:dev:mac 을 실행하면, dist/development 폴더에 빌드 파일이 만들어진다.

(3) firebase 설정해주기
이전에 firebase init 및 hosting을 했다면 이미 .firebaserc, firebase.json 파일이 만들어졌을 것이다.

먼저 .firebaserc 파일엔 간단하게 두 번째 호스팅 사이트를 추가해주기만 하면 된다

{
  "projects": {
    "default": "firebase-my-project"
  },
  "targets": {
    "firebase-my-project": {
      "hosting": {
        "prod-web": [
          "my-website"
        ],
        // >>>> 새로 추가하기
        "dev-web": [
          "my-website-dev"
        ]
        // <<<<
      }
    }
  },
  "etags": {},
  "dataconnectEmulatorConfig": {}
}

firebase.json엔 이렇게 수정해주자..

{
  "hosting": 
  // >>>> 새로 추가하기
  [
    {
      "public": "dist/development",
      "target": "dev-web",
      "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
      "rewrites": [
        {
          "source": "**",
          "destination": "/index.html"
        }
      ]
    },
    // <<<<
    {
      "public": "dist/production",
      "target": "prod-web",
      "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
      "rewrites": [
        {
          "source": "**",
          "destination": "/index.html"
        }
      ]
    }
  // >>>> 새로 추가하기
  ]
  // <<<<
}

좀 더 간편하게 배포하기 위해 (계속 firebase deploy --only hosting:... 명령어 쓰기 귀찮으니까.) 나는 아래와 같이 package.json도 수정해주었다.

  "scripts": {
    "start": "craco start",
    "test": "craco test",
    "eject": "craco eject",
    "build": "craco build",
    "start:dev": "env-cmd -f .env.development craco start",
    "start:prod": "env-cmd -f .env.production craco start",
    "build:dev": "set \"BUILD_PATH=.\\dist\\development\" && env-cmd -f .env.development craco build",
    "build:prod": "set \"BUILD_PATH=.\\dist\\production\" && env-cmd -f .env.production craco build",
    "deploy:dev": "npm run build:dev && firebase deploy --only hosting:dev-web",
    "deploy:prod": "npm run build:prod && firebase deploy --only hosting:prod-web",
    "build:dev:mac": "BUILD_PATH='./dist/development' && env-cmd -f .env.development craco build",
    "build:prod:mac": "BUILD_PATH='./dist/production' && env-cmd -f .env.production craco build",
    "deploy:dev:mac": "npm run build:dev:mac && firebase deploy --only hosting:dev-web",
    "deploy:prod:mac": "npm run build:prod:mac && firebase deploy --only hosting:prod-web"
  },

그럼 이제 npm run deploy:dev 만 써도 dev-website에, npm run deploy:prod 를 쓰면 prod-website에 배포될 것이다.