Создаём своё первое десктопное приложение при помощи HTML, JS и Node-WebKit

Original author: Danny Markov
  • Translation
В наше время при помощи JavaScript и HTML можно сделать практически всё. А благодаря Node-WebKit (недавно переименован в NW.js) можно делать даже десктопные приложения, которые выглядят, как нативные и имеют доступ ко всем частям ОС. Сегодня мы покажем, как создать простое десктопное приложение при помощи Node-WebKit, используя jQuery и несколько модулей для Node.js.

Node-WebKit — комбинация Node.js и встроенного браузера WebKit. Код JavaScript выполняется в особом окружении, из которого есть доступ и к стандартному API браузеров, и к Node.js.

Устанавливаем Node-WebKit


Для разработки нужно скачать исполняемый файл node-webkit и вызывать его из командной строки. Позже всё вместе упакуется в одну программу, которая будет запускаться пользователем.

Скачайте файлы, подходящие для вашей системы, и распакуйте их в подходящее место. Запускать их нужно так:

# если у вас linux/osx

/path/to/node-webkit/nw /your/project/folder

# если у вас windows

C:\path\to\node-webkit\nw.exe C:\your\project\folder

# (пути указаны только для примера)


Откроется новое окно node-webkit, в которое будет выведено множество отладочных сообщений.

Первое приложение



Мы подготовили для вас тестовое приложение для примера. Оно скачивает последние статьи с Tutorialzine и делает из них карусельку при помощи jQuery Flipster.

image
структура каталогов

В архиве содержатся вышеуказанные файлы. Выглядят они как статический сайт, но работать в браузере при запуске index.html не будут – им нужны модули Node.js. Для запуска воспользуйтесь командой

/path/to/node-webkit/nw .


Она и запустит наше превосходное приложение.

image

Как это сделано


Всё начинается с файла package.json, который node-webkit ищет при запуске. Там описано, что нужно загружать и даны разные настройки окна.

package.json

{
  "name": "nw-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.html",
  "scripts": {
    "test": "echo \"Ошибка: тест не задан\" && exit 1"
  },
  "author": "",
  "window": {
    "toolbar": false,
    "width": 800,
    "height": 500
  },
  "license": "ISC",
  "dependencies": {
    "pretty-bytes": "^1.0.2"
  }
}


В свойстве window описана необходимость открыть окно размера 800 х 500 пикселей и спрятать у него тулбар. В него загрузится файл из свойства main. У нас это

index.html

<!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Tutorialzine Node-Webkit Experiment</title>

    <link rel="stylesheet" href="./css/jquery.flipster.min.css">
    <link rel="stylesheet" href="./css/styles.css">

</head>
<body>

    <div class="flipster">
        <ul>
            <!-- Tutorialzine's latest articles will show here -->
        </ul>
    </div>

    <p class="stats"></p>

    <script src="./js/jquery.min.js"></script>
    <script src="./js/jquery.flipster.min.js"></script>
    <script src="./js/script.js"></script>
</body>
</html>


И наконец, наш файлик с JavaScript. Вот где самое интересное.

// Смешать в одном файле код jQuery и Node.js? Да не вопрос!

$(function(){

    // Показать данные о компьютере, используя модуль os 

    var os = require('os');
    var prettyBytes = require('pretty-bytes');

    $('.stats').append('Number of cpu cores: <span>' + os.cpus().length + '</span>');
    $('.stats').append('Free memory: <span>' + prettyBytes(os.freemem())+ '</span>');

    // Нативная библиотека Node webkit для UI. Понадобится попозже
    var gui = require('nw.gui');

    // Загрузить последние посты с Tutorialzine

    var ul = $('.flipster ul');

    // Ограничений на запрос данных с других доменов нет, поэтому
    // мы можем отправить ajax-запрос на другой сайт.

    $.get('http://feeds.feedburner.com/Tutorialzine', function(response){

        var rss = $(response);

        // Найдём статьи в RSS фиде

        rss.find('item').each(function(){
            var item = $(this);
            
            var content = item.find('encoded').html().split('</a></div>')[0]+'</a></div>';
            var urlRegex = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g;

            // Загрузим первую картинку из статьи
            var imageSource = content.match(urlRegex)[1];

            // Создадим li для каждой статьи и добавим в ненумерованный список

            var li = $('<li><img /><a target="_blank"></a></li>');

            li.find('a')
                .attr('href', item.find('link').text())
                .text(item.find("title").text());

            li.find('img').attr('src', imageSource);

            li.appendTo(ul);

        });

        // Инициализируем плагин flipster 

        $('.flipster').flipster({
            style: 'carousel'
        });

        // По клику на карусельке откроем страницу в дефолтном браузере.
        // Иначе она открылась бы в нашем окне, а нам это не надо.

        $('.flipster').on('click', 'a', function (e) {

            e.preventDefault();
            
            // откроем URL в дефолтном браузере
            gui.Shell.openExternal(e.target.href);

        });

    });

});


В браузере нельзя получить доступ к информации на другом домене через jQuery. Но node-webkit убирает эти ограничения.

Использованные модули:

  • Shell – модуль node webkit для работы с десктопом
  • OS – встроенный в Node.js модуль. Умеет возвращать объём свободной системной памяти
  • Pretty Bytes – преобразует байты в человеко-читаемые строки 1337 → 1.34 kB.


Также есть jQuery и плагин jQuery-flipster. И всё!

Пакуем и распространяем


Конечно, для удобства пользователя нужно запаковать всё это в отдельную программу, которую можно будет запускать простым двойным кликом.

Вручную это довольно муторно делать, особенно если вы хотите подготовить приложение для разных платформ. Но есть для этого и автоматические библиотеки.

Есть и минус – исполняемые файлы получаются уж очень большими (бывает, что и 40-50 Мб), поскольку в них упихивается и браузер webkit и node.js, и ваш код. Возможно, для создания простых небольших десктопных приложений это не идеальный вариант.

Заключение


Node-webkit – мощная штучка, открывающая новые возможности для веб-разработчиков. С её помощью можно создавать вспомогательные приложения для ваших веб-сервисов и делать десктопные клиенты, у которых будет полный доступ к компьютеру пользователя. Подробнее о node-webkit читайте в их wiki.
Support the author
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 39

    +15
    А можно еще брать dosbox, старый QBasic и текст проги в bas-файле, запихивать все это дело в самораспаковывающийся архив со скриптом, запускающим досбокс, запускающим qbasic, открывающим bas файл и исполняющим как интерпретатор эту прогу. Выполнение проги в интерпретаторе, запущенном в эмуляторе — это нормально, ибо как сказали, кажется, в майкрософте — если у вас не пашут, лагают и тормозят наши неоптимизированные проги, то просто выкиньте свой комп и купите более мощный. Аминь =)
      –12
      Node-webkit – мощная штучка, открывающая новые возможности для веб-разработчиков.

      Ну да, как С++/Java/PHP программисты тащат в JS свои классы, так и JS программисты пытаются делать всё старым проверенным способом. Но если в первом случае страдает производительность, то во втором — пользователь.
        +14
        Расскажите мне, как я страдаю, пользуясь Popcorn Time.
          0
          А он на Node-Webkit написан?
          +1
          Большое спасибо за ссылку, крутое приложение
        –8
        На мой взгляд, для desktop приложений, все же, лучше использовать NET или Java, чем такие инструменты. Мне они напоминают php-gtk
          +11
          Это не так, ведь PHP не создавался для UI, в отличии от HTML, CSS, JS. Собственно, десктопные приложения на этом стеке технологий пишутся уже давным-давно, в том или ином виде контейнеров (Adobe Air, .NET + WebBrowser, Java + WebView, в итоге Apache Cordova). Знаю очень много корпоративного софта, написанного подобным образом еще с 2002 года.
            –4
            Если говорить именно о HTML и CSS, то я обоими руками «за» использование данных технологий для оформления — они для этого и создавались, и выполняют свою функцию прекрасно. Но использование JS для кода самого приложения, на мой взгляд жирно.
            Если сможете продемонстрировать, что JS быстрее и ест меньше памяти чем С# или Java для решения одной и той же задачи, я сильно изменю свой взгляд на JS.
              +2
              Если сможете продемонстрировать, что JS быстрее и ест меньше памяти чем С# или Java для решения одной и той же задачи, я сильно изменю свой взгляд на JS.

              Это не аргумент, CLR и JVM тоже медленные)
                +3
                habrahabr.ru/post/123154/
                Попробуйте повторить на C# или Java на том же железе — это сильно пошатнет вашу веру в них.
                  –3
                  Я не бенчмарчил, но в чем проблема-то? Берешь и пишешь асинхронный код в c# и получишь как минимум те же самые лям соединений. Или есть какая-то проблема, о которой я не знаю?
                    +2
                    Не получишь. Памяти сожрется больше + тупо форкать потоки на клиентов даже с пулом — заткнется достаточно быстро с быстрым повышением времени отклика.
                      –2
                      Хм, для меня ваши заявления выглядят странно. К сожалению, повторить опыт пока что не удастся, да и лениво. Но…
                      Памяти сожрется больше

                      Ты хочешь сказать, что компилируемый (с легкой смещенностью в сторону интерпретируемого, но можно добиться native-компиляции) язык со статической типизацией будет жрать больше, чем интерпретируемый (с легкой смещенностью в сторону компилируемого благодаря v8)… Почему ты думаешь, что в C# памяти будет жраться больше?

                      тупо форкать потоки на клиентов даже с пулом — заткнется достаточно быстро с быстрым повышением времени отклика.

                      Объясни, пожалуйста. Есть асинхронные неблокирующие операции, есть тред-пул. В node.js все точно так же. В чем разница?
                        +2
                        Почему ты думаешь, что в C# памяти будет жраться больше?

                        Ну попробуй, увидишь. Хотя бы 100к коннектов сделай — приложение уже будет не совсем адекватно отвечать вместе с хостом. Довольно странно, но V8 + IO обвязка жрут меньше ресурсов на обработку, как памяти, так и cpu.
                        Есть асинхронные неблокирующие операции, есть тред-пул

                        Асинхронность делается фактически через тот же пул потоков. Нода — однопоточная, как бы это странно ни звучало. Весь код — это фактически реакция на события, вызываемые нейтивной частью. Как конкретно реализовано, к сожалению, сказать не могу, давно бросил native и пристрастился к managed, обратно возвращаться как-то не хочется. :)
                          –2
                          Ну попробуй, увидишь

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

                          Асинхронность делается фактически через тот же пул потоков.

                          В указанной статье сказано, что есть распределение на ядра. Так что не надо тут про однопоточность. И я гарантирую, что в C# можно на одном потоке держать больше одного соединения благодаря тем же асинхронным операциям.

                          Весь код — это фактически реакция на события, вызываемые нейтивной частью.

                          А вот теперь уже верю. Если часть кода написана на си/плюсах, то естественно эта часть будет быстрее C#-кода (хотя у C# часть вещей тоже реализована нативно). И естественно, что на примитивных случаях (типа того, которое описано в статье) большая часть работы будет отводиться на нейтив код.
                          А если добавим больше логики и операций, то гораздо больше времени будет занимать managed код и тут уже выигрыш будет у C#.
                            0
                            моей машине 4 гб памяти и большая часть занята. Плюс я на Windows. И делать 100к коннектов несколько напряжно.

                            Нода есть под все основные платформы, включая Windows. Если не хватает ресурсов, то можно организовать тест на меньших циферках, сколько допустимо. Нода выиграет везде, где нужно много операций ввода-вывода — оно заточено именно под этот сценарий работы, а не под сложные и длительные операции обработки (которые можно распилить на стадии и колбеки или вообще вынести в нейтив, что не совсем честно, раз разговор про managed).
                            Так что не надо тут про однопоточность.

                            Ну гугль в руки, раз нет доверия. Нода однопоточная. То, что в коде примера спаунятся новые инстансы такой же ноды и первый инстанс балансит нагрузку по ним — почему нет, тем более что почти ничего для этого писать не нужно.
                            И я гарантирую, что в C# можно на одном потоке держать больше одного соединения благодаря тем же асинхронным операциям.

                            Еще раз — асинхронность .net внутри обеспечивается пулом потоков внутри, а не какой-то магией рантайма, позволяющей работать в одном потоке. Можно проверять текущий тред в колбеке — он будет / может быть отличным от основного потока.
                            Если прочитать статью по ссылке, то видно, что нода плохо переваривает хип боьше 500мб — выполнялся запуск с ключиками, настраивающими это поведение. В шарпе такое невозможно в общем случае — сборка мусора не дает гарантированного контроля. Да, можно установить размер хипа и ловить эксепшн + форсировать сборку мусора, но… это не работа для пользовательского кода.
                              +2
                              Извиняюсь что вклиниваюсь в беседу многоуважаемых мужей, но:
                              1. async/await — не жрет потоки из тред пула, а разворачивается в стэйт машину и использует IOCP. Просто у вас есть выбор — использовать асинхронность по необходимости.
                              http://blog.stephencleary.com/2013/11/there-is-no-thread.html

                              2. Проблема Asp.Net была в потреблении памяти — каждый HttpContext — около 30 кб. Эта проблема решена
                              в Asp.Net 5.
                              http://gunnarpeipman.com/2014/07/asp-net-5-new-httpcontext/

                              3. Сборка мусора — отдельная тема. Многопоточный, неблокирующий GC проекрасно справляется ;)

                              В Java не спец, но на C#/.Net сейчас реально написать сервер, который выдержит может и не миллион соедиений(но близко к этому. Надо смотреть финальный код), но уж точно будет в выигрыше, если там появится бизнес логика.

                              Сугубо имхо
                                0
                                Верно, но вот бы все это (>=FW5) завести на любой платформе, а не только Windows :) Mono в этом отношении слабоват в плане совместимости и особенностей реализации.
                                  0
                                  Как-бы довольно скоро будет официальный .net под линукс.
                                    0
                                    К релизу обещались что усе ок будет. CoreClr пилят очень активно под Unix.
                                    5 часов назад https://github.com/dotnet/coreclr/issues/366 например.

                                    На данном витке развития причин недоверять MS нет) Я пробовал запускать тестовые приложения на Ubuntu — работает. Понятно, что еще рано писать тесты, но думаю будет шустро. Да и нодоводам может понравиться, что новый Asp.Net очень похож на Ноду со строгой типизацией;) К релизу готовят еще и родную поддержку PostgreSQL в EF7.

                                    public class Startup
                                        {
                                            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
                                            {
                                                app.UseStaticFiles();
                                            }
                                    }
                                    


                                    var express = require('express');
                                    var app = express();
                                    app.use(express.static(__dirname + '/public'));
                                    app.listen(process.env.PORT || 3000);
                                    


                                    Структура пакетов кстати тоже как у Ноды — каждый пакет имеет свой граф зависимостей.
                                      0
                                      Так ведь только core, а не весь bcl. Ну и когда это будет, а релизить надо как обычно — вчера :) Сейчас используется самописный аналог pomelo (видео-конфа с разработчиком) на сервере, на клиенте mono 2.6.3 (unity). Гоняется реалтайм трафик поверх wss-вебсокетов между узлами кластера и клиентами и фронтенд узлами, тормозов не замечается.
                                    –2
                                    Спасибо за вклинывание в беседу. У вас получилось гораздо лучше.
                              –2
                              в ноде один процесс. нет нитей, тредов, прочих синонимов. никто никуда не форкается, все в одном пространстве, мухи от котлет отделяются под капотом. Как в шарпах — хз, это была росто реплика в ваш диалог.
                                +2
                                *читать комментарии буду я
                  +5
                  Проект недавно переименовался и теперь называется nw.js.
                    0
                    Есть еще минус — весь ваш код открыт.
                      –1
                      так это ок для упаковки сложных веб-проектов — там и так код открыт
                        0
                        Не совсем. Серверный код обычно скрыт.
                          0
                          а при чем тут серверный код то? Максимум — в клиентскую часть впихивают автообновление. Все остальное как было через Ajax/sockets, так и остается. Лишь как бонус можно использовать UDP/TCP обычные сокеты
                            +1
                            А, Вы про веб-морду сайта-сервиса? Зачем это оформлять отдельным приложением? Какие функции ОС нужны для этого?
                              0
                              Скорость, интеграция с десктопом, дополнительный функционал, который нельзя или сложно сделать внутри барузера, невозможность использовать современный браузер у клиента, сеть, работа с файлами прозрачная — много возможностей, но это специфические случаи.
                                +2
                                Получается, что я например таким образом могу создать веб-морду веб-приложения, которое будет у пользователя Windows запускаться как обычное приложение и даже при необходимости взаимодействовать с его программами на компьютере (например, САПР)? Я правильно понимаю? Если нет, подскажите пожалуйста примеры дополнительных возможностей, недоступных в браузере.
                                  +1
                                  На счет взаимодействия с программами — возможно придется писать бинарный модуль (плагин для v8/io.js). в остальном да.
                        +1
                        Помнится в далеком студенчестве делали такие штуки. HTA вроде называлось. Сейчас driverpack solution так же делает если ничего не спутал.
                          –13
                          Пожалуйста ребята не надо, теперь и десктопные приложения будут тормозить. Я конечно понимаю ребята что вы начинали с самого дна верстальщиками и что-то кроме убогого джаваскрипта выучить у вас ума не хватило, но джаваскрипт подходит для разработки десктопных приложений чуть менее, чем никак. Пусть джабоскрипт останется в вебе.
                            +5
                            Пожалуйста, расскажите ещё этих замечательных историй про JavaScript. Только на этот раз бездарям из Epic Games, начинавшим верстальщиками с самого дна. Ведь они, к сожалению, не выучив ничего, кроме убогого и тормозного JavaScript, из-за нехватки ума и чувства вселенской несправедливости теперь транслируют в него игры на Unreal Engine 4.7. [/sarcasm]
                              +6
                              Пыхера ответ.

                            Only users with full accounts can post comments. Log in, please.