Skip to content

Moduły EcmaScript

Mechanizm modułów został wprowadzony do JavaScript w momencie gdy język przestał być używany tylko w celu tworzenia małych skryptów wpływających na działanie strony i jej interakcje z użytkownikami a zaczęto budować pełnoprawne aplikacje, które mają wiele kodu, który jest dociągany w zależności od tego czy jest wymagany w danym miejscu. Moduły wykorzystywane są nie tylko w aplikacjach uruchamianych w przeglądarce, ale także w tych uruchamianych przy pomocy NodeJS.

Wcześniej wiele bibliotek jak i narzędzi wspomagało rozbijanie aplikacji na moduły, teraz większość przeglądarek wspiera rozwiązanie, które zapewnia język JavaScript.

Pierwszy moduł

Nasz moduł będzie dosyć trywialnym przykładem, ale dzięki niemu lepiej zrozumiemy zasadę działania. Na początku stwórzmy plik o nazwie injected-div.js, który będzie skryptem generującym kod HTML.

Funkcja przyjmuje argument, który powinien być tekstem, który będzie dodawany jako wnętrze diva. Pamiętajmy o eksporcie naszej funkcji a właściwie modułu.

//injected-div.js

function injectedDiv(msg) {
	const div = document.createElement("div");

	div.textContent = msg;

	document.body.appendChild(div);
}

export { appendDiv };

Teraz stwórzmy prosty plik HTML, gdzie wewnątrz tagu script będziemy wywoływać powyższy skrypt.

// index.html

<html>
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<title></title>
		<meta name="description" content="" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="" />
	</head>
	<body>
		<script type="module">
			import { injectedDiv } from "./injected-div.js";
			injectedDiv("Put some message here to call injectedDiv script");
		</script>
		<script type="module" src="./script-src.js"></script>
	</body>
</html>

Zwróćmy w tym miejscu uwagę na tag script i jego atrybut type="module". To właśnie za pomocą tej właściwości przeglądarka odróżnia moduły od skryptów. Podczas procesu uruchamiania kodu atrybut ten powoduje kilka różnic, z którego główną różnicą jest to, że kod z danego pliku możemy użyć jako moduł.

Aby uruchomić taki kod, nie możemy po prostu uruchomić pliku HTML w przeglądarce, gdyż otrzymamy błąd.

Jest to spowodowane tym, gdyż nasz moduł powinniśmy uruchomić ten plik przy pomocy protokołu HTTP.

W najprostszym rozwiązaniu potrzebujemy mieć zainstalowany Node na naszym komputerze a w konsoli wpisać npx serve. Komenda spowoduje uruchomienie plików na URL localhost:5000.

Po wejściu na podany adres wyświetli nam się tekst, który przekazaliśmy w wywołaniu funkcji. Natomiast w narzędziach developerskich możemy zauważyć, że plik został pobrany przy pomocy metody HTTP, a jego zawartość możemy podejrzeć i jest on dokładnie tym samym, co przed chwilą napisaliśmy.

Teraz spróbujmy nie wykorzystywać inline-script tylko wykonać go w innym pliku, który dociągniemy także jako moduł do pliku HTML.

// script-src.js

import { injectedDiv } from "./injected-div.js";

injectedDiv("Some other script call message");

W pliku HTML dodajmy kolejny tag script.

// index.html ...
<script type="module" src="./script-src.js"></script>
...

Po przeładowaniu strony widzimy, że teraz ładują się nam dwa pliki.

Stwórzmy jeszcze jeden skrypt, który będzie renderował div z opóźnieniem przy wykorzystaniu funkcji injectedDiv oraz metody setTimeout.

// async-script.js

import { injectedDiv } from "./injected-div.js";

function renderSomeDiv() {
	setTimeout(() => injectedDiv("Hello from async script"), 1500);
}

export { renderSomeDiv };

Kod natomiast uruchomimy wewnątrz script-src.js przy użyciu dynamicznego importu. Zwróćmy uwagę w tym miejscu, że przy importowaniu podajemy nazwę pliku wraz z jego rozszerzeniem. W innym wypadku taka operacja by się nie powiodła.

// script-src.js

import { injectedDiv } from "./injected-div.js";

injectedDiv("Hello from external script");

import("./async-script.js").then(
	(moduleExports) => {
		moduleExports.renderSomeDiv();
	},

	(error) => {
		console.error("An error occurred while loading a script!");

		throw error;
	}
);

Wynikiem jest wygenerowany z opóźnieniem tekst. Jednak nie to jest tu najważniejsze a trzy moduły, które otrzymujemy.

Podsumowanie

Moduły w JavaScript to potężne narzędzie i choć wydaje nam się, że takie rozwiązanie jest normalne i wszechobecne, to niestety kilka lat temu programiści nie mieli takiej możliwości ładowania dynamicznie kodu oraz dzielenia kodu w prosty sposób na wiele plików, oraz ich dynamicznego ładowania.

Są oczywiście narzędzia wspierające ładowane modułów takie jak Webpack czy RequireJS, ale warto znać od podszewki jak zaimplementować takie rozwiązanie samemu nawet na dosyć prostych przykładach.