Архив за Июль 2011

  • Веб-разработка в Eclipse: JavaScript

    Как отмечалось ранее, для работы JS вместо Spket IDE я теперь использую Eclipse JSDT, который входит в состав Eclipse Web Tools Project. Причины для такого перехода вполне естественные: проекты, с которыми я работаю, становятся всё сложнее и больше, нужно больше удобства и контроля над ситуацией.

    В JSDT меня больше всего привлекло следующее:

    • Рефакторинг: переименование объектов, выделение блока в отдельную переменную, объединение определения переменной и присваивания и т.д. Некоторые вещи вроде выделения в метод пока толком не работают, но, надеюсь, в ближайшее время это будет исправлено.
    • Валидация кода. Помимо обычной проверки синтаксиса, можно настроить более сложные проверки вроде поиска неиспользованных переменных, недостижимый код, переопределение переменной из внешней области видимости и т.д.
    • Выделение фрагментов camelCase-переменных с помощью Shift+Alt+← и Shift+Alt+→
    • Поддержка JSDoc.
    • Удобный Outline/Quick outline; дополнительные окна, в которых показывается документация и код определения текущего объекта.
    • Автоматическая отбивка кода при его перемещении из/в блок.
    • Подключение внешних библиотек.
    • Встроенный дебаггер.

    Лучше всего будет, если читатель поставит Eclipse for JavaScript Web Developers и изучит все настройки и менюшки — в том числе контекстные — JSDT (лучше включить перспективу JavaScript), потому что возможностей действительно очень много и их сложно описать в одной статье.

    Однако при всей «крутости» этой среды разработки, в ней есть ряд проблем, с которыми пришлось столкнуться прежде, чем окончательно перейти на JSDT.

    Начинаем работу

    Для того, чтобы полноценно использовать все возможности JSDT, обязательно нужно создать проект с JavaScript-природой. Делается очень легко: вызываем File > New > Project… и в появившемся окошке выбираем JavaScript Project. В появившемся диалоговом окне вводим название проекта и жмём Finish. По умолчанию создаётся веб-проект с поддержкой DOM, папкой с JS-исходниками является сам проект. Когда вы лучше освоитесь с JSDT, то сможете более тонко настраивать проект: указывать подключаемые библиотеки, исключать ненужные файлы и папки из индекса. Пока оставим как есть.

    Module pattern

    Главным преимуществом для меня в Spket IDE была поддержка современных паттернов, в том числе и модуля:

    var module = (function() {
    	return {
    		method: function() {}
    	};
    })();
    

    В Spket такая конструкция без проблем отображается в outline и по ней работает code complete, но в JSDT ни то, ни другое не работает:

    ss011

    Небольшой JSDoc исправит ситуацию:

    /**
     * @type module
     */
    var module = (function() {
    	return {
    		/**
    		 * @memberOf module
    		 */
    		method: function() {}
    	};
    })();
    

    Теперь работает как надо:

    ss021

    Но есть ещё одна проблема: приватные переменные и методы модуля не отображаются в Outline, а очень хотелось бы. Это можно исправить, описав самовызывающуюся функцию как конструктор несуществующего класса:

    /**
     * @memberOf __module
     * @type module
     */
    var module = (/** @constructor */ function() {
    
    	function myPrivateMethod() {
    
    	}
    
    	return {
    		/**
    		 * @memberOf module
    		 */
    		method: function() {}
    	};
    })();
    

    ss031

    Как видно из примера, я описал несуществующий класс __module, двойное подчёркивание я использую в качестве своеобразного соглашения об именовании объектов. Проблема в том, что этот несуществующий класс попадёт в code complete всего проекта, и использование двойного подчёркивания — простой и понятный способ отфильтровать ненужные данные при вызове code complete. Однако этот недостаток очень легко можно превратить в достоинство: таким образом можно описывать структуры объектов, доступ к описанию которых затруднён из-за отсутствия строгой типизации в JS:

    ss041

    Поддержка популярных библиотек

    Базовый набор библиотек для JSDT довольно невелик: это стандартные объекты JavaScript (Array, String и прочее) и стандартный DOM (HTMLElement, document и так далее). То есть если мы напишем, например, document. и вызовем code complete, то увидем список свойств и методов объекта document, экземпляра класса Document. Но современная веб-разработка немыслима без использования популярных библиотек вроде jQuery.

    Имея в своём распоряжении JSDoc, можно создать описание практически любого популярно фреймворка и использовать его для подсказок в коде. Так как таких описаний в интернете найдено не было, я воспользовался своим любимым принципом «если хочешь, чтобы что-то было сделано хорошо, сделай это сам» и запустил проект, в котором создаю описания популярных библиотек и фреймворков, с которыми работаю:

    jsdt-docs — JSDoc для популярных библиотек

    В этом проекте сейчас есть следующие библиотеки:

    • Modernizr 2
    • Browser Addons — разные методы и свойства, которые почему-то отсутствуют в стандартном описании DOM в JSDT.
    • console — небольшое описание объекта console, который присутствует в современных браузерах.
    • CSS2Properties — список CSS-свойств для свойства style DOM-элементов. Несмотря на то, что он называется CSS2, в нём присутствуют и CSS3-свойства: такое название выбрано потому, что в стандартном описании Element.prototype.style является объектом класса CSS2Properties.
    • JS SIgnals
    • Node.JS
    • Socket.IO
    • Underscore.js.
    • Zepto.js

    Добавить библиотеку довольно просто:

    1. Идём в настройки: Preferences > JavaScript > Include Path > User Libraries.
    2. Создаём новую библиотеку: нажимаем кнопку New…
    3. Вводим название библиотеки в появившемся окне и жмём ОК.
    4. Выделив только что добавленную библиотеку, нажимаем на кнопку Add .js file… и выбираем один или несколько файлов, относящихся к данной библиотеке.

    После того, как библиотека была создана, нужно добавить её в проект:

    1. Идём в настройки проекта: Project > Properties > JavaScript > Include Path > Libraries.
    2. Жмём кнопку Add JavaScript Library, выбираем User Library, а затем и библиотеки, которые хотим добавить.

    Теперь у вас в проекте будет работать code complete для указанных библиотек:

    ss051

    Поддержка jQuery

    Добавление поддержки своего любимого фреймворка оказалась не такой уж и простой задачей. Во-первых, он довольно большой и содержит внушительных объемов документацию. Во-вторых — многие методы в нём «перегружены»: например, val() возвращает текстовое значение поля, а val(str) — записывает его и возвращает уже jQuery-объект.

    К счастью, у документации к jQuery есть публичный API, который выдаёт описание всех методов в XML. Я написал парсер на node.js, который опрашивает API и преобразует XML в JSDoc, понятный для JSDT (и, надеюсь, другим IDE). Так что в случае выхода новой версии jQuery можно быстро перегенерировать всё документацию. Парсер я писал для себя и по-простому, он не поддерживает передачу параметров через командную строку, всё настраивается в main.js:

    • Можно сгенерировать документацию для определённой версии jQuery (TARGET_VERSION).
    • Можно сгенерировать описание в виде нескольких файлов. Это связано с особенностью JSDT. Как уже отмечалось ранее, в jQuery много «перегруженных» методов, и если их описать в одном JS-файле, то JSDT будет использовать только одно (самое последнее) описание. Однако если сохранить описание методов с одинаковым названием в разных файлах, то JSDT вполне неплохо покажет по ним code complete и документацию. Так что у вас есть выбор: при создании библиотеки jQuery добавить все файлы вида jquery-jsdoc-N.js (Eclipse JSDT) или же только jquery-jsdoс.js если ваша IDE способна прочитать описание с перегруженными методами.
    • Можно переписать некоторые определения для более удобной работы с code complete (class_map, prefix_map). Например, так переписываются описания для Deferred и Promise объектов, чтобы можно было использовать их описание в JSDoc:

    ss06

    В описании есть ряд классов, которые можно использовать в JSDoc: __jQueryDeferred, __jQueryPromise и __jQueryEvent.

    Пишем плагины к jQuery

    Собственно, как писать плагины рассказывать нет смысла, это подробно описано в документации. Покажу лишь как сделать так, чтобы ваш плагин появился в code complete. А сделать это очень просто, достаточно методу плагина указать, что он является членом класса jQuery:

    jQuery.extend(jQuery.fn, {
    	/** @memberOf jQuery */
    	myPlugin: function() {
    
    	}
    });
    
    $('div').m // тут можно вызвать code complete
    

    Поддержка Node.JS

    Отдельно стоит упомянуть Node.JS, так как к модулям нужно обращаться не напрямую, а через функцию require():

    var http = require('http');
    http.createServer(function() {
    
    });
    

    То есть подсказки для модуля должны зависеть от того, какой аргумент передали в функцию require(). В целом, в JSDT эта ситуация решаема: нужно написать отдельный плагин в виде подключаемой библиотеки, который будет находить вызовы функции require(), смотреть на аргумент и возвращать виртуальный объект с необходимыми методами, и может быть я когда-нибудь напишу такую библиотеку. А пока будем довольствоваться малым: указывать тип модуля через JSDoc.

    Все модули в моей документации описаны в виде классов Node{Name}Module, например: httpNodeHttpModule, utilNodeUtilModule. Поэтому для переменной, в которую записывается модуль, указываем через JSDoc нужный тип:

    /** @type NodeHttpModule */
    var http = require('http');
    http. // вызываем code complete
    

    Советы

    В качестве заключения дам несколько советов, которые помогут вам в работе с JSDT:

    • Не используйте фигурные скобки при указании типа переменной с помощью тэга @type — в некоторых случаях JSDT не сможет подцепить тип переменной. Лучше писать так: @type Array (вместо @type {Array}).
    • При описании модуля тэг @memberOf moduleName достаточно указать только у одного свойства/метода в литерале, все остальные подцепятся автоматически.
    • Если у вас в проекте есть непосредственно код библиотек (например, jQuery), то его лучше исключать из индекса, чтобы он не мешал работе code complete. Делается это так: заходите в настройки проекта Project > Properties > JavaScript > Include Path > Source. Разворачиваете папку с исходниками, двойной клик по фильтру Excluded и в диалоговом окне в секцию Exclusion patterns добавляете файлы, которые надо исключить.
  • Веб-разработка в Eclipse: HTML и CSS

    Когда-то давно, работая ещё в Студии Лебедева, я рассказывал про использование Eclipse IDE в веб-разработке. Тогда моими основными инструментами были Aptana для HTML и CSS и Spket IDE для JS. С тех пор много воды утекло: Aptana всё дальше отходила от идей Eclipse IDE, всё больше превращаясь в самостоятельный продукт для Rails-разработки, а Spket IDE не обновлялся с октября 2009. В это же время проекты, с которыми я работаю, становились всё больше и сложнее и текущего инструментария уже не хватало. Руководствуясь принципом «если хочешь, чтобы что-то было сделано хорошо — сделай это сам» я принялся допиливать IDE до нужного мне состояния.

    Самая главная проблема всех редакторов для веб-разработки: они пишутся людьми, которые этой самой веб-разработкой не занимаются. Нет, они [программисты], конечно, могут на досуге собрать в своём редакторе сайтик-другой, но что делать тем, кто занимается веб-разработкой профессионально? Выход я вижу только один: взять хорошую платформу и доработать её до нужного состояния.

    Как я уже написал, Aptana превратилось в некого монстра, с избыточным для не-Rails технологам функционалом. Поэтому в качестве платформы я выбрал более простой и, главное, лучше интегрированный в IDE плагин — Eclipse Web Tools Project.

    Eclipse Web Tools Project

    Как можно понять из названия, Eclipse WTP — это инструменты для веб-разработки, а не законченный проект (как Aptana, например). Цель этого проекта: создать платформу, на основе которой можно создавать другие, узкоспециализированные инструменты. Этот проект включает в себя редакторы для CSS, HTML, XML, XSL, JavaScript (отдельный большой проект под названием Eclipse JSDT; о нём расскажу в следующих частях). Проект частично включён практически во все официальные сборки Eclipse, но для начинающих пользователей рекомендую ставить Eclipse for JavaScript Web Developers, в ней есть всё.

    Чтобы не пересказывать документацию, кратко приведу основные возможности:

    • подсветка кода;
    • сворачивание/разворачивание кусков кода (code folding);
    • outline и quick outline (на последний рекомендую обратить особое внимание, по умолчанию вызывается через Ctrl+O или ⌘O);
    • выделение границ тэгов (aka Balancing), смотрите в основном меню Edit > Expand Selection To;
    • content assist по тэгам, атрибутам и значениям некоторых атрибутов;
    • quick fix: переименование тэга (автоматически меняет открывающий и закрывающий тэги), обрамление тэгом;
    • форматирование всего/выделенного кода;
    • автоматическое закрытие тэгов.

    Итак, с платформой определились, теперь нужно её настроить для комфортной работы.

    Включаем поддержку HTML5 и CSS3

    Eclipse WTP в версии 3.3 (которая доступна для Eclipse Indigo) появилась поддержка тэгов HTML5 и некоторых свойств CSS3. Однако сразу они не доступны, нужно немного пошаманить с проектом:

    1. Открываем свойства проекта: Project > Properties.
    2. Переходим на вкладку Project Facets и жмём на ссылку Convert to faceted form…
    3. В появившемся окне выбираем фасет Static Web Module, жмём Apply.
    4. Закрываем окно с настройками проекта.

    Теперь в content assist будут доступны новые тэги и свойства. Если нет — снова открываем свойства проекта и идём на вкладку Web Content Settings, где настраиваем профили для HTML и CSS.

    Включаем проверку правописания

    Eclipse IDE с версии 3.4 (если мне не изменяет память) поддерживает проверку правописания, и по умолчанию доступен только английский словарь. Чтобы включить проверку правописания русского языка, делаем следующее:

    1. Скачиваем и распаковываем русский словарь.
    2. Открываем настройки Eclipse, идём в General > Editors > Text Editors > Spelling
    3. В User defined dictionary выбираем распакованный ru.dict.
    4. Ставим кодировку UTF-8

    Всё, теперь, если редактор, которым вы пользуетесь, написан по гайдам Eclipse Platform, вам будет доступна проверка правописания.

    Eclipse WTP Sugar

    Самую большую ломку при переходе с Aptana на Eclipse WTP у меня вызывало отсутствие content assist для путей к файлам (например, в <script src="...">): приходилось писать все пути к файлам вручную, что сильно утомляло. Да и в Aptana он был не идеальным: работал только внутри атрибута src (<script src="...">, <img src="..."> и т.д.), но не работал внутри href (<link href="...">, <a href="...">) и уж тем более не в CSS (background url(...), @import url(...)).

    Поэтому, потратив несколько месяцев на изучение Java и архитектуры Eclipse IDE, я написал свой content assist, который исправит этот недостаток, а заодно несколько других (о них чуть позже).

    Свой проект я назвал Eclipse WTP Sugar, репозиторий для установки: http://media.chikuyonok.ru/eclipse/webdev/updates/, исходный код доступен на GitHub.

    Плагин устанавливается очень просто, как и все остальные:

    1. Идём в Help > Install New Software…
    2. В качестве репозитория (поле Work with) вбиваем http://media.chikuyonok.ru/eclipse/webdev/updates/.
    3. В появившемся списке плагинов выбираем необходимые и жмём кнопку Next.
    4. Далее проходим стандартную процедуру установки (соглашаемся с лицензией, всё время жмём Next или Finish) и перезапускаем Eclipse.

    Теперь, при нажатии Ctrl+пробел внутри атрибутов src и href можно увидеть список файлов:

    ss01

    Список файлов также выдаётся и в CSS, внутри функции url():

    ss02

    Список файлов по возможности фильтруется. Например, если его вызвал внутри тэга <script>, то увидите список файлов с расширением js, если внутри <link rel="stylesheet"> — файлы с расширением css.

    Возвращаясь к разговору о том, что создатели программ для вёрстки сами толком сайты не верстают. Что если нужно использовать абсолютные пути для ссылок на файлы? По умолчанию считается, что абсолютный путь нужно резолвить относительно папки с проектом. Но почему никому не пришла в голову мысль, что веб-пространство проекта не всегда совпадает с корневой папкой проекта? В этом плагине проблема решена: в настройках проекта можно указать, относительно какой папки нужно резолвить абсолютные пути (Project > Properties > Document root):

    ss03

    Quick outline

    Следующее, что хотелось изменить, так это quick outline: специальное контекстное окошко, которое показывает в компактном виде текущую структуру документа:

    ss04

    Эту структуру можно фильтровать, чтобы найти нужны элемент (поиск осуществляется с начала строки, можно использовать символы * и ?). Но, как видно из скриншота, в структуре выводятся только названия тэгов, что делает её малопригодной. WTP Sugar исправляет этот недостаток, выводя гораздо больше полезной информации, по которой, в том числе, можно искать:

    ss05

    Eclipse XV Browser

    Не так давно я написал просмотрщик XML-файлов под названием XV Browser. В том посте я показал, что его можно использовать внутри Eclipse, однако не учёл один важный факт: работать это будет только если у вас Mac, а в качестве основного браузера используется Safari с установленным плагином XV :)

    Eclipse XV Browser исправляет этот недостаток. Он представляет из себя обёртку для встроенного браузера (это может быть Webkit либо Mozilla, в зависимости от ваших настроек и версии Eclipse). С помощью этого плагина можно прросматривать любой сайт в виде XML-структуры (Window > Show View > Other… > XV Browser), либо открывать просматривать XML-файлы проекта (правый клик по файлу, Open With… > XV Browser).

    Пожелания?

    Если есьт какие-то идеи по улучшению плагинов — пишите в Issues проекта. Пока в планах:

    • content assist по классам и идентификаторам, описанных в CSS;
    • быстрый переход к CSS-определению класса или идентификатора;
    • виджеты для редактирования CSS Gradients и CSS Box Shadow.

    В следующей статье рассмотрим, как улучшить работу с Eclipse JSDT (JavaScript).

    Метки: , , ,