WebpackNr. 2 Większość języków programowania posiada swój sposób na importowanie kodu z jednego pliku do drugiego. JavaScript oryginalnie nie posiadał takiej funkcjonalności i nie został stworzony z myślą, aby taka funkcjonalność była. JavaScript z założenia powinna być uruchamiana tylko z poziomu przeglądarki bez dostępu do plików z komputera użytkownika przeglądarki.

Dlatego jak do tej pory kod JavaScript był organizowany w wielu plikach. Każda funkcjonalność była współdzielona dzięki zmiennym globalnym.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <link rel="stylesheet" href="index.css">
  <script src="node_modules/moment/min/moment.min.js"></script>
  <script src="index.js"></script>
</head>
<body>
  <h1>It's me HTML!</h1>
</body>
</html>

W poprzednim wpisie to właśnie zrobiliśmy. Strona HTML ładuje plik skrypty moment.min.js. Ten skrypt tworzy zmienną globalną moment, która jest dostępna dla każdego skryptu załadowanego po moment.min.js.

// index.js
var date = moment().format("DD[-]MM[-]YYYY");    

console.log(date);
document.write(date);

W roku 2009 powstały pierwsze idee i pomysły nad ekosystemem JavaScript, który byłyby uruchamiany poza przeglądarką.   Projekt ten nazywał CommonJS.

Tak właśnie powstała specyfikacja modułów, które pozwoliłyby JavaScript importować i eksportować kod pomiędzy plikami tak, jak to wygląda w innych językach programowania.

Najlepsza i najbardziej znana implementacja tych wszystkich pomysłów znajduje się właśnie w Node.js.

image

Node.js to silnik JavaScript, który pozwala uruchamiać kod po stronie serwera. Tak jak robią to inne znane języki programowania jak : PHP, C#, Python.

Gdybyśmy pisali aplikację JavaScript w node.js i chcieli ją uruchomić po stronie serwera, to jak byśmy zaznaczyli, że jest nam potrzebny inny skrypt do uruchomienia obecnego.

W node.js mamy do tego funkcje “require()”. Wczyta cały skrypt do zmiennej “moment”.

var moment = require('moment');
var date = moment().format("DD[-]MM[-]YYYY");    

console.log(date);
//document.write(date);
//to nie jest już strona internetowa

Tak działa wczytywanie modułów w Node.js. Ma to sens, gdyż teraz mamy do czynienia z kodem po stronie serwera, który powinien mieć dostęp do plików na serwerze.

Node.js pamięta też gdzie moduły się znajdują. Nie trzeba więc pisać takiego kodu

require('./node_modules/moment/min/moment.min.js)

Brzmi wspaniale. Istnieje oczywiście jeden poważny problem wynikający z kolizji tych dwóch światów. Gdy w aplikacji JavaScript po stronie przeglądarki zastosujesz funkcje require to oczywiście dostaniesz błąd aplikacji.

Przeglądarka nie ma dostępu do plików ze względów bezpieczeństwa. Pytanie więc brzmi jak rozwiązać ten problem? Tak, aby pliki skryptów były wczytywane dynamicznie synchronicznie lub asynchronicznie. Twardy orzech do zgryzienia. Przydałby się jakiś pomost.

Tak właśnie powstała idea stworzenia narzędzi, które takie moduły mogłyby stworzyć za nas. Takie narzędzia nazywamy module bundler.

Działa to w następujący sposób. Narzędzie to analizuje kod wszystkich twoich skryptów w trakcie procesu budowania twojej aplikacji. Ten proces dzieje się po stronie serwera na twoim komputerze. Będzie on analizował wszystkie wyrażenia “require” i działał zgodnie z nimi. Ostatecznie wypluje jeden plik JavaScript, który będzie  spójny z tym co napisałeś oryginalnie. Zostanie on też utworzony na podstawie wszystkich zależności pomiędzy wieloma skryptami, które miały wyrażenia “require”.

Najbardziej popularnym narzędziem “module bundler” był Browserify. Został on wydany w roku 2011 i pozwolił na używanie wyrażenia “require” po stronie front-end. Co w rezultacie pozwoliło NPM menadżerowi paczek z Node.js na stanie się głównym menadżerem.

W roku 2015 powstała alternatywa pod nazwą Webpack, która obecnie zyskała na popularności. Dlaczego? Webpack jest powiązany z facebook-owym framework-iem React, który szybko zdobył popularność.

Jak zawsze dla początkującego programisty JavaScript czeka mały dylemat, co powinien w końcu zainstalować. Tym razem chodzi o narzędzia typu module bundle. Istnieje ich trochę, ale ze wszystkich dostępnych narzędzi Webpack współcześnie daje sobie radę najbardziej.

Visual Studio Code

Jak zainstalować Webpack i z nim zacząć pracę. Trzeba zobaczyć jak wyrażenie “require(‘moment’)” będzie działać dla aplikacji JavaScript po stronie przeglądarki.

Po pierwsze musimy ściągnąć paczkę z menadżera NPM.

npm install webpack --save-dev

Warto zwrócić uwagę na argument instalacji “—save-dev”, Zapisuje on tę paczkę jako zależność deweloperska/środowiskowa.

Jest to paczka, która jest potrzebna do tworzenia aplikacji i nie będzie znajdować się w żaden sposób po stronie klienta i przeglądarki. Jest to dosyć istotny fakt, ponieważ czasami te narzędzia mogą zajmować dużo miejsca. Nigdy one jednak nie będą używane po stronie przeglądarki. Nie znajdą się one również na folderze produkcyjnym.

Nie ma wiec co się przejmować wielkością folderu “node-modules”.

Node_modules

Zmiana także wpłynie na plik konfiguracyjny package.json

{
  "name": "jsstart",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "moment": "^2.19.1"
  },
  "devDependencies": {
    "webpack": "^3.8.1"
  }
}

Dodajmy wyrażenia require do pliku index.js.

var moment = require('moment');

var datetest = moment().format("DD[-]MM[-]YYYY");    
console.log(datetest);

Przy wyrażeniach require Visual Studio Code też potrafi obliczyć wielkość potrzebnego skryptu do pracy w index.js

gzipped visual studio code

Czas na uruchomienie procesu spłaszczenie i analizy plików JavaScript.

Skrypt webpack znajduje się w folderze .bin.

webpack

W terminalu uruchomiamy go podając do niego pełną ścieżkę lokalną.

node_modules\.bin\webpack index.js bundle.js

Z ciekawości możesz sprawdzić jak elementy skryptów zostały ze sobą sklejone w jeden plik.

bundle.js

Do pliku index.html teraz dodajemy referencje tylko do jednego pliku.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <link rel="stylesheet" href="index.css">
  <script src="/bundle.js"></script>
</head>
<body>
  <h1>It's me HTML!</h1>
</body>
</html>

Istnieje jeszcze jeden problem. Za każdym razem, gdy wprowadzimy zmiany do naszych skryptów trzeba uruchomić polecenie webpack ponownie.  Obecnie możemy ułatwić ten proces umieszczając plik konfiguracyjny webpack, który określi jaki plik powinien być transformowany i co powinno być wyplute na samym końcu.

webpack.config.js

Plik konfiguracyjny wygląda tak

// webpack.config.js
module.exports = {
    entry: './index.js',
    output: {
      filename: 'bundle.js'
    }
  };

Teraz uruchamiając polecenie webpack nie musimy podawać tych parametrów.

node_modules\.bin\webpack

Jeśli nie chcesz też odwoływać się ciągle do ścieżki node_module zawsze możesz zainstalować paczkę web-pack globalnie.

npm install webpack -g

Będzie ona dostępna w każdym miejscu, w wierszu poleceń.

webpack

Mimo to warto ją też instalować w projekcie lokalnie, gdyż w ten sposób dajemy znać innym użytkownikom, że do kompilacji tej aplikacji potrzebny jest module-bundler webpack.

Wydaje się, że niewiele to zmieniło. Fakty są jednak inne. Zastosowanie słowa require w naszych skryptach tworzy większy ład we wszystkich naszych skryptach. Nie musisz się już martwić o kolejność ładowania skryptów w stronie HTML.

To jednak nie koniec. By zacząć pracę z JavaScript trzeba także zapoznać się z transcompiler Babel. Po co nam jest kompilator JavaScript, który wypluwa JavaScript. O tym w następnym wpisie.