javascript-модули "из прошлого в будущее"

52
JavaScript-модули “Из прошлого в будущее” Константин Ершов, frontend meetup, Ярославль, 10.12.2014

Upload: oelifantiev

Post on 24-Jul-2015

475 views

Category:

Technology


0 download

TRANSCRIPT

JavaScript-модули“Из прошлого в будущее”Константин Ершов,frontend meetup, Ярославль, 10.12.2014

Начало...

● легкая модификация DOM ● 50 строк кода

Что дает модульная система?

● Ограничение области видимости

● Реиспользование частей приложения

● Структуризация приложения

● Наглядный код

Простейшие модули

● Разделение на файлы

● Паттерн с самовызывающейся ф-цией

● Глобальная область видимости

//iMath.js(function(myNameSpace){

function square(x){ return x*x; }

myNameSpace.iMath = { square: square };

}(window.myNamespace = window.myNamespace || {}))

//main.js(function(){ alert(window.myNamespace.iMath.square(2));}())

Плюсы:- ограничение области видимости- это уже почти модули

Плюсы:- ограничение области видимости- это уже почти модули

Минусы:- нет поддержки зависимостей- для асинхронной загрузки модуля нужно

реализовывать обертку- нужно следить за порядком загрузки модулей

Asynchronous Module Definition (AMD)

- подход к организации модулей, который определяет API, следуя которому можно организовать асинхронную загрузку модулей и их зависимостей.

Asynchronous Module Definition (AMD)

Краткие характеристики

● работает без eval() или этапа компиляции, за счет синтаксиса;

● предназначен для асинхронной загрузки;

● преимущественно используется на стороне клиента.

define для определения модуля

require для загрузки

define - определение модуля

define( [module_name] /*опционально*/, [dependencies] /*зависимости - опционально*/, definition /*функция инстанцирования модуля или объект*/);

define('iMath', function(){ function square(x){ return x*x; }

return { square: square };});

define('anotherModule', ['iMath'], function(iMath){ alert(iMath.square(2));});

require - загрузка модулей

require( [modules] /*список модулей*/, callback /*функция вызываемая при успешной загрузке модулей*/ errback /*функция вызываемая при ошибке загрузки модулей*/);

require( ['anotherModule', 'yetAnotherModule'], function(aM, yAM){ //do something with modules }, function(error){ console.error(error); } );

Система плагинов

require(['tpl!main'], function(tplFn){ var html = tplFn(data);});

//плагин 'tpl!'define('tpl', ['templateEngine'], function(templateEngine){ return { load: function(name, parentRequire, onload, config){ parentRequire(['text!' + name], function(text){ onload(templateEngine.createTemplate(text)); }); } };});

Почему AMD - это лучший выбор для написания модульного js на клиенте?

● Имеет четкое представление о том как нужно подходить к определению гибких модулей.

● Значительно чище и безопасней, чем использование глобального нэймспейса● Определение модуля инкапсулировано, что помогает избежать загрязнения

глобальной области видимости.● Работает лучше чем альтернативные решения (например CommonJS, который

мы рассмотрим позже)● Не имеет проблем с кросс-доменностью, отладкой. Не нуждается в

инструменте на стороне сервера. Большенство загрузчиков AMD поддерживают загрузку модулей без процесса сборки.

● Обеспечивает подход «transport» для включения нескольких модулей в один файл.

● Поддерживает ленивую загрузку, если необходимо.

CommonJS

CommonJS

- рабочая группа, работающая над разработкой и стандартизацией JavaScript API. На сегодняшний день они работают над ратификацией стандарта для модулей и пакетов. Модули предложенные CommonJS определяют простой API для работы js на стороне сервера.

Краткие характеристики:

● компактный синтаксис;

● предназначен для синхронной загрузки;

● преимущественно используется на стороне сервера.

require для загрузки импортов

exports для публикации частей модуля

//iMath.jsfunction square(x){ return x*x;}exports.square = square;

//anotherModule.jsvar iMath = require('./iMath');console.log(iMath.square(2));

//iMath.jsdefine('iMath', function(){ function square(x){ return x*x; } return { square: square };});

//anotherModule.jsdefine('anotherModule', ['iMath'], function(iMath){ alert(iMath.square(2));});

Подходит ли CommonJS для браузера?

Общие модули для клиента и сервера

● Загрузчики и фреймворки поддерживащие CommonJS модули в браузере:○ curl.js - загрузчик модулей на клиенте○ cajon - загрузчик разработанный поверх require.js

Общие модули для клиента и сервера

● Загрузчики и фреймворки поддерживащие CommonJS модули в браузере:○ curl.js - загрузчик модулей на клиенте○ cajon - загрузчик разработанный поверх require.js

● Использование Browserify, утилиты которая позволяет запускать любые node.js модули в браузере

Общие модули для клиента и сервера

● Загрузчики и фреймворки поддерживащие CommonJS модули в браузере:○ curl.js - загрузчик модулей на клиенте○ cajon - загрузчик разработанный поверх require.js

● Использование Browserify, утилиты которая позволяет запускать дюбые node.js модули в браузере

● Использование на сервере node-require (AMD на клиенте и на сервере)

Общие модули для клиента и сервера

● Загрузчики и фреймворки поддерживащие CommonJS модули в браузере:○ curl.js - загрузчик модулей на клиенте○ cajon - загрузчик разработанный поверх require.js

● Использование Browserify, утилиты которая позволяет запускать дюбые node.js модули в браузере

● Использование на сервере node-require (AMD на клиенте и на сервере)

● Использование оберток для модулей

ES6

Стандарт ES6 module состоит из двух частей:

● декларативный синтаксис (для импорта и экспорта);

● программной загрузки (чтобы задать конфигурацию загрузки модулей и для условной загрузки модулей).

Экспорт

let notExported = 'abc';export function square(x) { return x * x;}export const MY_CONSTANT = 123;

Импорт

import { square } from './iMath';console.log(square(3));

Импорт

import { square } from './iMath';console.log(square(3));

import { square, MY_CONSTANT } from './iMath';

Импорт

import { square } from './iMath';console.log(square(3));

import { square, MY_CONSTANT } from './iMath';

import './iMath' as c;console.log(c.square(3));

Импорт

import { square } from './iMath';console.log(square(3));

import { square, MY_CONSTANT } from './iMath';

import './iMath' as c;console.log(c.square(3));

import { square as squ } from './iMath';console.log(squ(3));

Экспорт по умолчанию

// myapp/models/Customer.jsexport default class { // анонимный класс constructor(id, name) { this.id = id; this.name = name; }};

Экспорт по умолчанию

// myapp/models/Customer.jsexport default class { // анонимный класс constructor(id, name) { this.id = id; this.name = name; }};

// myapp/myapp.jsimport Customer from 'models/Customer';let c = new Customer(0, 'Jane');

API программной загрузки

Позволяет делать две вещи:

● настраивать загрузку модулей

● программно работать с модулями и скриптами

Цепь загрузки и компиляции модуля

normalize

System.normalize = function(moduleName, options){ //преобразуем 'core!superLib' --> 'core/lib/superLib.coffee' return moduleName};

resolve

System.resolve = function(moduleName, options){ // преобразуем 'core/lib/superLib.coffee' --> // '/var/www/myProject/resources/core/lib/superLib.coffee' return moduleName};

fetch

System.fetch = function(url, options){ //читаем с диска или грузим через сеть};

translate

System.translate = function(source, options){ return CoffeeScript.translate(source);};

link

System.link = function(jsSource, options){ //можем вернуть объект, с зависимостями и колбэком

//можем вернуть модуль

//можем вернуть undefined тогда система решит, что мы загрузили // настоящий ES6 модуль и предоставит наружу все что он экспортирует};

Используем модули ECMAScript 6

● ES6 Module Transpiler: позволяет писать свои модули,

используя некую часть стандарта ECMAScript 6 (грубо говоря,

ECMAScript 5 + экспорт + импорт), и компилирует их в

модули AMD или CommonJS. Статья Райана Флоренца (Ryan

Florence) детально объясняет этот подход.

● ES6 Module Loader: позволяет использовать API загрузки

модулей ECMAScript 6 в современных браузерах.

Ещё:

● require-hm: плагин для RequireJS, позволяющий загружать модули ECMAScript 6

(только ECMAScript 5 + экспорт + импорт). Статья Каолана Макмахона (Caolan

McMahon) объясняет, как он работает. Предупреждение: плагин использует

более старый синтаксис.

● Traceur (компилятор ECMAScript 6 в ECMAScript 5): частично поддерживает

модули, возможно, в конечном счете будет поддерживать их полностью.

● TypeScript TypeScript (грубо говоря, ECMAScript 6 и поддержка статической

типизации): компилирует модули из внешних файлов (которые могут

использовать большую часть ECMAScript 6) в AMD или CommonJS.

Вопросы?

Материалы

● Статья про es6 модули на frontender.info

● Варианты использования es6 модулей - Иегуда Кац(Yehuda Katz)

● Блог Эдди Османи(Addy Osmani)

● Статья “Путь js модуля” - Михаил Давыдов (Mikhail Davydov)