-
Веб-разработка в 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 ни то, ни другое не работает:
Небольшой JSDoc исправит ситуацию:
/** * @type module */ var module = (function() { return { /** * @memberOf module */ method: function() {} }; })();
Теперь работает как надо:
Но есть ещё одна проблема: приватные переменные и методы модуля не отображаются в Outline, а очень хотелось бы. Это можно исправить, описав самовызывающуюся функцию как конструктор несуществующего класса:
/** * @memberOf __module * @type module */ var module = (/** @constructor */ function() { function myPrivateMethod() { } return { /** * @memberOf module */ method: function() {} }; })();
Как видно из примера, я описал несуществующий класс
__module
, двойное подчёркивание я использую в качестве своеобразного соглашения об именовании объектов. Проблема в том, что этот несуществующий класс попадёт в code complete всего проекта, и использование двойного подчёркивания — простой и понятный способ отфильтровать ненужные данные при вызове code complete. Однако этот недостаток очень легко можно превратить в достоинство: таким образом можно описывать структуры объектов, доступ к описанию которых затруднён из-за отсутствия строгой типизации в JS:Поддержка популярных библиотек
Базовый набор библиотек для 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
Добавить библиотеку довольно просто:
- Идём в настройки: Preferences > JavaScript > Include Path > User Libraries.
- Создаём новую библиотеку: нажимаем кнопку New…
- Вводим название библиотеки в появившемся окне и жмём ОК.
- Выделив только что добавленную библиотеку, нажимаем на кнопку Add .js file… и выбираем один или несколько файлов, относящихся к данной библиотеке.
После того, как библиотека была создана, нужно добавить её в проект:
- Идём в настройки проекта: Project > Properties > JavaScript > Include Path > Libraries.
- Жмём кнопку Add JavaScript Library, выбираем User Library, а затем и библиотеки, которые хотим добавить.
Теперь у вас в проекте будет работать code complete для указанных библиотек:
Поддержка 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:
В описании есть ряд классов, которые можно использовать в 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
, например:http
→NodeHttpModule
,util
→NodeUtilModule
. Поэтому для переменной, в которую записывается модуль, указываем через 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 добавляете файлы, которые надо исключить.
35 комментариев
Для Closure «Советы» не очень подходят, к сожалению…
Смотря с какими настройками сжимать. При стандартных у меня вроде не ругался на JSDoc.
Стандартные — это Advanced или Simple? Проверю в обеих.
Simple
Advanced рулит. В Closure есть сложные типы данных типа @typedef {{status: number, result: Object}}, которые не обходятся без фигурных скобок.
И проблема с goog.base при наследовании, к сожалению. Но лучше Eclipse пока нет.
Ну вообще фигурные скобки в
@type
никто не запрещает использовать, я просто указал, что в JSDT с этим могут быть проблемы 🙂 А какие проблемы с goog.base?Прочитал предыдущий пост, даже немного воодушевился, решил окончательно и бесповоротно перейти на eclipse. До этого, конечно, были эпизодические попытки перейти на него, и даже пару месяцев назад написал простенькое html5 приложение для android при помощи eclipse, но все равно так его и не осилил, все смущала неповоротливость и прожорливость ресурсов (в сравнении с notepad++).
Как и советовали, скачал Eclipse JSDT, денёк побаловался с локальными проектами — все было замечательно (если не считать лагание и глючность самого eclipse). Для локальной неторопливой разработки оказалось вполне себе ничего, но когда мне понадобилось перенести проект на сервер для интеграции с серверной частью (ajax, xml и т.п.) я понял, что это северная белая лиса. Как оказалось встроенных инструментов для работы с удаленными фс у eclipse нет, всезнающий гугл показал мне 3 буквы — rse (remote system explorer), хаброюзеры пугали муками при установке rse под линкус и я не желая испытывать судьбу решил для начала попробовать с виндой — это толстенная северная белая лиса, чуть сервер задержался с ответом — висит, случайно нажал сохранить во время синхронизации файлов с сервером — висит, после каждого сохранения он зачем-то заново загружает список файлов с сервера — нажал какую-нить кнопку — опять висит.
Потерянных 4х рабочих часов, в попытках хоть как-то это заставить работать стабильно, хвалило, что б очень на долго отбило у меня желание снова пытаться подружиться с eclipse, я даже подумывал вернуться к старым и верным notepad++ и winscp, но проекты все сложнее и обьемнее и без ide уже никак. Выбор пал на netbeans, и я не прогадал — стабильно, быстро, удобно, а eclipse в дальний сектор винчестера под запароленый архив, а код потерять
Вообще, конечно, работать напрямую с проектом через FTP — не самый правильный способ поддерживать проект в рабочем состоянии, ну да ладно 🙂 Мы у себя решаем эту проблему довольно просто: монтируем удалённый сервер по NFS/SSHFS, а версии синхронизируем через плагин FileSync, который автоматом закачивает изменившиеся файлы в нужную папку. За 2 года активного использования такого метода проблем не обнаружил.
Добрый день, Сергей.
Подскажите пожалуйста, возможно ли настроить отображение в Outline локальных переменных, расположенных внутри анонимных функций (не Module pattern, а обычная анонимная функция).
Сергей, спасибо, интересная инфа. Но по этому редактору, если сравнивать его с SPKet IDE, к которому я очень привык, есть несколько моментов:
1. Не удалось найти нормальной доки по JSDoc-диалекту JSDT — не ясно назначение некоторых специфичных тегов, которых нет ни в документации jsdoc-toolkit`а, ни где-то ещё, а он их предлагает, например, «@addon».
2. Почему-то не работает переход к коду по нажатию Ctrl+{клик мышкой на переменную или метод, описанный в другом файле}. При чём не только к внешней библиотеке, но даже между файлами внутри проекта :((( SPKet IDE с за-@include`ными файлами это проделывает легко.
3. Почему-то подчёркивает красным теговую разметку внутри JSDoc-комментариев, например, «@author Вячеслав«, да и дата в стандартном формате ему не нравится — «@date Jul 24, 2011 8:04:17 PM» — «Jul» подчёркивает… Есть простой способ, как в ворде, добавлять слова в личный словарь соответствующим пунктом из попап-меню?
(в п.3 предыдущего комментария имелись в виду HTML-теги внутри JSDoc — подчёркивает параметры, например, «href»)
Думаю это ответит на часть вопросов, багов очень много https://bugs.eclipse.org/bugs/buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=JSDT&component=General
Почему-то code complete вызывается только по ctrl+space. Подскажите, пожалуйста, это поправить?
Здравствуй. Немного не по теме, но все же есть такой вопрос. Если есть пару объектов и нужно наследование одного объекта другим, то какой из вариантов кода будет более предпочтителен:
1. с замыканием, как в твоих примерах. Здесь как понимаю наследование можно сделать через Parent.call(this).
var module = (/** @constructor */ function() {
function myPrivateMethod() {}
return { method: function() {} };
})();
2. Или через простые функции, например
function MainModel(){};
MainModel.prototype.somemethod = function(){};
function Article(){}
Article.prototype.somemethod2 = function(){};
а потом наследовать так
Article.prototype = MainModel; () // но еклипс не подцепляет методы MainModel.
ну или так
Article.prototype = new MainModel(); // при каждом наследовании вызывается конструктор модели, что не есть хорошо.
В приватных методах пока особую нужду не испытывал. Сомнения мучают потому, что второй вариант в файрбаге отображается как куча вложенных друг в друга prototype constructor. Нормальна ли такая ситуация? В разных книгах пишут по разному, а описания когда как лучше или как оптимально — нет.
Если можешь отпиши, нет — подскажи хорошую книгу, буду читать.
Макс, позволю себе ответить за автора =)
Лучшая книга по ООП и шаблонам проектирования в JS — http://jsdesignpatterns.com/ — глава 4, подробно описано классическое и основанное на прототипах наследование
sap1ens, спасибо за книгу. Ознакомился с подходами. Определил, что для меня наиболее подходящим является вариант mixin. Теперь вопрос уже по теме. Как научить eclipse правильно определять родителя в такой конструкции и соответственно давать на code complete все методы родителя (так как передача всего идет через третью функцию, то оно ничегошеньки не видит):
var Parent = function() {};
Parent.prototype.cancel = function(id) {
this.convertToText();
};
/* Child */
function Child(id, parent, value) {
this.id = id;
this.value = value || ‘default value’;
this.parentElement = parent;
this.createElements(this.id);
this.attachEvents();
};
augment(Child, Parent);
function augment(receivingClass, givingClass) {
if (arguments[2]) { // Only give certain methods.
for ( var i = 2, len = arguments.length; i < len; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
} else { // Give all methods.
for (methodName in givingClass.prototype) {
if (!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
}
Пробовал писать jsDoc, но ничего хорошего с этого не получилось. Подскажите пожалуйста.
// эх, почему так не работает?
$(‘div’).click(function(/** @type Event */ evt){
evt.| //ctrl+пробел
});
hipot, правильно писать вот так:
Добрый день. Не планируется ли подробной статьи по JSDoc в eclipse? В интернете только разрозненная информация, а душа просит чего-то упорядоченного.
Поставил WDT, создал JavaScript проект, добавил библиотеку (документацию) jQuery с GIT-а.
При вызове дополнения кода и объекта Jquery и переходе (стрелкой вниз) в панели методов на первый доступный метод — Eclipse залипает на 30-40 сек. и все тут. Т.е. сами методы объекта отображаются, но при вызове панели описания редактор вешается.
В проекте всего один JS-файл.
Также не работает code assist для такой конструкции:
$.map($(‘div’), function(/** @param jQuery el */ el) {
el;
});
и так не работает:
$.map($(‘div’), function(/** @type jQuery */ a) {
a;
});
и так:
$.map($(‘div’), function(/**jQuery*/ a) {
a;
});
В чем может быть дело? Спасибо.
to Sorbing, смотрите выше, вам следует так писать:
$.map($(‘div’), /** @param {jQuery} el */ function(el) {
el.|
});
В версии Eclipse 3.7.1 появились какие-то странные баги с code complete в JS, попробуйте откатиться на версию 3.7
А в вашем примере нужно писать так:
$.map($(’div’), /** @param {jQuery} a */function(a) {});
> …следует так писать /** @param {jQuery} el */ function(el) {}
Блиин! Где были мои глаза?! Спасибо, работает. Правда вариант записи Spket — /*Array*/ — более лаконичен, но да не будем уходить от темы.
> В версии Eclipse 3.7.1 появились какие-то странные баги с code complete в JS..
Ага, он оно что. Я то уже думал у меня с настройкой что-то не так, пустой Indigo 3.7.1 распаковывал, тестил. Да, работать анреал(.
Останусь пока на Spket.
Сергей, я начал работать в Eclipse PDT + Spket после просмотра Вашего скринкаста по код комплиту JavaScript.
Что было основной причиной для перехода на JSDT? Не увидел в нем ничего, чтобы можно было сказать «ВАУ! Ухтышка)».
Спасибо.
P.S. Offtop! Кстати, о Вас как раз сегодня вспоминали) — http://habrahabr.ru/blogs/eclipse/131211/
И еще, на дефолтной документации jQuery (c GIT-а) не поддерживается дополнение кода в цепочке методов.
Вот так: http://dl.dropbox.com/u/16177201/files/jsdt-jquery-assist-chain-not-support.png
Проверьте, может вы не так подключили (или вообще не подключили) библиотеку.
Возможно, это опять Eclipse 3.7.1 глючит. Я локально вносил кое-какие правки, у меня всё работает
Сергей, а Вы на какой версии Eclipse сейчас используете WDT?
Я скачал Eclipse 3.7, поставил WDT 3.3.1.(v201107072200). Подключил библиотеку jQuery (одним файлом) так:
Так же подключил ее в самом проекте — глюки те же. Окно комплита вешает Eclipse на 30-60 сек.
Блин, думал тег IMG работает в комментах..
Подключил библиотеку jQuery (одним файлом) так: http://dl.dropbox.com/u/16177201/files/jsdt-3.7.1-add-jquery-library.png
Попробуйте подключить несколько файлов. У меня автокомплит тоже подтормаживает на вызове статических методов jQuery, попробуйте в моём файле закомментировать строчку:
$.prototype = new jQuery();
и проверить работу автокомплита на
$('div').
Хе) Другое дело! Даже Eclipse не нужно рестартовать, только F5 на проекте и все работает как надо! Спасибо.
А зачем эта строчка была в документации?
Строчка нужна, чтобы работал кодкомплит по статическим методам в переменной
$
, например,$.ajax
. Сейчас работает только сjQuery.ajax
Подскажите пожалуйста, как правильно написать JSDoc для вот такого примера (все свои классы ложу в один namespace):
var namespace = {};
namespace.Class1 = Class.create({
method1: function() {}
});
Пробовал указывать @type namespace.Class1 и @memberOf namespace.Class1 — не помогло, пробовал @type Class1 и @memberOf Class1 — тоже не помогает, Outline показывает только
namespace : {}
Class1 : any
Indigo под win 7 не запускается, The Eclipse executable launcher was unable to locate its companion
Нашел только такое лекарство
http://vsingleton.blogspot.com/2009/09/eclipse-executable-launcher-was-unable.html
Попробывал сделать эти команды через командную строку,
пишу $ pwd, отдает ошибку «не удается найти $…». Я в командной строке еще тот мастер.
Попробывал другой способ с правами, что он пишет ниже.
Застрял на 13.-ом пункте, у меня нет в этом окне пользователя admin нет, есть только группы, выставил всем пользователям админской группы, где не было большинства галочек, но так и не запускается.
Я просто скачал его, залил в Program Files, и запускаю. Может что-то еще нужно перед этим сделать?
Спасибо за информацию.