Articles

Een ES6-project opzetten met Babel en webpack

In dit artikel gaan we kijken naar het maken van een build setup voor het omgaan met moderne JavaScript (dat draait in webbrowsers) met behulp van Babel en webpack.

Dit is nodig om ervoor te zorgen dat onze moderne JavaScript-code in het bijzonder compatibel wordt gemaakt met een breder scala aan browsers dan anders het geval zou zijn.

JavaScript, net als de meeste web-gerelateerde technologieën, evolueert de hele tijd. Vroeger konden we een paar <script>-tags in een pagina zetten, misschien jQuery en een paar plugins toevoegen en klaar was kees.

Maar sinds de introductie van ES6 zijn de dingen steeds ingewikkelder geworden. Browserondersteuning voor nieuwere taalfuncties is vaak fragmentarisch, en naarmate JavaScript-applicaties ambitieuzer worden, beginnen ontwikkelaars modules te gebruiken om hun code te organiseren. Dit betekent weer dat als je vandaag de dag moderne JavaScript schrijft, je een build-stap in je proces moet introduceren.

Zoals je kunt zien aan de links hieronder, verhoogt de conversie van ES6 naar ES5 het aantal browsers dat we kunnen ondersteunen drastisch.

  • ES6-compatibiliteit
  • ES5-compatibiliteit

Het doel van een build-systeem is het automatiseren van de workflow die nodig is om onze code gereed te maken voor browsers en productie. Dit kan stappen inhouden zoals het transporteren van code naar een andere standaard, het compileren van Sass naar CSS, het bundelen van bestanden, het minifiëren en comprimeren van code, en vele andere. Om ervoor te zorgen dat deze stappen consistent herhaalbaar zijn, is een build systeem nodig om de stappen in een bekende volgorde te starten vanaf een enkel commando.

Prerequisites

Om mee te kunnen volgen, moet je zowel Node.js als npm geïnstalleerd hebben (ze komen samen verpakt). Ik raad aan om een versiebeheerder zoals nvm te gebruiken om je Node-installatie te beheren (hier lees je hoe), en als je hulp nodig hebt om npm onder de knie te krijgen, bekijk dan SitePoint’s beginnersvriendelijke npm tutorial.

Instellen

Maak ergens op je computer een hoofdmap aan en navigeer daarin vanaf je terminal/command line. Dit zal uw <ROOT> map zijn.

Maak een package.json bestand aan met deze:

npm init -y

Note: De -y vlag maakt het bestand met standaard instellingen, en betekent dat u geen van de gebruikelijke details hoeft in te vullen vanaf de commandoregel. Deze kunnen later worden gewijzigd in uw code editor als u dat wenst.

Maak in uw <ROOT> map de mappen src, src/js, en public. In de src/js-map zetten we onze onbewerkte broncode, en in de public-map komt de getranspileerde code te staan.

Transpileren met Babel

Om te beginnen installeren we babel-cli, waarmee we ES6 kunnen transpileren naar ES5, en babel-preset-env, waarmee we de getranspileerde code kunnen richten op specifieke browserversies.

npm install babel-cli babel-preset-env --save-dev

U zou nu het volgende in uw package.json moeten zien:

"devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.6.1"}

Nadat we toch in het package.json bestand zijn, laten we de scripts sectie als volgt veranderen:

"scripts": { "build": "babel src -d public"},

Dit geeft ons de mogelijkheid om Babel via een script aan te roepen, in plaats van elke keer direct vanaf de terminal. Als u meer wilt weten over npm-scripts en wat ze kunnen doen, bekijk dan deze SitePoint-tutorial.

Tot slot, voordat we kunnen testen of Babel zijn ding doet, moeten we een .babelrc-configuratiebestand maken. Dit is waar ons babel-preset-env pakket naar zal verwijzen voor zijn transpileer parameters.

Maak een nieuw bestand aan in uw <ROOT> directory genaamd .babelrc en plak het volgende erin:

{ "presets": } } ] ]}

Dit zal Babel instellen om te transporteren voor de laatste twee versies van elke browser, plus Safari op v7 of hoger. Andere opties zijn beschikbaar, afhankelijk van welke browsers u moet ondersteunen.

Met dat opgeslagen, kunnen we nu de zaken uitproberen met een voorbeeld JavaScript-bestand dat ES6 gebruikt. Voor dit artikel heb ik een kopie van leftpad aangepast om op een aantal plaatsen ES6 syntax te gebruiken: template-literalen, pijlfuncties, const en let.

Bewaar dit als src/js/leftpad.js en voer in je terminal het volgende uit:

npm run build

Als alles naar wens is, zou je nu in je public map een nieuw bestand met de naam js/leftpad.js moeten vinden. Als u dat opent, zult u zien dat het geen ES6-syntax meer bevat en er als volgt uitziet:

Organizing Your Code with ES6 Modules

Een ES6-module is een JavaScript-bestand met functies, objecten of primitieve waarden die u beschikbaar wilt maken voor een ander JavaScript-bestand. Je export van de ene, en import in de andere. Elk serieus modern JavaScript project zou het gebruik van modules moeten overwegen. Ze stellen u in staat om uw code op te splitsen in op zichzelf staande eenheden en daardoor dingen gemakkelijker te onderhouden te maken; ze helpen u namespace-vervuiling te voorkomen; en ze helpen uw code meer draagbaar en herbruikbaar te maken.

Hoewel het merendeel van de ES6-syntaxis algemeen beschikbaar is in moderne browsers, is dit nog niet het geval met modules. Op het moment van schrijven zijn ze beschikbaar in Chrome, Safari (inclusief de laatste iOS-versie) en Edge; ze zijn verborgen achter een vlag in Firefox en Opera; en ze zijn niet beschikbaar (en zullen dat waarschijnlijk ook nooit worden) in IE11, noch op de meeste mobiele apparaten.

In de volgende sectie bekijken we hoe we modules kunnen integreren in onze build setup.

Export

Het export sleutelwoord is wat ons in staat stelt om onze ES6 modules beschikbaar te maken voor andere bestanden, en het geeft ons twee opties om dat te doen – named en default. Met de named export, kun je meerdere exports per module hebben, en met een default export heb je er maar één per module. Genoemde exports zijn vooral nuttig wanneer u meerdere waarden moet exporteren. U kunt bijvoorbeeld een module hebben die een aantal utiliteitsfuncties bevat die op verschillende plaatsen in uw apps beschikbaar moeten worden gemaakt.

Dus laten we ons leftPad bestand in een module veranderen, die we dan in een tweede bestand kunnen vereisen.

Naam export

Om een naam export te maken, voegt u het volgende toe aan de onderkant van het leftPad bestand:

export { leftPad };

We kunnen ook de "use strict"; declaratie verwijderen van de bovenkant van het bestand, omdat modules standaard in strict mode draaien.

Default Export

Omdat er slechts een enkele functie wordt geëxporteerd in het leftPad bestand, zou het eigenlijk een goede kandidaat kunnen zijn om export default te gebruiken:

export default function leftPad(str, len, ch) { ...}

Wederom, u kunt de "use strict"; declaratie bovenaan het bestand verwijderen.

Import

Om gebruik te maken van geëxporteerde modules, moeten we deze nu importeren in het bestand (module) waarin we ze willen gebruiken.

Voor de export default optie, kan de geëxporteerde module worden geïmporteerd onder elke naam die u wenst te kiezen. Bijvoorbeeld, de leftPad module kan worden geïmporteerd als volgt:

import leftPad from './leftpad';

Of het kan worden geïmporteerd onder een andere naam, als volgt:

import pineapple_fritter from './leftpad';

Functioneel zullen beide precies hetzelfde werken, maar het is natuurlijk zinvol om ofwel dezelfde naam te gebruiken als waaronder het werd geëxporteerd, of iets dat de import begrijpelijk maakt – misschien waar de geëxporteerde naam zou botsen met een andere variabele naam die al bestaat in de ontvangende module.

Voor de named export optie moeten we de module importeren met dezelfde naam als waaronder hij is geëxporteerd. Voor onze voorbeeldmodule importeren we op dezelfde manier als met de export default syntaxis, maar in dit geval moeten we de geïmporteerde naam omgeven met accolades:

import { leftPad } from './leftpad';

De accolades zijn verplicht bij een named export, en het zal mislukken als ze niet worden gebruikt.

Het is mogelijk om de naam van een named export bij import te veranderen als dat nodig is, en om dat te doen moeten we onze syntaxis een beetje wijzigen met behulp van een import as syntaxis. Net als bij export zijn er verschillende manieren om dit te doen, die allemaal worden beschreven op de MDN import pagina.

import { leftPad as pineapple_fritter } from './leftpad_es6';

Wederom is de naamsverandering een beetje onzinnig, maar het illustreert het punt dat ze kunnen worden veranderd in wat dan ook. Je moet je te allen tijde houden aan goede naamgeving, tenzij je natuurlijk routines schrijft voor het bereiden van fruit-gebaseerde recepten.

Gebruik maken van de geëxporteerde module

Om gebruik te maken van de geëxporteerde leftPad module, heb ik het volgende index.js bestand gemaakt in de src/js map. Hier loop ik door een array van serienummers, en voorzie ze van nullen om er een string van acht karakters van te maken. Later zullen we hier gebruik van maken en ze posten in een geordend lijstelement op een HTML-pagina. Merk op dat dit voorbeeld de standaard export syntax gebruikt:

Zoals we eerder deden, voer het build script uit vanuit de <ROOT> directory:

npm run build

Babel zal nu een index.js bestand maken in de public/js directory. Net als bij ons leftPad.js bestand, zou u moeten zien dat Babel alle ES6 syntax heeft vervangen en alleen ES5 syntax heeft achtergelaten. U zult ook zien dat het de ES6 module syntax heeft omgezet naar de Node-gebaseerde module.exports, wat betekent dat we het kunnen uitvoeren vanaf de commandoregel:

node public/js/index.js// 

Uw terminal zou nu een array van strings moeten uitloggen, voorafgegaan door nullen om ze allemaal acht karakters lang te maken. Nu dat gedaan is, is het tijd om naar webpack te kijken.

Inleiding tot webpack en integratie met Babel

Zoals gezegd, stellen ES6-modules de JavaScript-ontwikkelaar in staat om zijn code op te splitsen in hanteerbare brokken, maar het gevolg hiervan is dat die brokken aan de aanvragende browser moeten worden geserveerd, waardoor mogelijk tientallen extra HTTP-verzoeken naar de server moeten worden teruggestuurd – iets wat we eigenlijk zouden moeten proberen te vermijden. Dit is waar webpack om de hoek komt kijken.

webpack is een module bundelaar. Het primaire doel is om uw applicatie te verwerken door het opsporen van alle afhankelijkheden, en deze vervolgens allemaal te verpakken in een of meer bundels die in de browser kunnen worden uitgevoerd. Het kan echter veel meer zijn dan dat, afhankelijk van hoe het is geconfigureerd.

webpack configuratie is gebaseerd op vier belangrijke componenten:

  • een entry punt
  • een uitvoer locatie
  • loaders
  • plugins

Entry: Dit bevat het startpunt van uw applicatie van waaruit webpack zijn afhankelijkheden kan identificeren.

Output: Dit specificeert waar u wilt dat de verwerkte bundel wordt opgeslagen.

Loaders: Deze zijn een manier om een ding als invoer te converteren en iets anders als uitvoer te genereren. Ze kunnen worden gebruikt om de mogelijkheden van webpack uit te breiden om meer dan alleen JavaScript-bestanden te verwerken, en die dus ook om te zetten in geldige modules.

Plugins: Deze worden gebruikt om de mogelijkheden van webpack uit te breiden naar andere taken dan bundelen – zoals minification, linting en optimalisatie.

Om webpack te installeren, voert u het volgende uit vanuit uw <ROOT> directory:

npm install webpack webpack-cli --save-dev

Dit installeert webpack lokaal in het project, en geeft ook de mogelijkheid om webpack vanaf de opdrachtregel uit te voeren door de toevoeging van webpack-cli. U zou nu webpack moeten zien staan in uw package.json bestand. Terwijl u in dat bestand bent, wijzigt u de scripts sectie als volgt, zodat het nu weet dat het webpack moet gebruiken in plaats van Babel direct:

"scripts": { "build": "webpack --config webpack.config.js"},

Zoals u kunt zien, roept dit script een webpack.config.js bestand aan, dus laten we dat aanmaken in onze <ROOT> directory met de volgende inhoud:

Dit is min of meer het eenvoudigste config bestand dat u nodig heeft met webpack. U kunt zien dat het de eerder beschreven invoer- en uitvoersecties gebruikt (het zou met deze alleen kunnen functioneren), maar bevat ook een mode: 'development'-instelling.

webpack heeft de optie om ofwel “ontwikkeling” of “productie” modi te gebruiken. De instelling mode: 'development' optimaliseert de bouwsnelheid en debugging, terwijl mode: 'production' optimaliseert voor de uitvoersnelheid tijdens runtime en de bestandsgrootte van de uitvoer. Er staat een goede uitleg over modi in Tobias Koppers’ artikel “webpack 4: mode and optimization” als u meer wilt lezen over hoe ze kunnen worden geconfigureerd buiten de standaardinstellingen.

Volgende, verwijder alle bestanden uit de public/js map. Voer dan dit opnieuw uit:

npm run build

U zult zien dat het nu een enkel ./public/bundle.js bestand bevat. Open het nieuwe bestand, en de twee bestanden waar we mee begonnen zien er heel anders uit. Dit is het gedeelte van het bestand dat de index.js code bevat. Hoewel het behoorlijk is aangepast van ons origineel, kunt u nog steeds de variabele namen onderscheiden:

Als u node public/js/bundle.js uitvoert vanuit de <ROOT> map, zult u zien dat u dezelfde resultaten krijgt als we eerder hadden.

Transpiling

Zoals eerder vermeld, stellen loaders ons in staat om het ene ding om te zetten in iets anders. In dit geval, willen we ES6 omzetten in ES5. Om dat te doen, hebben we nog een paar pakketten nodig:

npm install babel-loader babel-core --save-dev

Om ze te gebruiken, moet aan de webpack.config.js een module sectie worden toegevoegd na de output sectie, zoals dit:

Dit gebruikt een regex statement om de JavaScript bestanden te identificeren die getranspiled moeten worden met de babel-loader, terwijl alles in de node_modules map daarvan wordt uitgesloten. Tenslotte wordt de babel-loader verteld om het eerder geïnstalleerde babel-preset-env pakket te gebruiken, om de transpileer parameters in te stellen in het .babelrc bestand.

Met dat gedaan, kunt u dit opnieuw uitvoeren:

npm run build

Controleer dan de nieuwe public/js/bundle.js en u zult zien dat alle sporen van ES6 syntax verdwenen zijn, maar het produceert nog steeds dezelfde uitvoer als voorheen.

Breng het naar de browser

Na het bouwen van een functionerende webpack en Babel setup, is het tijd om wat we hebben gedaan naar de browser te brengen. Een klein HTML bestand is nodig, en dit moet worden aangemaakt in de <ROOT> map zoals hieronder:

Een beetje meer JavaScript is nodig om de lijst weer te geven, dus laten we ./src/js/index.js aanpassen om dat te laten gebeuren:

Als u nu index.html in uw browser opent, zou u een geordende lijst moeten zien verschijnen, zoals hieronder:

Taking it Further

Zoals hierboven geconfigureerd, is ons build-systeem zo goed als klaar voor gebruik. We kunnen nu webpack gebruiken om onze modules te bundelen en de ES6-code naar ES5 te transporteren met Babel.

Het is echter een beetje vervelend dat we, om onze ES6-code te transporteren, npm run build moeten uitvoeren elke keer dat we een wijziging aanbrengen.

Een ‘watch’

Om de noodzaak om herhaaldelijk npm run build uit te voeren te ondervangen, kunt u een 'watch' op uw bestanden instellen en webpack automatisch laten hercompileren iedere keer dat het een wijziging ziet in een van de bestanden in de ./src map. Om dat te implementeren, wijzigt u de scripts sectie van het package.json bestand, zoals hieronder:

"scripts": { "watch": "webpack --watch", "build": "webpack --config webpack.config.js"},

Om te controleren of het werkt, voert u npm run watch uit vanaf de terminal, en u zult zien dat het niet langer terugkeert naar de opdrachtprompt. Ga nu terug naar src/js/index.js en voeg een extra waarde toe in de serNos array en sla het op. De mijne ziet er nu zo uit:

const serNos = ;

Als u nu de terminal controleert, zult u zien dat hij is uitgelogd, en dat hij de webpack build taak opnieuw heeft uitgevoerd. En als u teruggaat naar de browser en refresht, ziet u dat de nieuwe waarde is toegevoegd aan het eind van de lijst, na te zijn verwerkt met leftPad.

Ververs de browser automatisch

Het zou nu echt goed zijn als we webpack zover konden krijgen dat het de browser automatisch ververst telkens als we een wijziging aanbrengen. Laten we dat doen door een extra npm pakket te installeren genaamd webpack-dev-server. Vergeet echter niet om eerst Ctrl + c uit de watch taak te halen!

npm install webpack-dev-server --save-dev

Als dat klaar is, laten we een nieuw script toevoegen aan het package.json bestand om het nieuwe pakket aan te roepen. De scripts sectie zou nu het volgende moeten bevatten:

Let op de --open-page vlag die aan het eind van het script is toegevoegd. Dit vertelt webpack-dev-server om een specifieke pagina te openen in uw standaard browser met behulp van de iframe modus.

Nu npm start uitvoeren en u zou een nieuw browser tabblad geopend moeten zien worden op met de onderdelen lijst die wordt weergegeven. Om te laten zien dat 'watch' werkt, gaat u naar src/js/index.js en voegt u nog een nieuwe waarde toe aan het eind van de serNos array. Wanneer u uw wijzigingen opslaat, zou u ze bijna onmiddellijk in de browser moeten zien verschijnen.

Met dit compleet, is het enige wat overblijft voor de modus in webpack.config.js om te worden ingesteld op production. Zodra dat is ingesteld, zal webpack ook de code minifiëren die het uitvoert in ./public/js/bundle.js. Merk op dat als mode niet is ingesteld, webpack standaard de production configuratie zal gebruiken.

Conclusie

In dit artikel hebt u gezien hoe u een bouwsysteem voor modern JavaScript kunt opzetten. In eerste instantie werd Babel gebruikt vanaf de commandoregel om de ES6 syntax om te zetten naar ES5. Daarna hebt u gezien hoe u ES6 modules kunt gebruiken met de export en import sleutelwoorden, hoe u webpack kunt integreren om een bundeltaak uit te voeren, en hoe u een watch taak kunt toevoegen om webpack automatisch te laten draaien telkens wanneer wijzigingen aan een bronbestand worden gedetecteerd. Tenslotte hebt u gezien hoe u webpack-dev-server installeert om de pagina automatisch te verversen telkens wanneer een wijziging wordt aangebracht.

Wenst u hier verder mee te gaan, dan stel ik voor SitePoint’s diepe duik in webpack en module bundeling te lezen, evenals onderzoek te doen naar aanvullende loaders en plugins die webpack in staat stellen Sass en asset compressie taken af te handelen. Kijk ook eens naar de eslint-loader en de plugin voor Prettier.

Happy bundling …