ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Nuxt.js] Nuxt 학습기 - (1) 개념 및 설치
    Front-End(Web)/Vue 2021. 11. 16. 01:06
    반응형

    🤔 서론

    일전 Next.js를 공부하면서도, 그리고 회사의 이전 포털 사이트에 Nuxt.js를 사용하면서 SSR 프레임워크 환경을 어느정도 경험했었다.

    SSR(Server Side Rendering) 개념 자체가 이슈인 만큼, 학습뿐만이 아닌 다양한 경로(유튜브 등)를 통해 이를 접해왔었다.

     

    회사의 리뉴얼 버전 코드에선 팀장님께서 Vue를 활용한 임의의 SSR 환경을 구성해주셨고, 여기서 역시 Nuxt와 유사한 개발경험을 해볼 수 있었다. (head 프로퍼티, asyncData 등)

     

    이러한 개념들을 근본적으로 Nuxt.js 환경에서 개발해보고, 또 이외의 다양한 기능들을 학습해보고자 오픈API를 활용한 간단한 Nuxt.js 토이 프로젝트를 진행하였다.

     

    * Cocktail DB : https://www.thecocktaildb.com/

     

    이후 포스팅에선 Nuxt.js에서 활용한 주요 기능들을 소개하겠지만,

    이에 앞서 기본적으로 SSR과 CSR 개념을 우선 재정리하고, 여느때처럼 Nuxt.js 개념과 초기세팅을 한번 정리해보고자 한다!


    📗 SSR (Server-Side Rendering)

    SSR은 말 그대로 서버에서 페이지를 렌더링하여 클라이언트(브라우저)로 보내 화면에 표시하는 기법을 의미한다.

    현재, React, Vue 등 트렌드를 선도하던 CSR(Client-Side Rendering) 및 SPA(Single Page Application) 기법이 통용됨에도 불구하고, 서버에서 정적인 페이지를 선구성해서 브라우저로 보내주는 상대적으로 오래된 방식이 재조명된 이유를 짚고 넘어가야겠다.

     

    - SPA(Single Page Application) & CSR(Client-Side Rendering)

    더보기

    페이지를 불러오지 않고, 현재의 페이지를 동적으로 다시 작성함으로서 사용자와 소통하는 웹 어플리케이션이나 웹사이트를 말한다. 이러한 접근은 연속되는 페이지들 간의 사용자 경험의 간섭을 막아주고, 애플리케이션이 더 사용자 친화적으로 동작하도록 만들어준다.

    SPA웹 어플리케이션을 Single Page(HTML)로 만드는 기법이다.

    즉, 최초 한 번만 페이지 전체를 로딩한 후, 데이터만 변경하여 사용할 수 있는 애플리케이션을 의미한다.

    매 요청시마다 서버로부터 리소스를 받아 화면에 그리던 전통적인 SSR 방식에 비해, SPA는 트래픽을 감소시키고 사용자에게 최적화된 환경을 제공하는 등 다양한 장점을 보였다.

     

    이렇게 최초 페이지를 로딩한 뒤로는, 페이지 리로딩(깜빡임) 없이 필요한 부분만 서버로부터 받아 화면을 갱신하는 렌더링을 구현하는 것이 바로 CSR 인 것이다.

     

    * CSR 장점

    • 자연스러운 UX
    • 필요한 리소스만 부분적으로 로딩 (성능)
    • 서버의 템플릿 연산을 클라이언트로 분산 (성능)
    • 컴포넌트 별 개발 용이 (생산성)
    • 모바일 앱 개발을 염두한다면, 동일한 API를 사용하도록 설계 가능 (생산성)

     

    * CSR 단점

    • JS파일을 번들링해서 한번에 받기 때문에 초기 구동속도가 느림 (Webpack의 Code Splitting으로 해결 가능)
    • SEO(검색 엔진 최적화) 가 어려움 (웹 크롤링 봇이 JS를 실행시킬 수 없음)
    • 보안 이슈 (프론트엔드에 비즈니스 로직이 최소화되야함)

     

    - SSR

    서버 사이드 렌더링. 전통적인 MPA(Multiple Page Application)에서 사용되었던 방식이다.

    말 그대로 서버에서 사용자에게 보여줄 페이지를 모두 렌더링하여, 각 요청시에 서버로부터 불러오는 방법인 것이다.

    이렇게 초기 렌더링에서 HTML을 받아온 뒤, JS로 웹페이지를 완전하게 작동시키는 것이다.

     

    * SSR 장점

    • CSR에 비해 초기 로드속도가 빠름
    • SEO(검색 엔진 최적화) 에 용이 (페이지가 미리 구성되어있어 웹 크롤링 봇이 정보를 가져올 수 있음)

     

    * SSR 단점

    • 페이지 이동 시 화면 깜빡임 (재요청)
    • 페이지 이동 시 불필요한 템플릿도 중복 로딩 (성능)
    • 서버 렌더링에 따른 추가적인 부하 (성능)
    • 모바일 앱 개발시 추가적인 백엔드 작업 필요 (생산성)

    단, 이는 old SSR 방식이다. 이 단점을 보완하기 위해 새로운 SSR 개념인 Universal SSR 이 등장하게 된 것이다.

    Nuxt.js 역시 Universial 을 구현한 프레임워크로, Nuxt.js의 소개와 함께 이 개념에 대해 짚어보도록 하겠다.


    📗 Nuxt.js 란?

    Nuxt.js는 Vue.js 프레임워크 기반의 개발환경 구축에 도움을 주는 프레임워크이다.

    즉, Vue.js 프로젝트에 사용되는 여러 유용한 라이브러리들을 기본적으로 탑재하고 있는 것이다.

    • Vue 2
    • Vue Router
    • Vuex
    • Vue Server Renderer
    • vue-meta
    • vue-loader
    • babel-loader
    • Webpack

     

    또한, Nuxt.js는 Vue + 라이브러리 구조이기에, 아래와 같은 특징들을 가진다.

    • Vue 파일 사용
    • 코드 분할 자동화
    • SSR(서버 사이드 렌더링)
    • 비동기 데이터 기반의 강력한 라우팅 시스템
    • 정적 파일 전송
    • ES2015+ 지원
    • JS & CSS 코드 번들링 및 압축
    • <head> 요소관리 (<title>, <meta> 등)
    • 개발 중 Hot module 대체
    • 전처리기 지원 : SASS, LESS, Stylus 등

     

    마지막으로, Nuxt.js를 사용했을 때 강점들을 확인하면 이를 사용하는 정당성이 어느정도 납득이 갈 것이다.

    • Nuxt 설치만으로 이미 scaffolding(프로젝트 구조화)이 되므로, 프로젝트 구조에 대한 고민이 적어진다.
    • vue.js에서 잡던 라우팅을, Nuxt Pages 디렉토리 구조로 형성할 수 있다.
    • Layout, Store, Middleware 와 같은 요소들은 이미 구분지어주고, 필요한 항목들을 처리하기에 순전히 개발에만 집중가능.
    • SSR에 필요한 요소가 준비되어 있다.
    • Webpack을 통한 빌드 시스템이 구현되어 있다. npm run 만 해주면 된다.
    • Nuxt.js 를 사용해야 하는 10가지 이유(링크) : http://develophotograph.blogspot.com/2018/11/nuxt-10.html  

     

    - 설치 및 실행

    // 설치
    npx create-nuxt-app <pjt-name>
    yarn create nuxt-app <pjt-name>
    npm init nuxt-app <pjt-name>

    설치는 위 커멘드들로 실시할 수 있다. (vue-cli를 통해서도 설치 가능하나 권장되지 않음.)

    Nuxt.js 프로젝트 설치가 되면, 초기설정 옵션들이 진행된다. 각 리스트는 해당 링크를 참조하자!

     

    // 실행
    npm run dev
    yarn dev

    실행을 했을 때 브라우저에서 보이는 화면이다! (기본포트는, https://localhost:3000)

     

    - 디렉토리 구조

    앞서 언급했듯, Nuxt.js는 기본적인 Scaffolding을 제공한다. 그만큼, 각 디렉토리는 존재의의가 있으며 이를 알아보도록 하자.

    1) assets

    • css, image, font 와 같은 리소스들을 포함
    • URL loader가 관리하여, Nuxt 프로그램 내 절대경로를 통해 asset 파일들 접근가능
    • 프로젝트 루트 디렉토리에 직접적으로 번들. 따라서, /<파일경로> 접근가능

     

    2) components

    • 애플리케이션에서 사용될 컴포넌트들을 포함
    • Nuxt.js 비동기 데이터 함수인 asyncData(), fetch() 등을 사용할 수 없다.

     

    3) layouts (디렉토리명 변경불가)

    • 애플리케이션 전체에 대한 레이아웃 컴포넌트를 포함
    • 기본적으로 default.vue 가 생성됨. 해당 컴포넌트의 형상이 모든 페이지에 통용됨.

     

    4) middleware

    • 애플리케이션 구동에 사용될 middleware를 포함
    • middleware는 페이지 또는 레이아웃이 렌더링되기 전에 실행된다. 바인딩된 페이지(혹은 레이아웃)가 렌더링되기 전 매번 실행된다.

     

    5) node_modules

    • Nuxt 프레임워크의 핵심기능을 확장, 통합, 추가할 수 있다. 사용자가 직접 모듈을 작성할 수 있음.

     

    6) pages (디렉토리명 변경불가)

    • 실제 애플리케이션의 페이지 구성을 포함
    • 디렉토리의 구조에 따라 router가 자동으로 형성된다.

     

    7) plugins

    • 애플리케이션에 바인딩될 외부 혹은 내부 plugins 들을 포함
    • 애플리케이션이 인스턴스화 되기 전에 실행되며, 전역적으로 등록할 함수 또는 상수를 삽입한다.

     

    8) static (디렉토리명 변경불가)

    • 정적 파일 포함. 구성에 따라 html, js 파일도 포함할 수 있다.
    • 프로젝트 루트 디렉토리에 직접적으로 번들. 따라서, /<파일경로> 접근가능

     

    9) store

    • 애플리케이션에 사용될 vuex store 파일들을 포함한다. 
    • 기본적으로 비활성화 상태이며, store 디렉토리에 index.js 파일을 작성하면 활성화된다.
    • 구성에 따라 모듈 형태의 store를 형성할 수 있다.

     

    - 설정

    요즘, 회사의 프로젝트 혹은 개인 프로젝트를 진행하면서, 매우 중요하게 생각되는 부분이 바로 개발환경의 설정이다.

    각각의 프레임워크(라이브러리) 및 툴들은 본인의 config 파일을 가지며, 이를 설정함에 따라 개발자들이 상대적으로 편하게 개발할 수 있는 환경이 구성될 수 있음을 많이 느꼈다.

    (공식문서 : https://develop365.gitlab.io/nuxtjs-0.10.7-doc/ko/guide/configuration/ )

     

    위같은 취지에서, Nuxt.js 의 설정파일인 nuxt.config.js (루트 디렉토리) 를 설정하는 다양한 방법도 한 번 짚고 넘어가고자 했다.

    export default {
      // Target: https://go.nuxtjs.dev/config-target
      target: 'static',
    
      // Global page headers: https://go.nuxtjs.dev/config-head
      head: {
        title: 'nuxt-cocktail',
        htmlAttrs: {
          lang: 'en'
        },
        meta: [
          { charset: 'utf-8' },
          { name: 'viewport', content: 'width=device-width, initial-scale=1' },
          { hid: 'description', name: 'description', content: '' },
          { name: 'format-detection', content: 'telephone=no' }
        ],
        link: [
          { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' }
        ]
      },
    
      // Global CSS: https://go.nuxtjs.dev/config-css
      css: [
        '@/assets/global.scss',
        '@/assets/transition.scss',
      ],
      loading: '~/components/common/Loader.vue',
      // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
      plugins: [
        { src: '~/plugins/greater.ts' },
      ],
      // Auto import components: https://go.nuxtjs.dev/config-components
      components: true,
    
      // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
      buildModules: [
        // https://go.nuxtjs.dev/typescript
        '@nuxt/typescript-build',
      ],
    
      // Modules: https://go.nuxtjs.dev/config-modules
      modules: [
        'nuxt-session',
      ],
      // Build Configuration: https://go.nuxtjs.dev/config-build
      build: {
        vendor: ['axios'],
      }
    }

    이는, 내가 토이 프로젝트를 진행하며 간단히 설정한 config 파일로, 각 프로퍼티의 설정방법에 대해 한번 훑어보겠다!

     

     

    1) build

     

    Loader, 파일이름, 웹팩구성 및 변환 과 같은 build 단계에 대한 다양한 설정을 구성할 수 있다.

    • analyze(Boolean, Object) : webpack-bundle-analyzer 을 통한 번들링 시각화, 최적화 사용 여부. 기본은 false
    • babel(Object) : JS, Vue 파일의 babel 사용자 정의. 기본은 { presets: ['@nuxt/babel-preset-app'] }
    • extend(Function) : 서버 번들, 클라이언트 번들 각 2회에 호출되는 확장 시 옵션을 적용.
    • filenames(Object) : 번들 파일명의 사용자 정의.
    • loaders(<Object[]>) : Webpack Loaders 의 사용자 정의. 
    • plugins(Array) : Webpack에 적용할 플러그인 추가. 기본값은 빈 배열([]).
    • postcss(Array) : postcss 옵션의 사용자 정의.
    • publicPath(String) : Nuxt는 성능향상을 위해 dist 파일들을 CDN에 업로드하는데 이 경로값 설정. 기본은 '/_nuxt_/'
    • vendor(<String[]>) : vendor.bundle.js 파일 내 모듈을 추가하여 번들의 용량을 줄여준다. axios 같은 외부모듈 사용에 유용.

    2) cache

     

    컴포넌트의 캐싱유무를 설정하여, 렌더링 성능을 향상시킬 수 있다. 타입은 Boolean (or Object), 기본값은 false 이다.

    Object로 설정한다면, max(캐시에 사용되는 컴포넌트 수), maxAge(캐시시간) 2개 프로퍼티를 설정할 수 있다.

    module.exports = {
      cache: true
      // 또는
      cache: {
        max: 1000,
        maxAge: 900000
      }
    }

    캐시가 너무 커지면 메모리 공간을 많이 차지하게 되므로 적당한 값을 선정하는 것이 중요하다.

     

    3) css

     

    모든 페이지에서 전역으로 사용할 CSS 파일 / 모듈 / 라이브러리를 설정할 수 있다. 타입은 Array (String or Object).

    module.exports = {
      css: [
        // node.js 모듈을 로드합니다.
        'hover.css/css/hover-min.css',
        // 전처리기가 사용된 node.js 모듈.
        { src: 'bulma', lang: 'sass' },
        // 프로젝트 내부의 Css 파일
        '~assets/css/main.css',
        // 프로젝트의 sass 파일
        { src: '~assets/css/main.scss', lang: 'scss' } // sass 대신 scss
      ]
    }

     

    4) dev

     

    개발 또는 프로덕션 모드를 정의할 수 있다. 타입은 Boolean, 기본값은 true.

    Nuxt cmd 로 프로퍼티가 덮어씌워진다.

    • true : nuxt, nuxt dev
    • false : nuxt build, nuxt start, nuxt generate
    module.exports = {
      dev: (process.env.NODE_ENV !== 'production')
    }

     

    5) env

     

    클라이언트 및 서버에서 사용 가능한 환경변수를 정의한다. 타입은 Object.

    env 파일 내, BASE_URL 이 설정되어있다면 baseUrl 프로퍼티를 추가 가능하며, 기본 포트는 3000 이다.

    module.exports = {
      env: {
        baseUrl: process.env.BASE_URL || 'http://localhost:3000'
      }
    }

     

    6) generate

     

    nuxt generate 커멘드로 형성되는 정적 웹 어플리케이션에 관한 설정을 할 수 있다. 타입은 Object.

    • dir(String) : nuxt generate 진행 시 폴더명. 기본값은 'dist'.
    • minify(Object) : html-minifier (HTML 코드 경량화) 관련 설정
    • path(Array) : 동적 경로값(_id.vue 등)은 generate 가 무시된다. 이것에 대한 URL 경로를 수동으로 설정하는 옵션.
    const axios = require('axios')
    
    module.exports = {
      generate: {
        routes: function () {
          return axios.get('https://my-api/users')
          .then((res) => {
            return res.data.map((user) => {
              return '/users/' + user.id
            })
          })      
        }
      }
    }

     

    7) head

     

    어플리케이션의 모든 기본 meta 데이터를 정의할 수 있다. 타입은 Object.

    module.exports = {
      head: {
        titleTemplate: '%s - Nuxt.js',
        meta: [
          { charset: 'utf-8' },
          { name: 'viewport', content: 'width=device-width, initial-scale=1' },
          { hid: 'description', name: 'description', content: 'Meta description' }
        ]
      }
    }

     

    8) loading

     

    Nuxt.js 사용 시 기본적으로 불러올 로딩 컴포넌트를 사용자 정의 할 수 있다.

     

    * Progress Bar

    module.exports = {
      loading: {
        color: 'blue',		// css 색상
        failedColor: 'red',		// catch(error) 시 색상
        height: '5px',		// bar 높이
        duration: '5000',		// 최대 진행시간
      }
    }

     

    * Loading 컴포넌트

    • start(), 필수 : 경로가 변경될 때 호출되며, 이 때 컴포넌트가 보여짐.
    • finish(), 필수 : 경로가 로드되었을 때(fetch 완료) 호출되며, 이 때 컴포넌트는 숨겨짐.
    • fail(), 옵션 : 경로가 로드되지 않았을 때 호출. (fetch error 등)
    • increase(num), 옵션 : 경로가 로딩중인 동안, num 정수가 100보다 작을 때 호출.
    // src/components/loading.vue
    
    <template lang="html">
      <div class="loading-page" v-if="loading">
        <p>로딩중...</p>
      </div>
    </template>
    
    <script>
    export default {
      data: () => ({
        loading: false
      }),
      methods: {
        start () {
          this.loading = true
        },
        finish () {
          this.loading = false
        }
      }
    }
    </script>
    
    <style scoped>
    .loading-page {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(255, 255, 255, 0.8);
      text-align: center;
      padding-top: 200px;
      font-size: 30px;
      font-family: sans-serif;
    }
    </style>
    // nuxt.config.js
    
    module.exports = {
      loading: '~components/loading.vue'
    }

     

    9) plugins

     

    Root Vue.js 어플리케이션을 인스턴스화 하기 전에 실행할 Javascript 플러그인을 정의할 수 있다. 타입은 Array(String or Object).

    module.exports = {
      plugins: ['~plugins/vue-notifications']
    }

    이 플러그인은, 실제 pluings 디렉토리에 존재해야 한다.

    import Vue from 'vue'
    import VueNotifications from 'vue-notifications'
    
    Vue.use(VueNotifications)

     

    10) rootDir

     

    프로젝트의 워크스페이스를 정의한다. 타입은 String, 기본은 process.cwd() 이다.

    기본경로를 변경하는데 쓰이며, 대신 node_modules가 rootDir 폴더내에 있어야 하므로 이를 이동시키거나 srcDir 옵션을 설정한다.

     

    11) router

     

    Nuxt.js Router의 사용자 정의를 한다.

    • base : 어플리케이션 기본 URL.
    • mode : 기본값은 'history' 로, 이외 'hash' 등을 설정할 수 있다. 하지만, SSR로 변경하는 것을 권장하지 않는다.
    • linkActiveClass : 현재 도메인과 일치하는 <nuxt-link> 태그의 클래스를 정의. 기본은 'nuxt-link(-exact)-active'
    • scrollBehavior : 페이지가 렌더링될 떄마다 스크롤 위치에 대한 사용자 정의 동작을 설정한다. 기본적으론, 최상단으로 감.
    • middleware : 모든 페이지에 대한 기본 미들웨어를 설정한다.
    • extendRoutes : Pages 폴더구조에 따른 기본적인 Router에, 사용자 정의 경로를 추가하는 옵션이다.

     

    12) srcDir

     

    src 디렉토리의 경로를 사용자 정의한다.

     

    13) transition

     

    페이지 이동 시, transition CSS의 프로퍼티를 설정한다. 타입은 String or Object, 기본 및 예제는 아래를 참고하자.

    // Default
    import Vue from 'vue'
    import VueNotifications from 'vue-notifications'
    
    Vue.use(VueNotifications)
    
    
    // Custom
    module.exports = {
      transition: 'page'
      // or
      transition: {
        name: 'page',
        mode: 'out-in',
        beforeEnter (el) {
          console.log('Before enter...');
        }
      }
    }

    Nuxt.js를 본격적으로 공부해보면서, SSR 개념을 다시금 짚고 넘어가고 초기설정 방법과 디렉토리 구조 등을 정확히 알 수 있었다.

     

    Nuxt.js가 기본적으로 SSR을 지원하는 Vue.js 기반 프레임워크이나, 위에서 언급한것처럼 이 SSR모드는 기존의 방식과는 조금 다르다.

    다음, 포스팅은 위를 포함한 Nuxt.js의 3가지 렌더링 모드 (SPA, Universal, Static)에 대해 좀 더 자세히 짚고 넘어가고자 한다!

     

    [출처]

     

    반응형
Designed by Tistory.