JavaScript b LiveJournal

Команда

  • Perl: 9
  • JS: 3
  • HTML/CSS: 5

История проекта

  • 14 лет
  • Развитие
  • Усложнение структуры кода
  • Смена нескольких поколений разработчиков

jQuery UI (Widget factory)


$.widget('lj.colorpicker, $.lj.basicWidget, {
  options: {
    selectors: {
      button: ‘.b-colorpicker-button’ }
    }
  },

  _create: function() {
    $.lj.basicWidget.prototype._create.apply(this);
  },

  _bindControls: function() {
    this._el(‘button’).click(this._clickHandler.bind(this));
  },

  /* ... */
});

Минусы

  • DOM-зависимость
  • Нет четкой структуры
  • Инициализация

Декларативные виджеты


Компонент

  • JS
  • CSS
  • HTML-темплейт
  • Языковые переменные (i18n)

Зависимости


LJ::need_res(qw{
  lib1.js
  lib2.js
  widget1.js
  widget2.js
  style1.css
  style2.css
}); # => <script src="/??lib1.js,lib2.js,widget1.js,widget2.js"...
    # => <link href="/??style1.css,style2.css"...

LJ::need_string(qw{
  colorpicker.button.save
}); # => Site.page.ml['colorpicker.button.save']
            

Зависимости


# Config
colorpicker => {
  js => [
    'js/color.js',
    'js/jquery/jquery.lj.colorpicker.js'
  ],
  css => [
      'stc/popup/popupus.css'
  ],
  templates => ['templates/Widgets/colorpicker.tmpl'],
  ml => [
      'colorpicker.title.new'
  ]
}
# Controller
LJ::need_res_group('colorpicker')

Существующие решения

  • AMD
  • CommonJS
  • Наш вариант

Подключение скриптов


//= require js/core/string.js
//= require js/core/object.js

;(function () {
    'use strict';

    /** Module implementation */
}());

Подключение шаблонов


/* popup.js */

//= require_template core/popup.html
          

Site.page.templates['core/popup.html'] =
'
<!-- ... -->
';

Открытые проблемы

  • css
  • i18n

Backbone

main.png

AngularJS

  • Идеология, основные компоненты
  • digest loop
  • scope inheritance (prototypal)

Angular в ЖЖ

  • Толстые сервисы, тонкие контроллеры
  • Модульность
  • Никакой сложной логики в шаблонах

Работа с темплейтами

Site.page.templates[...] => $templateCache


//= require js/lib/angular.min.js
//= require js/core/angular/common.js

//= require_template angular/controlstrip/friend.ng.tmpl
//= require_template angular/controlstrip/join.ng.tmpl

// add templates module as a dependency
angular.module('Controlstrip', ['LJ.Templates']);

i18n


//= require js/core/angular/common.js
//= require_template angular/controlstrip/friend.ng.tmpl

// add directives module as a dependency
angular.module('Controlstrip', ['LJ.Directives']);





Взаимодействие с существующим кодом

  • ng-app + Формы
  • pushState + $locationProvider
  • Частое использование $apply()
  • html5Mode + ссылки на странице

Советы

  • Чтение исходного кода
  • Понимание концепций: DI, Scope inheritance
  • Angular Batarang + named callbacks

Написание кода

  • Code style
  • JSHint
  • YUIDoc
  • Wiki
  • Changelog

Рефакторинг

  • es5-shim, json3
  • Один namespace: LJ
  • basic.js, livejournal.js: - LJ.String - LJ.Object - LJ.Support - ...
  • Подключение ресурсов "по запросу"
  • Legacy/depracated код
  • Средства: Google Code Search, ack
  • Тестирование

Тестирование клиентского кода

Модульное тестирование

(Unit testing)

Специфика проекта

Чего хотелось достичь?

  • Работа с реальными браузерами
  • Работа из командной строки
  • Простое включение-отключение тестируемых модулей
  • Работа в режиме реального времени (редактируем тест и видим результат)
  • Интеграция с CI сервером (Jenkins)

Технологии

  • Karma test runner
  • AMD (Asynchronous module definition)
  • Jasmine (Test framework)
  • Grunt
  • VirtualBox

Демо

Workflow

  1. Red
  2. Green
  3. Refactoring

Функциональное тестирование

(Functional testing)

Технологии

  • Grunt
  • CasperJS (PhantomJS)

Покрытие кода

(Code coverage)

Зачем?

Coverage

Технологии

  • Grunt
  • Karma Test Runner
  • Istanbul

Просмотр отчета по папке

Coverage

Отчет о покрытии

Coverage

Мониторинг ошибок

Logger

Планы

  • Continuous Integration
  • Тестирование визуальных регрессий
  • Совершенствование логгера
  • Минификация кода
  • SPA
  • NodeJS на сервере

Спасибо за внимание!

http://livejournal.com