Як зробити багатоплатформовий десктопное додаток на базі веб-технологій



Дмитро Дудін (xbSoftware)
Сьогодні я вам розповім про технологію nw.js більшість слайдів моєї презентації буде присвячено їй. Це технологія дозволяє розробляти десктопні програми і писати їх на html, javascript і css. Причому додаток буде багатоплатформовий — під Windows, Linux і Mac. Можна їх сбилдить і вони будуть мати доступ до графічного інтерфейсу системи, тобто зможуть працювати з менюшками і т. д.

Мене звати Діма (@nedudi), я працюю в компанії XB Software, я з Мінська.

Ми робимо всякі Javascript компоненти webix для админок, тобто для великих обсягів даних — можете знайти і подивитися. Ще ми займаємося аутсорсом, крім цього, я пишу блог html5.by. Ще у нас в Мінську є фронтенд-спільнота 4front, яке ми організовуємо, і ще — ми раз у півроку проводимо «What the Hack» — це такий захід, де ми робимо непотрібні для життя хакі, тобто антистартаперское, але дуже круте.

Перейдемо до теми.


Ми всі дуже любимо робити веб-додатки. Напевно, все люблять робити веб-додатки. Ми оточуємо їх турботою, прикріплюємо до них якісь гранти, постпроцессоры, препроцессоры, ми просто тащимся від всієї цієї розробки. Але, якщо чесно сказати, то більшість додатків, які ми використовуємо для роботи, це все-таки десктопні програми. Це ті додаток, у яких є значок на робочому столі, які запускаються і можуть тижнями висіти в тлі. Це якісь графічні редактори, файлові менеджери, редактори аудіо, відео, якісь системні утиліти. І чому б не писати це все на веб-технологіях? Тут є такий бар'єр — браузер, який дуже дбає про нашу безпеку.

Припустимо, я хочу написати програму на веб-технологіях і я хочу, щоб воно працювало за принципом десктопного додатка. Які бар'єри у мене є? Я їх буду висловлювати як «я хочу»:

  • Я хочу, щоб веб додаток мало доступ до файлової системи, системним процесам, буферу обміну, якимось сполучень клавіш і т. д.
  • Хочу, щоб воно могло працювати в фоні, могло запускатися при старті системи, могло працювати повністю автономно онлайн, при цьому, не піклуючись про те, що воно працює оффлайн.
  • Хочу, щоб воно не запитувала кожен раз доступ до камери і мікрофону, коли чоловік запускає його.
  • Хочу використовувати у своєму додатку Web GL, Web Audio, Web RTC, всі нові веб API, і при цьому бути впевненим, що вони будуть працювати на одному і тому ж движку. Тобто движок, який я встановив, а не який є у людини в браузері.
  • Хочу, щоб воно могло створювати системні менюшки, вікна, всякі іконки в треї, могла ними керувати.
  • Хочу з допомогою програми, припустимо, робити повноекранні скріншоти.
  • Хочу користуватися системною нотифікацією.
  • Хочу робити кроссдоменные запити, змінювати UserAgent, завантажувати Google у фреймі. Що це таке — деякі сайти, коли вони завантажуються у кадр, цьому всіляко чинять опір, вони перевіряють: або це вікно верхнього рівня, або ні, і в вікна не верхнього рівня не завантажуються. Наприклад, Google видає якусь табличку, Твіттер, завантажуючись в кадр, намагається знайти parent-вікно і туди завантажитися. Я хочу цьому протидіяти.
  • Хочу мати повноекранний режим як в іграшках, з якого не так просто вийти, тобто повноекранний режим, в якому додаток запускається і в ньому ж працює. Не браузерний FullScreen.
  • Хочу розповсюджувати, рекламувати свою програму через маркети. Зараз дуже багато маркетів, дуже модно туди свій додаток завантажувати, там є маркетингові ходи, щоб розкручуватися.
  • І просто, але дуже важливо — я хочу, щоб моє виконувати цю програму по кліку на іконочку. Я не хочу набирати url або змушувати користувача набирати цей url. Я хочу дати йому це додаток, він його встановить, натисне на іконку, і воно запуститься.
Можливо все це зробити в додатках, написаних на веб-технологіях з допомогою nw.js? Так, це можливо. І це можливо зробити дуже легко. До nw.js, про який я буду розповідати (він зовсім недавно так виліз на поверхню і став таким популярним), які ще є рішення?

Є Adobe Flash (http://www.adobe.com/products/flash.html), Chrome apps https://www.google.com/chrome/webstore/apps-games.html), Tide SDK (ex. Titanium Desktop   http://www.tidesdk.org/), App.js http://appjs.com/), Brackets Shell (https://github.com/adobe/brackets-shell), Tint (https://www.trueinteractions.com/tint2/docs) і ін

Всі вони приблизно намагаються займатися тим же самим, але, коли ми починаємо читати документацію до них, стає дуже сумно, тому що там є якісь свої правила, свої засади. Вам спочатку потрібно зрозуміти їхню філософію, їх API. Щоб написати якесь просте додаток вам потрібно розібрати якісь приклади документації, і це займає реально багато часу. А, може, ви цю технологію не будете використовувати?



З nw.js http://nwjs.io/) все набагато простіше. Якщо ви коли-небудь писали веб-додаток, а ще експериментували або працювали з Node.js, то ви вже години через дві будете мати можливість написати десктопное додаток під три платформи, яка буде працювати.

На мою суб'єктивну думку, на ринку є два гідних рішення для цього. Це nw.js, про який ми будемо говорити, і Electron (http://electron.atom.io/).



Це, насправді, послідовник nw.js він розробляється розробниками Github, які роблять Atom, IDE Atom написано на Electron. Він раніше називався Atom Shell, і буквально у квітні вони його перейменували в Electron.

Ми сьогодні будемо робити вибір «зірок», тобто я зайшов на Github, подивився у кого з них більше зірок, більше ком'юніті, і ви брав для себе одне з них. Насправді, Electron подає дуже великі надії, тому, може бути, через рік варто задуматися, щоб переключитися на Electron. Треба дивитися, як він буде розвиватися. У будь-якому випадку у них зовсім не багато принципових відмінностей. Тому перейти через рік з nw.js на Electron буде не так складно. І я в кінці розповім принципова відмінність між ними.

nw.js проект раніше називався node-webkit, у нього є історія.



У 2011 році у Roger'а Wang'а — розробника з Китаю — з'явилася ідея схрестити Node і webkit, зробити веб-додаток. Назвав він його node-webkit, тому що webkit тоді був рендер-движком Chromium'а зараз це Blink. Йшли роки, проект розвивався, все було добре, але до теперішнього моменту він втратив свою назву.

В квітні 2013-го Chromium переїхав на Blink (http://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html, тобто webkit загубився, а з січня 2015-го проект почав використовувати io.js https://groups.google.com/forum/#!msg/nwjs-general/V1FhvfaFIzQ/720xKVd0jNkJ). Тут вже Node.js загубився. Хоча Node.js можливо, скоро повернеться, судячи з новин. Тому проект перейменували в nw.js і заклали в цю nw такий сакральний сенс — native web. Підтримується він Intel і gnor.net.

Основна ідея.

У нас є десктопні програми. Чим вони принципово відрізняються від веб-додатків? Тим, що та машина, яка розмальовує інтерфейс, на ній же в основному відбуваються і зміни. Тобто файловий менеджер, який розмальовує інтерфейс, дозволяє змінювати файли на машині, на якій працює це додаток. У веб-додатках, в основному, все організовано по-іншому: є браузер, який щось малює, а все змінюється на сервері, який десь далеко. Тому в nw.js розробники захотіли наблизити веб-додатки до десктопних додатків. Як вони це зробили?



У nw.js є дві складові частини — це Chromium і io js.

Що таке Chromium? Це браузер з відкритим вихідним кодом, який дуже схожий на Chrome, підтримується він Google, Opera software, Яндексом, Nvidia — такими великими дядьками. У нього в основі лежить Blink як движок для рендеринга, движок javascript — це V8.

Node.js-написана на С++, що працює на рівні протоколів прикладного рівня, у неї є доступ до якихось мережевих взаємодій, файлової системи і іншим системним фішках. Тобто вона з-за цього більше використовується на серверах і для автоматизації якийсь.

Обидва вони використовують V8. Один і той же V8. Знаєте звідки така назва?



Коли розробники створювали V8, вони взяли за основу таку ідею движка… V8 — бо клапана розташовані літерою V і їх 8 (клапанів). Двигун V8 вже давним-давно використовується.

В 1902 році, ця штука називалася арианет, по-моєму, і в ній вже використовувався V8:



А це Chevrolet Camaro 2015 року і в ній теж використовується V8.



Якщо браузерний V8проживет таку ж життя, то буде дуже класно.

Повернемося до V8. Основна ідея — це об'єднати два цих світу і зробити їх робітниками на одному і тому ж движку в одному і тому ж контексті. Тобто ви можете з хати викликати безпосередньо функції Node.js, підключати модулі Node.js, передавати об'єкти за посиланням, працювати в єдиному контексті, мати один event loop. Якщо точніше сказати, то тут Node.js працює на движку V8, який є у Chromium'а.

Давайте наведу невеликий приклад.



У нас є fs Node.js для роботи з файловою системою. Ми можемо дивитися за змінами в якомусь лог-файлі, і якщо вони сталися, то ми беремо DOM елемент і промальовуємо в нього вміст цього лог-файлу. Просто на сервері це неможливо, на клієнті це теж неможливо, немає доступу до файлової системи юзера. А в додатку декстопном nw.js все це буде працювати відмінно.

Як вони це зробили?

Було дві основних проблеми: зробити все в одному робочому event loop, і щоб воно працювало в єдиному контексті. Тобто немає якогось window і global, є глобальний контекст, в якому є і Node.js і браузерний javascript. Тут можна почитати докладніше   https://github.com/nwjs/nw.js/wiki/How-node.js-is-integrated-with-chromium.

Починаємо занурення. Як почати працювати з nw.js? Ви заходите на nwjs.io, завантажуєте звідти файл для своєї платформи для білдів, і далі ваш додаток ви можете будувати по якому завгодно принципом.



Ніхто вам не каже, куди класти html, куди — css, ви просто маєте додаток так, як хочете, повністю всю структуру. Єдине, що ви повинні мати, це package.json. Це файл абсолютно такий же, як у будь-якому Node.js додатку, але у нього будуть ще кілька додаткових полів.



Це main — з якого файлу почати роботу.

Багато установок для параметрів вікна, dependencies, які потрібні для нода.

Потім можна ще передавати туди прапори, з якими запускається Chromium, прапори, з якими запускається Node, і ще якісь системні налаштування, яких вистачає.



Далі, ми в нашому тестовому разі напишемо такий додаток. У нас буде div, у якого є якийсь контент, додамо трохи CSS, і все, що нам потрібно запустити, — це nw app. Де nw app — це шлях до директорії з вашим додатком. При цьому на екрані ви побачите щось таке:



Тобто запуститься додаток, з'явиться иконочка. Це дуже схоже на браузер. Насправді, це і є браузер, це просто звичайний Chromium.

Але тут відразу хочеться зробити його менш схожим на браузер, тому що це все-таки десктопное додаток, а тут ще багато всього там зверху.

Для цього є безліч налаштувань, коротко пробіжимося по деяким з них. Можна прибрати toolbar, це в конфіги.



Буде виглядати якось так:



Можемо далі прибрати фрейм, тобто ту штуку з кнопочками.



Якось так:



Вже більше схоже на щось таке декстопное.

Далі можемо зробити це взагалі все transparent, тобто прозорим:



При цьому, у нас буде просто текст в висіти над нашим робочим столом — ніяких ознак браузера:



Можна запустити додаток в kiosk mod'е.



Kiosk mod використовується для іграшок, в основному. Ще добре використовується для всяких терміналів, інфо-кіоски, великих всяких панелей, які відображають меню в Макдональдсі і т. п. Він повноекранний, з нього вийти дуже важко, з нього виходять тільки описаними методами, або alt+tab або ctrl+alt+del в вінді. Тому, якщо вам потрібно в kiosk mod'е, виглядає це все ось так, т. е. повністю займає ваш екран:



Це не FullScreen, ніяких панельок не буде виїжджати, якщо ви будете кудись підводити мишку. Для нього потрібно буде передбачити кнопочки для того, щоб дати користувачеві вийти з усієї цієї краси. Інакше користувач повинен буде вбити його в процесах.

Або ви можете взагалі запускати додаток в тлі, взагалі без вікна, буде ось так:



Що ще є з красивих всяких булочок?



Nw.js у стандартному пакеті дає вам API для керування якимись системними елементами інтерфейсу. Це можна створювати всілякі менюшки, іконки в треї, notifications, можна працювати з буфером обміну, з системними комбінаціями клавіш, тобто не браузерних, коли у вас додаток в фокусі, і якщо ви що-то натиснули, у вас щось станеться, а сполученнями клавіш на рівні системи. Тобто у вас програми не видно, що ви щось натиснули, воно з'явилося, або щось зробила — скріншот або ще щось. Все це підключається через require nw.gui. Ця штука йде в стандартні поставки, її підключати нізвідки не треба.

Коротко пробіжимося по ним. Контекстні меню.



Створюються дуже просто: пишете такий Javascript — нам потрібно меню, нам потрібні декілька пунктів цього меню, нам потрібен один сепаратор, тобто роздільник між пунктами, і на один з пунктів меню, ми повісимо «привіт». Вийде штука, яку ми повісимо на праву кнопочку, і у нас буде така системна менюшка:



Тобто вона на маці буде виглядати ось так, на вінді вона буде виглядати абсолютно по-виндовому, на убунте або іншому лінуксі, абсолютно по-линуксовому.

Віконне меню.



Така ж історія. Створюємо таку ж менюшку, тільки даємо їй роль менюбара. Отримуємо таку менюшку з вкладеними пунктами меню:



Трей або менюбар, в інших ОС.



Теж створюємо іконку в треї, можемо вішати на неї якісь випадають менюшки, є иконочка, назва, тут якісь чекбоксики, що випадають списочки, тобто все це теж можна зробити.



Причому, всі ці евенты, які там будуть викликатися, будуть доходити до вашого браузерного вікна, і там можете щось робити, або в ноде, або в DOM'е, не важливо.

Поєднання клавіш.



Теж все дуже просто. Ви текстом пишете, яке поєднання клавіш вас цікавить, намагаєтесь зареєструвати його в системі, якщо таке поєднання клавіш в системі вже є, він вам скаже: «Вибач, фейл, треба щось інше спробувати». Якщо все добре, він його зареєструє і почне на нього реагувати. Тобто всі евенты при натисканні юзером на ці клавіші будуть переходити сюди активні.

Буфер обміну. Clipboard.



Така ж історія. Поки вони підтримують тільки текстовий кліпборд, обіцяють з розміткою в майбутньому теж підтримувати, але поки що ви можете покласти щось у буфер обміну і отримати щось з буфера обміну. Тобто можна вже придумати собі якесь додаток, де ви натискаєте якесь поєднання клавіш, і ваш буфер обміну відправляється кудись в хмару, або ще що-небудь. Тут головний принцип   не нашкодити. Тому що nw.js знімає дуже багато обмежень щодо безпеки. Ви можете видаляти юзерские файли, ви можете їх посилати куди завгодно, ви можете псувати все підряд. Насправді це круто. Свобода — це круто, а не те, що можна все псувати.

Зберігання даних.

У додатках зберігання даних можна розділити на дві категорії: структуровані дані, які зазвичай ми зберігаємо в якихось базах даних, і якісь статичні файли, тобто якісь локальні ресурси цього додатка, картинки, відео, аудіо, проміжні, які нам треба зберігати. Як приклад, якщо ви пишете десктопну іграшку, то в ній потрібно, як мінімум, зберігати результати, останні результати, якщо ви пишете програму, то останні відкриті файли, якісь локальні налаштування.



Для зберігання цих статичних файлів nw.js дати вам таку змінну App.dataPath (https://github.com/nwjs/nw.js/wiki/App), це директорія, вона буде на кожній ОС різна, але якщо ви будете використовувати саме цю директорію для зберігання вашого статичного контенту, то ви можете бути спокійні, він там буде добре зберігатися, буде все добре. Воно складається з імені вашого додатки, так що ніякого конфлікту між додатками в цій папці не буде.

Для зберігання структурованих даних, ви можете використовувати все, що вже було створене у Chromium'е (у вас під руками останній Chromium), тому Web SQL Database, IndexedDB, Web Storage, Local Storage, Session Storage, Application Cache, все що завгодно. Можу тільки порадити: в чистому вигляді їх використовувати не дуже приємно, тому в nw.js були написані тонни плагінів, я в статті у себе згадав посилання на те, де ці всі плагіни є.

Налагодження. З налагодженням все теж дуже добре. Є такий шлях — у вас в тулбарі є така шестереночка:



Відкривається дебагер, абсолютно такий же як у Chrom'е останньому. Ви там всі дебажите. Нічим не відрізняється від Chrom'а. Якщо ви хочете ще більше свободи, ви можете запустити nw.js remote debugging port 1234, припустимо, і у вас той же хромовский дебагер відкриється за адресою.

Є можливість Livereload (https://github.com/nwjs/nw.js/wiki/Livereload-nw.js-on-changes), тобто коли ви міняєте код, ваш додаток автоматично оновлюється. Вони там нічого нового не придумали, вони використовують плагіни, вотчи, які просто перезавантажують це віконце.

Зі складанням додатків (https://github.com/nwjs/nw.js/wiki/How-to-package-and-distribute-your-apps ). Якщо ви вперше зіткнетеся з nw.js будь ласка, не намагайтеся робити це все вручну. Тому що документація порадить вам щось ось таке:



Це сторінка документації, і коли її читаєш, там багато всяких dll, якихось линуксовых заморочок, ще чогось. Перше відчуття, що все, на цьому я закінчив працювати з nw.js. Але насправді, є прекрасний плагін, називається він node-webkit-builder (https://github.com/mllrsohn/node-webkit-builder):



Там вже вся ця штука описана, автоматизована і працює. Все, що вам потрібно зробити, це завантажити його, запустити команду nwbuild з шляхом до вашого додатком, і можете ще задати багато прапорців різних, припустимо, під які ОС билдить. При цьому він полізе, выкачает останню збірку для всіх ОС, завантажить собі, все сбилдит, розкладе вам по татусям. Тобто у вас буде лінукс 64, лінукс 32, віндовс 64, видновс 32 і т. д. Всі ці татка вже з готовими файликами для виконання. Все, що вам залишається, це їх відкрити або під віндою, або під лінуксом, або під маком.

Що у мене вийшло? Після запуску цієї команди, так додаток виглядає на маці:



Так на вінді:



Правда, шрифту робота в вінді немає, тому шрифт поїхав, але я його просто не підключив.

І так виглядає під убунтой:



Тобто менюшки виглядають так само, як будь-які убунтовские менюшки.

Хочеться сравить nw.js і Electron. Тому що Electron все більше набирає обертів. Насправді, nw.js і Electron відрізняються зовсім трошки.



Є така історія, яку розповідав Роджер Ванг в одному з доповідей, те, що коли він розробляв node-webkit на одній із стадій ним зацікавилися розробники Github. І почали якісь питання задавати: що, як, чому? І які в них були ідеї щодо спільного використання цього всього. І з ним працював його інтерн, тобто поряд чувак, який теж щось там пише, допомагає. Ось і через якийсь час цього найняли в Github, який почав писати Electron. Потім вони зробили Atom Shell, потім Atom, потім Electron. Тому концептуальних відмінностей між ними дуже мало. Відмінності є, але для кінцевого розробника вони дуже невеликі.

Перше — це точка входу, т.е. в nw.js ми відразу відкриваємо якийсь файлик index.html і показуємо його у віконці. У Electron ви працюєте більше з Javascript, тобто ви відразу не показуєте ніякого html. Ви в Javascript створюєте це віконце, і потім його показуєте. Це, напевно, все відмінності. У Electron у них різні принципи побудови білдів, що, в принципі, нас не хвилює, тому що я все одно не хочу читати всю ту документацію. Змінений проти оригінального Chromium'а, тобто хлопці в Electron, який колишній Atom Shell, не захотіли змінювати Chromium, вони як-то там викручуються, щоб, взагалі, ніяк не патчити Chromium і використовувати той, який є. В nw.js вони його пропатчивают і прибирають якісь налаштування безпеки і ще щось.

І ще одна відмінність — у контексті. В nw.js загальний контекст, якщо ви насоздаете багато віконець, то в Electron він різний. В принципі, для простих додатків, це не особливо важливо. Детальніше з точки зору розробників Electron, чим вони відрізняються від nw.js (там, звичайно, ухил у бік Electron), можна почитати тут — https://github.com/atom/electron/blob/master/docs/development/atom-shell-vs-node-webkit.md.

І кілька хороших прикладів. Приклади — це не найуспішніші продакшн додатка, але це просто додатки, різні за своєю суттю. Може, вас наштовхне на якісь думки, ідеї, що б розробити.



Перше — це Popcorn Time. Додаток, яке дозволяє стримить з торрентів кіно та серіали.

На відміну від таких подібного роду додатків, воно абсолютно user friendly, воно ніде вам не говорить з якого торрента і як воно все це стрім, ви заходьте, там багато серіалів, ви вибираєте один з них і дивіться. Написаний на nw.js, працює під маком, віндовс і лінукс.

Є програми більше системні. Ця штука така mongo management studio, дуже нагадує php my admin толмко для mongo. Еу, таке gui для mongo.



Є Light table — редактор, дуже схожий на Sublime або Atom. Вони стверджують, що він набагато крутіше, тому що у нього якась певна філософія. Я її не збагнув, але є адепти…



Є ось такі штуки — ви можете відчути себе в ролі радіоведучого, стримить своє аудіо в маси:



Є дуже схожі клони десктопних додатків, наприклад, показують весь ваш диск ось так тегами:



Ви можете подивитися, де лежать великі файлики і їх повидаляти.



Є обгортки для веб додатків, тобто такі навчалки, які… по-моєму, ця повчання сама як десктопное додаток мало чого робить, вона просто бере контент з інтернету і відображає його в додатку.

І от, єдине, що я знайшов російською мовою на nw.js, ця штука для швидкої здачі податків:



Я думав, що в Росії податки ніхто не здає, виявляється, для цього навіть софт передбачено. І цю штуку почали розробляти в 2013 році, вона була призначена для телефонів окремо, для десктопів окремо і окремо для терміналів та інфо-кіосків. Ця версія для терміналів, тобто в терміналах ви теж можете побачити додатки, розроблені на nw.js. Але все-таки я був правий, що податки в Росії ніхто не здає, тому вона так і загнулася в 2013 році і далі у неї ніякої долі не було.

Ще дуже багато додатків вони у себе в репозиторії (https://github.com/nwjs/nw.js/wiki/List-of-apps-and-companies-using-nw.js ) збирають. Якщо ви щось хороше напишете, додатковий якийсь маркетинг, може, від цього вам буде, ви можете теж там у них в репозиторії розмістити, і ваш додаток буде в цьому великому списку. Список дуже великий, там близько 100 додатків.

Хотілося б зробити якісь висновки. Чи варто писати програми на веб-технологіях під десктоп?



Мені здається, суб'єктивно, але хочу поділитися.

По-перше, це найлегша кросплатформеність. Тобто, практично, нічого не треба робити, все за вас зробить сам інструмент, і вам знадобляться якісь складні білди тільки у разі, якщо ви робите щось таке дуже екстраординарне. У типових випадках все буде так добре билдиться.

Працює досить швидко. Звичайно, можна сказати, що програми будуть працювати швидше, які написані на IT-технологіях, але якщо взяти співвідношення швидкості роботи до грошей і ресурсів, витрачених на розробку, то, можливо, nw.js буде набагато далеко попереду.

Зростаючий тренд — все і всі пишуть на вебі скрізь, для квадрокоптеров, телевізорів, холодильників і, в тому числі, для десктопа зараз, чому б ні? Просто писати програми для себе. Тобто написати таку програму, припустимо, у вас є якийсь скрпит, який чогось там билдит, потім тестує, і потім викладає на продакшн або на стейджинг. І ви хочете зробити це вручну, не якимись тулзами, а вручну. Зазвичай ви запускаєте в консольке якісь команди. Але ви хочете, щоб це міг робити, припустимо, тестувальник, або ви хочете, щоб це міг робити верстальник, який не хоче взагалі бачити вашу консоль. І для цього можете написати простеньку десктопное додаток з трьома кнопками (це займе хвилин 20), яке буде в командній оболонці запускати потрібні команди, при натисканні на ці кнопочки.

Пишіть додатки для себе. І це дешево у всіх відносинах. Це дешево в навчанні розробників, тому що їх не треба навчати, їм потрібно дати подивитися слайди і все. Далі це дешево з точки зору, що потрібні вам просто веб-розробники, вам не потрібні якісь вузькопрофільні розробники, які вам будуть писати програми під лінукс або під мак.

Якщо залишилися питання, то дивіться ще:

Контакти
» Блог http://html5.by/
» Твіттер @html5by і @nedudi
» Група ВК http://vk.com/html5by
» Група FB http://facebook.com/html5by

Ця доповідь — розшифровка одного з кращих виступів на конференції фронтенд-розробників FrontendConf.

Ну і головна новина — ми почали підготовку весняного фестивалю "Російські інтернет-технології", в який входить вісім конференцій, включаючи FrontendConf.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.