4월 첫째주 인턴일지 🤓: 공용 모듈 npm package로 관리하기📦

Ko Seoyoung·2021년 4월 20일
0

공용 모듈 npm package로 관리하기📦

4월에는 핔 개발물들에서 공용으로 사용되는 interface, enum, type, gql, hook 등을 정의한 npm package인 @pickk/common을 만들어 publish 했다.

기존에는 모두 같은 모듈들을 어드민, , 프로젝트에 따로따로 추가하고 있었다. 그래서 코드의 일관성을 유지시키는 것이 번거로웠던 문제가 있었는데, package를 install하여 사용하게 되니 공용 모듈을 사용하기가 편리해졌다 👍


패키지 구조

  • 공통으로 사용되는 모듈은 common 폴더에
  • 나머지는 모델마다 폴더를 분류했다.
  • 각 모델 폴더는 graphql fragment와 query, mutation문들이 있는 gqls 폴더와 query hook, mutation 훅들을 커스텀훅으로 감싼 hooks폴더로 구성된다.

알게된 점

패키지를 작성하면서 graphql query 작성에 대해 공부했다.

1) fragment

query와 mutation은 정말 어렵지 않게 작성할 수 있었는데, 그러다 output 코드가 계속 겹치는 문제를 발견했다.
예를들어, 판매자를 create 한 후 판매자의 데이터를 반환받을 때 여기에는 브랜드 정보, 유저 정보 등이 포함되어있었다. 그런데 브랜드를 create, update 하고 난 후에도 같은 브랜드 정보를 반환받는데 이 때 쓰이는 field가 똑같았다.

이런 경우 GraphQL fragment를 사용하여 여러 query나 mutation간의 겹치는 로직을 분리할 수있다. (Fragment 사용법)

fragment [fragment 이름] on [반환하는 필드들을 포함하는 데이터 타입] {
  필드1
  필드2
}

2) export

publish를 하고 이제 라이브러리를 쓰려하는데 내가 원했던 import 그림이 아니였다.

import  {useCourier} from '@pickk/common/dist/lib/modules/item/couriers/hooks/couriers.query';
import { useCreateCourier } from '@pickk/common/dist/lib/modules/item/couriers/hooks/couriers.mutation';

🤔 ???

import React, { useEffect, useState } from 'react';

이렇게 이름만으로 import하려면 어떻게 해야할까?

다른 npm package들의 코드를 통해 이름만으로 모듈을 import 하기위해서는 라이브러리가 시작되는 entry point인 index.js 까지 모든 폴더의 모듈들을 export 해야한다는 것을 알게되었고,

이렇게! 모두 export 함으로써 간단히 해결했다


apollo:codegen 도입

커스텀 hook은 다음과 같이 작성했다.

export const useCreateSeller = () =>
  useMutation<CreateSeller, CreateSellerVariables>(CREATE_SELLER_MUTATION, {
    ignoreResults: false,
  });

처음에는 CreateSeller와 CreateSellerVariables 등의 타입을 직접 graphql api문서를 보며 타입폴더에 작성해주었다. 하지만, 이 방법은 사람이 직접 타입을 써줘야하므로 실수를 할 수도 있고(오타나 타입지정 등), 하나하나 타입을 써줘야하는 귀찮음도 있었다. 만약 mutation의 variables 형태가 변경되면 해당 타입을 찾아 바꿔줘야하는 등 번거로웠다.

이런 고민을 하던 중 우연히 과선배로부터 apollo:codegen이라는 것을 알게되었다! (진짜 고민 당일날 바로 이렇게 문제가 해결될줄이야ㅎㅎ)

codegen이 알아서 타입을 만들어 주는 것 뿐만아니라, gql이 서버의 쿼리 형식과 다르게 작성되어있다면 (ex) 오타가 나거나, 타입이 다르다거나 등) 버그를 알려주면서 codegen에 실패하므로 client에서 정확한 gql을 작성할수 있어 유용하다.

apollo:codegen 프로젝트에 설정해주기

apollo-tooling 참고

1. apollo.config.js

module.exports = {
  client: {
    includes: [
      './lib/**/*.fragment.ts',
      './lib/**/*.query.ts',
      './lib/**/*.mutation.ts',
      // => gql을 query, mutation 등을 작성한 폴더
    ],
    tagName: 'gql',
    service: {
      name: '[graphql 서버 이름]',
      url: 'https://[graphql 서버 도메인]/graphql',
    },
  },
};

2. package.json에 script 추가

"scripts": {
	// 다른 script
	"apollo:codegen": "rm -rf [타입 폴더경로] && apollo schema:download && apollo client:codegen [타입 폴더경로] --target=typescript --outputFlat"
}
  • [타입 폴더경로]에는 타입 코드가 만들어질 경로를 적는다. ex) lib/__generated__

3. npm run apollo:codegen

터미널에서 npm run apollo:codegen script를 실행하면 타입들이 generate된다!


npm publish

버전을 지정해주고, npm publish로 새버전으로 publish한다. (npm 로그인 필요)

  • npm version patch : 1.0.0 -> 1.0.1
  • npm version minor : 1.0.0 -> 1.1.0
  • npm version major : 1.0.0 -> 2.0.0

이 블로그 글을 참고한다.


내 발목을 잡았던 오류 🐛

1. Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

에러메세지가 해보라는 리액트 버전 맞추기 등을 해보았는데, 계속 같은 오류가 발생했다.

이 에러는 패키지를 publish 하기 전 다른 프로젝트에서 패키지 사용을 테스트하기위해 npm link를 통한 모듈 사용을 시도하다 발생한 에러이다.

stack overflow에서도 나 같은 오류가 나는 사람이 참 많았다ㅎ..

이 분도 나처럼 삽질을 하고 계셨다. 여기서 들어간 이 링크로 문제가 해결되었다.

원인은 react 패키지를 사용하는 핔 common package를 설치하려던 다른 프로젝트에서도 react 패키지를 사용했기 때문이다. 여러가지 해결책이 있었지만, 어차피 publish를 해야하므로 이 가브리엘님을 따랐다! (감사해서 좋아요, 하트 뿅뿅 눌러드렸다 😜)


update:

하지만 이렇게 해결하는 경우 테스트를 해보지 않고, publish를 하는 문제가있다. 그래서 alias를 사용하는 방법으로 다시 해결해 보아야겠다.

profile
Web Frontend Developer 👩🏻‍💻 #React #Nextjs #ApolloClient

0개의 댓글