프론트/Vue

[Nuxt] 글 표출, SSR 확인, 서버에 올리기

ZestLee 2022. 2. 6. 20:16

2019-11 에 작성된 글입니다.

1. 글 표출

글을 작성할 수만 있고 확인할 수가 없다면, 그건 완벽한 페이지가 아니겠죠? 그렇기 때문에, 저는 작성한 게시글들을 가져와서 제 메인페이지에 보여 줄 것입니다.

이 역시 카드 형태로 보여 줄 텐데요, 카드의 맨 밑까지 스크롤하면 무한으로 글들을 가져오는 형태로 만들겠습니다.

 

메인 페이지에 Cards.vue 를 추가해 줄 텐데요, 이 카드는 다른 페이지에서도 계속 쓸 예정이기 때문에, 컴포넌트 형태로 작성해 주겠습니다.

Components에 Cards.vue 를 추가해 주고, Vuetify의 card 를 이용하여 template을 작성해 줍니다.

그리고 여기에서는 특이하게 vue-infinite-loading이라는 모듈을 사용할 건데요, 스크롤 이벤트를 만들다 발견한 좋은 모듈입니다. 이렇게 잘 만들어진 모듈을 사용한다면, 프로젝트를 만드는 시간이 덜 들겠죠? 😍 사용법은 하단 링크를 통하여 참고해 주세요!

카드의 하단에 추가한 모듈을 적어 줍니다.

<client-only>
  <infinite-loading @infinite="infiniteHandler" spinner="spiral"></infinite-loading>
</client-only>

여기서 client-only는 방금 사용한 모듈 자체가 서버에서 렌더링할 수 없기 때문에 적어 줍니다.

이제 저기에 적어 준 infiniteHandler라는 함수를 작성해야 할 텐데요, 저는 위의 링크를 참고하여 밑과 같이 작성하였습니다.

    infiniteHandler($state) {
      let api = "/posts";
      this.$axios
        .$get(api, {
          params: {
            type: this.content,
            offset: this.offset,
            limit: this.limit
          }
        })
        .then(response => {
          if (response.results.length > 0) {
            for (var i = 0; i < response.results.length; i++) {
              this.cards[0].push(response.results[i]);
            }
            this.offset += 6;
            this.limit += 6;
            $state.loaded();
          } else {
            $state.complete();
          }
        })
        .catch(e => {
          console.log(e);
        });
    }

Cards.vue의 script methods 부분에 추가해 준 함수입니다.

 

data에 offset과 limit의기본값을 0과 5로 설정했고, cards라는 빈 배열을 선언하였습니다.

 

서버 api에 게시글들을 요청하고, 응답해 온 결과물이 1개 이상일 경우 cards라는 빈 배열 안에 넣은 후에 현재 상태를 로드하는 것입니다. 실행하여 스크롤 이벤트를 발생시켜 주세요. 카드들이 잘 나온다면 성공입니다.

2. SSR 확인

현재 상태에서 postman을 실행하여 페이지 소스를 확인해 주세요. 분명 저는 SSR을 위해 Nuxt.js 를 사용했지만, 그 어디에도 현재 카드의 내용이 보이지 않습니다. 이는 데이터를 서버 렌더링으로 가져오지 않았기 때문인데요, 이 비동기 데이터는 무한 스크롤과 같이 사용할 수 없기 때문에, 처음의 몇 개의 카드는 서버에서 렌더링 할 때 데이터들을 가지고 오도록 asyncData를 이용하겠습니다.

asyncData는 pages 컴포넌트 단위에서만 호출할 수 있기 때문에, index.vue 에서 호출한 뒤, 그 데이터들을 Cards 컴포넌트에 전달해 주는 형태로 만들겠습니다.

  asyncData({ params }) {
    return axios
      .get("http://.../api/posts", {
        params: {
          offset: 0,
          limit: 5
        }
      })
      .then(response => {
        if (response.data.results.length > 0) {
          return { cardsData: response.data.results };
        }
      })
      .catch(e => {
        console.log(e);
      });
  }

asynData는 this를 쓸 수 없기 때문에, 다른 함수에서와는 달리 api주소를 하드코딩했습니다.

6개의 게시글을 가져와서 cardsData에 넣고, Cards 컴포넌트를 호출할 때 cardsData도 함께 넘겨 줍니다.

<Cards :cardsData="cardsData" />

그리고, 다시 Cards.vue 컴포넌트로 돌아가서 offset과 limit의 기본값을 5, 10으로 바꿔 준 뒤, 아래 코드를 추가해 줍니다.

props: ["cardsData"],
mounted() {
  this.cards.push(this.cardsData);
}

이는 props로 부모 컴포넌트에서 cardsData를 받아온 뒤, 그 데이터를 현재 컴포넌트의 cards에 push하는 형태입니다.

 

다시 실행한 후 postman을 확인해 주세요.

 

뭔가 이상한 점을 발견하셨나요? 바로, 현재 카드들의 데이터들이 script에서만 표출이 된다는 점인데요, 이는 asyncData로 데이터를 가져왔기 때문에 서버 렌더링을 하여 script에서는 보이지만, 받아와서 데이터를 가공할 땐 mounted 이용했기 때문에 보이지 않는 것입니다. 아까 첨부한 위 링크를 다시 확인해 주세요.

mounted는 서버 렌더링에 사용할 수 없습니다. 따라서, 위에 mounted 를 사용하여 cards에 넣어 줬던 부분을, created로 변경해 주세요.

변경한 후 postman에서 확인하면, 드디어 소스에 우리의 데이터들이 보입니다. 이렇게 SSR까지 완성되었습니다!

3. 서버에 올리기

자, 프로젝트를 완성시켰고, 서버에 올리기만 하면 완료입니다. 이 시리즈에서는 Nuxt.js 위주로 작성할 계획이었기 때문에, 서버에 올리는 작업과 Django 작업은 제 삽질 위주로 간단하게 작성하겠습니다. (혹시 궁금하신 부분이 있으시다면 Nuxt.js 가 아니더라도 자유롭게 댓글 남겨 주세요.)

서버에 현재 프로그램을 올린 후 npm run generate를 실행하니 corejs 관련 에러가 있었습니다.

Module not found: Error: Can't resolve 'core-js/modules/es6.array.iterator' in '/app/.nuxt'

확인하니, 이는 npm update를 하며 발생한 에러였고, corejs를 2로 다운그레이드 하니 이 에러가 사라졌습니다. 아래 링크를 참고해 주세요.

generate를 완료한 후 npm start를 실행하니 서버 주소의 페이지에 아무것도 표출이 되지 않았습니다. 이는 package.json 의 script부분에 호스트 주소를 아래처럼 바꿔 줘야 했습니다.

"scripts": {
  "dev": "nuxt",
  "build": "nuxt build",
  "start": "HOST 0.0.0.0 nuxt start",
  "generate": "nuxt generate"
}

변경 후 다시 실행해 보니 페이지가 정상표출 됐습니다. 하지만, 로컬에서 잘 보이던 카드가 표출되지 않았고, 로그를 확인하니 cors 에러로 서버에서 데이터를 가져오는 것이 불가능했습니다.

 

이는 데이터를 JSONP로 가져다 쓰거나, 클라이언트 측에서 chrome에서 특정 앱을 다운 받아서 접속하면 가능하지만, JSONP는 get방식일 때만 가능하고, 모든 사용자가 특정 앱을 다운 받는 것은 현실적으로 불가능하기 때문에 백앤드 쪽을 변경해 줬어야 했습니다.

 

다시 실행해 보니, 로그인부터 글 작성까지 정상적으로 작동하였습니다.