JavaScript moduļu 2. daļa: moduļu apvienošana

Šīs ziņas I daļā es runāju par to, kas ir moduļi, kāpēc izstrādātāji tos izmanto, un par dažādiem veidiem, kā tos iekļaut jūsu programmās.

Šajā otrajā daļā es pievērsīšos tam, ko tieši nozīmē moduļu “apvienošana”: kāpēc mēs komplektējam moduļus, dažādus veidus, kā to izdarīt, un moduļu nākotni tīmekļa izstrādē.

Kas ir moduļu apvienošana?

Augstā līmenī moduļu apvienošana ir vienkārši moduļu grupas (un to atkarību) apvienošana vienā failā (vai failu grupā) pareizajā secībā.

Tāpat kā visos tīmekļa izstrādes aspektos, arī velns ir detaļās. :)

Kāpēc vispār jāpievieno moduļi?

Sadalot programmu moduļos, jūs parasti sakārtojat tos dažādos failos un mapēs. Iespējams, jums būs arī moduļu grupa izmantotajām bibliotēkām, piemēram, pasvītrojums vai reakcija.

Rezultātā katrs no šiem failiem ir jāiekļauj jūsu galvenajā HTML failā pt> tagu, kuru pārlūkprogramma ielādē, kad lietotājs apmeklē jūsu mājas lapu. Ja katram failam ir sep arate & l ; script> tagi, tas nozīmē, ka pārlūkprogrammai ir jāielādē katrs fails atsevišķi: pa vienam… pa vienam.

... Kas ir slikta ziņa par lapas ielādes laiku.

Lai apietu šo problēmu, mēs visus failus apvienojam vai “savienojam” vienā lielā failā (vai atkarībā no gadījuma - pāris failos), lai samazinātu pieprasījumu skaitu. Kad dzirdat izstrādātājus runājam par “būvēšanas soli” vai “būvēšanas procesu”, par to viņi runā.

Vēl viena izplatīta pieeja, lai paātrinātu komplektēšanas darbību, ir kompleksa koda “samazināšana”. Minimizēšana ir nevajadzīgu rakstzīmju noņemšana no avota koda (piemēram, atstarpes, komentāri, jaunas rindiņu rakstzīmes utt.), Lai samazinātu kopējo satura lielumu, nemainot koda funkcionalitāti.

Mazāks datu daudzums nozīmē mazāku pārlūka apstrādes laiku, kas savukārt samazina laiku, kas nepieciešams failu lejupielādēšanai. Ja esat kādreiz redzējis failu, kuram bija “min” paplašinājums, piemēram, “pasvītrojums-min.js”, iespējams, pamanījāt, ka saspiestā versija ir diezgan niecīga (un nelasāma) salīdzinājumā ar pilno versiju.

Uzdevumu skrējēji, piemēram, Gulp un Grunt, apvieno un saīsina izstrādātājus, nodrošinot, ka cilvēkiem lasāms kods paliek atklāts izstrādātājiem, kamēr mašīnai optimizēts kods tiek piegādāts pārlūkprogrammām.

Kādi ir moduļu apvienošanas veidi?

Failu savienošana un samazināšana lieliski darbojas, ja moduļu definēšanai izmantojat kādu no standarta moduļu modeļiem (par kuriem runāja iepriekšējā ziņojumā). Viss, ko jūs patiešām darāt, ir sasmalcināt virkni vienkārša vaniļas JavaScript koda.

Tomēr, ja jūs ievērojat vietējās moduļu sistēmas, kuras pārlūkprogrammas nevar interpretēt, piemēram, CommonJS vai AMD (vai pat vietējos ES6 moduļu formātus), jums būs jāizmanto specializēts rīks, lai pārveidotu moduļus pareizi sakārtotā pārlūkprogrammā. draudzīgs kods. Tieši šeit parādās pārlūkprogrammas Browserify, RequireJS, Webpack un citi “moduļu saišķotāji” vai “moduļu ielādētāji”.

Papildus moduļu apvienošanai un / vai ielādēšanai moduļu paketes piedāvā daudz papildu funkciju, piemēram, automātisku atkārtotu kompilēšanu, kad veicat izmaiņas vai izveidojat avota kartes atkļūdošanai.

Apskatīsim dažas izplatītākās moduļu komplektēšanas metodes:

Komplektācija CommonJS

Kā jūs zināt no 1. daļas, CommonJS sinhroni ielādē moduļus, kas būtu lieliski, izņemot to, ka pārlūkprogrammām tas nav praktiski. Es pieminēju, ka tam ir risinājums - viens no tiem ir moduļu pakete, ko sauc par Browserify. Browserify ir rīks, kas apkopo CommonJS moduļus pārlūkprogrammai.

Piemēram, pieņemsim, ka jums ir šis fails main.js, kas importē moduli, lai aprēķinātu vidējo skaitļu masīvu:

Tātad šajā gadījumā mums ir viena atkarība (myDependency). Izmantojot zemāk esošo komandu, pārlūkprogrammas Pārveidošana rekursīvi tiek apvienoti visi nepieciešamie moduļi, sākot no main.js, vienā failā ar nosaukumu bundle.js:

Pārlūka verifikācija to veic, ieejot, lai parsētu AST katram pieprasītajam zvanam, lai šķērsotu visu projekta atkarības diagrammu. Kad būs noskaidrots, kā tiek strukturētas jūsu atkarības, tās visas pareizajā secībā tiek apvienotas vienā failā. Tajā brīdī jums atliek tikai ievietot vienu pt> tagu ar failu bund le.js” html, lai nodrošinātu, ka viss avota kods ir lejupielādēts vienā HTTP pieprasījumā. Bam! Komplektā iet.

Līdzīgi, ja jums ir vairāki faili ar vairākām atkarībām, jūs vienkārši pastāstāt pārlūkprogrammai, kāds ir jūsu ieraksta fails, un sēdiet, kamēr tas veic burvību.

Gala produkts: komplektā esošie faili ir sagatavoti un gatavi tādiem rīkiem kā Minify-JS, lai samazinātu komplektēto kodu.

AMD komplektēšana

Ja izmantojat AMD, vēlēsities izmantot AMD iekrāvēju, piemēram, RequireJS vai Curl. Moduļu iekrāvējs (salīdzinājumā ar komplektētāju) dinamiski ielādē moduļus, kas ir nepieciešami jūsu programmai.

Atgādinām, ka viena no galvenajām AMD atšķirībām no CommonJS ir tā, ka tā moduļus ielādē asinhroni. Šajā ziņā, izmantojot AMD, jums tehniski nav nepieciešams būvniecības solis, kurā jūs moduļus apvienojat vienā failā, jo moduļus ielādējat asinhroni - tas nozīmē, ka jūs pakāpeniski lejupielādējat tikai tos failus, kas ir noteikti nepieciešami, lai izpildītu nevis lejupielādēt visus failus uzreiz, kad lietotājs pirmo reizi apmeklē lapu.

Tomēr patiesībā liela apjoma pieprasījumiem laika gaitā par katru lietotāja darbību nav lielas jēgas ražošanā. Lielākā daļa tīmekļa izstrādātāju joprojām izmanto būvniecības rīkus, lai optimizētu veiktspēju un apvienotu savus AMD moduļus, izmantojot, piemēram, tādus rīkus kā RequireJS optimizer, r.js

Kopumā atšķirība starp AMD un CommonJS saistībā ar komplektēšanu ir šāda: izstrādes laikā AMD lietotnes var izkļūt bez veidošanas soļa. Vismaz līdz brīdim, kad jūs nospiedīsit kodu tiešsaistē, tajā brīdī var tikt izmantoti optimizētāji, piemēram, r.js.

Lai iegūtu interesantu diskusiju par CommonJS pret AMD, skatiet šo ierakstu Toma Deila emuārā :)

Webpack

Ciktāl paketes iet, Webpack ir jauns bērns blokā. Tas tika veidots tā, lai tas būtu agnostiķis jūsu izmantotajai moduļu sistēmai, ļaujot izstrādātājiem attiecīgi izmantot CommonJS, AMD vai ES6.

Jums varētu būt jautājums, kāpēc mums ir nepieciešama Webpack, kad mums jau ir citi grupētāji, piemēram, Browserify un RequireJS, kuri paveic darbu un dara tajā diezgan labu darbu. Pirmkārt, Webpack piedāvā dažas noderīgas funkcijas, piemēram, “koda sadalīšana” - veids, kā sadalīt koda bāzi “gabalos”, kas tiek ielādēti pēc pieprasījuma.

Piemēram, ja jums ir tīmekļa lietotne ar koda blokiem, kas nepieciešami tikai noteiktos apstākļos, iespējams, nav efektīvi visu koda bāzi ievietot vienā masīvā komplektā esošā failā. Šajā gadījumā jūs varētu izmantot koda sadalīšanu, lai kodu izvilktu komplektos, kurus var ielādēt pēc pieprasījuma, izvairoties no problēmām ar lielām priekšējām kravām, kad lielākajai daļai lietotāju ir nepieciešama tikai jūsu lietojumprogrammas kodols.

Koda sadalīšana ir tikai viena no daudzajām pārliecinošajām Webpack piedāvātajām funkcijām, un internets ir pilns ar spēcīgiem viedokļiem par to, vai Webpack vai Browserify ir labāki. Šeit ir tikai dažas no vairāk līmeņa diskusijām, kuras man šķita noderīgas, lai aplauztu galvu par šo jautājumu:

  • //gist.github.com/substack/68f8d502be42d5cd4942
  • //mattdesl.svbtle.com/browserify-vs-webpack
  • //blog.namangoel.com/browserify-vs-webpack-js-drama

ES6 moduļi

Vai jau esat atgriezies? Labi! Jo nākamais es vēlos runāt par ES6 moduļiem, kas dažos veidos nākotnē varētu samazināt vajadzību pēc saišķiem. (Jūs īslaicīgi redzēsiet, ko es domāju.) Vispirms sapratīsim, kā tiek ielādēti ES6 moduļi.

Vissvarīgākā atšķirība starp pašreizējiem JS moduļu formātiem (CommonJS, AMD) un ES6 moduļiem ir tā, ka ES6 moduļi ir veidoti, ņemot vērā statisko analīzi. Tas nozīmē, ka, importējot moduļus, importēšana tiek atrisināta kompilēšanas laikā, tas ir, pirms skripts sāk izpildīt. Tas ļauj mums pirms programmas palaišanas noņemt eksportus, kurus citi moduļi neizmanto. Neizmantotā eksporta noņemšana var ievērojami ietaupīt vietu, samazinot pārlūka stresu.

Viens izplatīts jautājums, kas rodas, ir: kā tas atšķiras no mirušā koda izslēgšanas, kas notiek, ja koda samazināšanai izmantojat kaut ko līdzīgu UglifyJS? Atbilde ir, kā vienmēr, "tas ir atkarīgs".

(PIEZĪME: mirušā koda atcelšana ir optimizācijas solis, kas noņem neizmantoto kodu un mainīgos - domājiet par to kā liekās bagāžas noņemšanu, kas jūsu komplektētajai programmai nav jāpalaiž, * pēc tam, kad * tā ir apvienota).

Dažreiz mirušā koda izslēgšana varētu darboties tieši tāpat starp UglifyJS un ES6 moduļiem, un citreiz nē. Rollup's wiki) ir foršs piemērs, ja vēlaties to pārbaudīt.

ES6 moduļus atšķir atšķirīgā pieeja mirušā koda izslēgšanai, ko sauc par “koku kratīšanu”. Koku kratīšana pēc būtības ir atmirusi koda izslēgšana. Tas ietver tikai kodu, kas jāpalaiž jūsu komplektam, nevis izslēdz kodu, kas jums nav nepieciešams. Apskatīsim koku kratīšanas piemēru:

Pieņemsim, ka mums ir fails utils.js ar zemāk norādītajām funkcijām, un katru no tām mēs eksportējam, izmantojot ES6 sintaksi:

Pieņemsim, ka mēs nezinām, kādas utils funkcijas mēs vēlamies izmantot mūsu programmā, tāpēc mēs turpinām importēt visus mod.js moduļus šādi:

Un tad mēs vēlāk izmantojam tikai katru funkciju:

Mūsu mod.js faila “koku satricinātā” versija izskatīsies šādi, tiklīdz moduļi būs ielādēti:

Ievērojiet, kā tiek izmantoti tikai eksportētie produkti: katrs .

Tikmēr, ja mēs nolemjam katras funkcijas vietā izmantot filtra funkciju, mēs izskatīsim kaut ko līdzīgu šim:

Koka satricinātā versija izskatās šādi:

Ievērojiet, kā šoreiz tiek iekļauti gan katrs, gan filtrs . Tas ir tāpēc, ka filtrs ir definēts tā, lai tos izmantotu katru , tāpēc, lai modulis darbotos, mums ir nepieciešami abi eksporta veidi.

Diezgan gluds, ja?

Es izaicinu jūs spēlēt un izpētīt koku drebēšanu Rollup.js tiešraidē un redaktorā.

ES6 moduļu veidošana

Labi, tāpēc mēs zinām, ka ES6 moduļi tiek ielādēti atšķirīgi no citiem moduļu formātiem, taču mēs joprojām neesam runājuši par būvniecības darbību, kad izmantojat ES6 moduļus.

Diemžēl ES6 moduļiem joprojām ir nepieciešams papildu darbs, jo pagaidām nav vietējas ieviešanas, kā pārlūkprogrammas ielādē ES6 moduļus.

Šeit ir dažas iespējas, kā izveidot / pārveidot ES6 moduļus darbam pārlūkprogrammā, un šodien visizplatītākā pieeja ir # 1 :

  1. Izmantojiet transpileru (piemēram, Babel vai Traceur), lai pārsūtītu savu ES6 kodu uz ES5 kodu vai nu CommonJS, AMD vai UMD formātā. Pēc tam pārsūtiet pārkodēto kodu caur moduļu paketi, piemēram, Browserify vai Webpack, lai izveidotu vienu vai vairākus komplektā esošos failus.
  2. Izmantojiet Rollup.js, kas ir ļoti līdzīgs 1. opcijai, izņemot to, ka apkopojums nodrošina ES6 moduļu jaudu, lai statiski analizētu jūsu ES6 kodu un atkarības pirms komplektēšanas. Tas izmanto “koku kratīšanu”, lai komplektā iekļautu minimālo minimumu. Kopumā Rollup.js galvenais ieguvums salīdzinājumā ar Browserify vai Webpack, kad izmantojat ES6 moduļus, ir tas, ka koku kratīšana varētu padarīt jūsu saišķus mazākus. Brīdinājums ir tāds, ka apkopojums nodrošina vairākus formātus, ar kuriem jūsu kods tiek apvienots, tostarp ES6, CommonJS, AMD, UMD vai IIFE. IIFE un UMD paketes jūsu pārlūkprogrammā darbotos tādas, kādas tās ir, taču, ja jūs izvēlaties apvienot ar AMD, CommonJS vai ES6, jums jāatrod citas metodes, kā šo kodu pārveidot pārlūkprogrammai saprotamā formātā (piemēram, izmantojot pārlūka Webpack, RequireJS utt.).

Lecot cauri stīpām

Kā tīmekļa izstrādātājiem mums ir jālec cauri daudziem lokiem. Ne vienmēr ir viegli pārveidot mūsu skaistos ES6 moduļus par to, ko pārlūkprogrammas var interpretēt.

Jautājums ir, kad ES6 moduļi darbosies pārlūkprogrammā bez visa šī pieskaitāmā apjoma?

Atbilde, par laimi, "agrāk nekā vēlāk".

Pašlaik ECMAScript ir specifikācija risinājumam, ko sauc par ECMAScript 6 moduļa ielādētāja API. Īsāk sakot, šī ir programmatiska, uz Promise balstīta API, kurai ir paredzēts dinamiski ielādēt jūsu moduļus un saglabāt tos kešatmiņā, lai nākamie importēšanas laikā netiktu atkārtoti ielādēta jauna moduļa versija.

Tas izskatīsies apmēram šādi:

myModule.js

main.js

Varat arī definēt moduļus, tieši skripta tagā norādot “type = module”, piemēram:

Ja vēl neesat pārbaudījis moduļa ielādētāja API polifill repo, es ļoti iesaku vismaz palūrēt.

Turklāt, ja vēlaties izmēģināt šo pieeju, apskatiet SystemJS, kas ir uzbūvēts virs ES6 moduļa iekrāvēja polifilmas. SystemJS pārlūkprogrammā un mezglā dinamiski ielādē jebkura moduļa formātu (ES6 moduļus, AMD, CommonJS un / vai globālos skriptus). Tas izseko visus ielādētos moduļus “moduļu reģistrā”, lai izvairītos no iepriekš ielādētu moduļu atkārtotas ielādes. Nemaz nerunājot par to, ka tas arī automātiski pārsūta ES6 moduļus (ja vienkārši iestatāt opciju) un tam ir iespēja ielādēt jebkura veida moduli no jebkura cita veida! Diezgan veikls.

Vai tagad, kad mums ir vietējie ES6 moduļi, mums joprojām būs vajadzīgi saiņotāji?

ES6 moduļu pieaugošajai popularitātei ir dažas interesantas sekas:

Vai HTTP / 2 padarīs moduļu paketes novecojušas?

Izmantojot HTTP / 1, katram TCP savienojumam ir atļauts tikai viens pieprasījums. Tāpēc, ielādējot vairākus resursus, ir nepieciešami vairāki pieprasījumi. Izmantojot HTTP / 2, viss mainās. HTTP / 2 ir pilnībā multipleksēts, tas nozīmē, ka vairāki pieprasījumi un atbildes var notikt paralēli. Rezultātā mēs varam apkalpot vairākus pieprasījumus vienlaikus ar vienu savienojumu.

Tā kā maksa par HTTP pieprasījumu ir ievērojami zemāka nekā HTTP / 1, ķekaru moduļu ielāde ilgtermiņā nebūs milzīga veiktspējas problēma. Daži apgalvo, ka tas nozīmē, ka moduļu apvienošana vairs nebūs nepieciešama. Tas noteikti ir iespējams, bet tas patiešām ir atkarīgs no situācijas.

Pirmkārt, moduļu apvienošana piedāvā priekšrocības, kuras HTTP / 2 neņem vērā, piemēram, neizmantoto eksportu noņemšana, lai ietaupītu vietu. Ja veidojat vietni, kurā ir svarīgi katrs mazais sniegums, komplektēšana var dot jums papildu priekšrocības ilgtermiņā. Tas nozīmē, ka, ja jūsu veiktspējas vajadzības nav tik ārkārtējas, jūs varētu ietaupīt laiku ar minimālām izmaksām, pilnībā izlaižot būvēšanas soli.

Kopumā mēs joprojām esam diezgan tālu no tā, ka lielākā daļa vietņu savu kodu apkalpo, izmantojot HTTP / 2. Es sliecos prognozēt, ka būvniecības process ir šeit, lai paliktu vismaz tuvākajā laikā.

PS: Pastāv arī citas atšķirības ar HTTP / 2, un, ja jūs zināt, šeit ir lielisks resurss.

Vai CommonJS, AMD un UMD būs novecojuši?

Kad ES6 kļūst par moduļa standartu, vai mums tiešām ir vajadzīgi citi moduļu veidi, kas nav vietējie?

ES par to šaubos.

Tīmekļa attīstībai ir liels ieguvums no vienas standartizētas metodes, kā importēt un eksportēt moduļus JavaScript, bez starpnieka darbībām. Cik ilgs laiks būs vajadzīgs, lai sasniegtu punktu, kur ES6 ir moduļa standarts?

Izredzes ir, diezgan ilgu laiku;)

Turklāt ir daudz cilvēku, kuriem patīk izvēlēties “garšas”, tāpēc “viena patiesa pieeja” nekad nevar kļūt par realitāti.

Secinājums

Es ceru, ka šī divdaļīgā ziņa palīdzēja noskaidrot dažus žargona izstrādātājus, kurus viņi izmanto, runājot par moduļiem un moduļu apvienošanu. Pārejiet uz priekšu un pārbaudiet I daļu, ja kāds no iepriekš minētajiem noteikumiem jums šķiet neskaidrs.

Kā vienmēr, runājiet ar mani komentāros un droši uzdodiet jautājumus!

Priecīgu komplektēšanu :)