node_modules의 클론으로 인해 다운 되었습니까? 파일 시스템 중복 제거

(2019 년 3 월 14 일)

[email protected]의 사본 수 너는 좋아한다? ( Unsplash 浮萍 闪电 의 사진)

업데이트 : 아래 설명 된 구현에는 종속성이있는 파일 (require / import 문 ). node\_modules/의 구조로 인해 두 위치에있는 동일한 파일이 서로 다른 버전의 자체 종속성을 가져올 수 있으므로 더욱 안전하게하려면 0으로 파일을 중복 제거하도록 제한해야합니다.

여러 대규모 Node.js / React Native / 웹 앱 프로젝트에서 Tradle에서 발생한 문제 중 하나는 node\_modules가 특정 종속성. 앱이 시작될 때 동일한 모듈을 여러 번 구문 분석하고 실행 한 다음 메모리를 낭비합니다.

일반적인 이전 Node.js에서는 일반적으로 큰 성능 저하가 발생하지 않습니다. 그러나 그것이 일어나고 있다는 것을 아는 것은 여전히 ​​아파요. 모바일 / 웹에서 징징 거리는 것은 필수입니다. 한때 React Native 앱에 readable-stream 버전의 10 개 사본이 있다고 생각하는데 저는 이모지가 좋지 않아서 Wat가 저에게 말하도록하겠습니다.

Wat는 Chaucer 영어를 가르칩니다.

고통을 느끼고 싶습니까? 다음은 문제를 일으키는 샘플 종속성 구조입니다.

# assume for simplicity that deps specify exact versions, i.e.:
# myProject"s package.json specifies "lodash": "4.0.0"
# depA and depB"s package.json specifies "lodash": "3.0.0"myProject/
node\_modules/
lodash # 4.0.0
depA
node\_modules/lodash # 3.0.0
depB
node\_modules/lodash # 3.0.0 <- not cool

프로젝트는 [email protected]에 종속되지만 종속성은 [email protected]에 따라 다릅니다. [email protected]가 거기에 있기 때문에 패키지 관리자는 [email protected]를 루트까지 올려서 중복을 제거 할 수 없습니다. 따라서 두 개의 [email protected] 사본이 생성됩니다. 하나는 depA 아래에 하나는 depB 아래에 있습니다. . 그들은 동일합니다. PR을 depAdepB의 작성자에게 전송하여 업그레이드 할 시간이없는 한 이에 대해 할 수있는 작업이 없습니다. [email protected] (병합하는 데 몇 달이 걸릴 수있는 PR), 병합 될 때까지 기다립니다. 또는 두 모듈 모두의 포크를 유지하십시오. 그래서 당신은 다른 문제를 해결합니다.

그가 모든 것을 어떻게 알았는지 모르겠습니다. 그 당시

축하합니다! 이제 중복 제거 문제를 번 들러로 연기했습니다. Webpack, Browserify 및 Metro는 이제 각각 독립적으로 해결해야합니다. 다음은 Webpack의 미해결 문제 입니다. 2017 년부터 열려 있었고, 제가 Webpack이라면 제 문제로 만들려고 애쓰는 사람들에게 짜증을 낼 것입니다.

이 문제는 새로운 것이 아니며 많은 사람들처럼 부업에서 참을성있게 비웃었습니다. Node.js 및 브라우저에 대한 패키지 관리자 및 번 들러의 화신. 이것은 아마도 왕성한 디지털 바퀴벌레처럼 잠시 동안있을 것입니다.

다행히도 최근의 세금 감면으로 인해 이제 우리는 터널 끝에서 불을 켤 여유가 있습니다. (하지만 부자들에게만 해당).

터널 끝의 불빛

Tradle의 React Native 앱 번들에서 동일한 종속성 사본을 정리하기 위해 우리는 시도하지 않기로 결정했습니다. Metro Packager에 지원을 추가하거나 Metro Packager 팀에 호소하십시오. 또한 웹팩과 함께 번들로 제공되는 웹용 React Native와 함께 앱을 제공하고 두 가지 모두에서 작동하는 트릭을 원했습니다.

우리는 모든 패키지 관리자와 번 들러가 공통적으로 갖는 것을 대상으로 결정했습니다. Node.js의 resolve() 알고리즘. 파일 시스템에서 모듈의 절대 경로를 찾기 위해 require("some-module")를 실행할 때 실행되는 알고리즘입니다. 패키지 관리자와 번 들러 모두이 알고리즘에 의존합니다. 첫 번째는 node\_modules 디렉토리 구조를 빌드하고 두 번째는이를 트래버스하여 번들을 빌드합니다.

해결 방법은 다음과 같습니다. 간단합니다. node\_modules를 탐색하고 모든 중복 항목을 식별하고 그중 하나를 표준 (예 : 알파벳순)으로 선택하고 *.js 파일을 다른 모든 것은 표준을 가리 킵니다. 중복 폴더의 *.js 파일은 다음과 같이 보입니다.

// deduped by dedupe-deps
module.exports = require("../../../changes-feed/node\_modules/readable-stream/duplex.js")

약간 더럽지 만 그것은 작동하고 우리의 번들을 더 작게 만들어서 더 빠르게로드합니다. 모듈은 오픈 소스이므로 자유롭게 사용해보세요. https://github.com/tradle/dedupe-deps

더 나은 방법이있을 것 같습니다

여러분 중 일부는 아마도 지금 눈을 굴리며 "pnpm를 사용하세요!”조심스럽게 눈을 굴리면 중독성이 있습니다. 그리고 당신은 그들이 당신에게 무엇을 처방하는지 알고 싶어하지 않습니다. 도시. 하드 링크와 심볼릭 링크의 조합을 사용하여 모듈이 주어진 프로젝트의 node\_modules에 한 번만 존재하도록합니다. 사실, 전체 파일 시스템에서 한 번만 존재 함을 보장합니다! 이것은 매우 멋지다. 언젠가는 모두 pnpm를 사용할 것이며 모든 것이 마술처럼 작동 할 것입니다.하지만 오늘날에도 일부 번 들러와의 호환성 문제가있을 것 같습니다.

… 네, 방금 확인한 결과 Metro에서 여전히 문제이지만 해결 방법을 찾고있는 것 같습니다. https://github.com/facebook/metro/ pull / 257

한 단계 더 나아가

파일 시스템 기반 솔루션으로 돌아갑니다. 우리는 한 걸음 더 나아가 같은 돌로 더 많은 새를 죽일 수 있습니다. 틀림없이 이것은 원래의 새보다 훨씬 더 큰 새입니다. 이 종속성 트리가 있다고 가정 해 보겠습니다.

myProject/
node\_modules/
lodash # 4.0.0
depA
node\_modules/lodash # 3.0.5
depB
node\_modules/lodash # 3.0.0 <- not cool

여기에 [email protected]의 두 가지 버전이 있습니다. 그러나 depAlodash에 지정된 semver 범위에 따라 및 depB, 중복 제거가 가능할 수 있습니다. 현재 dedupe-deps 모듈은이 시나리오를 다루지 않지만 PR을 수락하게되어 기쁩니다.