Pull to refresh

Модульный файловый менеджер Cloud Commander 2.0

Reading time 8 min
Views 20K
В прошлой статье было рассказано о том, что представляет собой Cloud Commander, об основных причинах появления, недостатках, достоинствах, процессе разработки, а так же философии файлового менеджера. Сегодня мы поговорим о том, что изменилось с того времени, и как эти изменения влияют на дальнейшее развитие приложения. В статье будет рассмотрено множество модулей node.js, о некоторых, возможно, читатель услышит впервые.

Изменения


Изменений много, есть внешние, кидающиеся в глаза, и есть мало заметные. Наконец появилась поддержка дисков в Windows, а также возможность выбирать между редакторами: Dword и Edward. Но это не главное.

Главным изменением можно считать смену курса развития. Раньше Cloud Commander развивался как цельное монолитное приложение, которое не зависело от сторонних модулей, могло их использовать, если они были в наличии, но могло и обходится без них лишаясь части функциональности, но при этом стабильно работая.

Минусов в таком подходе несколько:
  • После того, как часть приложения была улучшена новым функционалом или исправленными багами, она не могла стать доступной до тех пор, пока не обновится все приложение, в котором тем временем появлялась новая порция багов, и так без конца. Поскольку компоненты друг от друга зависят мало, пользователь, ожидая, что в новом релизе починят меню в редакторе мог наткнутся на то, что меню работает отлично, но теперь поломалась консоль. И починят ее только в новой версии, через несколько месяцев, поломав что-то другое.
  • Монолитное приложение сложно документировать не только потому, что оно само на себе завязано, и в нем постоянно что-то меняется, а еще и по той причине, что оно достаточно большое, и описание функционала такого гиганта означает заморозку в развитии, либо поддержку не актуальной документации. В любом случае документирование всего подряд может себя не окупить, и иногда лучше просто рефакторить код, что бы он был понятен сам по себе.
  • В монолитном коде высок порог вхождения, есть большая разница в том, смотреть на функцию в 10 строк или 10 страниц, и дело тут не только в опытности разработчика, в котором возникло желание внести изменения в программу, а еще и в том, что психологически гораздо проще понять, вникнуть и осознать короткий код. Проще найти ошибку: логическую или опечатку. И гораздо проще вносить изменения, не только основным разработчикам, но и новичкам.

В предыдущей статье говорилось о том, что Cloud Commander использует модули. И это правда, с первых дней разработки, приложение писалось таким образом, что бы код мог использоваться повторно. Таким образом функционал, который повторно используется выносился в отдельные функции и файлы. Но он весь реализовывался в рамках одного проекта с использованием присущих лишь ему особенностей. Соответственно код не был переносим в полной мере, его не могли просто взять и использовать в других приложениях. Он был завязан сам на себе.

Осознавая это, очень сложно было бы продолжать разработку в той же манере. Было принято решение о том, что функционал, который может быть использован повторно должен быть вынесен в отдельные модули npm. Где они смогут повторно использоваться другими людьми, которые возможно захотят улучшить код, или найдут в нем ошибку. В конечном итоге от этого выиграют все.

Состав


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

Таких модулей оказалось довольно много, и о них мы поговорим.

Minify


minify представляет собой солянку из модулей, которые обрабатывают: js, css, html и переводят изображения в base64. При этом результат складывают в папку tmp, для более быстрого получения результата, при следующем обращении. Делается это с помощью модуля tomas.

Join


Есть разные способы ускорить загрузку веб-страницы: объединить файлы, минифицировать, скомпилировать с помощью browserify. join работает иначе, но цель у него та же.

Он склеивает файлы на лету в один http-запрос, при необходимости минифицируя их с помощью Minify. Подключить его достаточно просто, поскольку он представляет собой middleware совместимый с express.

И такого кода вполне достаточно:
app.use(join({
    dir: __dirname
}));

Склеивание, в свою очередь, происходит таким образом:
<link rel="/join:/css/normilize.css:/css/style.css">


Restafary


Restafary — это реализация REST для CRUD файловой системы, которая выполнена как middleware для express и может использоваться везде, где есть необходимость в сетевой обработке файлов.

Console


Console

Console — еще один middleware совместимый с express.
Подключается в пару строчек: на сервере и клиенте.
Вот часть на сервере:
Console({
    server: server,     /* only one should be passed: */
    socket: socket,     /* server or socket  */
    online: true,       /* default */
    minify: true,       /* default */
    prefix:'/console'   /* default */
})

И на клиенте:
<div class="console"></div>
<script src="/console/console.js"></script>
<script>
Console('.console', function() {
    console.log('console ready')
});
</script>

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

Spawnify


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

Edward


Edward

Редактор Edward, основанный на ace так же выделился в отдельный модуль, который может использовать не только Cloud Commander, но и любое другое приложение, так как это тоже express middleware. Из коробки есть горячие клавиши, а так же minify и beautify. Для начала использования достаточно кода на сервере:
app.use(edward({
    minify  : true,  /* default */
    online  : false, /* default */
    diff    : true,  /* default */
    zip     : true   /* default */
}));

И клиенте :
<div class="edit" data-name="js-edit"></div>
<script src="/edward/edward.js"></script>

html, body, .edit {
    height: 100%;
    margin: 0;
}

edward('[data-name="js-edit"]', function(el) {
    console.log('edward is ready');
});


Dword


Dword

Редактор Dword в плане кода, полностью совместим с Edward. Основное отличие в том, что Dword основан на CodeMirror. Теперь пользователи Cloud Commander имеют возможность выбирать редактор по вкусу. И Ace и CodeMirror достаточно зрелые проекты. Правда у них обоих есть недостатки:
  • с помощью Ace не получится нормально редактировать код на мобильном, поскольку нет возможности скролить код.
  • CodeMirror не использует Web Workers, поэтому, при использовании JSHINT редактор начинает работать медленнее, чем Ace.

Во время адаптации CodeMirror к возможности стать полноценной заменой Ace было написано несколько плагинов:
  • CodeMirror Searchbox — аналогичен используемому в Ace, инструмент для поиска и замены текста.
  • CodeMirror Show Invisibles — добавляет режим показа невидимых символов похожий на тот, что используется в Ace и Chrome Developer Tools, но в отличие от последнего, способен показывать окончания строк.

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

Mollify


Последним middleware на сегодня будет mollify. Он позволяет на лету минифицировать js, css и html. Для этого он использует Minify описанный выше.

Rendy


Когда нужен действительно простой шаблонизатор Rendy может пригодится.Он делает одну вещь. Делает это максимально просто. Работает во всех окружениях, поддерживающих ES5. Использовать можно таким образом:

var Tmpl    = 'hello {{ where }}';
    result  = rendy(Tmpl, {
        where: 'in browser'
    });
    // returns
    'hello in browser'


Ponse


В комментариях к предыдущей статье меня спрашивали по поводу используемого веб-сервера.Так вот, это Ponse. Простой веб-сервер. С express тягаться не будет,но с некоторыми вещами справляется неплохо.

Pipe-io


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

Один из них таков: обработчики ошибок должны навешиватся на каждый стрим при использовании pipe, иначе, в случае ошибки будет крэш. Pipe-io помогает решить эту проблему, упростив синтаксис до минимума.

Было так:
var fs      = require('fs'),
    read    = fs.createReadStream('README.md'),
    write   = fs.createWriteStream('README2.md'),
    
    open    = function(msg) {
        read.pipe(write);
    },
    finish  = function() {
        console.log('done');
        done();
    },
    error   = function(e) {
        e && console.error(e.message);
        done();
    },
    done    = function() {
        read.removeListener('error', error);
        write.removeListener('error', error);
        write.removeListener('open', open);
        write.removeListener('finish', finish);
    }

/* обработчики ошибок */
read.on('error', e);
write.on('error', e);

/* когда файл откроется на запись - можно начинать */
write.on('open', open);

/* сюда мы зайдем в самом конце, если все успешно закончится */
write.on('finish', finish);

Стало так:
var fs      = require('fs'),
    pipe    = require('pipe-io'),
    read    = fs.createReadStream('README.md'),
    write   = fs.createWriteStream('README2.md'),
    error   = function(e) {
        e && console.error(e.message);
        return e;
    }
    
pipe([read, write], function(e) {
    error(e) || console.log('done');
});

Потоков в массиве может быть сколько угодно, на каждый из них навесится обработчик ошибок. Если что-то пойдет не так, в callback попадет ошибка. В конце работы функции pipe все обработчики снимутся со стримов.

Win32


Получить список дисков в Windows можно с помощью специального модуля win32. Поддерживаются системы от XP до 8-ки.

Flop


Удалять, копировать, читать и перемещать папки можно с помощью модуля flop. Это его основное предназначение.

Copymitter


Когда нужно отслеживать состояние копирования, для отображения статуса прогресса, например, подойдет модуль Copymitter. Он будет генерировать события, на каждом скопированном файле, или на изменении статуса прогресса, который может быть от 1% до 100%. В случае ошибки — процесс может быть прерван, либо продолжен.

Разработка


Процесс разработки не особо изменился, главное отличие в том, что разработка ведется не только в одном глобальном репозитории, а и в репозитории модуля, в котором найден баг или нужна новая фича. В главный репозиторий, в арсенал проверки кода и документации, добавились два инструмента: jscs и yaspeller.

В процессе генерации конфига .jscsrc с помощью --auto-configure, выяснилось, что мой код, с небольшим исключением, больше всего удовлетворяет соглашениям Дугласа Крокфорда. С которыми я, конечно, был знаком раньше. Но почему-то мне казалось, что у нас с ним гораздо больше различий.

Хочется сказать пару слов о последнем на сегодня модуле wisdom. Он состоит из нескольких маленьких модулей, каждый из которых упрощает и автоматизирует рутинную работу JavaScript программиста, такую как:
  • генерация ChangeLog
  • обновление версии в package.json и bower.json (если существует)
  • добавление тега
  • публикация в npm
  • создание релиза на GitHub

Все эти задачи легко можно было реализовать с помощью Gulp. Но копируя очередной раз gulpfile.js в новый проект, я себя словил на мысли, что слишком часто это делаю, и это не очень удобно, все время его за собой тащить. Wisdom не требует конфигурационного файла. Он просто делает все необходимые вещи, которые нужны перед публикацией модуля. Это не замена для Gulp или Grunt. Это просто взгляд под другим углом. Мой workflow этот инструмент автоматизировал, упростил и сделал значительно удобнее.

Установка


К собственному сожалению, должен признать: процесс установки немного усложнился. Поскольку модули могут использоваться не только для бэкенда, но и для фронтенда, не имеет смысла дублировать код, ведь его установка возможна разными способами. Код установленный через npm будет в папке node_modules, но никто не гарантирует, того, на сколько высоко, относительно текущего каталога, она будет находится.

Это хорошо для приложений написанных на node.js или использующих browserify. Для остальных же вполне может подойти bower. Он забирает файлы, помеченные нужным тегом из репозитория и помещает их в папку modules (согласно .bowerrc). Таким образом, обновленный модуль будет доступен как для сервера, так и для клиента. Это положительная сторона. Но есть и отрицательная. Для нормальной установки Коммандера должен быть установлен Git и собственно Bower. После чего достаточно выполнить в терминале команду:
npm install cloudcmd -g

Кроме того, читатель всегда может взять собранный архив со всеми зависимостями (кроме Нода) со страницы релизов. Либо взять самую свежую версию из репозитория и выполнить команду:
npm install -g


Послесловие


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

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

Обо всех опечатках, в случае нахождения, прошу оповещать в личку, либо в hidden ветку репозитория.
Tags:
Hubs:
+14
Comments 0
Comments Leave a comment

Articles