Ostatnio poznaliśmy SystemJS – uniwersalny, dynamicznym module loader. Pora naszą wiedzę na temat SystemJS wykorzystać do poznania JSPM – JavaScript Package Manager. Jest to produkt, który istnieje tylko dlatego, że SystemJS istnieje.

W skórcie, JSPM to po prostu narzędzie do zarządzania zależnościami stworzone na bazie SystemJS. Dokładnie mówiąc wykorzystujące wszystko to co daje SystemJS (a jak wiemy daje więcej niż ładowanie zależności) i dokładające do tego różne źródła pochodzenia paczek – npm, github itp.

Więc JSPM jest takim małym magikiem co niby robi wszystko, a tak naprawdę uzależniony jest silnie od SystemJS,.

Instalacja

Podobnie jak prawie ze wszystkimi innymi produktami opisywanymi w Co to Jest, mamy dwie instalacje JSPM .

Globalną:

npm install jspm -g

instalującą command line interface (cli), który umożliwia wykorzystywanie komendy JSPM w konsoli.

Oraz lokalną:

npm install jspm --save-dev

niezbędną, jeżeli chcemy wykorzystać JSPM w projekcie.

Inicjalizacja projektu

Podobnie jak grunt i npm, możemy wykonać inicjalizację.

jspm init

Inicjalizacja ta wykonuje trochę więcej czynności niż w pozostałych przypadkach. Dokładnie mówiąc, jak nie ma pliku package.json to zostanie on utworzony (chyba, że tego nie będziemy chcieli). Do tego, inicjalizacja utworzy nam plik config.js – miejsce konfiguracyjne  SystemJS. JSPM wie jak go czytać i pisać. Domyślny plik przy domyślnych opcjach już przypomina trochę śmietnik RequireJS – na szczęście raczej go dotykać nie musimy:

System.config({
  baseURL: "/",
  defaultJSExtensions: true,
  transpiler: "babel",
  babelOptions: {
    "optional": [
      "runtime",
      "optimisation.modules.system"
    ]
  },
  paths: {
    "github:*": "jspm_packages/github/*",
    "npm:*": "jspm_packages/npm/*"
  },

  map: {
    "babel": "npm:[email protected]",
    "babel-runtime": "npm:[email protected]",
    "core-js": "npm:[email protected]",
    "github:jspm/[email protected]": {
      "assert": "npm:[email protected]"
    },
    "github:jspm/[email protected]": {
      "buffer": "npm:[email protected]"
    },
    "github:jspm/[email protected]": {
      "path-browserify": "npm:[email protected]"
    },
    "github:jspm/[email protected]": {
      "process": "npm:[email protected]"
    },
    "github:jspm/[email protected]": {
      "util": "npm:[email protected]"
    },
    "github:jspm/[email protected]": {
      "vm-browserify": "npm:[email protected]"
    },
    "npm:ass[email protected]": {
      "assert": "github:jspm/[email protected]",
      "buffer": "github:jspm/[email protected]",
      "process": "github:jspm/[email protected]",
      "util": "npm:[email protected]"
    },
    "npm:[email protected]": {
      "process": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "base64-js": "npm:[email protected]",
      "child_process": "github:jspm/[email protected]",
      "fs": "github:jspm/[email protected]",
      "ieee754": "npm:[email protected]",
      "isarray": "npm:[email protected]",
      "process": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "fs": "github:jspm/[email protected]",
      "path": "github:jspm/[email protected]",
      "process": "github:jspm/[email protected]",
      "systemjs-json": "github:systemjs/[email protected]"
    },
    "npm:[email protected]": {
      "util": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "process": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "assert": "github:jspm/[email protected]",
      "fs": "github:jspm/[email protected]",
      "vm": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "inherits": "npm:[email protected]",
      "process": "github:jspm/[email protected]"
    },
    "npm:[email protected]": {
      "indexof": "npm:[email protected]"
    }
  }
});

Jak widać, w pliku występują przedrostki npm: i github: co to znaczy? To oznacza, że dana zależność pochodzi albo z githuba albo z npm. Czyli przy komendzie jspm install (tak jak npm install, bower install itp. instaluje wszystkie zadeklarowane zależności) zostaną pobrane paczki z różnych źródeł.

Pozostałe opcje

JSPM daje bardzo dużo opcji, które są jeszcze rozszerzalne o SystemJS. Wejście w nie i opisanie ich to raczej zadanie dla dokumentacji, do której polecam zajrzeć.  Zapamiętanie ich bez codziennego korzystania z JSPM graniczy z cudem. Na pewno zaś uda się zaobserwować pewne wzorce. Jak z tymiinstall, init, czy też instalacją odpowiedniej wersji biblioteki – jeżeli korzystaliśmy z bower, npm, to powinno to być dość proste.

Jedną z ciekawych opcji jest opcja określania metadanych dla paczek, które nie znajdują się w rejestrze paczek JSPM . To znaczy, jeżeli znaleźliśmy bibliotekę na github, to możemy ją dodać do projektu z wykorzystaniem JSPM . Jednak by tego dokonać, musimy powiedzieć JSPM w jaki sposób ta paczka ma być ładowana – czy to jest amd/commonjs czy może global package. Dzięki czemu nie jesteśmy ograniczeni do paczek zdefiniowanych w rejestrze. W łatwy sposób możemy wykorzystać każdą bibliotekę z github.

By to zrobić do komendy install dodajemy parametr -o do którego dodajemy jsona. Przykład wzięty z dokumentacji rejestru:

jspm install github:twbs/bootstrap -o "{ main: 'js/bootstrap', shim: { 'js/bootstrap': ['jquery'] } }"

Moim zdaniem bardzo fajna opcja. Dzięki Kuba za jej wskazanie!

Podsumowanie

Jak widać, JSPM daje nam kilka fajnych opcji oraz zdejmuje z nas kłopot zarządzania zależnościami. Daje przy tym możliwość posiadania kilku wersji jednej biblioteki, co umożliwia posiadanie bibliotek wymagających starszych lub nowszych wersji zależności.

JSPM jest ciekawym produktem, który może rozwiązać nam wiele problemów jakie wiążą się z wykorzystaniem wielu narzędzi do zarządzania zależnościami. Jednak życie pokazuje, że niekoniecznie to się sprawdza i firmy/produkty odchodzą od JSPM na rzecz webpack. Do tego unifikacja zawsze ma jakąś cenę. Problem polega na tym, że JSPM jest ściśle powiązany z SystemJS – tak naprawdę to mógłby nie istnieć. Dodatkowo to co możemy jęczeć i może nam nie działać tak jak chcemy wcale nie musi być problemem JSPM, może to być SystemJS i vice versa. Bo co tak naprawdę robi JSPM? Nakłada na SystemJS pobieranie paczek i zapisywanie ich tak by SystemJS wiedział jak ma zrobić zapytanie by plik pobrać. Robi on też jedną dodatkową bardzo ważną rzecz, bundluje nam kod na różne sposoby, z wykorzystaniem SystemJS – ale to może już pominę ;)