Dzielenie kodu aplikacji na wiele plików jest niezbędne do utrzymania porządku w projekcie. Dotychczas JavaScript nie posiadał wbudowanych mechanizmów do wygodnego współdzielenia kodu między plikami. Deweloperzy byli zmuszeni wrzucać każdy plik do osobnego tagu script w htmlu, co było niezmiernie irytujące, bądź korzystać z zewnętrznych bibliotek, jak requireJS. Na szczęście z nadejściem ES6 moduły oraz ich import i eksport stały się proste jak niemiecka autostrada i wygodne jak fotel z wysuwanym podnóżkiem.

Import i eksport

Podstawowa teoria modułów w ES6 jest banalnie prosta i wystarczy kilka przykładów, by załapać, o co chodzi. Tak więc bez zbędnych ceregieli, przejdźmy do kodu.

/* lib.js */

export const PI = 3.141592;

export function double(x) {
  return x * 2;
}

export class Robot {
  constructor(name) {
    this.name = name;
  }

  sayName() {
    console.log(this.name);
  }
}

Lub zbierając wszystkie eksporty w jednym miejscu:

/* lib.js */

const PI = 3.141592;

function double(x) {
  return x * 2;
}

class Robot {
  constructor(name) {
    this.name = name;
  }

  sayName() {
    console.log(this.name);
  }
}

export { PI, double, Robot };
/* main.js */

import { PI, double, Robot } from './lib';

console.log(PI); //3.141592
console.log(double(5)); //10

const robotron = new Robot('Robotron');
robotron.sayName(); //My name is Robotron

Jak widać na przykładach, aby użyć funkcji, stałej, czy klasy znajdującej się w innym pliku, wystarczy przy jej deklaracji dopisać słowo kluczowe export, a następnie zaimportować do pliku docelowego podając nazwę importowanego modułu i ścieżkę do pliku źródłowego.

Co jednak w przypadku, gdy chcemy zaimportować wiele stałych i wypisywanie ich wszystkich w imporcie zajęłoby zbyt dużo czasu i miejsca? Wystarczy posłużyć się znakiem gwiazdki (*) i słowem kluczowym as.

/* const.js */
export const THE_ANSWER = 42;
export const PI = 3.141;
export const EULER = 2.718;
export const BEAST = 666;
export const GOLDEN_RATIO = 1.618;
/* main.js */

import * as numbers from './const';

console.log(numbers.PI); //3.141
console.log(numbers.EULER); //2.718
console.log(numbers.BEAST); //666

Gwiazdka sprawia, że importujemy wszytko, co zostało wyeksportowane, a as pozwala nadać nazwę zbiorczą, pod którą znajdą się wszystkie moduły.

Default

Moduły w ES6 to temat dość szeroki i nie będę opisywał tu wszystkich ich możliwości. Warto jednak wspomnieć jeszcze o eksportach domyślnych oznaczanych słowem kluczowym default. Konstrukcja ta używana jest przede wsztystkim wtedy, gdy z całego pliku eksportowany jest tylko jeden moduł. Na przykład:

/* lib.js */

const square = x => x * x;

export default function quadruple(x) {
  return square(x) * square(x);
}
/* main.js */

import libQuadruple from './lib'; //brak nawiasów klamrowych wokół nazwy importu

console.log(libQuadruple(2)); //16

Zauważ, że importując moduł wyeksportowany z użyciem default, przy imporcie możesz nazwać go zupełnie dowolnie.

Obsługa przez przeglądarki

W momencie pisania tego artykułu sprawa wygląda tak, że popularne przeglądarki niestety nie obsługują modułów wcale. Chwalebnym wyjątkiem jest Safari 10, które jako jedyne wspiera 100% standardu ES6/2015. Najprostszym sposobem na użycie ES6 modules już dzisiaj jest więc skorzystanie z narzędzi takich jak Babel i Webpack, które przekonwertują kod modułów ES6 na zrozumiały przez przeglądarki. Tutorial, jak to zrobić, znajdzieciesz tutaj: http://www.2ality.com/2015/04/webpack-es6.html.