Ни для кого не секрет, что в наше время JavaScript стал одним из самых популярных языков программирования. В далекие 90е годы, в момент зарождения языка, когда он был создан с единственной целью добавить интерактивность веб страницам и улучшить процесс взаимодействия с пользователем, кто бы мог подумать, что он достигнет столь небывалых высот. Ведь сейчас на нем можно делать практически все что угодно. Хотите написать сайт: и бэкэнд и фронтэнд на JavaScript? пожалуйста! Хотите написать мобильное приложение на JavaScript? нет проблем. Программируете микроконтроллер – и тут вам на помощь придет JavaScript.

Есть конечно небольшие минусы в подходе использования JavaScript везде, но если поразмыслить, то сколько времени и сил можно сэкономить, изучив всего лишь одни язык, особенно, если то же самое приложение должно работать на разных платформах. Разных платформах говорите? Хм… Точно – разных платформах – теперь JS может позволить себе десктопные приложения для Windows, Linux, Mac, как спросите вы? Ответ прост: встречайте – NW.js.

По первым буквам можно прочитать – Node.js + Webkit, если данные понятия вам пока не знакомы, то скоро вы поймете о чем идет речь.

Node.js – программная платформа, основанная на движке V8, который транслирует наш скрипт в машинный код. Данная платформа была создана в 2009 году преимущественно для работы с бэкэндом сайтов.

WebKit — свободный движок, разработанный компанией Apple. Впервые был анонсирован в составе Safari в 2003 году
Итак, коду, написанному на JS для данной технологии, будут доступны как Node.js модули, так и стандартный браузерный API (соответственно WebKit)

Быстрый старт


Все это конечно хорошо, но с чего же начать? На github можно найти и скачать репозиторий с исходным кодом. Так же здесь можно найти прямые ссылки для скачивания под ту платформу, на которой будет вестись разработка. Помимо прочего нам понадобится установленная node.js.

После того, как необходимое ПО скачано и установлено, вы написали свое приложение на любимом JS (как это сделать читайте далее) и локализовали все в одну папку. Полдела сделано, теперь остается самое сложное и долгое – упаковать все в один файл и подготовить для распространения. Для упрощения вы можете воспользоваться готовыми библиотеками, например nw-builder. Установка библиотеки не составит труда, если вы уже работали с node.js. Как известно, в состав node.js входит менеджер пакетов npm, с которым нужно работать из командной строки. Для того, чтобы поставить какую-либо библиотеку, необходимо выполнить команду:

> npm install  [имя_библиотеки] [опции]

Обратите внимание, что библиотеку можно ставить, как локально, так и глобально, для локальной установки используйте опцию --save-dev, для глобальной -g. Таким образом поставим наш сборщик для NW.js глобально, выполнив команду:

> npm install nw-builder -g

Для того, чтобы собрать наше приложение, необходимо выполнить команду (с большим количеством опций можно ознакомиться в документации):

> nwbuild -p [имя_платформы] -o [путь_к_папке_для_собранной_версии] [путь_до_приложения]

В качестве имени платформы могут быть следующие значения: win32, win64, osx32, osx64, linux32, linux64.

Во время разработки нет нужды каждый раз собирать приложение, можно просто запустить его как есть и оно откроется в отдельном окне. Для этого нужно запустить приложение nw.exe из командной строки и передать в качестве параметров путь к папке с вашим приложением. Кроме того, если вы работаете под Windows, можно просто методом drag-n-drop перетащить папку с исходным кодом приложения на JS (обратите внимание, что именно папку целиком) в nw.exe.

Hello, world!


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

Для данного приложения, нам даже не понадобится JavaScript, только HTML. Создадим папку с названием HelloWorld. Поместим внутрь файл index.html со следующей разметкой:

<html>
  <head>
    <title> Hello, world </title>
  </head>
  <body>
    <div>
      Hello, world, from NW.js
    </div>
  </body>
</html>

Кроме того для каждого приложения под NW.js необходим файл, который обязательно должен называться package.json. Из него будет браться информация для построения приложения. Создадим простейший вариант файла и поместим в папку HelloWorld. Итак:

{
  	"name": "hello-world",
  	"version": "1.0.0",
  	"description": "First application",
  	"main": "index.html",
 	 "author": "Developer",
  	"window": {
   		 "toolbar": false,
    		"width": 500,
   		 "height": 200
 	 }
}

Содержимое файла понятно без пояснений (обратите внимание, что обязательные поля только main и name). В main необходимо записать файл с разметкой, который будет являться точкой входа в приложение. Секция window настраивает параметры окна (в данном случае мы отключаем панель инструментов и задаем размеры окна 500x200).

Кроме того, можно настроить такие поля как (за полным списком опций обращайтесь в документацию):

  • icon – указываем путь до иконки (переопределить стандартную)
  • position – можно указать позицию окна при загрузке (null, center или mouse)
  • min_width, min_height, max_width, max_height – ограничение размеров окна
  • resizable – логическое значение, которое показывает можно ли пользователю изменять размеры окна
  • fullscreen – включить полноэкранный режим
  • kiosk – включить режим киоска
  • transparent – сделать окно прозрачным

Приложение создано и можно его запустить. После запуска (о том как это сделать, смотри раздел выше) вы должны получить следующее окно:



Приложение написано, но в нем всего один div элемент и совсем нет логики, а что делать, если у нас богатая на элементы разметка и сложная логика? На помощь к нам приходит элемент конфигурационного файла toolbar, который мы установили в false. Для того, чтобы сделать доступными средства отладки, необходимо установить toolbar в true. Проделав это при запуске приложения мы получим следующее окно:



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



Работа с нативными контролами


NW.js позволяет работать с нативными контролами. Рассмотрим работу на примере меню. Для работы с нативным UI контролами в nw.js необходимо использовать модуль nw.gui, который можно подключить следующим образом:

var gui = require('nw.gui');

Общий шаблон для использования контролов:

var element = new gui.ElementName(option);

Таким образом для создания элементов меню можно воспользоваться следующей конструкцией:

var menu = new gui.Menu();

Кроме того любые свойства созданного нами объекта можно легко изменить стандартными конструкциями JS, например так:

menu.title = 'New Title';

Меню создано, теперь нужно его заполнить, для манипуляции дочерними элементами существуют методы:

menu.append(new gui.MenuItem({label: 'Label of menu item'}));
menu.removeAt(0);

Кроме того для более гибкого добавления элементов в menu можно воспользоваться методом insert, в параметрах которого необходимо передать MenuItem и номер позиции, куда его вставить (позиция перед первым элементом соответствует 0).

Для доступа к созданным элементам можно использовать свойство items:

menu.items[0].title = "New title"

Обратите внимание, что нельзя напрямую создавать элементы:

menu.items[2] = new gui.MenuItem(); // НЕПРАВИЛЬНО

Самое главное при работе с нативными контролами, это помнить, что любая ошибка при работе с ними может привести к краху всего приложения, поэтому необходимо быть крайне внимательными и по возможности при удалении элементов, также присваивать переменной значение null. Таким образом для удаления контрола, можно выполнить следующее:

control.remove();
control = null;

Для более удобной работы с контролами, они унаследованы от EventEmitter, поэтому хорошая новость в том, что мы можем легко работать с событиями, например так:

menuitem.on('click', function() {
   // сделать что-нибудь полезное
});

Меню было создано, но если запустить приложение, то никакого меню вы не увидите. Для отображения меню существует метод popup, в параметрах которого необходимо передать координаты для отображения меню.

Для демонстрации основных возможностей меню добавьте следующий скрипт к созданному ранее проекту Hello, world:

var gui = require('nw.gui');
var menu1 = new gui.Menu();
menu1.append(new gui.MenuItem({label: 'Item 1'}));
	
var subMenu1 = new gui.Menu();
subMenu1.append(new gui.MenuItem({label: 'Item 2'}));
menu1.append(new gui.MenuItem({
	label: "Submenu",
	submenu: subMenu1
}));
	
document.body.addEventListener('contextmenu', function(ev) { 
	 ev.preventDefault();
	 menu1.popup(ev.x, ev.y);
	 return false;
});

После запуска приложения, мы можем увидеть созданное контекстное меню для body. Таким образом, мы можем определить контекстное меню для любого элемента.



Итак, теперь кроссплатформенные приложения может создавать каждый, но за все нужно платить. В данном случае мы жертвуем как скоростью, так и занимаемым объемом памяти (собранное приложение получается достаточно большим, более 50 Мб). Список приложений, созданных, используя данную технологию можно найти на github.

Во второй части статьи мы рассмотрим технологию более подробно.

Комментарии (22)


  1. koltykov
    04.12.2015 10:36
    +2

    OFFTOP: Хорошо бы под Cut разместить


  1. IncorrecTSW
    04.12.2015 11:18
    +4

    Недавно вместо NW.js попробовал Electron. Субъективно Electron получше будет, правда весит метров на ~20 больше.

    Technical Differences Between Electron and NW.js


    1. dannyzubarev
      04.12.2015 17:53
      +1

      Поддержу. Мне больше импонирует идея main process, который управляет renderer'ами. В то время как входной точкой в NW.js является HTML, где обычно с контекстами выполнения кода такая невообразимая каша получается. Да и документация у Electron гораздо лучше.


      1. Zenitchik
        04.12.2015 20:26

        Ну, HTML — это не смертельно. Пишем простую страничку без ничего, подтягиваем к ней скрипт — типа как для толстого клиента, и радуемся жизни.


  1. Akuma
    04.12.2015 11:22

    А какие-то способы ужать результирующий exe имеется? Я конечно понимаю почему так много получается, но все же.


    1. IncorrecTSW
      04.12.2015 11:26

      Помнится ASPack'ом неплохо урезал вес.


  1. faiwer
    04.12.2015 12:38

    Интересно, а есть ли инструменты, позволяющие вменяемо писать на javascript, но без HTML и, соответственно, webkit-а? Например с привязкой к QT, gtk и другим системам? Просто мне кажется тащить за собой такую мощь в большинстве случаев избыточно.


    1. x512
      04.12.2015 12:41
      +5

      Есть. QML в Qt



    1. Simplevolk
      04.12.2015 13:11
      -4

      А можно ли писать десктопные приложения на TypeScript? По мне, так он более удобен (особенно если на Java,C# пишешь).


      1. arusakov
        04.12.2015 14:48
        +2

        Он транслируется в JavaScript, так что если подо что-то можно писать на JavaScript, то на TypeScript можно автоматически.


      1. sev89
        04.12.2015 15:38

        одна из двух составляющих NW.js — Node.js, поэтому можно использовать модули Node.js, например TypeScript npm module


  1. poxu
    04.12.2015 16:56
    +10

    Был у меня друг один. Всё на JavaScript писал. И клиента и бэкенд и десктоп даже. И базы данных на джаваскрипте делал и игрушки клепал. Говорил удобно, быстро, клёво. Всё работает, всё устраивает.
    Ну, потом его в дурку сдали конечно…


    1. Alex_At_Net
      04.12.2015 18:55
      -2

      И неправильно и [?|||||?] (боян)


      1. poxu
        05.12.2015 02:17

        Боян. Но очень смешной и очень в тему :). Ну и анекдот он и есть анекдот. Или вы имели в виду, что я неправильно его рассказал?


  1. jhekasoft
    04.12.2015 18:53
    +1

    Я вот сделал приложение для запуска игр на nw.js: https://github.com/jhekasoft/insteadman. Меньше 50МБ получилось.


  1. rogrom
    04.12.2015 21:01
    +4

    Ожидал увидеть нечто большее, чем перевод Readme c гитхаба: работа с сетью, ассеты, связка с архитектурными js фреймворками, кастомизация контролов, собственные контролы под все платформы, нотификейшены, какие ограничения, что с тестируемостью, проблемы с платформозависимыми вещами, какая производительность, отладка нативного когда, способы уменьшения бинарников… Как вариант, портировать боевое веб приложение, обернув в nw.js


    1. sev89
      05.12.2015 01:16
      -1

      Я и не отрицаю, что пользовался документацией при написании статьи, а кто не пользуется? не пользуются разве что фантасты, которые придумывают на ходу. А данная статья и не претендует на всеобъемлющее руководство по nw.js.пожалуйста, прочитай название, это только первая часть, вводная, вступительная, целью которой было показать, что есть такая технология и как ей начать пользоваться. А если прочитав статью, ты считаешь, что потратил время зря, значит она написана не для тебя


  1. goss
    04.12.2015 22:53
    +1

    Спасибо, я давно ждал такой пост!
    Что у нас с OS X в связи с этим?


  1. rdc
    05.12.2015 03:55
    -4

    дурацкий вопрос.
    а зачем вообще привязывать к какой-то конкретной системе изначально независимую от платформы технологию?
    т.е. почему не писать на js в обычном html файле? который откроется локально где угодно любым браузером


    1. some_x
      05.12.2015 07:55
      +1

      Потому что это
      1) Не удобно для пользователя
      2) Если пишешь для конкретного движка, то ориентируешься только на то что поддерживает этот движок (в данном случае всё весьма свежее). В разы сокращаются затраты на тестирование.
      3) Протокол file:// имеет много ограничений.


    1. Zenitchik
      05.12.2015 14:13
      +1

      В первую очередь из-за ограничений протокола file:///