solmumoduulien kloonit saivat sinut alas? Poista tiedostojärjestelmäsi

(14. maaliskuuta 2019)

Kuinka monta kopiota [email protected]: sta pidät? (Kuva: 浮萍 闪电 sivustossa Unsplash )

PÄIVITYS: Alla kuvatulla toteutuksella on ongelmia tiedostojen kanssa, joilla on riippuvuuksia (require / import -lausekkeet ). node\_modules/ -rakenteen takia identtinen tiedosto, joka asuu kahdessa paikassa, saattaa hakea omien riippuvuuksiensa eri versioita, joten ollaksesi erityisen turvallinen, sinun on rajoituttava tiedostojen deduplikaatioon nollalla riippuvuudet.

Yksi ongelmista, jonka kohtaamme Tradlessa useissa suurissa Node.js / React Native / web-sovellushankkeissa, on se, että node\_modules pääsee kopioihin tietyt riippuvuudet. Kun sovellus käynnistyy, se jäsentää, suorittaa ja tuhlaa muistia samalla moduulilla useita kertoja.

Tavallisessa vanhassa Node.js-tiedostossa ei yleensä ole tarpeeksi suurta suorituskyvyn rangaistusta, jotta voisit huutaa, mutta sattuu silti tietää, että se tapahtuu. Matkapuhelimessa / verkossa valitus on pakollista. Yhdessä vaiheessa luulen, että React Native -sovelluksessamme oli 10 kopiota readable-stream -versiosta, enkä osaa emojia, joten annan Watin sanoa sen minulle:

Wat opettaa Chaucerille englantia

Haluatko tuntea tuskan? Tässä on esimerkki riippuvuusrakenteesta, joka aiheuttaa ongelman:

# 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

Projektisi riippuu [email protected], mutta kahdesta riippuvuudet riippuvat [email protected]. Pakettihallintasi ei voi monistaa [email protected] nostamalla sitä juurelle, koska [email protected] istuu siellä. Joten saat kaksi kopiota tiedostosta [email protected], yhden alle depA ja toisen depB . Ne ovat identtisiä. Eikä siinä voi tehdä mitään, ellei sinulla ole aikaa lähettää PR: itä depA ja depB kirjoittajille päivittääksesi ne [email protected] (PR: t, joiden yhdistäminen voi viedä kuukausia), ja odota, että ne yhdistetään. Se tai ylläpitää molempien moduulien haarukoita. Joten menet ratkaisemaan jonkin muun ongelman.

En tiedä miten hän tiesi kaiken tapa sitten

Onnittelut! Olet nyt lykännyt deduplikaatio-ongelmaa niputtimellesi. Webpack, Browserify ja Metro täytyy nyt ratkaista se itsenäisesti. Tässä on avoin ongelma Webpackissa. Se on ollut avoinna vuodesta 2017, ja jos olisin Webpack, minua ärsyttäisi ihmiset, jotka yrittävät tehdä siitä ongelmani.

Tämä ongelma ei ole uusi ja on kärsivällisesti piilottanut sivulta kuten monet Node.js: n ja selaimen pakettienhallinnan ja niputtimien inkarnaatiot. Se on todennäköisesti vielä jonkin aikaa, kuten runsas digitaalinen torakka.

Onneksi äskettäisten veronalennusten myötä meillä on nyt varaa sytyttää valo tunnelin päässä. (Mutta vain rikkaille).

Valo tunnelin päässä

Leikataksemme Tradlen React Native -sovelluksen nippuun samanlaiset riippuvuuskopiot päätimme olla yrittämättä lisää tukea Metro Packagerille tai voita Metro Packager -tiimille. Lähetämme sovelluksemme myös React Native for Web -ohjelmistoon, joka niputetaan Webpackin kanssa, ja halusimme temppun, joka toimisi molemmille.

Päätimme kohdistaa asiaan, joka on kaikille paketinhallinnoijille ja niputtajille yhteinen: Node.js: n resolve() algoritmi. Tämä on algoritmi, joka suoritetaan suoritettaessa require("some-module"), jotta löydetään moduulin absoluuttinen polku tiedostojärjestelmästä. Sekä paketinhallinta että niputtajat luottavat tähän algoritmiin, ensimmäinen rakentaa hakemistorakenteen node\_modules, toinen kulkee sen yli paketin rakentamiseksi.

Ratkaisu on yksinkertainen: kulkee node\_modules, tunnista kaikki kaksoiskappaleet, valitse yksi niistä ensisijaisiksi (esim. ensimmäinen aakkosjärjestyksessä) ja kirjoita *.js -tiedostot uudelleen kaikki muut osoittavat kanonista. Kopiokansioissa olevat *.js -tiedostot näyttävät tältä:

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

Tämä tuntuu hieman lialta, mutta se toimii ja tekee nipustamme pienemmäksi ja siten nopeammin latautuvaksi. Moduuli on avoimen lähdekoodin, kokeile sitä vapaasti: https://github.com/tradle/dedupe-deps

On oltava parempi tapa

Jotkut teistä luultavasti pyörittävät silmiänne ja huutavat "käytä vain pnpm!”Varovainen siellä, silmien pyöriminen voi olla riippuvuutta. Ja et halua tietää, mitä he määräävät sinua ottamaan reunan silmänräpäyksestä.

pnpm on suhteellisen uusi pakkaaja kaupunki. Se käyttää kovien linkkien ja symlinkkien yhdistelmää sen varmistamiseksi, että moduuli on läsnä vain kerran tietyn projektin node\_modules -osiossa. Itse asiassa se takaa, että se on läsnä vain kerran koko tiedostojärjestelmässäsi! Tämä on erittäin siistiä. Jonain päivänä me kaikki käytämme pnpm ja kaikki toimii maagisesti, mutta minusta tuntuu, että joissakin niputtimissa on edelleen yhteensopivuusongelmia.

… Jep, tarkistan juuri, ja se on edelleen ongelma Metroissa, vaikka näyttää siltä, ​​että he ovat ratkaisemassa ratkaisua: https://github.com/facebook/metro/ pull / 257

Ottaen askeleen pidemmälle

Joten palaa tiedostojärjestelmään perustuvaan ratkaisuun. Voimme viedä asiat askeleen pidemmälle ja tappaa enemmän lintuja samalla kivellä. Epäilemättä nämä ovat jopa suurempia lintuja kuin alkuperäinen. Kuvitellaan, että meillä on tämä riippuvuuspuu:

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

Täällä meillä on kaksi eri versiota [email protected]. Riippuen kuitenkin semver -alueista, jotka on määritetty lodash -kohdassa depA ja depB, ne voivat hyvinkin olla kykeneviä käyttämään dedupe-toimintoja. Tällä hetkellä dedupe-deps -moduuli ei käsittele tätä skenaariota, mutta otamme mielellämme vastaan ​​PR-ilmoituksia.