후기) 브런치 메인페이지


패스트 캠퍼스 프론트 엔드 스쿨에서 진행했던 1주일 프로젝트 브런치 페이지의 후기입니다.

프로젝트의 시작 / 주제 정하기

학원에서 자바스크립트 수업을 막 끝낸 시점에서 우리들은 1주일 짜리 팀프로젝트를 진행하게 되었다. 어쩌다 보니 나는 조장이 되었고 팀원들도 짜였다. 왜지..

팀원분 중 한 분이 깔끔한 디자인을 가진 페이지를 추천해본다며 브런치 페이지를 추천해주셨다. 슬라이드, 마우스 휠 이벤트 등 우리가 배운 자바스크립트를 활용해볼만한 기능 들이 녹아들어있다 생각되어서 이 브런치의 메인페이지를 클론하게 되었다. 일주일이라는 시간이 매우 긴데도 불구하고 하나의 페이지만을 클론한 이유는 우리는 이제 자바스크립트의 이론을 끝낸 몸이었고, 해당 프로젝트를 진행할 때, 고정된 데이터가 아닌 서버와 DB를 연결하여 진해해보고 싶었기에 하나의 페이지를 제작하더라도 꼼꼼하게 만들어보기로 했다.

프로젝트의 준비 / 구현기능 정하기

페이지가 하나 뿐이더라도 총 4개의 섹션이 존재해서 3명의 팀원이서 배분하기 쉬웠다. 먼저 내가 서버와 DB구축 및 메인 슬라이더와 공지사항파트를 맡았다. 그 외의 부분을 팀원의 역량과 자신의 욕심에 따라 배분하고 진행하기로 했다.

팀의 컨벤션으로 css선택자와 변수 컨벤션을 정하고 진행했다. 이때 문서화를 잘 했어야 했다.

프로젝트의 변동 / 추가 팀원

다른 조에서 팀원 한 분이 편입을 오게되었다. 이미 우리조원들은 기능 구분 및 컨벤션을 다 회의로 정했기에 큰 문제가 없다고 판단하여 새로운 팀원을 받고 헤더 파트를 맡겼다.

프로젝트 / 서버와 DB구축

난 분명 프론트엔드 개발자이지만, 화면에 보여주는 데이터는 백엔드가 건네주는 것이기 때문에 백엔드에 대한 지식도 필요하다 생각했다. 때문에 내가 복잡하고 보안성 있는 서버가 아니더라도 직접 express를 이용하여 서버를 구축하고 mysql를 이용하여 DB를 다뤄보기로 했다. 일단 프로젝트 필요한 데이터는 작가, 글, 이미지, 키워드 였다. 이 정보들이 오밀조밀하게 관계를 가지고 있는 구조로 DB를 구현하기로 했다.

people테이블은 작가들의 정보, category테이블은 글의 카테고리정보, peopleCategory테이블은 작가들의 카테고리 정보를 넣어둔 테이블이다. 작가들은 인당 2개의 카테고리를 가지고 있었다.

이렇게 DB를 구현하고 각각 팀원들이 필요한 데이터를 서버에서 건네주기 위해서 쿼리문을 짜기 시작했다. 필요한 쿼리문은 2가지였다. 저장되어 있는 글들을 가져오는 것 그리고 클라이언트가 카테고리를 보내오면 해당 카테고리에 속하는 사람들의 정보를 보내주는 것이었다.

앞의 요청을 간단히 해결했지만, 뒤의 요청이 문제가 되었다. 하나의 카테고리를 클라이언트가 보내면 해당 카테고리를 받아서 먼저 category에 있는 id를 찾고, 카테고리의 id로 peopleCategory의 peopleId를 찾는다. 그러면 해당 카테고리를 가지고 있는 사람들이 나온다. 이제 이 사람들이 가지고 있는 카테고리들을 알아야한다. 그러면 일단 이 사람들id정보를 킵해두고, 다시 peopleId까지 찾은 다음 peopleCategory테이블에서 peopleId로 사람들의 카테고리를 가져온 다음 이전에 찾은 정보와 합쳐서 보내줘야했다. 이 sql문을 짜는데 정말 어려웠던것 같다.

우여곡절 끝에 서버와 DB 그리고 RESTAPI모두 구축을 완료했고 mysql의 DB정보를 export해서 팀원들의 mysql에 심어준 후 서버코드는 github에 올려서 공유했다. 이제 나도 프론트엔드 개발을 할 수 있다 ㅠㅠ.

프로젝트 / webpack 설정

일단 내가 조장이기에 웹팩 설정이 나의 몫이 되었다. webpack.config.js를 이용하여 번들링 경로와 css 번들링을 설정하였다.

module.exports = {
  // entry file
  entry: ['@babel/polyfill','./src/js/main.js'],
  // 컴파일 + 번들링된 js 파일이 저장될 경로와 이름 지정
  output: {
    path: path.resolve(__dirname, 'dist/js'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src/js'),
        exclude: /node_modules/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-proposal-class-properties']
          }
        }]
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader:'css-loader',
            options: {
              url: true,
              import:true
            }
          },
          "postcss-loader",
          {
            loader: 'resolve-url-loader',
            options: {
              attempts: 1
            }
          }
        ]
      },
      {
        test:/\.(png|jpe)$/,
        loader: 'file-loader',
        options: {
          publicPath: './dist/'
        }
      }
    ]
  },

프로젝트 / 슬라이드

자바스크립트를 짤 때 주의 했던 점은 번들링을 진행할 때, 혹시라도 자바스크립트는 하나의 네임스페이스를 사용하니까 변수명이 중복되면 에러가 분명 날것이라는 점이었다. 때문에 변수의 이름과 함수의 이름은 명시적으로 구분될 수 있게 지어주었다.

슬라이드를 구현함에 있어서 내가 제작할 슬라이드는 버튼을 이용한 이동, 네비게이션 숫자를 이용한 이동이 있었다. 때문에 이 두 기능을 하나로 묶을 필요가 있었다.

const checkNowSlidePage = pageNum => {
  [...mainSlideNumber.children].forEach( (li, idx) => {
    li.classList.toggle("main-nowPage",idx === pageNum);
  })
}
const mainSlideBtnFunction = (function(){
  let slideNum = 0;
  const countSlide = (clickBtnNum)=> {
    if(typeof clickBtnNum === "number"){
      slideNum = clickBtnNum
    }
    mainSlidePrevBtn.classList.toggle("no-show",slideNum === 0);
    mainSlideNextBtn.classList.toggle("no-show",slideNum === 8);
    mainUl.style.transform = `translateX(-${slideNum*960}px)`;
    checkNowSlidePage(slideNum);
  }
  const clickMainSlideNext = clickBtnNum => {
    ++slideNum;
    countSlide(clickBtnNum)
  };
  const clickMainSlidePrev = clickBtnNum => {
    --slideNum;
    countSlide(clickBtnNum)
  }
  return {
    clickMainSlideNext,
    clickMainSlidePrev
  }
})();
mainSlideNumber.onclick = e => {
  if( !e.target.matches(".main-silde-numbering li a")) return;
  [...mainSlideNumber.children].forEach((li,idx) => {
    if(li === e.target.parentNode){
      mainSlideBtnFunction.clickMainSlideNext(idx)
    }
  })
}

숫자 네비게이션에 클래스 토글이벤트를 달아주고 클로저를 이용하여 변수를 가려주고 translateX를 이용하여 보이는 페이지를 이동시켰다. 해당 DOM에 transition을 줌으로 슥슥 움직이는 애니메이션도 구현할 수 있었다. 나중에서야 알게되었지만, react에서 props를 이용하여 코드를 재활용한 느낌으로 이동 기능을 재활용하였다.

프로젝트 / 카카오 로그인API

조원들과 상의한 필수 구현 기능을 모두 구현하고 시간이 조금 남아서 카카오 로그인 API를 이용하여 로그인을 구현하였다. 카카오로그인 SDK를 이용하여 구현하였기에 크게 어려운 점은 없었다.

if(Kakao.Auth.getAccessToken()){
    Kakao.API.request({
    url:'/v2/user/me',
    success: res => {
      loginInfo = JSON.parse(JSON.stringify(res))
      console.log(loginInfo);
      Kakao.API.request({
        url:'/v2/user/me',
        success: res => {
          loginInfo = JSON.parse(JSON.stringify(res));
          sideInfo.innerHTML = `<img class="kakao-profile-Img" src=${loginInfo.properties.thumbnail_image}></img>
          <p class="slogan">${loginInfo.kakao_account.email}</p>
          <p class="slogan-writer">${loginInfo.properties.nickname}</p>
          <a id="brunchSigninButton" href="javascript:logoutFormWithKakao()" 
          class="#side_request btn_apply_author"><button
                  class="btn-request">로그아웃하기</button></a>`;
          loginstateBtn.innerHTML = `<a href="javascript:logoutFormWithKakao()" class="f-r btn-request btn-default">로그아웃</a>`
        }
        ,fail: err => {
          console.log(JSON.stringify(err))
        }
      })
      // checkLogin.innerHTML= loginInfo.properties.nickname;
      // kakaoImg.innerHTML = `<img src="${loginInfo.properties.thumbnail_image}"/>`
    }
    ,fail: err => {
      console.log(JSON.stringify(err))
    }
  })}

마무리

처음으로 서버와 DB를 연동하는 프로젝트를 진행하여 프로젝트 발표 시간까지 잘 마쳐서 끝을 낼 수 있었다. 하지만 중간에 합류한 팀원이 숙지할 컨벤션이 문서화 되어 있지 않아서 css번들링 작업을 할 때, 고생을 많이 했지만 그래도 팀원 모두가 불화 없이 같이 진행하여 의미있는 프로젝트였다고 생각한다.

좋은 웹페이지 즐겨찾기