К концу 2015 года в распоряжении JavaScript разработчиков образовалось огромное количество инструментов. В этой экосистеме легко потеряться, поэтому успешные команды следуют выработанным правилам, которые позволяют не терять время и сохранять здоровье проектов. Под катом перевод статьи 2016 года от команды Heroku, в которой они рассказывают о десяти привычках веб разработчиков, у которых все работает и ничего не болит. Скорее всего 80% написанного вы уже знаете – тем интереснее вам будет прочитать об оставшихся двух приемах!


1. Начинайте новый проект командой npm init


Эта команда сразу создаст правильный package.json, основываясь на имени директории проекта и ваших ответах на вопросы визарда:

$ mkdir my-awesome-app
$ cd my-awesome-app
$ npm init --yes

Использование флага --yes позволяет не отвечать на вопросы визарда, а в поле engines получившегося package.json можно сразу установить нужную версию ноды (node -v):

"engines": {
  "node": "4.2.1"
}

2. Используйте «умный» .npmrc


По умолчанию npm не записывает установленные зависимости в package.json (а за зависимостями надо следить всегда!).

Если вы воспользуетесь флагом --save для автоматического обновления package.json, то npm сохранит имя зависимости с префиксом ^. Семантическое версионирование ставит ваши зависимости под угрозу, так как при чистой инсталляции в проект могут установиться другие версии зависимостей, и кто знает, какие в них могут быть баги и проблемы. Такой способ хорош во время разработки, но не в продакшне. Одно из решений – сохранять точную версию зависимости:

$ npm install foobar --save --save-exact

А еще лучше – поменять глобальные настройки npm в ~/.npmrc, чтобы все происходило автоматически:

$ npm config set save=true
$ npm config set save-exact=true
$ cat ~/.npmrc

При такой конфигурации установка зависимостей сохранит точную версию и ваш проект никогда не настигнет жуткий “version drift”!

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

3. Не упустите уходящий поезд ES6


Начиная с 4-й версии Node.js вы можете использовать многие функции ES6. Начните использовать уже сейчас простые и удобные улучшения синтаксиса, которые сделают ваш код проще и понятнее:

let user = users.find(u => u.id === ID);
console.log(`Hello, ${ user.name }!`);

4. Придерживайтесь нижнего регистра


Некоторые языки рекомендуют именовать файлы так же, как классы. Например, файл, имплементирующий MyClass, предлагается называть MyClass.js. Не делайте так в node. Используйте нижний регистр:

let MyClass = require('my-class');

Node.js это редкий пример линуксовой программы с великолепной поддержкой кроссплатформенности. Несмотря на то, что OSX и Windows будут считать файлы myclass.js и MyClass.js одним и тем же файлом, Linux так считать не будет. Если вы хотите писать кросс-платформенный код, вам необходимо именовать файлы в том же регистре, который вы используете для require.

Самый простой пусть сделать все правильно – это использовать нижний регистр, то есть my-class.js (примечание переводчика: или my_class.js, что все-таки популярнее среди программистов, нежели css нотация).

5. Кластеризируйте ваше приложение


Так как процесс node ограничен одним ядром и полутора гигабайтами оперативной памяти, деплой некластеризованного приложения на мощный сервер является тратой полезных ресурсов впустую. Чтобы использовать несколько ядер и много памяти, добавьте в свое приложение поддержку кластеризации. Даже если сейчас вы запускаете приложение на одноядерной vps с гигом памяти, добавление кластеризации будет хорошим заделом на будущее.

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

const CONCURRENCY = process.env.WEB_CONCURRENCY || 1;

Использование кластеризации позволяет не изобретать велосипед для управления потоками. Если вам нравится разделение по файлам на “master” и “worker”, то попробуйте forky. Если же вы предпочитаете единую точку входа, то throng.

6. Следите за переменными окружения


Используйте переменные окружения вместо конфиг файлов. Для этого установите node-foreman:

$ npm install --save --save-exact foreman

Затем создайте Procfile, чтобы указать тип приложения:

web: bin/web
worker: bin/worker

И установите альяс для запуска:

"scripts": {
  "start": "nf start"
}

Теперь, чтобы изменить настойки окружения, достаточно создать (и добавить в .gitignore) файл с именем .env, который будет автоматически загружен node-foreman:

DATABASE_URL='postgres://localhost/foobar'
HTTP_TIMEOUT=10000

С такими настройками достаточно одной команды npm start, чтобы запустить web и worker процессы, а затем прменить к ним настройки в соответствии с переменными окружения. Это намного проще, чем 'config/abby-dev.js', 'config/brian-dev.js', 'config/qa1.js', 'config/qa2.js', 'config/prod.js', итд.

7. Избегайте мусора


Node.js (в лице движка V8) использует «ленивый» и «жадный» сборщик мусора. С лимитом по умолчанию в полтора гигабайта он часто ждет до последнего, прежде чем освободить не используемую память. Если у вас постепенно растет использованная память, это может быть не ее утечка, а вполне штатное поведение сборщика мусора node.

Для лучшего контроля за сборщиком мусора, в Procfile можно поместить команды для движка V8:

web: node --optimize_for_size --max_old_space_size=920 --gc_interval=100 server.js

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

web: node --optimize_for_size --max_old_space_size=460 --gc_interval=100 server.js

8. Используйте хуки


“Lifecycle scripts” в node.js предоставляют широкие возможности для автоматизации. К примеру, если вам нужно что-нибудь запустить перед сборкой приложения, вы можете воспользоваться скриптом preinstall. Нужно собрать ассеты с помощью grunt, gulp, browserify или webpack? Используйте скрипт postinstall. Все эти скрипты можно задать прямо в package.json:

"scripts": {
  "postinstall": "bower install && grunt build",
  "start": "nf start"
}

И конечно вы можете использовать переменные окружения для управления скриптами:

"postinstall": "if $BUILD_ASSETS; then npm run build-assets; fi",
"build-assets": "bower install && grunt build"

Если скрипты стали слишком сложные – перенесите их в файлы:

"postinstall": "scripts/postinstall.sh"

Важно: скрипты в package.json выполняются с ./node_modules/.bin автоматически добавленным в PATH, так что вы можете напрямую вызывать локально установленные npm пакеты, такие как webpack. Это позволяет вообще не устанавливать пакеты глобально.

9. Only git the important bits


Мне настолько понравился этот заголовок, что я оставил его без перевода. Красивая игра слов – «гитуйте только важные биты» = «добавляйте в git только то, что важно». Большинство приложений состоят из файлов двух типов: которые можно или нельзя сгенерировать автоматически. Когда вы используете систему контроля версий, избегайте добавлять в нее файлы, которые можно сгенерировать автоматически.

Например, у вашего приложения есть директория node_modules с установленными зависимостями. Да, есть люди, которые добавляют ее в систему контроля версий! Не надо так делать. Указание нужных версий зависимостей в package.json намного надежнее, так как npm install не очищает node_modules, и если там уже будут файлы из системы контроля версий, может случиться беда.

Также добавление генерируемых файлов производит много лишнего шума в логах и нотификациях вашего репозитория. Более того, некоторые зависимости требуют компиляции при установки, так что добавление установленной версии в репозиторий делает ваше приложение непортабельным и может привести к странным ошибкам.
По тем же причинам не стоит добавлять bower_components или скомпилированные grunt ассеты. Если в проекте директория node_modules уже добавлена в систему контроля версий, то ее всегда можно убрать, например, вот так:

$ echo 'node_modules' >> .gitignore
$ git rm -r --cached node_modules
$ git commit -am 'ignore node_modules'

Также я обычно добавляю в игнор логи npm, чтобы не засорять код:

$ echo 'npm-debug.log' >> .gitignore
$ git commit -am 'ignore npm-debug'

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

10. Упрощайте


Предсказания в айти – дело неблагодарное. Но я все-таки сделаю одно. Предсказываю, что для JavaScript 2016 год станет годом упрощения.
Все больше программистов упрощают архитектуру своих решений. На смену монолитных MVC решений приходит статический фронтенд, который так удобно раздавать через CDN, и Node.js бэкенд для динамических данных.

Мы также начали замечать, насколько сложные системы сборки усложняют наши проекты. На острие прогресса разработчики упрощают эти решения, в частности, используя npm скрипты вместо bower, gulp и grunt.

И, наконец, в 2016 году мы будем упрощать написанный нами код. В ряде случаев это будет отказ от лишних фичей, как показал Douglas Crockford в своих The Better Parts. Или, наоборот, упрощение придет от добавления новой функциональности. Такой, как мои любимые async и await. В ноде их пока нет, но всегда можно воспользоваться транспайлером, например BabelJS.

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

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


  1. erlyvideo
    23.02.2016 12:20
    +1

    bower, grunt, gulp, brunch, webpack

    Они все одно и то же делают?


    1. f0rk
      23.02.2016 12:27

      Не совсем
      bower — менеджер пакетов для клиентских библиотек
      grunt и gulp — примерно одно и тоже, просто таск раннеры
      brunch — не знаю что такое
      webpack — бандлер и загрузчик модулей


      1. denar90
        23.02.2016 15:14

        brunch — не знаю что такое

        Brunch
        Очень удобный сборщик.


      1. dom1n1k
        23.02.2016 15:31
        +2

        Вот интересно, как человек со стороны должен понять разницу между "менеджером пакетов" и "загрузчиком модулей". Звучит как синонимы :)


        1. erlyvideo
          23.02.2016 22:24

          угу, для меня это одно и то же: 8 копий одной тулзы, которые просто сделаны разными людьми, NIH


    1. mdnsresponder
      23.02.2016 12:39

      • grunt и gulp по сути одно и то же, но с разным синтаксисом и подходом к написанию сценариев сборки.
      • webpack в ряде случаев (но не во всех) может заменить grunt и gulp
      • bower дает более широкие возможности по сравнению с установкой из npm, но можно обойтись и без него


      1. spmbt
        23.02.2016 12:43

        bower особенно важен для фронта, т.к. объединяет зависимости одинаковых имён.


        1. kahi4
          23.02.2016 14:48
          +1

          Bower — архаизм, но зачастую в npm отсутствует нужный модуль, а ручками копировать и отслеживать не хочется.
          Webpack — гибкая и мощная система сборки, однако, в отличие от grunt и gulp, для бэка практически бесполезна, основное — сборка фронта. И нет задач, которые не смог бы решить вебпак (еще бы, у него достаточно мощная система расширений), но, к сожалению, зачастую нужные вещи написаны под грант или галп, а на вебпак переводить слишком накладно. Правда именно так и плодится зоопарк (у меня сейчас галп создает иконичный шрифт из набора svg и запускает регрессионное тестирование, все остальное силами webpack. И если первое — нужно просто посидеть немного, то второе — даже идей нет как впилить, а беглый поиск в гугле ничего внятного не предложил).


  1. f0rk
    23.02.2016 12:23
    +1

    (примечание переводчика: или my_class.js, что все-таки популярнее среди программистов, нежели css нотация).

    Все же в node.js для именования файлов, по моему субъективному ощущению, чаще используется дефис.


    1. mdnsresponder
      23.02.2016 12:40
      -3

      У дефиса есть бо-о-о-о-ольшой минус — большинство редакторов и утилит командной строки воспринимает его как разделитель слов. А имя файла обычно используют как одно слово.


      1. f0rk
        23.02.2016 12:55
        +2

        Ну не такой уж и бо-о-о-о-ольшой, я вот вообще не вижу проблемы. В большинстве случаев, имя файла используется в import директивах, а там есть нормальный автокомплит от IDE.


  1. spmbt
    23.02.2016 12:58
    +1

    > Only git the important bits

    bits — это кусочки. (Но на русский всё равно плохо мантруется, да.)
    А по оставлению важных кусочков — мысль более глубокая, если считать, что важные != необходимые.
    К примеру, для проекта может быть важно наличие в нём последней рабочей сбоки без необходимости ставить Ноду и запускать сборку. Не нужно держать /node-modules, но полезно — конечную сборку, хотя бы в тестовой папке, или в /dist, и часто — полезно держать /bower-components — сразу есть возможность запустить проект без сборки.

    > Попробуйте не соревноваться друг с другом в том, сколько новых технологий можно запихнуть в один проект
    +1


    1. deniskreshikhin
      23.02.2016 17:00
      -4

      Да с позиции английского языка это вообще ничего не значащая фраза, типа "только негодяй, важные куски") Т.к. слово a git никаких глаголов не образует.

      Видимо автор хотел сделать отсылку что в некоторых диалектах США get произносится как git, и тогда фраза читается как "получайте/держите только важное". Если поискать строчку в интернете, то легко найти автора. Это некий Hunter Loftis. На LinkedIn указано что он из Северной Каролины, т.е. с юга США, где как раз и распространено это произношение, если верить викисловарю https://en.wiktionary.org/wiki/git#Alternative_forms


      1. velvetcat
        23.02.2016 17:32
        +3

        Видимо автор хотел сделать отсылку что в некоторых диалектах США get произносится как git
        Это здесь не причем. «To git smth» образовалось так же, как и «to google smth».


        1. deniskreshikhin
          23.02.2016 17:49
          -2

          Если приведете пример употребления у носителей языка, то я вам поверю. Я лично не встречал такого употребления.

          Да to google есть такое явление и в русском, глагол "гуглить". Но никто не говорит "гитовать", ни у нас, ни у них.


          1. RomanPyr
            23.02.2016 18:31
            +1

            Да, обычно говорят "запушь"/"запуши" :)


          1. szubtsovskiy
            23.02.2016 19:33
            +2

            А как же известное "We will rock you"? Ведь в этой фразе явно не в значении "качать" глагол rock употреблён.

            Мне всегда казалось, что в разговорном английском языке норма взять существительное и сделать из него глагол. И даже сомнений не вызвало значение фразы "Only git the important bits", особенно после приведённой расшифровки.


            1. deniskreshikhin
              23.02.2016 20:58

              Существительное становится глаголом, если есть вспомогательные слова или функцию слова можно понять из контекста.
              Для тех, кто не знает что git это менеджер кода фраза является бессмыслицей. Я лично не встречал что бы кто-то использовал git как глагол, типа "to git something", "gitted code" и т.д. И гугл кстати тоже (если загуглить).

              Сами американцы тоже неоднозначно пишут http://english.stackexchange.com/questions/309249/is-it-correct-to-use-git-as-verb, типа в узком кругу специалистов сойдет. Кто-то пишет, что это произношение get в южных штатах.


              1. szubtsovskiy
                23.02.2016 21:06

                Шикарно, вы даже не поленились спросить на StackExchange. :-)

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

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


                1. deniskreshikhin
                  23.02.2016 21:36

                  Ага, согласен. Мне было интересно насколько это легально использовать слово git таким образом.


  1. k12th
    23.02.2016 13:33
    -4

    my-class.js
    Если честно, хочется убивать за такое, и особенно за такие советы.

    Как я должен догадаться, что экспортируется из этого файла, MyClass, myClass, my_class или вообще myclass? Ну если есть слово class, то еще понятно, а если там (M|m)y(-_)?(T|t)hing? Неужели так трудно сразу назвать файл в нормальном кейсе?


    1. frux
      23.02.2016 14:18

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

      const myClass = require('my-class');
      
      const myclass = require('my-class');
      
      const my_class = require('my-class');

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


      1. k12th
        23.02.2016 15:09
        +2

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


        1. frux
          23.02.2016 15:18
          -1

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


          1. cutwater
            23.02.2016 15:33
            +1

            Именно поэтому умные люди придумали PEP8, решив тем самым проблему глобально на уровне языка.


            1. k12th
              23.02.2016 15:43

              Вот чего JS не хватает, так это чего-нибудь вроде PEP8 или PSR. Зато есть 11 пресетов для JSCS и полдесятка форматов для написания документации.


          1. k12th
            23.02.2016 15:37
            +2

            Какбэ нет. Класс для работы с датами называется Date, а не $date или Dat_e или еще что-нибудь. Аналогично с прочими встроенными вещами. PascalCase для классов, camelCase для методов, свойства и функций, UPPER_CASE для констант. Никакого кебаб-кейса или снейк_кейса. Вот чтобы не было разнобоя, надо ориентироваться на это. Ради общего блага. Чтобы не тратить время на идиотские споры, как именовать файлы.


            1. frux
              23.02.2016 19:37
              -1

              А что вы скажите по поводу объекта Math, который ни разу не класс? Или про константу Math.pi? EcmaScript плохой пример стандарта единым кодстайлом.


              1. k12th
                23.02.2016 19:38
                +1

                1. frux
                  23.02.2016 19:45

                  Да, согласен, с PI ошибся, но Math все также не кошерно пишется с заглавной буквы.


                  1. faiwer
                    23.02.2016 20:45
                    +2

                    Пардон, а чем Math не "static class"?


                    1. frux
                      23.02.2016 20:49

                      По такой логике любой объект можно назвать статическим классом и писать с большой буквы.


                      1. faiwer
                        23.02.2016 20:54
                        +1

                        Отчего же? Math содержит ряд математических методов и констант. Этакий namespace по смыслу, helper. Вот, к примеру, document.location это скорее набор полей, отличающихся от страницы к странице.

                        Правда мне не ясно, почему же тогда crypto, вместо Crypto. При том что Crypto тоже наличиствует, но на мои попытки им как-то воспользоваться ругается illegal constructor. Судя по документации к нему нужно обращаться через window.crypto. Ребята явно чего-то перемудрили.


              1. Aingis
                23.02.2016 20:50
                +1

                Калька с Явы. По поводу природы JS советую посмотреть выступление DmitryBaranovskiy «Zen of Javascript» https://www.youtube.com/watch?v=QHs55-5FzgA


                1. DmitryBaranovskiy
                  24.02.2016 06:51

                  Присоединяюсь к совету. :)


          1. michael_vostrikov
            23.02.2016 16:56

            И не мне это решать и не вам

            Простите, а кому это решать?


            1. frux
              23.02.2016 19:42

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


      1. mrsum
        23.02.2016 15:48
        +2

        Речь не о том, как надо называть ваши ячейки памяти, а о том, что название файлов под разными ОС ведут себя по разному. Регистро, или не регистрозависимые


    1. Eternalko
      02.03.2016 18:36
      -1

      Как я должен догадаться, что экспортируется из этого файла

      Вы как будто ни одной строчки в node.js не написали.


  1. Mithgol
    23.02.2016 23:23
    +1

    По умолчанию npm не записывает установленные зависимости в package.json (а за зависимостями надо следить всегда!).
    Это не проблема, если после установки зависимости открывать package.json и вручную вписывать зависимость в него.

    Понятно, что это вроде как лишний труд, но его не так много (подумаешь, одну строчку в текстовый файл воткнуть!), а преимуществом такого подхода является контроль над тем, какой диапазон версий зависимости считать приемлемым.

    Почему это полезно?

    Потому, что для обозначенного подозрения («кто знает, какие в них могут быть баги и проблемы») не существует общего решения, всюду годного пути обхода.

    Для одних зависимостей годится предложенное в этой блогозаписи решение (сохранять в package.json точную версию, а обновления запретить, потому что кто знает, какие в них могут быть баги и проблемы), но для других не годится (а в package.json про них вписываешь «~x.y.z» для разрешения установки новой пропатченной версии, потому что кто знает, какие в нынешней версии могут быть баги и проблемы).

    Выбор между этими двумя стратегиями лучше делать индивидуально (ориентируясь на возможность разработчиков зависимостей находить и исправлять ошибки, не создавая новых багов и проблем) и делать его именно в момент вписывания зависимости в package.json.


  1. Suvitruf
    24.02.2016 00:14

    Кластеризируйте ваше приложение
    У нас в supervisord висит просто nodejs приложений по числу ядер. Использование `process.env.WEB_CONCURRENCY` лучше?


  1. Balek
    24.02.2016 00:29

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


    1. gearbox
      24.02.2016 00:41

      мне кажется конфиги в файлах не любят те кто не догадался до require('./config');
      Других причин не любить конфиги — не вижу.
      Но есть ситуации когда переменные окружения удобнее — например при сборке webpack-ом, которая запускается через npm скриптинг — скажем npm run target, а каждый target выставляет TARGET=blabla webpack… а там уже в конфиге сборки подхватывается.
      В общем тут от повара зависит — у каждого свои рецепты.


      1. Mithgol
        24.02.2016 12:36
        +1

        Самое печальное — видеть, как поклонники линуксовой и маковой среды начинают портировать проект на Windows, а у них в package.json ужe полным-полно команд в формате «переменная1=значение1 переменная2=значение2 команда параметры», который в Windows командною строкою не поддерживается в качестве средства пополнения переменных окружения, в котором выполняется команда.

        Мрачно подозреваю также, что require('./config') не нравится тем разработчикам, которых отталкивает чрезмерная строгость языка JSON, а простота формата «переменная=значение» (по сравнению с форматом «"переменная": "значение"», где символов больше, а ошибка в любом из них приводит к неработоспособности) представляется привлекательною.

        Немного поразмыслив над этим, я стал сознавать ещё бoльшую привлекательность простого текстового формата конфигураций, в котором и знак равенства не нужен, а простой пробел (или несколько пробелов) отделяет имя переменной от значения:

        # Описание пользователя:
        User      Mithgol
        Karma     60?
        ReadOnly  No
        
        # Социальные сети:
        Fidonet   2:50/88
        Twitter   FidonetRunes

        После этого я пошёл и сочинил модуль для чтения такого формата, потому что готовые модули мне как-то не попадалися для этой цели.


        1. gearbox
          24.02.2016 14:10

          который в Windows командною строкою не поддерживается

          Соглашусь полностью, этот момент не учел в своем высказывании.

          После этого я пошёл и сочинил модуль

          Интересный модуль, правильная лицензия — утянул в копилку.


  1. forgotten
    24.02.2016 09:02
    +4

    Используйте переменные окружения вместо конфиг файлов
    Теперь, чтобы изменить настойки окружения, достаточно создать (и добавить в .gitignore) файл с именем .env

    Одного меня что-то в этом смущает? Вместо конфиг-файла у нас теперь есть конфиг-файл и тулза, которая его читает. Нужно больше абстракций, ага.


  1. atd
    24.02.2016 12:05

    echo 'node_modules' >> .gitignore

    А потом, когда у вас в офисе начал лагать инет, или сам нпм слёг (да, несколько раз бывало и такое), вы сидите и тупо курите бабмук...


    1. vinograd19
      24.02.2016 13:32
      +1

      Есть кэш, есть sinopia. И есть раздувшийся репозиторий.


      1. gearbox
        24.02.2016 17:22

        спасибо за sinopia — как то она на глаза не попадалась.


    1. gearbox
      24.02.2016 14:17

      сам не делал, но знаю что народ вообще-то свой gitlab разворачивает в локалке и с него тянет модули. И на него же обновляет с github-a. И при форсмажорах чувствует себя в сухе и тепле. Совать модули в проект я вижу только одну причину — пропатченный модуль до момента принятия владельцем пулл-реквеста.