Configurarea unui proiect ES6 folosind Babel și webpack
În acest articol, ne vom uita la crearea unei configurații de construire pentru a gestiona JavaScript modern (care rulează în browsere web) folosind Babel și webpack.
Acest lucru este necesar pentru a ne asigura că codul nostru JavaScript modern, în special, este compatibil cu o gamă mai largă de browsere decât ar putea fi altfel.
JavaScript, la fel ca majoritatea tehnologiilor legate de web, evoluează tot timpul. În vremurile bune de odinioară, puteam să aruncăm câteva tag-uri <script>
într-o pagină, poate include jQuery și câteva plugin-uri, apoi să fim gata de utilizare.
Cu toate acestea, de la introducerea ES6, lucrurile au devenit progresiv mai complicate. Suportul browserelor pentru cele mai noi caracteristici ale limbajului este adesea fragmentat și, pe măsură ce aplicațiile JavaScript devin mai ambițioase, dezvoltatorii încep să folosească module pentru a-și organiza codul. La rândul său, acest lucru înseamnă că, dacă astăzi scrieți JavaScript modern, va trebui să introduceți o etapă de compilare în procesul dumneavoastră.
După cum puteți vedea din link-urile de mai jos, conversia de la ES6 la ES5 crește dramatic numărul de browsere pe care le putem suporta.
- Compatibilitate ES6
- Compatibilitate ES5
Scopul unui sistem de construire este de a automatiza fluxul de lucru necesar pentru a ne pregăti codul pentru browsere și producție. Acest lucru poate include etape precum transpunerea codului la un standard diferit, compilarea Sass în CSS, gruparea fișierelor, minificarea și comprimarea codului și multe altele. Pentru a ne asigura că acestea sunt repetabile în mod consecvent, este nevoie de un sistem de compilare pentru a iniția pașii într-o secvență cunoscută dintr-o singură comandă.
Precondiții
Pentru a putea urmări, va trebui să aveți instalate atât Node.js, cât și npm (acestea vin la pachet). V-aș recomanda să folosiți un manager de versiuni, cum ar fi nvm, pentru a vă gestiona instalarea Node (iată cum), iar dacă doriți ajutor pentru a vă familiariza cu npm, consultați tutorialul npm pentru începători de la SitePoint.
Set Up
Crearea unui folder rădăcină undeva pe computerul dumneavoastră și navigați în el din terminal/linia de comandă. Acesta va fi folderul dvs. <ROOT>
.
Creați un fișier package.json
cu acest lucru:
npm init -y
Nota: Stegulețul -y
creează fișierul cu setările implicite și înseamnă că nu trebuie să completați niciunul dintre detaliile obișnuite din linia de comandă. Acestea pot fi modificate ulterior în editorul de cod, dacă doriți.
În cadrul folderului <ROOT>
, creați directoarele src
, src/js
și public
. Dosarul src/js
va fi cel în care vom pune codul sursă neprocesat, iar dosarul public
va fi cel în care va ajunge codul transpilat.
Transpilarea cu Babel
Pentru a începe, vom instala babel-cli, care oferă posibilitatea de a transpila ES6 în ES5, și babel-preset-env, care ne permite să țintim anumite versiuni de browser cu codul transpilat.
npm install babel-cli babel-preset-env --save-dev
Ar trebui să vedeți acum următoarele în fișierul package.json
:
"devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.6.1"}
În timp ce ne aflăm în fișierul package.json
, să schimbăm secțiunea scripts
pentru a se citi astfel:
"scripts": { "build": "babel src -d public"},
Acest lucru ne oferă posibilitatea de a apela Babel prin intermediul unui script, mai degrabă decât direct din terminal de fiecare dată. Dacă doriți să aflați mai multe despre scripturile npm și despre ce pot face acestea, consultați acest tutorial SitePoint.
În cele din urmă, înainte de a putea testa dacă Babel își face treaba, trebuie să creăm un fișier de configurare .babelrc
. Acesta este cel la care pachetul nostru babel-preset-env
se va referi pentru parametrii săi de transpilere.
Creați un nou fișier în directorul <ROOT>
numit .babelrc
și lipiți următoarele în el:
{ "presets": } } ] ]}
Acest lucru va configura Babel să transpileze pentru ultimele două versiuni ale fiecărui browser, plus Safari la v7 sau mai mare. Sunt disponibile și alte opțiuni, în funcție de browserele pe care trebuie să le suportați.
După ce am salvat, acum putem testa lucrurile cu un fișier JavaScript de probă care folosește ES6. În scopul acestui articol, am modificat o copie a leftpad pentru a folosi sintaxa ES6 într-un număr de locuri: literali de șablon, funcții săgeată, const și let.
Salvați acest lucru ca src/js/leftpad.js
și din terminal rulați următoarele:
npm run build
Dacă totul este conform intenției, în folderul public
ar trebui să găsiți acum un nou fișier numit js/leftpad.js
. Dacă îl deschideți, veți constata că nu mai conține nicio sintaxă ES6 și că arată astfel:
Organizarea codului dvs. cu module ES6
Un modul ES6 este un fișier JavaScript care conține funcții, obiecte sau valori primitive pe care doriți să le puneți la dispoziția unui alt fișier JavaScript. Se export
de la unul și import
în celălalt. Orice proiect JavaScript modern și serios ar trebui să ia în considerare utilizarea modulelor. Acestea vă permit să vă împărțiți codul în unități de sine stătătoare și, astfel, să faceți lucrurile mai ușor de întreținut; vă ajută să evitați poluarea spațiului de nume; și vă ajută să vă faceți codul mai portabil și mai reutilizabil.
În timp ce majoritatea sintaxei ES6 este disponibilă pe scară largă în browserele moderne, acest lucru nu este încă cazul modulelor. La momentul redactării acestui articol, acestea sunt disponibile în Chrome, Safari (inclusiv în cea mai recentă versiune pentru iOS) și Edge; sunt ascunse în spatele unui steguleț în Firefox și Opera; și nu sunt disponibile (și probabil nu vor fi niciodată) în IE11, nici în majoritatea dispozitivelor mobile.
În următoarea secțiune, vom analiza modul în care putem integra modulele în configurația noastră de construire.
Export
Cuvântul cheie export este cel care ne permite să facem modulele noastre ES6 disponibile în alte fișiere și ne oferă două opțiuni pentru a face acest lucru – numit și implicit. Cu exportul numit, puteți avea mai multe exporturi pe modul, iar cu exportul implicit aveți doar unul pe modul. Exporturile cu nume sunt deosebit de utile în cazul în care trebuie să exportați mai multe valori. De exemplu, este posibil să aveți un modul care să conțină un număr de funcții utilitare care trebuie să fie disponibile în diverse locuri din aplicațiile dumneavoastră.
Așa că haideți să transformăm fișierul nostru leftPad
într-un modul, pe care îl putem cere apoi într-un al doilea fișier.
Export cu nume
Pentru a crea un export cu nume, adăugați următoarele în partea de jos a fișierului leftPad
:
export { leftPad };
export { leftPad };
De asemenea, putem elimina declarația "use strict";
din partea de sus a fișierului, deoarece modulele rulează implicit în modul strict.
Export defectuos
Ca urmare a faptului că există o singură funcție care trebuie exportată în fișierul leftPad
, acesta ar putea fi de fapt un candidat bun pentru a folosi export default
în schimb:
export default function leftPad(str, len, ch) { ...}
Din nou, puteți elimina declarația "use strict";
din partea de sus a fișierului.
Import
Pentru a utiliza modulele exportate, acum trebuie să le importăm în fișierul (modulul) în care dorim să le folosim.
Pentru opțiunea export default
, modulul exportat poate fi importat sub orice nume doriți să alegeți. De exemplu, modulul leftPad
poate fi importat astfel:
import leftPad from './leftpad';
Sau poate fi importat sub un alt nume, astfel:
import pineapple_fritter from './leftpad';
Funcțional, ambele vor funcționa exact la fel, dar, evident, are sens să se folosească fie același nume sub care a fost exportat, fie ceva care să facă importul ușor de înțeles – poate în cazul în care numele exportat ar intra în conflict cu un alt nume de variabilă care există deja în modulul receptor.
Pentru opțiunea de export cu nume, trebuie să importăm modulul folosind același nume cu care a fost exportat. Pentru modulul nostru de exemplu, îl vom importa într-o manieră similară cu cea pe care am folosit-o cu sintaxa export default
, dar în acest caz, trebuie să înfășurăm numele importat cu paranteze curbe:
import { leftPad } from './leftpad';
Parantezele sunt obligatorii cu un export cu nume, iar acesta va eșua dacă nu sunt folosite.
Este posibil să schimbăm numele unui export cu nume la import, dacă este necesar, și pentru a face acest lucru, trebuie să modificăm puțin sintaxa noastră folosind o sintaxă import as
. Ca și în cazul export
, există o varietate de moduri de a face acest lucru, toate fiind detaliate pe pagina de import MDN.
import { leftPad as pineapple_fritter } from './leftpad_es6';
Din nou, schimbarea numelui este puțin lipsită de sens, dar ilustrează faptul că acestea pot fi schimbate în orice. Ar trebui să respectați întotdeauna bunele practici de denumire, cu excepția cazului în care, bineînțeles, scrieți rutine pentru prepararea rețetelor pe bază de fructe.
Consumarea modulului exportat
Pentru a utiliza modulul leftPad
exportat, am creat următorul fișier index.js
în folderul src/js
. Aici, parcurg în buclă o matrice de numere de serie și le prefixez cu zerouri pentru a le transforma într-un șir de opt caractere. Mai târziu, ne vom folosi de acest lucru și le vom afișa într-un element de listă ordonată pe o pagină HTML. Rețineți că acest exemplu folosește sintaxa de export implicită:
Cum am făcut-o mai devreme, rulați scriptul de construire din directorul <ROOT>
:
npm run build
Babel va crea acum un fișier index.js
în directorul public/js
. Ca și în cazul fișierului nostru leftPad.js
, ar trebui să vedeți că Babel a înlocuit toată sintaxa ES6 și a lăsat în urmă doar sintaxa ES5. De asemenea, ați putea observa că a convertit sintaxa modulului ES6 în module.exports
bazat pe Node, ceea ce înseamnă că îl putem rula din linia de comandă:
node public/js/index.js//
Terminalul dvs. ar trebui să înregistreze acum o matrice de șiruri de caractere prefixate cu zerouri pentru a le face pe toate de opt caractere. Acestea fiind făcute, este timpul să aruncăm o privire la webpack.
Introducing webpack and Integrating it with Babel
După cum am menționat, modulele ES6 permit dezvoltatorului JavaScript să își fragmenteze codul în bucăți ușor de gestionat, dar consecința este că aceste bucăți trebuie să fie servite către browserul solicitant, adăugând potențial zeci de cereri HTTP suplimentare înapoi la server – ceva ce chiar ar trebui să căutăm să evităm. Aici intervine webpack.
webpack este un bundler de module. Scopul său principal este de a procesa aplicația dvs. prin urmărirea tuturor dependențelor sale, apoi de a le împacheta pe toate într-unul sau mai multe pachete care pot fi rulate în browser. Cu toate acestea, poate fi mult mai mult decât atât, în funcție de modul în care este configurat.
Configurarea webpack se bazează pe patru componente cheie:
- un punct de intrare
- o locație de ieșire
- loaders
- plugins
Intrare: Acesta deține punctul de start al aplicației dvs. de unde webpack poate identifica dependențele sale.
Output: Aici se specifică unde doriți ca pachetul procesat să fie salvat.
Loaders: Acestea sunt o modalitate de a converti un lucru ca intrare și de a genera altceva ca ieșire. Ele pot fi folosite pentru a extinde capacitățile webpack pentru a gestiona mai mult decât doar fișiere JavaScript și, prin urmare, pentru a le converti și pe acestea în module valide.
Plugins: Acestea sunt folosite pentru a extinde capacitățile webpack în alte sarcini dincolo de împachetare – cum ar fi minificarea, linting și optimizarea.
Pentru a instala webpack, rulați următoarele din directorul <ROOT>
:
npm install webpack webpack-cli --save-dev
Aceasta instalează webpack local în proiect și oferă, de asemenea, posibilitatea de a rula webpack din linia de comandă prin adăugarea lui webpack-cli
. Ar trebui să vedeți acum webpack listat în fișierul package.json
. În timp ce vă aflați în acel fișier, modificați secțiunea de scripturi după cum urmează, astfel încât să știe acum să folosească webpack în loc de Babel direct:
"scripts": { "build": "webpack --config webpack.config.js"},
După cum puteți vedea, acest script apelează la un fișier webpack.config.js
, așa că haideți să îl creăm în directorul nostru <ROOT>
cu următorul conținut:
Acesta este mai mult sau mai puțin cel mai simplu fișier de configurare de care aveți nevoie cu webpack. Puteți vedea că folosește secțiunile de intrare și ieșire descrise mai devreme (ar putea funcționa doar cu acestea), dar conține și o setare mode: 'development'
.
webpack are opțiunea de a folosi fie modul „development”, fie modul „production”. Setarea mode: 'development'
optimizează viteza de compilare și de depanare, în timp ce mode: 'production'
optimizează viteza de execuție în timpul rulării și dimensiunea fișierului de ieșire. Există o explicație bună a modurilor în articolul lui Tobias Koppers „webpack 4: mode and optimization”, dacă doriți să citiți mai multe despre modul în care acestea pot fi configurate dincolo de setările implicite.
În continuare, eliminați toate fișierele din dosarul public/js
. Apoi rulați din nou acest lucru:
npm run build
Veți vedea că acum conține un singur fișier ./public/bundle.js
. Deschideți noul dosar, totuși, și cele două fișiere cu care am început arată destul de diferit. Aceasta este secțiunea din fișier care conține codul index.js
. Chiar dacă este destul de puternic modificat față de originalul nostru, încă puteți distinge numele variabilelor sale:
Dacă rulați node public/js/bundle.js
din folderul <ROOT>
, veți vedea că obțineți aceleași rezultate ca și cele pe care le-am avut anterior.
Transpunerea
După cum am menționat mai devreme, încărcătoarele ne permit să transformăm un lucru în altceva. În acest caz, dorim ca ES6 să fie convertit în ES5. Pentru a face acest lucru, vom avea nevoie de încă câteva pachete:
npm install babel-loader babel-core --save-dev
Pentru a le utiliza, webpack.config.js
are nevoie de o secțiune de modul care să i se adauge după secțiunea de ieșire, astfel:
Aceasta folosește o declarație regex pentru a identifica fișierele JavaScript care urmează să fie transpilate cu babel-loader
, excluzând în același timp tot ceea ce se află în folderul node_modules
din aceasta. În cele din urmă, i se spune lui babel-loader
să folosească pachetul babel-preset-env
instalat mai devreme, pentru a stabili parametrii de transpilare stabiliți în fișierul .babelrc
.
După ce s-a făcut acest lucru, puteți rula din nou acest lucru:
npm run build
Apoi verificați noul public/js/bundle.js
și veți vedea că toate urmele de sintaxă ES6 au dispărut, dar produce în continuare aceeași ieșire ca anterior.
Aducând-o în browser
După ce am construit o configurație webpack și Babel funcțională, este timpul să aducem ceea ce am făcut în browser. Este nevoie de un mic fișier HTML, iar acesta ar trebui să fie creat în folderul <ROOT>
, după cum urmează:
Este nevoie de puțin mai mult JavaScript pentru a afișa lista, așa că haideți să modificăm ./src/js/index.js
pentru a face acest lucru:
Acum, dacă deschideți index.html
în browserul dumneavoastră, ar trebui să vedeți o listă ordonată care să apară, astfel:
Continuând
După cum a fost configurat mai sus, sistemul nostru de construcție este aproape gata de funcționare. Acum putem folosi webpack pentru a grupa modulele noastre și pentru a transpila codul ES6 în ES5 cu Babel.
Cu toate acestea, este un pic supărător faptul că, pentru a transpila codul nostru ES6, trebuie să rulăm npm run build
de fiecare dată când facem o modificare.
Aducerea unui „watch”
Pentru a depăși necesitatea de a rula în mod repetat npm run build
, puteți configura un 'watch'
pe fișierele dvs. și puteți face ca webpack să recompileze automat de fiecare dată când vede o modificare într-unul din fișierele din folderul ./src
. Pentru a implementa acest lucru, modificați secțiunea scripts
din fișierul package.json
, după cum urmează:
"scripts": { "watch": "webpack --watch", "build": "webpack --config webpack.config.js"},
Pentru a verifica dacă funcționează, rulați npm run watch
din terminal și veți vedea că nu se mai întoarce la promptul de comandă. Acum întoarceți-vă la src/js/index.js
și adăugați o valoare suplimentară în matricea serNos
și salvați-o. Al meu arată acum așa:
const serNos = ;
Dacă verificați acum terminalul, veți vedea că s-a deconectat și că a rulat din nou sarcina webpack build
. Iar dacă vă întoarceți la browser și reîmprospătați, veți vedea noua valoare adăugată la sfârșitul listei, după ce a fost procesată cu leftPad
.
Reîmprospătarea automată a browserului
Acum ar fi foarte bine dacă am putea face ca webpack să reîmprospăteze automat browserul de fiecare dată când facem o modificare. Să facem acest lucru prin instalarea unui pachet npm suplimentar numit webpack-dev-server
. Totuși, nu uitați să apăsați Ctrl + c pentru a ieși mai întâi din task-ul watch
!
npm install webpack-dev-server --save-dev
După ce am făcut asta, să adăugăm un nou script la fișierul package.json
pentru a apela noul pachet. Secțiunea scripts
ar trebui să conțină acum acest lucru:
Observați steagul --open-page
adăugat la sfârșitul scriptului. Acesta îi spune lui webpack-dev-server
să deschidă o anumită pagină în browserul dvs. implicit folosind modul iframe.
Acum rulați npm start
și ar trebui să vedeți cum se deschide o nouă filă de browser la cu lista de piese afișată. Pentru a arăta că
'watch'
funcționează, mergeți la src/js/index.js
și adăugați o altă valoare nouă la sfârșitul matricei serNos
. Când salvați modificările, ar trebui să le observați reflectate aproape imediat în browser.
Cu acest lucru finalizat, singurul lucru rămas este ca modul din webpack.config.js
să fie setat la production
. Odată ce acesta este setat, webpack va minifica și codul pe care îl scoate în ./public/js/bundle.js
. Trebuie să rețineți că, dacă mode
nu este setat, webpack va folosi în mod implicit configurația production
.
Concluzie
În acest articol, ați văzut cum să configurați un sistem de construire pentru JavaScript modern. Inițial, acesta a folosit Babel din linia de comandă pentru a converti sintaxa ES6 în ES5. Ați văzut apoi cum să folosiți modulele ES6 cu ajutorul cuvintelor cheie export
și import
, cum să integrați webpack pentru a efectua o sarcină de împachetare și cum să adăugați o sarcină de supraveghere pentru a automatiza rularea webpack de fiecare dată când sunt detectate modificări ale unui fișier sursă. În cele din urmă, ați văzut cum să instalați webpack-dev-server
pentru a reîmprospăta automat pagina de fiecare dată când se face o modificare.
Dacă doriți să aprofundați acest subiect, vă sugerez să citiți studiul aprofundat al SitePoint despre webpack și gruparea modulelor, precum și să cercetați încărcătoarele și plugin-urile suplimentare care vor permite webpack să se ocupe de Sass și de sarcinile de compresie a activelor. De asemenea, uitați-vă la eslint-loader
și la pluginul pentru Prettier too.
Happy bundling …
.