Зовнішні залежності
За певних обставин вам можуть знадобитися можливості бібліотеки, написаної на JavaScript, аналогу якої немає в ClojureScript, тобто вам буде потрібно підключити таку бібліотеку в проект.
Залежно від бібліотеки способів підключення може бути багато. Розглянемо деякі з них.
Бібліотеки, сумісні з модулями Google Closure
Якщо бібліотека сумісна з системою модулів в Google Closure Library, вам потрібно лише додати її до проекту і звернутися до неї через простір імен так само, як це роблять з просторами імен в ClojureScript.
Це найпростіший спосіб, бо модулі Google Closure напряму сумісні з ClojureScript, і ви спокійно можете використовувати їх у вашому коді.
Давайте спробуємо підключити такий модуль у проекті за допомогою шаблона mies.
lein new mies myextmods
cd myextmods
Далі створіть модуль Google Closure для експерименту:
.src/myextmods/myclosuremodule.js
goog.provide("myextmods.myclosuremodule");
goog.scope(function() {
var module = myextmods.myclosuremodule;
module.get_greetings = function() {
return "Hello from google closure module.";
};
});
Тепер відкрийте REPL та спробуйте імпортувати простір імен і викликати функцію з нього:
(require '[myextmods.myclosuremodule :as cm])
(cm/get_greetings)
;; => "Hello from google closure module."
ЗАУВАЖЕННЯ: ви можете відкрити ClojureScript REPL в Node.js, виконавши скрипт
./scripts/repl
.
Бібліотеки, сумісні з модулями CommonJS
Завдяки популярності Node.js формат модулів CommonJS є найбільш вживаним в JavaScript бібліотеках незалежно від того, де вони використовуються: у клієнтських застосунках чи на сервері.
Подивимося, що вийшло. Створіть файл з модулем у форматі CommonJS (дуже схожий на модуль з попереднього прикладу):
.src/myextmods/mycommonjsmodule.js
function getGreetings() {
return "Hello from commonjs module.";
}
exports.getGreetings = getGreetings;
Для того, щоб ми могли застосувати цю бібліотеку, нам треба підключити її за допомогою спеціальної конфігурації для компілятора. У полі :foreign-libs
описуються модулі JavaScript: шлях до файлу, формат модуля та ім'я простору імен, під яким цей модуль буде доступний з ClojureScript.
Відкрийте файл scripts/repl.clj
та замініть його вміст на цей:
(require
'[cljs.repl :as repl]
'[cljs.repl.node :as node])
(repl/repl
(node/repl-env)
:language-in :ecmascript5
:language-out :ecmascript5
:foreign-libs [{:file "myextmods/mycommonjsmodule.js"
:provides ["myextmods.mycommonjsmodule"]
:module-type :commonjs}]
:output-dir "out"
:cache-analysis false)
ЗАУВАЖЕННЯ: Шлях до файлу модуля може бути не тільки локальним, а й у вигляді посилання на файл на іншому веб-сервері, який завантажиться автоматично.
Спробуємо застосувати цей модуль у REPL. Запустіть REPL за допомогою скрипта ./scripts/repl
і спробуйте виконати наступні команди:
(require '[myextmods.mycommonjsmodule :as cm])
(cm/getGreetings)
;; => "Hello from commonjs module."
Бібліотеки без модулів
Хоча сьогодні більшість бібліотек побудована з використанням модулів, все ще існують такі, що просто експортують глобальний об'єкт. У вас може виникнути необхідність використовувати їх в ClojureScript.
Для застосування бібліотек, які використовують глобальні обʼєкти, слід створити конфігурацію, схожу на ту, що потрібна для модулів CommonJS. Відмінністю буде те, що в описі модуля не потрібно вказувати поле :module-type
.
В результаті буде створений синтетичний простір імен, який треба імпортувати, щоб мати доступ до глобального об'єкту модуля у просторі імен js/
. Простір імен називається синтетичним, бо не містить жодних об'єктів, він просто вказує компілятору на необхідність підключити залежність.
Перевіримо результат. Створіть файл з глобальною функцією:
.src/myextmods/myglobalmodule.js
function getGreetings() {
return "Hello from global scope.";
}
Відкрийте scripts/repl.clj
та змініть його вміст на цей:
(require
'[cljs.repl :as repl]
'[cljs.repl.node :as node])
(repl/repl
(node/repl-env)
:language-in :ecmascript5
:language-out :ecmascript5
:foreign-libs [{:file "myextmods/mycommonjsmodule.js"
:provides ["myextmods.mycommonjsmodule"]
:module-type :commonjs}
{:file "myextmods/myglobalmodule.js"
:provides ["myextmods.myglobalmodule"]}]
:output-dir "out"
:cache-analysis false)
Тепер спробуємо застосувати цей модуль в REPL:
(require 'myextmods.myglobalmodule)
(js/getGreetings)
;; => "Hello from global scope."