Кстати, вы заметили как Chromium похоже на Canonium? — Раньше я даже и не думал об этом.

Если вы читаете любую статью из этой серии, то подразумевается, что вы хоть как-то знакомы с Node.js и в состоянии прочесть документацию по нему.

У меня уже руки чешутся начать! А у вас?

План

Как по мне, то материал проще усваивать небольшими порциями. Поэтому мне нужно указать некое содержание:

Самое необходимое

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

Node.js

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

Node или Node.js — программная платформа, основанная на движке V8 (транслирующем JavaScript в машинный код), превращающая JavaScript из узкоспециализированного языка в язык общего назначения. Node.js добавляет возможность JavaScript взаимодействовать с устройствами ввода-вывода через свой API (написанный на C++), подключать другие внешние библиотеки, написанные на разных языках, обеспечивая вызовы к ним из JavaScript-кода.

Chromium

Chromium — это веб-браузер с открытым исходным кодом, на котором строится всем известный Google Chrome. Каждый день браузер обновляется, и в нём происходят какие-то перемены: от исправления багов до внедрения нового функционала. Собственно говоря, большинство (если не все) фишек из Chromium рано или поздно переползают в Chrome.

node-webkit

node-webkit — это среда выполнения приложения, которая сочетает в себе Chromium и Node.js, позволяющая создавать кроссплатформенные приложения с интерфейсом. Иначе говоря, node-webkit позволяет создавать такие же веб-приложения, которые уже сейчас есть в браузере (StackEdit, например) в некий оффлайн. Разумеется, если функционал веб-приложения это позволяет, и в этом есть хоть какой-то практический смысл. При этом разрабатывается приложение на горячо нами любимом Javascript с применением API node.js, который даёт доступ к системе пользователя, позволяя уйти за рамки обычных возможностей браузера.

Grunt.js

Grunt — это инструмент для сборки проектов из командной строки с использованием задач. В рамках этой статьи он нужен для построения нашего приложения под три популярные операционные системы.

Подготовка

Перед тем как начать что-то писать, нужно позаботиться об удобстве. Для этого нам и понадобится Grunt.

Внимание

Если по религиозным или иным соображениям вы не можете пользоваться Grunt, то посмотрите в сторону Gulp или главу «Альтернативный способ сборки» в конце этой статьи.

Благодаря Grunt или Gulp (суть не в этом) мы можем автоматизировать сборку нашего приложения, которая будет выполняться тогда, когда мы изменили какой-либо его ресурс.

Просто создаём файл package.json и пишем в него:

{
  "name": "grunt-node-webkit-app",
  "devDependencies": {
    "grunt": "latest",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-node-webkit-builder": "latest"
  }
}

И файл Gruntfile.js:

module.exports = function(grunt) {

grunt.initConfig({
    watch: {
      node: {
        files: ['app/**/*'],
        tasks: ['nodewebkit'],
        options: {
          spawn: false,
        }
      }
    },
    nodewebkit: {
      options: {
        platforms: ['win', 'osx', 'linux32', 'linux64'], // Платформы, под которые будет строиться наше приложение
        buildDir: './build', // Путь, по которому будет располагаться построенное приложение
      },
      src: './app/**/*' // Путь, по которому располагаются исходные коды приложения
    },
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-node-webkit-builder');
  grunt.registerTask('default', ['watch']);
};

Если это ваша первая встреча с Grunt, то вам понадобится Grunt CLI, который можно установить, написав в консоли:

npm i -g grunt-cli

После этого переходите в папку с проектом и выполняете команду:

npm i

Запускать сейчас ничего не нужно. На этом подготовительный этап завершён.

Если вы хотите подробнее узнать о Grunt, то обратите свой взор на видео от Sorax.

Обновление (17.01.2015)

Существует способ запускать приложения из командной строки, при этом обновлять их содержимое, при необходимости, используя тулбар.

Установим глобально nodewebkit:

npm i -g nodewebkit

Перейдём в директорию с приложением и запустим его (Не забываем точку):

nodewebkit .

После изменения ресурсов приложения воспользуйтесь кнопкой обновления (самая правая в тулбаре). Только не забудьте включить тулбар в package.json.

Архитектура приложения

Отныне и до конца, нашим местом дислокации будет папка app. Поэтому переходим в неё и приступаем к проектированию архитектуры.

Для начала всё просто:

project/ └──app/ ├── fonts/ │ ├── images/ │ ├── scripts/ │ └── vendor/ │ ├── styles/ │ └── vendor/ │ └── views/ └── app.html

Манифест приложения

Первым делом нам снова придётся создать файл app/package.json, в котором будет описано наше приложение. Однако, на этот раз не всё так просто. Нужно разбираться.

Обязательные поля

Каждый манифест (package.json) приложения обязан предоставить следующие поля:

  • name (string) — Уникальное имя приложения, предоставленное в виде name-of-application. Может включать в себя следующие символы: ._-.
  • main (string) — Страница, которая будет открыта при запуске приложения.

Дополнительные поля

Я не буду перечислять все дополнительные поля, так как количество их довольно велико, поэтому пройдёмся по самым базовым:

  • version — Версия приложения по методике семантического версионирования.
  • chromium-args (string) — Включение или отключение возможностей браузера Chromium, используя аргументы командной строки. Список аргументов командной строки доступен по этому адресу.
  • window — Самое полезное для нас поле, которое содержит подполя:
  • title (string) — Заголовок главного окна.
  • width/height (int) — Начальная ширина/высота главного окна.
  • toolbar (boolean) — Отображение панели навигации.
  • icon (string) — Путь до иконки (значка) приложения.
  • position (string) — Позиция окна при запуске приложения: null или center или mouse.
  • min_width/min_height (int) — Минимальная ширина/высота окна.
  • max_width/max_height (int) — Максимальная ширина/высота окна.
  • resizable (boolean) — Разрешение изменения размера окна.
  • always-on-top (boolean) — Отображать окно приложения поверх остальных окон.
  • fullscreen (boolean) — Разрешение полноэкранного режима.
  • show_in_taskbar (boolean) — Отображение на панели задач или в доке. Значение по умолчанию - true.
  • frame (boolean) — Отображение рамок приложения. Установив значение false, вы получаете пустое окно с белым фоном.
  • show (boolean) — Отображение окна приложения при запуске.

Исходя из требований и дизайна будущего приложения, можно достаточно гибко сконфигурировать его на начальном этапе.

Полный список полей манифеста можно посмотреть на этой странице. К слову, на Wiki страницах самого проекта node-webkit, находится много полезной информации.

В нашем случае, package.json будет содержать в себе следующие поля:

{
  "name": "node-webkit-nodepad",
  "main": "views/app.html",
  "version": "0.1.0",
  "window": {
    "title": "NodePad",
    "toolbar": false,
    "frame": false,
    "width": 800,
    "height": 500,
    "min_width": 400,
    "min_height": 200,
    "position": "center"
  }
}

Ах, да, совсем забыл сказать, что мы будем делать простейший блокнот с автоматическим сохранением в Local Storage и возможностью ввода и вывода текста в формате markdown.

Зависимости

Дальнейшие махинации будут проходить с npm (пакетный менеджер node.js). Если вы не знакомы с этим понятием, то вам следует срочно ознакомиться с ним, перейдя по этой ссылке и посмотреть видео, автором которого является Илья Кантор.

Итак, у нас есть идея создания простейшего блокнота с применением техники markdown. Будем сами писать парсер синтаксиса? — Разумеется, нет. Это долго и не нужно, так как велосипед нам уже изобрели и оформили в виде пакета npm.

Переходим на сайт пакетного менеджера npm и отправляемся в поиски необходимого нам пакета.

Открываем консоль и в папке app/ прописываем команду:

npm i markdown --save

Произойдёт загрузка пакета и, благодаря флагу --save, добавление зависимости к нашему приложению в манифесте:

{
  ...
  "dependencies": {
    "markdown": "^0.5.0"
  }
}

По идее, нам этого хватит.

Первый билд приложения

Вот и подошли мы к тому, что создаём файл app/views/app.html:

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My first node-webkit application</title>
  </head>
  <body>
    Content
  </body>
</html>

Очень странное приложение, не правда ли? Я тоже вначале ожидал кучу кода и непонятные мне конструкции, но всё оказалось банальным.

А давайте соберём наш первый билд?

Переходим в консоли к папке project и запускаем grunt командой:

grunt nodewebkit

Начнётся загрузка пакетов для выбранных вами операционных систем:

Внимание

Пакеты загружаются один раз, поэтому не стоит паниковать заранее. Однако, если это не финальная (релизная) сборка приложения, то советую указывать ту операционную систему, под которую вы будете разрабатывать приложение, так как скорость отдачи пакетов может огорчить любого.

Обращу ваше внимание ещё раз на то, что сборку приложения можно автоматизировать, прописав в консоли grunt и изменив какой-либо его ресурс.

После загрузки пакетов самого node-webkit сразу же стартует сборка нашего проекта:

Ура! Скорее к приложению!

Переходим в папку project/build/node-webkit-nodepad/, выбираем свою платформу и запускаем приложение. Работает!

Альтернативный способ сборки

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

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

Что-то я устал от Windows, поэтому на этот раз будем использовать OS X Yosemite.

Внимание!

Не стоит паниковать! Команды для сборки будут приведены ниже для Windows и Linux.

Итак, будем считать, что у нас есть директория, в которой находится node-webkit.app и наше приложение.

Шаг 1

Необходимо создать nw пакет. По сути, это обычный zip архив. Поэтому запускаем терминал, переходим в папку с приложением и пишем команду:

zip -r ../${PWD##*/}.nw *

В ответ система создаст nw файл:

На Linux всё аналогично. А вот для тех, кто использует Windows у меня плохие новости: архив придётся создавать самому и после сменить .zip на .nw.

Шаг 2

На втором шаге нужно переименовать получившийся файл в app.nw, но так как у нас он уже имеет такое имя, то идём дальше.

Шаг 3

Переходим к файлу node-webkit.app и просим OS X показать нам содержимое пакета.

Переходим в директорию Contents/Resources/ и переносим туда пакет нашего приложения (app.nw). Получится примерно так:

В Linux слегка иначе:

cat /usr/bin/nw app.nw > app && chmod +x app

В Windows тоже всё просто:

copy /b nw.exe+app.nw app.exe

Мы вышли на финишную прямую!

Внимание!

Для работы приложения в Windows и Linux необходимо скопировать следующие файлы из папки node-webkit в папку собранного приложения: nw.pak и icudtl.dat.

Шаг 4

Запускаем наше приложение и радуемся появлению пустого окна :)

Вывод

Я очень рад, что рассказал про этот способ, так как он даёт базовое понятие того, как собирается ваше приложение. И всё же, будет лучше, если вы не будете использовать этот вариант сборки. Просто забудьте об его существовании.

Если захотите подробнее узнать про описанный здесь метод, то посетите посвящённую этому страницу Wiki. Там же можно ознакомиться с приложениями, которые упрощают сборку до нажатия на одну кнопку «Build».

Интерфейс NodePad

Совсем кратко поговорим о вёрстке нашего приложения, так как верстать, я думаю, умеет каждый.

Интерфейс нашего приложения будет похож на StackEdit, то есть у нас будет одно текстовое поле для ввода данных (разметки Markdown) и справа от него область, в которой мы будем сразу видеть представление этих данных и их изменение в режиме реального времени.

Если вы помните, то node-webkit включает в себя браузер Chromium, а это означает, что:

  • Можно использовать все новейшие технологии без опасения, что в каком-нибудь браузере что-то пойдёт не так.
  • Не нужно заботиться о кроссбраузерности.
  • Вам не нужны браузерные префиксы, если только Chromium не требует их для конкретного свойства.
  • Можно не заботиться о количестве запросов на ресурсы, так как выход в интернет нашему приложению не требуется.

Замечательно! Пришло время использовать Flexbox и SVG!

И снова не могу промолчать и утаить от вас ужасную, для многих, истину — всё таки оптимизировать ресурсы придётся. Нет, это не из-за того, что скорость работы node-webkit плохая или ещё чего-то в этом духе. Причина довольно банальная — конечный размер приложения.

Вы уже видели сколько места занимает наше пустое приложение на диске? — В Windows 43 Мб, а это не хухры-мухры. И это без учёта необходимых для его работы библиотек (icudtl.dat10.5 Мб и nw.pak5.7Мб). А теперь прибавьте к этой цифре вес JavaScript библиотек, шрифтов, изображений и остальных ресурсов приложения. Мы уже к сотне подходим. Конечно, если вы будете делать установщик, то размер уменьшится, но до тех пор, пока пользователь не установит приложение. Мне бы не хотелось, чтобы простой блокнот весил под 100 Мб.

Подробнее про размер приложения, его оптимизацию и сжатие мы поговорим в третьей части нашей небольшой серии статей.

Замечание

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

Вы уже успели расстроиться? — Да, без вёрстки скучновато жить. Однако, не забывайте, что цель статьи не показать как работает Flexbox и как сверстать пару кнопок, а ознакомиться с node-webkit на реальном примере.

Вывод к первой части

В этой статье мы познакомились с удивительным внешним видом мира node-webkit. Разобрались, как собирать наше приложение, запускать его и проектировать архитектуру на начальном этапе.

В следующей части статьи мы подробнее поговорим про внутреннее устройство нашего приложения и организации его логики. На повестке дня будет:

  • Взаимодействие пользователя с интерфейсом.
  • Работа с файлами.
  • Работа с данными.
  • Прочие мелочи.

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

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

Домашнее задание

Иии...

Не стоит переживать, это не неожиданный финал статьи, а всего лишь её первая часть. Вторую и третью часть вы сможете найти на страницах блога уже в ближайшее время. Тем временем постарайтесь сохранить в себе желание попробовать в действии node-webkit.