requirejs і magento 2
Post on 14-Jan-2017
422 Views
Preview:
TRANSCRIPT
Монолитный спагетти-код
• script.js, содержащий код всего сайта• множество глобальных объектов, нет инкапсуляции,конфликты
• функциональность разбросана внутри script.js иinline-скриптов
• местами inline-код
Нет разделения сложной задачи на более простые — любаязадача будет сложной. Нужна модульность.
2 / 28
JavaScript модуль
(function () {var privVar
function privFunc() {}
return {pubFunc: function () {}
}})()
• реализация скрыта• нет глобальныхпеременных
• простой внешний фасаддля сложной внутреннейреализации
• отдельная единицазагрузки
3 / 28
Использование модулей
• модули зависят от других модулей• модули нужно загружать• и только когда это необходимо
Нужно стандартное решение:
• обеспечивающее загрузку по требованию• гарантирующую подгрузку зависимостей• делающее это эффективно
4 / 28
AMD
Asynchronous Module Definitionhttps://github.com/amdjs/amdjs-api/wiki/AMD
Стандартный способ определения модуля с учетомзависимостей и возможностью асинхронной загрузки.
define(id?, dependencies?, factory);
5 / 28
AMD: id
define(id?, dependencies?, factory);
• строковый идентификатор — имя модуля• необязателен, если не указан — идентификатор, которыйбыл использован для загрузки файла
• всегда абсолютный, относительные имена не допускаются
6 / 28
AMD: dependencies
define(id?, dependencies?, factory);
• массив идентификаторов зависимостей• зависимости разрешаются перед запуском factory• экземпляры зависимостей передаются в factory всоответствующих по порядку аргументах
• относительные идентификаторы — относительнозагружаемого модуля
• по умолчанию [’require’, ’exports’, ’module’]
7 / 28
AMD: factory
define(id?, dependencies?, factory);
• фабричная функция или объект• функция выполняется только один раз• возвращаемое значение функции — экспортируемоезначение модуля
• объект непосредственно присваивается экспортируемомузначению
8 / 28
AMD: factoryСпециальные зависимости:
require функция получения объекта загруженного модуляexports список экспортируемых значений
define(’alpha’,[’require’, ’exports’, ’beta’],function(require, exports) {
exports.verb = function () {return require(’beta’).something();
}});
9 / 28
Require.js
http://requirejs.org
• одна из реализаций AMD (самая популярная)• базовый стандарт + различные дополнения• возможность статического анализа кода и последующаяоптимизация за счет сборки и компрессии модулей
10 / 28
Базовый API
Определение
define([’dep1’, ’dep2’
], function(dep1, dep2) {...
});
define({color: "black",size: "unisize"
});
Загрузка
require([’dep1’, ’dep2’
], function(dep1, dep2) {...
});
Конфигурирование
requirejs.config({baseUrl: ’/another/path’,...
});
11 / 28
Модули в Require.js• один файл — один модуль• объединение в один файл только оптимизатором• не надо указывать имен — этим занимается оптимизатор• модуль require — различные полезные утилиты• относительные пути — с помощью модуля require:
define(function(require) {var mod = require("./relative/name");
});
define(["require"], function(require) {var cssUrl = require.toUrl("./style.css");
});
12 / 28
Бонус — JSONP
require(["http://site.com/api/data.json?callback=define"],function (data) {
//The data object will be the API response// for the JSONP data call.console.log(data);
});
Предназначено для использования при начальнойинициализации приложения.
13 / 28
Конфигурированиеrequirejs.config(options)
basePath основной путь к загружаемым модулямpaths отдельные пути к различным префиксамshim внешние определения для не модульных скриптовmap псевдонимы для модулейconfig параметры конфигурации модулей
callback пользовательский обрабочик события загрузкиurlArgs дополнительные параметры для запроса
. . .
14 / 28
Структура модулей приложения
www/js/
app/ код приложенияlib/ библиотечные модули
lib1.jslib2.js
common.js код, общий для всех страницpage1.js код для отдельной страницыpage2.js
lib/ внешние библиотекиconfig.js конфигурация require.js
Приложение отдельно, библиотеки отдельно, постраничноеразбиение — если необходимо.
15 / 28
Структура модулей библиотек
www/js/lib/ внешние библиотекиjquery/
fancybox.js плагины jQueryeasing.js
jquery-ui/timepicker-addon.js плагины jquery-ui
jquery.js jQueryjquery-ui.js jQuery UIrequire.js Require.js
Используем единую схему именования файлов плагинов дляполучения простых имен соответствующих модулей
16 / 28
Базовая конфигурация
config.js
require.config({baseUrl: "/js/lib",paths: {
"app": "/js/app"}
});
common.js
define([’jquery’,’app/lib/ui’
], function($, ui) {...
});
17 / 28
Загрузка модулейСначала загрузчик, потом конфиг, все остальное только послеконфига, чтобы проинициализировались пути.
<script src="js/lib/require.js"></script><script>
require([’js/config’], function(config) {require([’app/common’, ’app/page1’]);
});</script>
Сокращенная форма для одностраничных приложений:
<script src="js/lib/require.js" data-main="js/main.js">
18 / 28
Адаптация существующего кода
Проблемы:
• всегда глобальная область видимости• вызов глобальных функций непосредственно изHTML-кода
• inline код в HTML• jQuery-плагины — не AMD модули
19 / 28
Что делать: модули
• группируем код по функциональности• разбиваем на функции• функции используются другими модулями —библиотечный модуль, возвращает объект
• нужна только настройка DOM — просто выполняемфункцию
• все переменные и функции определяем внутри модуля,снаружи они недоступны
20 / 28
Модуль-функция
define([’jquery’,’app/lib/ui’
], function ($, ui) {
$(function () {setup();$(window).resize(resize);
});function setup() {
ui.slider(’#slider’);}function resize() {...}
});
21 / 28
Модуль-библиотека
define([’jquery’,
], function($) {
var privateVar;
return {slider: function (id) {
...}
}
function privateFunc() { ... }});
22 / 28
Что делать: глобальные объектыВ идеале — не использовать, не получается — использование иявный экспорт с помощью window.
function () {window.checkForm = validate;
function validate(form) {var mode = window.globalMode
...}
}
Используем window, легче отследить и потом избавиться.23 / 28
Что делать: inline-код в HTML
• <script> — выносим в страничные модули• onclick . . . — обычной привязкой событий• компромиссный вариант — группировать весь inline-код
require([’js/config’], function(config) {require([
’jquery’, ’app/common’, ’app/page1’], function ($) {
// тут весь inline-код.}
});
24 / 28
Что делать: jQuery-плагины• jQuery плагины должны быть AMD-модулями дляасинхронной загрузки
• не забываем про зависимости
(function (root) {var amdExports;define([’jquery’], function (jQuery) {...}.call(root));return amdExports;
}); }(this));
Преобразование вручную или программой, например, volo.25 / 28
Внешние библиотеки — еслиничего не помогает
shim config
requirejs.config({shim: {
’module’: {deps: [’underscore’, ’jquery’],exports: ’Module’
});
26 / 28
AMD/Require — архитектурныепреимущества
• минимальный API• отсутствие жесткой структуры• отсутствие глобального объекта приложения• соответствие базовым паттернам JavaScript• легко сконвертировать существующий код
27 / 28
Что читать
• https://github.com/amdjs/amdjs-api/wiki/AMD —стандарт AMD
• http://requirejs.org — документация по Require.js• https://github.com/requirejs/example-multipage —пример для мультистраничных сайтов
• http://addyosmani.com/writing-modular-js/ — Writingmodular JavaScript with AMD, CommonJS and ES Harmony.
28 / 28
top related