Hexo에서 `punycode` DeprecationWarning 해결하기

Introduction

언젠가부터 Hexo 블로그를 서빙 또는 배포할 때마다 아래와 같은 DeprecationWarning이 뜨기 시작했다.

(node:39714) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.

찾아보니 Node 버전이 21로 올라가면 발생하는 문제로 보였는데, 버전을 낮추는 방식은 마음에 들지 않아 어케저케 비벼서 해결해보았다.

Conclusion

결론부터 말하자면, Hexo에 적용한 추가적인 플러그인 중 일부에서 발생하는 패키지 없뎃 이슈였다.

  • [상황1] 수동으로 만든 패키지의 devDependency가 오래되어 이슈 발생

    • [해결방법1-1] 해당 패키지의 package.json에서 의존성 정보를 직접 업데이트
    • [해결방법1-2] 만일 devDependency가 불필요하다면 일괄 삭제
    예시) 커스텀한 hexo-generator-searchdb 플러그인

    [상황]

    • 이 블로그에서는 다언어(한/영) 환경에 맞게 코드를 많이 수정했는데,
      그 중 하나가 search.xml 생성 시에 해당 포스팅의 언어를 함께 저장하여 검색에 활용하는 것이었음
      현재 사이트가 한글이라면, 한글로 작성된 포스팅이 최우선으로 검색되게 함

    • 이를 위해 source/js/ 하단에 hexo-generator-searchdb 소스 코드를 복제해서 hexo-generator-searchdb-custom이라는 이름의 로컬 패키지를 만들어 아래와 같이 사용했음

      1
      2
      3
      "dependencies": {
      "hexo-generator-searchdb": "file:source/js/hexo-generator-searchdb-custom"
      }

    [문제]

    • 문제는, 이 상태에서 npm install을 실행하면 해당 로컬 패키지의 devDependency도 함께 설치
      • --production 옵션이 디폴트라서 외부 패키지를 사용할 때는 devDependency가 설치되지 않는데, 로컬 패키지를 사용할 때는 왜 이 옵션이 적용되지 않는지 잘 모르겠음
      • 암튼 이 devDependency에 eslint@7.32.0가 포함되어 있었는데, 이게 punycode를 예전 방식으로 사용하고 있는 것

    [해결]

    • 근데 사실 본인은 devDependency에 있는 패키지를 사용할 일이 없으므로 그냥 쿨하게 devDependency를 해당 패키지에서 삭제

    • 아님 아래와 같이 hexo-generator-searchdb-custom/package.json를 직접 수정해서 사용했을 듯

      1
      2
      3
      4
      "devDependencies": { // 현시점 최신 버전으로 설정해서 잘 되는지 확인
      "eslint": "^9.18.0",
      "@next-theme/eslint-config": "^0.0.4"
      }
  • [상황2] 불러온 패키지의 dependencies 중 오래된 버전이 존재하여 이슈 발생

    • [해결방법2-1] override 활용하여 의존성 정보를 최신으로 덮어씌우기
    • [해결방법2-2] node_modules 내에서 직접 punycode 관련 코드를 수정
      권장되지 않는다는 건 알지만, 달리 방법이 없을 땐 어쩔 수 없으니까..
    예시) hexo-renderer-markdown-it 플러그인

    [상황]

    • 본인 블로그에서는 hexo-renderer-markdown-it 플러그인을 통해 마크다운을 렌더링하고 있음
      • 이 블로그에서는 KaTex로 수식을 렌더링하고 있는데,
        KaTex 사용 시에는 hexo-renderer-markdown-it을 권장한다[1]고 하여
        Hexo에서 기본으로 제공하는 hexo-renderer-markdown 플러그인 대신 사용 중
    • 그리고 이 hexo-renderer-markdown-it 플러그인에서 markdown-it@13.0.2를 사용하고 있음

    [문제]

    • 문제는 이 markdown-it@13.0.2에서 punycode를 예전 방식으로 불러오고 있음
      • const punycode = require('punycode')가 아닌
        const punycode = require('punycode/')로 불러와야 함[2]
    • 따라서 버전을 오버라이딩하거나 직접 해당 코드를 수정해야 함
    • 진짜 문제는 markdown-it을 14.0.0 이상으로 올리면 그냥 hexo-renderer-markdown-it 자체가 돌아가지 않아 오버라이딩이 불가능하다는 것… 그거까지 해결하고 싶진 않았음.. 난 Node.js 공부해본 적 없는 걸..

    [해결]

    • 따라서, 어쩔 수 없이 node_modules/hexo-renderer-markdown-it/ 안에 있는 node_modules/markdown-it/lib/index.js을 아래와 같이 수정함

      1
      2
      // const punycode = require('punycode');  // 기존 코드
      const punycode = require('punycode/'); // 수정 코드
      • 슬래시 하나 추가했을 뿐인데 문제가 해결되었을 때의 기분을 서술하시오. (1000점)
      • 이렇게 되면, node에 설치된 punycode를 사용하게 되므로
        만일 punycode가 설치되어 있지 않다면 추가적으로 npm install punycode --save를 실행
    • 매번 수정하기 귀찮다면 postinstall 스크립트를 활용하여 자동화하면 됨 (아래 설명 참고)

How I Got Resolved

결론은 결론이고, 모두가 위에서 언급한 패키지에 대해 문제가 생기지는 않을 것이다.
따라서 내가 어떻게 문제를 해결했는지에 대한 과정을 의식의 흐름대로 적어보았다.

Check Status

일단 사용 중인 Node 버전을 확인해보았던 걸로 기억한다.

1
2
$ node -v
v21.7.3

버전을 20으로 낮춰도 아마 해결은 되겠지만, 낮추는 건 왠지 자존심이 허락 안하는걸~
(은 아니고 그냥 Node.js에 관한 지식이 없어서 버전별 차이를 모르기 때문에 최신이 최선이라고 생각했음)

punycode vs. punycode/

구글에 “npm punycode deprication” 따위로 검색해서 이것저것 살펴보니, 결국 punycode를 사용하는 패키지에서 punycode를 불러오는 코드를 최신화하지 않아서 발생하는 문제였다.

그니까, 대충 뭐 punycode 깃헙 리드미[2:1]를 읽어보면

  1. punycode를 설치하고
  2. require('punycode')가 아닌 require('punycode/')로 불러와야 한다는 것 같다.

대체 둘이 뭐가 다른지 모르겠지만, 뭐 그냥 파이썬에 비유하면 from .utils import *from utils import * 사이의 간극 정도 아닐까하고 적당히 넘어감.^^

punycode dependency

아무튼 그러한 이유로 punycode를 사용하는 모듈을 모두 찾기로 한다.
블로그 루트 디렉토리로 가서 npm ls punycode로 punycode의 상속 여부를 찾아보자.

1
2
3
4
5
6
7
$ npm ls punycode
hexo-blog@0.0.1 /루트/디렉토리/
├─┬ hexo-generator-searchdb-custom@1.4.1 -> /루트/디렉토리/node_modules/hexo-generator-searchdb-custom
│ └─┬ eslint@7.32.0
│ └─┬ ajv@기억.안남.0
│ └─┬ uri-js@기억.안남.0
│ └── punycode@기억.안남.0

대충 이런 결과가 뜬다. (기억이 가물가물해서 버전은 유추해서 적은 것)

보다시피 punycode를 쓰는 uri-js를 쓰는 ajv를 쓰는 eslint를 쓰는 hexo-generator-searchdb-custom이 문제인 걸로 확인되었다. ㅋㅋ

안 그래도 구글링할 때 eslint, ajv, uri-js 패키지 관련 이슈가 자주 나왔던 것이 생각나서, 이 세 개의 패키지도 마찬가지로 npm ls [패키지명] 명령어로 확인해보았다.

결과적으로 두 패키지에서 구버전 eslint를 사용하는 걸로 확인되었다.

  • hexo-generator-searchdb-custom
  • hexo-generator-sitemap-custom

Fix (1)

처음에는 이 패키지들의 버전을 최신으로 업데이트하면 되겠지 싶어서 각 패키지의 package.json을 열어보았는데, 둘 다 eslintdevDependencies로 설정된 케이스였다.

두 패키지 이름에서 짐작되겠지만, 둘 다 기존의 플러그인을 로컬에서 커스텀한 플러그인이었다. 기존 패키지를 전체적으로 거의 다 고쳐야 해서 그냥 로컬로 복제한 뒤 수정하여 아래와 같이 사용했는데 이게 문제였다.

1
2
3
4
"dependencies": {
"hexo-generator-searchdb": "file:source/js/hexo-generator-searchdb-custom",
"hexo-generator-sitemap": "file:source/js/hexo-generator-sitemap-custom"
}

이유는 모르겠으나 이렇게 직접 만든 로컬 패키지를 사용할 때는 devDependencies까지 함께 설치되었다.

  • npm install--production 옵션이 적용되지 않는 것으로 추정
  • 구글링해도 이유를 못 찾아서 포기

어짜피 개발의 편의를 위해 기존 패키지를 수정한 것에 불과해서 devDependencies가 필요 없었다.
그래서 그냥 두 패키지의 package.json에서 devDependencies 부분을 모두 삭제하고 아래의 코드로 패키지들을 재설치했다.

1
2
3
$ rm -r node_modules
$ rm package-lock.json
$ npm install

Fix (2)

그 때는 해결될 줄 알았는데… Warning 또 뜨는 걸 보고 진심… 노트북 던져버릴 뻔 여기까지 오는 데에 이틀이나 걸렸기 때매…

그래서 그냥 마음을 비우고 find 명령어로 punycode를 사용하는 js 파일을 모두 찾기로 했다.
좀 무식하긴 한데, 별다른 방법을 모르겠어서 그냥 이렇게 했음ㅎㅎ

1
2
$ cd node_modules
$ find . -type f -name "*.js" -exec grep -H "punycode" {} \;

결과가 굉장히 많이 나오는데, 그 중에 이런 게 있었다:
./hexo-renderer-markdown-it/node_modules/markdown-it/lib/index.js: var punycode = require('punycode');

일단 하나라도 찾았으니, 이 파일부터 하나씩 수정해보자는 마음으로 해당 파일을 열어보았다.

보니깐, hexo-renderer-markdown-it 플러그인에서 markdown-it@13.0.2를 사용하고 있는데, 이 버전의 lib/index.js에서 punycode를 예전 방식으로 불러오고 있었다.

그래서 그냥 슬래시 하나 추가해주고 저장하기만 했다.

1
2
// const punycode = require('punycode');  // 기존 코드
const punycode = require('punycode/'); // 수정 코드

그리고 다시 한 번 hexo server -o를 실행해보니 이번엔 punycode가 설치되어 있지 않다는 문구가 떴다.
이는 punycode/로 불러오는 방식이 node_modules에 설치된 punycode를 사용하게 되기 때문인 걸로 보인다.

가볍게 npm i punycode --save로 블로그 루트에 punycode를 설치한 후 다시 서버를 실행해보니 드디어 DeprecationWarning이 뜨지 않았다.

와! 다행! 이제 노트북을 던지지 않아도 된다!

Postinstall Script

그런데, 이렇게 매번 수정하기 귀찮기도 하고 node_modules를 직접 건드리는 게 맞나 싶기도 해서 좀 검색해보니까 바로 postinstall 스크립트를 활용법이 나오더라.

방법은 상당히 간단하다.

  1. patch-package 패키지 설치

    1
    $ npm install patch-package --save-dev
  2. node_modules 안에서 수정하고 싶은 파일을 찾아서 수정

    • 이미 수정되어 있으니 생략
  3. package.jsonpostinstall 스크립트 추가

    1
    2
    3
    "scripts": {
    "postinstall": "patch-package"
    }
  4. 수정된 파일을 패치로 저장

    1
    $ npx patch-package [패키지명]

    주의) 여기서는 패키지 속 패키지를 수정했기 때문에
    npx patch-package hexo-renderer-markdown-it으로 실행하면 해당 패키지에서 바뀐 게 아무 것도 없다는 메시지가 뜬다.

    따라서 npx patch-package hexo-renderer-markdown-it/markdown-it으로 실행해야 한다.

  5. 끝!

    • /patches 디렉토리가 생성되고 그 안에 패치 파일이 생성된다.
    • npm install 시 자동으로 해당 폴더의 패치들이 적용되므로 더 이상 직접 수정할 필요가 없다.

P.S.

  • 고작 DeprecationWarning 하나 때문에 이렇게 고생을 하다니 ㅠㅠ 나 진짜 Node.js 쪽은 파지 말아야지🫠
  • 나중에 markdown-it 버전을 올리는 “overrides” 방식도 시도해봤는데 안 됐음. 근데 오버라이딩은 정말 쉬우니 시도해보면 좋을 듯[3].

참고 링크

  1. Butterfly document - Theme Configuration # Math(link) ↩︎

  2. Github - mathiasbynens/punycode.js (link) ↩︎ ↩︎

  3. npm Docs - package.json (link) ↩︎

작성자 :extreme-rearranger
링크 :https://ex-rearranger.github.io/posts/ko/Solving-DeprecationWarning-in-Hexo/
저작권 :모든 게시물은 별도의 언급이 없는 한 CC BY-SA 4.0 라이선스를 따릅니다.
댓글