Moduły ECMAScript w Node.js

Czas czytania: 2 min
Liczba słów: 389
Data: 31-03-2020
Udostępnij:

W Node.js każdy plik jest traktowany jako osobny moduł, a że nie piszemy całej aplikacji w jednym pliku to musimy w jakiś sposób nimi zarządzać. Do tej pory w środowisku Node.js korzystaliśmy z modułów CommonJS ale to się może zmienić w przyszłości kiedy stabilne będą moduły ECMAScript.

Moduły CommonJS

Z tymi modułami zetknął się każdy kto chodź raz pisał jakiś skrypt w Node.js. Do zaimportowania zewnętrznego modułu wykorzystujemy składnię reqiure. Natomiast aby udostępnić jakieś funkcje czy wartości dla innych modułów mamy module.exports lub exports

const { database } = require('./database')

module.exports = {
    connection: database.connect('...')
}

Zastanawialiście się kiedyś jak to działa? Skąd się bierze metoda require i obiekt module? Idea mechanizmu jest prosta w przeciwieństwie do implementacji (jeśli ktoś ma chwilę wolnego czasu to może zerknąć do repozytorium). Każdy moduł, który używamy w naszej aplikacji jest opakowywany w funkcję

(function (exports, require, module, __filename, __dirname) { 
	// zwartość naszego modułu
 });

Nasz moduł wygląda wtedy następująco:

(function (exports, require, module, __filename, __dirname) { 
    const { database } = require('./database')

    module.exports = {
        connection: database.connect('...')
    }
});

Dzięki temu, w taki trochę magiczny i ukryty sposób, możemy eksportować i importować moduły w CommonJS.

Moduły ECMAScript

To po co nam właściwie inny sposób radzenia sobie z modułami? Po co nam nowy mechanizm skoro stary się sprawował dobrze przez tyle lat? Ponieważ tak naprawdę to moduły ECMAScript są oficjalnym sposobem na radzenie sobie z modułami w JS'ie. Dzięki temu, że zostały wprowadzone to mamy to zunifikowane dla JS'a i możemy tworzyć biblioteki, które będą z tego mechanizmu korzystały w każdym miejscu gdzie możemy użyć języka JavaScript.

Jak teraz będzie wyglądało korzystanie z innych modułów? Mamy tutaj składnię, którą kojarzymy np.: z React'a czyli import i export

import { database } from './database'

export const connection = database.connect('...')

Oczywiście nie możemy od razu z tego skorzystać gdyż jest to ciągle funkcjonalność eksperymentalna. Na szczęście nie musimy też jej włączać żadnymi flagami gdyż jest domyślnie włączona. Aby skorzystać z tej funkcjonalności mamy dwie drogi:

  • W pliku package.json dołożyć wpis "type": "module"
  • Użyć rozszerzenia *.mjs zamiast *.js do plików

Top-level await

Jest jeszcze jedna zaleta korzystania z modułów ECMAScript. Od jakiegoś czasu w najnowszej wersji Node'a jest dla tych modułów uruchomiony top-level await. Dzięki temu nie musimy opakowywać naszego kodu w IIFE (Immediately-invoked function expression) tylko możemy skorzystać z await bezpośrednio

await Promise.resolve(console.log('promise'));

console.log('after Promise');

W przypadku Node'a jest to o tyle wygodne, że wiele rzeczy dzieje się asynchronicznie a na które potrzebujemy czekać np.: nawiązanie połączenia z bazą danych żeby wystartować resztę aplikacji. Jednak aby włączyć tę funkcjonalność musimy ją jeszcze aktywować przy pomocy flagi

node --harmony-top-level-await nazwa_pliku.mjs

A wy co sądzicie o nowych modułach i top-level await? Korzystaliście już z tego czy czekacie aż będzie to rozwiązanie stabilne? Myślicie, że zmieni to sposób w jaki tworzymy aplikacje?