Skip to content

Instantly share code, notes, and snippets.

@Jonghakseo
Last active March 17, 2023 11:16
Show Gist options
  • Save Jonghakseo/9fc9f429e1f22e3ea74958764399328e to your computer and use it in GitHub Desktop.
Save Jonghakseo/9fc9f429e1f22e3ea74958764399328e to your computer and use it in GitHub Desktop.
이슈이슈

발단

creatrip-web 레포 최상위 폴더에 있는 stay를 packages/stay/app 하위로 정리하기로 함

다음과 같은 순서로 진행

  1. packages/stay/app 폴더 생성
  2. stay 폴더 내용 통째로 packages/stay/app 내부로 이동
  3. npm init -w ./packages/stay/app 으로 npm workspace 생성
  4. 패키지 이름 @creatrip-stay/app 으로 생성
  5. npm install => node_modules에 @creatrip-stay/app symlink 생성
  6. npm run re-codegen
  7. npm run build

빌드 에러가 나서 살펴보니, 생성된 __generated__ 폴더에 생성된 의존성 타입 파일이 깨져있었음

스크린샷 2023-03-17 오후 5.44.16.png

해결 시도

1. baseType 파일을 참조하는 곳에서 문제가 생겼겠구나

codegen.yml로 이동 후, generate key값(출력 파일 경로)이 graphql/, components/ 로 되어있음을 확인

스크린샷 2023-03-17 오후 5.46.00.png

'아 여기에 packages/stay/app 경로를 추가해주면 되겠다!'라고 생각

baseType 경로는 출력 폴더의 상대경로이니까 아래와 같이 추가

  packages/stay/app/:
      preset: near-operation-file
      presetConfig:
        baseTypesPath: ../../../graphql/types.ts
        folder: __generated__
      plugins:
        - "typescript-operations"
        - "typescript-react-apollo"

결과: 똑같이 깨짐

2. baseTypesPath 추론에 버그가 있나보다

near-operation-file-preset config 공식 문서를 보니, baseTypesPath에 "~" 물결 표시를 넣으면 절대 경로로 인식된다는 것 확인

import * Types from "graphql/types"로 인식되어도 절대경로로 잘 추론되기 때문에 요 값을 사용해야겠다고 생각

다음과 같이 수정

  packages/stay/app/:
      preset: near-operation-file
      presetConfig:
        baseTypesPath: ~graphql/types
        folder: __generated__
      plugins:
        - "typescript-operations"
        - "typescript-react-apollo"

결과: 이제는 무슨 꼬리까지 달리기 시작

스크린샷 2023-03-17 오후 5.51.33.png

아... 쉽지 않다는 것을 직감...ㅠ

3. 디버거 사용

codegen 명령어에 디버거 걸어서 한 줄 한 줄 디버깅 시작 ㅠ

npm run codegen 명령어를 실행하면 다음과 같은 플로우로 동작하는 것을 확인

@graphql-codegen/cli/cjs/cli.js

  • runCli()

@graphql-codegen/cli/cjs/generate-and-save.js

  • generate(): executeCodegen 호출의 결과를 fs 모듈 사용하여 실제 파일 저장까지 실행

@graphql-codegen/cli/cjs/codegen.js

  • executeCodegen(): codegen.yml 설정에 따라 schema와 documents를 가져온 후, codegen을 호출해서 content 생성 후 output으로 반환

@graphql-codegen/cli/node_modules/@graphql-codegen/core/cjs

  • codegen() : 실제 output content 생성 구현

executeCodegen() 결과까지 디버거로 확인했을 때, 정상적인 출력값들이 들어있는것을 확인 ? 그럼 어떤 프로세스로 정상적인 output이 이상한 결과로 바뀌는 것인지??

의심되는 곳은 generate() 내부의 writeOutput().

output 값이 정상적이었기 때문에 문제는 쓰는(write) 곳에서 발생할 것으로 예상

그리고 output을 디버거로 찍어보면서 알게 된 사실.

  1. near-operation-file-preset을 사용하면 긁어온 모든 graphql document를 대상으로 어차피 generate가 동작한다. 사실상 components/ 라고 되어있는 부분은 baseType 파일의 경로 계산 외에는 큰 의미가 없음;
  2. package/stay 하위에 있는 document가 2개씩 생성되고 있음.

스크린샷 2023-03-17 오후 6.35.40.png 스크린샷 2023-03-17 오후 6.34.49.png

useMyLikedStay 훅의 output이 총 2개가 생성되었는데, 하나는 정상적인 내용이 들어있고(node_moudules), 또 하나는 import를 제외한 내용이 비어있음(packages)

543번 output의 내용이 비어있는 이유를 파악하기 위해 excutePlugin 코드를 확인했는데, 실행의 제어권이 plugin쪽으로 넘어가고 있어서 일단 제외. 덮어씌워지는 문제가 핵심이기 때문에 쓰는 곳에 집중하기로 함.

writeOuput 메소드는 Promise.all을 통해 모든 output(generationResult)에 대한 파일 생성 동작을 하는데, 이 때 symbolic link로 존재하는 node_modules 내부의 __generate__ 파일과, 실제 원본인 packages 내부의 __generate__ 파일이 동시에 쓰여지게 됨(명시된 경로상으로는 다르나 symLink 특성상 symlink 파일의 수정은 원본 파일의 수정과 동일하게 동작)

스크린샷 2023-03-17 오후 7.35.29.png

즉, fs.promise.write를 통해 symlink가 걸린 node_moudles 내부의 파일을 수정하고, 동시에 packages 내부의 파일도 수정하면서 일종의 충돌이 발생했다고 추측 가능. (두 결과값이 다른 이유는 typescript-react-apollo plugin을 열어봐야 할 것으로 보임. 혹은 그 앞단의 캐싱 문제일수도...?)

해결

node_mouduls 내부의 document를 모두 가져오는것을 막는다면 문제 해결이 가능할 것으로 예측

codegen.yml 내부에서 document를 가져오는 glob pattern은 다음과 같았음

documents: "**/!(types|*.d|*.generated).{ts,tsx,graphql}"

여기서 node_modules 하위 폴더의 파일들을 제외하면 될 것 같음 아래와 같이 수정

documents:
  - "**/!(types|*.d|*.generated).{ts,tsx,graphql}"
  - "!node_modules/**/!(types|*.d|*.generated).{ts,tsx,graphql}"

스크린샷 2023-03-17 오후 8.00.33.png

출력 결과에서 중복된 output이 제거되었고

스크린샷 2023-03-17 오후 8.02.07.png

__generate__ 내부 파일 역시 제대로 생성된 것을 볼 수 있음

정리

예상과 달랐던 codegen 동작

graphql-codegen cli 동작시, codegen.yml 에 설정한 gerated-key 값(components/)은 preset으로 near-operation-file을 사용할 경우 의미가 없다. 어차피 documents를 다 긁어서 생성하기 때문에 components/내부의 것들만 생성해주는게 아님. 생성 범위를 좁히고 싶다면 components/ 설정 내부에서 documents를 선언 후 사용(전역 documents와 중복되므로 전역값은 제거 필요)

symlink 주의

npm workspace는 로컬 패키지 파일을 node_modules 내부로 symlink를 생성해주는데, 이 과정에서 예상치 못한 동작이 생길 수 있으니...주의 필요. (왠만한 작업에서 node_modules를 exclude시켜두기 때문에 큰 문제는 없을 것 같으나, 이번처럼 exclude를 시키지 않은 경우 symlink 동작으로 인해 디버깅이 어려운 이슈가 발생할 수 있음)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment