28
Практическое использование require.js Interlabs 3 декабря 2012 1 / 28

Практическое использование RequireJS

  • View
    7.244

  • Download
    4

Embed Size (px)

DESCRIPTION

JavaScript допускает использование различных подходом к реализации модульной структуры приложений. Подход, предлагаемый в рамках стандарта AMD обеспечивает разбиение приложения на отдельные функциональные модули и их загрузку с учетом зависимостей друг от друга, накладывая при этом минимум ограничений на сам код. Поэтому этот стандарт может быть использован не только для разработки новых приложений, но и для рефакторинга уже существующих с относительно небольшими затратами. Использование одной из реализаций стандарта - RequireJS позволяет не только выстроить модульную структуру приложения, но и оптимизировать итоговый результат, уменьшив количество выполняемых запросов.

Citation preview

Практическоеиспользование require.js

Interlabs

3 декабря 2012

1 / 28

Монолитный спагетти-код

• 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