79
SPA инструменты Роман Дворнов Avito SPA Meetup, февраль 2015

SPA инструменты

  • Upload
    basisjs

  • View
    857

  • Download
    0

Embed Size (px)

Citation preview

Page 1: SPA инструменты

SPA инструментыРоман Дворнов

AvitoSPA Meetup, февраль 2015

Page 2: SPA инструменты

О себе• Работаю в Avito • Делаю SPA • Автор basis.js

2

Page 3: SPA инструменты

Все непросто…

3

Page 4: SPA инструменты

Веб сегодня – большой мир возможностей...

4

Page 5: SPA инструменты

Бла-бла-бла…

5

Page 6: SPA инструменты

Программирование абстрактно, нужно многое держать в голове –

легко упустить детали

6

Page 7: SPA инструменты

Нам нужны помощники – инструменты, которые помогут нам больше видеть и понимать

7

Page 8: SPA инструменты

Слож

ность

(кол

-во бо

ли)

Размер проекта (в попугаях)

Все делаем сами

8

Page 9: SPA инструменты

Слож

ность

(кол

-во бо

ли)

Размер проекта (в попугаях)

Все делаем самиИспользуем инструменты

9

Page 10: SPA инструменты

Инструменты

10

Page 11: SPA инструменты

Типы инструментов

• среда разработки – редаторы, IDE + плагины

• консольные – командная строка

• браузерные – in-app и плагины

11

Page 12: SPA инструменты

Среда разработки• Нам "не повезло" – веб-технологии слишком гибкие

• либо базовые вещи – мало подсказок

• либо все подряд – слишком много подсказок

• обламываемся, если CommonJS, ES6 modules…

• обламываемся, если среда не знает "фреймворк"

12

Page 13: SPA инструменты

Консольные инструменты• Расцвет эпохи Task Runner'ов (node.js, io.js)

• "сборка" - конкатенация, пре-/пост-процессоры, ...

• FS watch – live reload, пересборка, ... • запуск тестов, линтеры, валидаторы • …

13

Page 14: SPA инструменты

Браузерные инструменты

• браузерные "Developer Tools"

• простые утилитарные плагины

• плагины фреймворков (React, Ember, Basis.js)

• runtime приложения

14

Page 15: SPA инструменты

Что делать, если существующих инструментов не хватает?

15

Page 16: SPA инструменты

Создать свои!

16

Page 17: SPA инструменты

Лучше день потерять, потом за 5 минут долететь…

Page 18: SPA инструменты

Главное видеть проблемы и стараться решать их

18

Page 19: SPA инструменты

Какого типа инструменты делать?

19

Page 20: SPA инструменты

В идеале – все три

20

Среда разработки

Консольные инструменты

Браузерные решения

+

+

Page 21: SPA инструменты

Сборка

21

Консольный инструмент

Page 22: SPA инструменты

Обычная практика• находим файлы по маске

• прогоняем через пре-/пост-процессоры

• объединяем, минизируем

• ...

• PROFIT!22

Page 23: SPA инструменты

Плюсы и минусы

+ достаточно просто

– разные типы контента обрабатываются независимо

– файлы попадают в сборку, без разбора используются или нет

– каждое изменение файла – пересборка

23

Page 24: SPA инструменты

А как по другому?

24

Page 25: SPA инструменты

В идеале сборщик должен понять, что мы хотели

и сделать из этого оптимальную сборку

25

Page 26: SPA инструменты

Сценарий• указываем html-файл (у нас же single page!)

• он находит используемые файлы

• прогоняет через пре-/пост-процессоры и т.д. • объединяет, перестраивает, перелинковывает контент

• ...

• PROFIT!26

Page 27: SPA инструменты

Плюсы и минусы

+ не нужно объяснять лишнего сборщику

+ в сборку попадается только нужное

– несколько сложнее реализация сборщика

– менее надежно (не пишите непонятного ;)

27

Page 28: SPA инструменты

DEMO

28

Page 29: SPA инструменты

Ключевой компонент – профиль приложения

29

Page 30: SPA инструменты

Профиль приложения

• граф зависимостей – в частном случае файлы и их связи

• факты о контенте – что и где используется

30

Page 31: SPA инструменты

Как собрать профиль?• для этого сборщик должен быть немного

"браузером" :)

• разобрать контент "файлов"

• найти и интерпритировать конструкции

• собрать информацию воедино31

Page 32: SPA инструменты

Разбор полетов

32

контента

AST: туда и обратно

Page 33: SPA инструменты

Способы работы с контентом

• Как со строкой – Regular Expressions

• Структурированное представление – AST*

33

* Abstract Syntax Tree

Page 34: SPA инструменты

RegExp+ дешевое решение для простых задач

– под каждую задачу свой RegExp

– ненадежно

– трудно поддерживать и расширять

– почти невозможно делать сложные вещи34

Page 35: SPA инструменты

AST+ надежно + универсальное решение + гораздо проще поддерживать + возможность выполнять задачи любой сложности – более дорогое решение для простых задач – можно потерять часть информации (формат и т.д.)

35

Page 36: SPA инструменты

Наш выбор – AST

36

Page 37: SPA инструменты

Пример

37

ASTCSS

[ "stylesheet", [ "atrules", [ "atkeyword", [ "ident", "import" ] ], [ "s", " " ], [ "string", "'path/to/file.css'" ] ]]

@import 'path/to/file.css';

gonzales (csso)

Page 38: SPA инструменты

Пример

38

ASTJavaScript

[ "toplevel", [ [ "var", [ [ "module", [ "call", [ "name", "require" ], [ [ "string", "module" ] ] ] ] ] ]] ]

var module = require('module');

uglifyjs 1.x

Page 39: SPA инструменты

Пример

39

ASTJavaScript

{ "type": "Program", "body": [ { "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "module" }, ...

var module = require('module');

ESTree (Esprima, uglifyjs 2.x, …)

Page 40: SPA инструменты

Все уже придумано до нас

• JavaScript – Esprima, acorn, uglifyjs, …

• CSS – gonzales (csso), postCSS, …

• (X)HTML, XML – htmlparser2, sax, …

40

Для многих форматов есть парсеры, производящие AST

Page 41: SPA инструменты

Работаем с AST• walker – делает рекурсивный обход дерева

• анализ = walker + сбор фактов

• трансформер (transformer) = walker + модифицикация дерева

• транслятор (translator) = walker + генерация кода (строка)

41

Page 42: SPA инструменты

Пример walker'а

42

function gonzalesAstWalker(ast, handlers){ function walk(token){ for (var i = 2, child; child = token[i]; i++) { var handler = handlers[child[1]]; if (typeof handler == 'function') handler(child); walk(child); } }!

walk([{}, '', ast]);};

для AST производимого gonzales

Page 43: SPA инструменты

Используем

43

var ast = gonzales.parse( '.foo { background: url("foo.jpg"); }' + '.bar { background: url("bar.png"); }', 'stylesheet', true);!

gonzalesAstWalker(ast, { 'uri': function(token){ console.log(token[2][2]); }});

находим все url(…)

Вывод в консоли: "foo.jpg""bar.png"

Page 44: SPA инструменты

Поиск Священного Грааля

44

связей

Page 45: SPA инструменты

HTML• <script src="{url}"></script>• <script>{inlineScript}</script>• <link rel="stylesheet" href="{url}">• <style>{inlineStyle}</style>• <img src="{url}">• <element style="{inlineStyleBlock}">• ...

45

Page 46: SPA инструменты

CSS

• @import {url}

• url({url})

46

Page 47: SPA инструменты

CSS

• @import {url}

• url({url})

46

Вы уже знаете как это сделать ;)

Page 48: SPA инструменты

JavaScript

47

Все несколько сложнее…

Нужно несколько проходов и больше телодвижений

Page 49: SPA инструменты

JavaScript проход №1• определяем области видимости • для определенных значений добавляем

обработчики:

48

var fnToken = someScope.get('require');fnToken.run = function(token, args){ // интерпритация функции для сборщика};

Page 50: SPA инструменты

JavaScript проход №2• делаем базовую интерпритацию

• объявления, присвоения • вызов функций • return • стараемся понять, что можем понять

49

Page 51: SPA инструменты

Примерно вот так

50

jsAstWalker(ast, { 'call': function(token, scope){ var expr = token[1]; var args = token[2]; var fn = scope.resolve(expr);!

if (fn && fn[0] == 'function' && fn.run) fn.run(token, args.map(function(a){ return scope.resolve(a) || a; })); }, ...});

обработка вызовов функций

Page 52: SPA инструменты

Успешно понимаем

51

var foo = basis.require;foo('./path/to/file.ext');// и даже такvar prefix = './path/to';var bar = foo;bar(prefix + '/foo.ext');

на примере basisjs-tools

сборщик правильно распознает вызов

basis.require и значения аргументов

Page 53: SPA инструменты

Так просто не обманешь

52

function example(){ var basis = { require: function(){ … } }; basis.require('module');}

на примере basisjs-tools

Этот вызов будет проигнорирован, т.к. функция не оригинальная

Page 54: SPA инструменты

Да, понимает не все

53

var require = basis.require;var modules = ['foo', 'bar'];modules.forEach(function(name){ require(name);});

на примере basisjs-tools

сборщик распознает вызов basis.require, но не сможет разрешить названия модулей

Page 55: SPA инструменты

Можно упороться и научить сборщик понимать более

сложные патерны

54

Page 56: SPA инструменты

С другой стороны это "фича", которая останавливает от

написания "странного" кода ;)

55

Page 57: SPA инструменты

Профиль приложения полезен не только для сборки

56

Page 58: SPA инструменты

Профиль приложения

• Профиль + трансформации = сборка

• Профиль + проверки = линтер

• Профиль + … = …

57

Page 59: SPA инструменты

Главное: знаем все связи и можно работать со всеми

видами контента одновременно

58

Page 60: SPA инструменты

DEMO

59

Page 61: SPA инструменты

Матчинг CSS классов• Сохраняем карту – какие классы используются в HTML (шаблонах)

• Сохраняем карту – какие классы используются в селекторах

• Есть в HTML, но нет в CSS –> варнинг

• Есть в CSS, но нет в HTML –> варнинг60

Page 62: SPA инструменты

Делаем свой линтер

61

Page 63: SPA инструменты

Делаем свой линтер

• Пишем консольную утилиту, которая выводит список ошибок и файлов с местоположением ошибки

• Интегрируем с редактором

62

Это очень важно

Page 64: SPA инструменты

Интеграция с Sublime Text

63

from SublimeLinter.lint import NodeLinter, util!

class Basisjs(NodeLinter): syntax = ('javascript', 'javascriptnext', 'html', 'css', 'json') cmd = ('basis', 'lint', '@', '-r', 'checkstyle') regex = ( r'^\s+?<error line="(?P<line>\d+)" ' r'column="(?P<col>\d+)" ' r'severity="(?P<warning>error)" ' r'message="(?P<message>.+?)"' ) multiline = True tempfile_suffix = '-'

плагин для SublimeLinter

Вызываем консольную

утилиту

Page 65: SPA инструменты

PROFIT!

64

Page 66: SPA инструменты

Стыкуем все вместе

65

Page 67: SPA инструменты

DEMO

66

Page 68: SPA инструменты

67

Плагин

Браузер Dev-сервер Среда разработки

Web Socket (socket.io) Файловая система

DOM события

Page 69: SPA инструменты

Немного деталей

• Сервер слушает файловую систему, и отправляет браузеру уведомления об изменениях

• Браузер отправляет серверу команды и слушает уведомления

68

Page 70: SPA инструменты

Открытие файла в редакторе

• Браузер отправляет команду dev-серверу openFile('path/to/file.ext:10:20')

• dev-сервер выполняет консольную команду subl path/to/file.ext:10:20

69

Page 71: SPA инструменты

Кое-что еще…

70

Page 72: SPA инструменты

DEMO

71

Page 73: SPA инструменты

Под капотом все то же: парсер, AST, walker'ы, …

72

Page 74: SPA инструменты

И еще немного магии• Dev-режим

• Компонентный подход

• DOM шаблонизация

• Разделение логики и представления

• Модульность

• Sandbox

• …73

Page 75: SPA инструменты

В заключении

74

Page 76: SPA инструменты

Если чего-то не хватает – делайте это сами!

75

Page 77: SPA инструменты

Наша эффективность зависит от инструментов, не меньше чем от фреймворков и нашего опыта

76

Page 78: SPA инструменты

Главное видеть проблемы и стараться решать их

77

Page 79: SPA инструменты

Спасибо!

78

Роман Дворнов @rdvornov [email protected]

basis.js basisjs.com

github.com/basisjs