A node_modules klónjai lebuktatták? Dedupe a fájlrendszert

(2019. március 14.)

A [email protected] hány példánya lenne kedveled? (Fotó: 浮萍 闪电 a Sablon eltávolítása )

FRISSÍTÉS: az alábbiakban ismertetett megvalósításnak problémái vannak a függőségű fájlokkal (require / import utasítások ). A node\_modules/ felépítéséből adódóan egy két helyen élő azonos fájl saját függőségeinek különböző verzióit képes behúzni, ezért, hogy extra biztonságban legyünk, korlátoznunk kell magatokat nulla fájlok deduplikációjára függőségek.

Az egyik kérdés, amelyet a Tradle-nál számos nagy Node.js / React Native / webalkalmazás-projektben elértünk, az az, hogy node\_modules a bizonyos függőségek. Amikor az alkalmazás elindul, elemzi, futtatja, majd több memóriára pazarolja a memóriát, ugyanaz a modul többször is.

A szokásos régi Node.js-ben általában nincs elég nagy teljesítménybüntetés, amiért nyafogni lehet, de még mindig fáj tudni, hogy ez történik. Mobilban / webben a nyafogás kötelező. Egy pillanatban azt hiszem, hogy a React Native alkalmazásban 10 példányban rendelkezünk a readable-stream verzióval, és nem vagyok jó az emoji-ban, ezért hagyom, hogy Wat elmondja helyettem:

Wat megtanítja Chaucer angolt

Szeretné érezni a fájdalmat? Itt van egy példa a problémát okozó függőségi struktúrára:

# 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

A projekt a [email protected], de a két a függőségek [email protected] függenek. A csomagkezelő nem tudja deduplikálni a (z) [email protected] fájlt azzal, hogy a gyökérig emeli, mert [email protected] ott ül. Tehát a [email protected] két példánya lesz, az egyik a depA alatt és a depB alatt. . Egyformák. És nem tehet róla, kivéve, ha van ideje PR-eket küldeni a depA és a depB szerzőknek, hogy frissítsék őket [email protected] (PR-ek, amelyek összevonása hónapokba telhet), és várja meg, amíg összeolvadnak. Mindkét modul villáinak fenntartása vagy fenntartása. Tehát megoldja valamilyen más problémát.

Nem tudom, hogy tudta mindezt visszafelé

Gratulálunk! Most elhalasztotta a deduplikációs problémát a csomagban. A Webpack-nak, a Browserify-nak és a Metro-nak most mindegyiknek önállóan kell megoldania. Íme a nyitott kérdés a Webpack webhelyen. 2017 óta nyitva van, és ha Webpack lennék, bosszankodnék azon embereken, akik megpróbálják ezt problémává tenni.

Ez a probléma nem új, és türelmesen pofázott a széléről, mint sokan a Node.js és a böngésző csomagkezelőinek és kötegereinek inkarnációi. Valószínűleg még egy darabig fennáll, mint egy kiadós digitális csótány.

Szerencsére a közelmúltbeli adócsökkentésekkel most megengedhetjük magunknak, hogy az alagút végén felgyújtjuk a villanyt. (De csak a gazdagok számára).

A fény az alagút végén

A Tradle React Native alkalmazás csomagjában lévő függőségek azonos példányainak metszéséhez úgy döntöttünk, hogy nem próbálunk meg adjon támogatást a Metro Packagerhez, vagy forduljon a Metro Packager csapathoz. Az alkalmazásunkat a React Native for Web-hez is szállítjuk, amely a Webpackhoz tartozik, és szerettünk volna egy olyan trükköt, amely mindkettőnek megfelel.

Úgy döntöttünk, hogy megcélozzuk azt a dolgot, amely minden csomagkezelőben és kötegelőben közös: A Node.js resolve() algoritmusa. Ez az az algoritmus, amelyet a require("some-module") futtatásakor hajtanak végre, hogy megtalálják a modul abszolút elérési útját a fájlrendszerben. Mind a csomagkezelők, mind a csomagkezelők erre az algoritmusra támaszkodnak, az első a node\_modules könyvtárstruktúrát, a második pedig a csomag felépítéséhez használja.

A megoldás egyszerű: traverse node\_modules, azonosítsa az összes másolatot, válasszon közülük kanonikusat (pl. az első betűrendben), és írja át a *.js fájlokat a a többiek a kanonikusra mutatnak. A duplikátummappákban található *.js fájlok végül így néznek ki:

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

Ez kissé piszkosnak tűnik, de működik, és a csomagunkat kisebbé és ezáltal gyorsabban betölthetővé teszi. A modul nyílt forráskódú, nyugodtan próbálja ki: https://github.com/tradle/dedupe-deps

Kell lennie egy jobb módnak

Néhányan valószínűleg most forgatják a szemüket, és azt kiáltják, hogy „csak használd a pnpm -t!”Óvatosan, a szemforgatás függőséget okozhat. És nem akarod tudni, mit fognak előírni neked, hogy vedd le a szemgördülés visszavonását.

pnpm egy viszonylag új csomagoló város. A hard linkek és a linkek kombinációját használja annak biztosítására, hogy egy modul csak egyszer legyen jelen egy adott projekt node\_modules projektjében. Valójában garantálja, hogy a teljes fájlrendszerben csak egyszer lesz jelen! Ez nagyon klassz. Egy napon mindannyian használjuk a pnpm -et, és minden varázslatosan működni fog, de úgy érzem, hogy ma még mindig akadnak kompatibilitási problémák néhány csomagban.

… Igen, most ellenőriztem, és ez még mindig probléma a Metro-ban, bár úgy tűnik, hogy megoldást keresnek: https://github.com/facebook/metro/ pull / 257

Egy lépéssel tovább

Tehát térjünk vissza a fájlrendszer-alapú megoldásunkra. Egy lépéssel tovább haladhatunk, és ugyanazzal a kővel több madarat is megölhetünk. Vélhetően ezek még nagyobb madarak, mint az eredeti. Képzeljük el, hogy megvan ez a függőségfa:

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

Itt a [email protected] két különböző verziója van. Azonban a semver tartományoktól függően, amelyek meg vannak adva a lodash mezőben a depA és depB, nagyon jól el tudják használni őket. Jelenleg a dedupe-deps modul nem foglalkozik ezzel a forgatókönyvvel, de örömmel fogadjuk a PR-eket.