Как стать автором
Обновить

Комментарии 31

Что думаете о сборке всего бекенда в 1 файл вебпаком?
Вот примерно это и думаю делать в будущем. Как уже сказал — вполне можно это делать с сурсмапами, отладка при этом не страдает. И вроде бы ничего не ломается при минификации. Вроде бы. Но, как опять же сказал, многие модули не готовы к сборке — то динамические зависимости, то ещё какая-то фигня. Но я знаю людей, которые успешно это делают в продакшне — а заодно это даёт им использовать все последние возможности JS вне зависимости от версии и поддержки Node.JS (правда, оптимальность таких транспиляций — это отдельный вопрос).

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

В связи с пассажем про динамические зависимости был очень удивлен, что пункт "Как правильно делать динамические зависимости" не включен в опрос. Кстати, я правильно понимаю, что это о том, как использовать опциональные зависимости в своем проекте?

Прошу прощения, не понял вопрос, уточните, пожалуйста.

Ну вы тут в посте жалуетесь, что проблемы доставляет неправильное использование динамических зависимостей. Что это за проблемы и как их избежать?


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

Я об этом

А, понял. На отдельный пост вряд ли потянет, поэтому дам развёрнутый комментарий:

1. Следует избегать динамических require() — то есть, тех, которые осуществляются не при подгрузке скрипта, а внутри функций.

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

1.1 Если у вас не дай бог мутируют глобальные объекты или прототипы, то финальная мутация будет зависеть от последовательности загрузки.
1.2. Очень легко в какой-то момент наступить на всякие противные вещи вроде циклических зависимостей — особенно если вы используете частичные экспорты.
1.3 Может выйти так, что в какой-то момент у вас не подгружен или не инициализирован тот модуль, который вы считали уже работающим.

2. Стоит избегать загрузки модулей из переменных. Это мало того, что небезопасно, но приводит к тем же проблемам, что и в пункте 1, плюс даёт возможность в какой-то момент не найти нужный модуль. Ну и у вас умирает половина возможностей по статическому анализу, включая линтинг, покрытие тестами, автоматический рефакторинг, подсказки IDE и так далее.

3. Стоит избегать загрузки сущностей по строковым именам. Например, видел примеры фабрик, которые инстанциируют классы по переданным им строкой именам. Не надо так! Опасности в целом те же, что и в пункте 2.

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

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

Почему-то все инструменты мне показывают разные результаты, так что сделал так:


mkdir test
cd test
npm init
npm i update-notifier --only=production
du -sh --apparent-size ./node_modules/

Выходит "1,2M ./node_modules/"


Если что не так делаю — поправьте, пожалуйста.


Насчёт "лезть в реестр" — ну блин, это ж один http запрос, который должен делаться нативными средствами.

НЛО прилетело и опубликовало эту надпись здесь
Посмотрел, как это делает update-notifier.
1. В его зависимостях есть www.npmjs.com/package/latest-version
2. latest-version делает это через www.npmjs.com/package/package-json
3. А он обращается к регистри через www.npmjs.com/package/registry-url

Для публичных модулей это всего лишь запрос к registry.npmjs.org/ — например, такой:
registry.npmjs.org/diarrhea?version=3.0.5
Для непубличных — да, чуть сложнее — надо подставить свой регистри и передать токен.

Но это вот вообще не повод цеплять столько транзитивных зависимостей с таким весом.
Как минимум, можно было бы собирать бандл.
А я бы вообще их импортировал копи-пейстом, потому что очень важно минимизировать размер таких модулей.
НЛО прилетело и опубликовало эту надпись здесь
Да это вообще жесть, что для такой базовой вещи, как http запросы, приходится ставить сторонние модули. Причём в большом проекте обычно стоит пачка разных модулей и их версий в транзитивных зависимостях.
А знаете что забавнее?
То — зачем 'request' и 'node-fetch', когда этот функционал пишется самостоятельно из уже существующего API node.js в 10-15 строк? Объясните, пожалуйста, кто-нибудь: зачем так делать, и что это за наркомания, где на каждый «чих» ставить из NPM пакеты, к-е тянут другие пакеты, к-е тянут д…
Всякий там request это офигительно удобно, когда у тебя огромный бэкенд проект, и надо в куче разных форматах обращаться к разным сервисам и обрабатывать ответ.

Но в данном случае, когда у тебя всего полтора варианта запроса — всё именно так, как вы описали — наркомания.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Так если нужны редиректы, POST, PUT, и прочее прочее — никто не спорит.


Но если мы говорим о модулях, в которых один(!!!) стандартный запрос, то получение версии пакета для update-notifier может выглядеть вот так:


const https = require('https');

function getPackageVersion(packageName) {
  return new Promise((resolve, reject) => {
    let rawData = '';
    https.get(`https://registry.npmjs.org/${packageName}`, (res) => {
      res.on('data', (d) => rawData += d)
        .on('error', (e) => reject(e))
        .on('end', () => {
        try {
          const parsedData = JSON.parse(rawData);
          resolve(parsedData['dist-tags'].latest);
        }
        catch (e) {
          reject(e);
        }
      });
    });
  })
}

getPackageVersion('diarrhea')
  .then((version) => console.log(`last version: ${version}`))
  .catch((err) => {
    console.log(`fetch error: ${err}`)
  });

И это ещё и с промисами.
Собственно, для полного варианта не хватает только переключения http/https и подстановки токена. И не надо никакую библиотеку тащить.

НЛО прилетело и опубликовало эту надпись здесь
Попробовать стоит — как минимум, написать его, написать куда-нибудь на медиум статью, закинуть нескольким авторитетным разрабочикам и создать issue в npm (вряд ли на них особо обращают внимание, но всё же).
При всём при этом обратите внимание, что в итоге всё равно не выйдет 2МБ кода. :).
Фишки и плюшки для каждого проекта можно оставить свои.
Давным давно существует node-prune от прекрасного разработчика. В чем эта поделка выигрывает?

Если честно, просто не нашёл node-prune. Но он какой-то совсем куцый, и вообще никак не настраивается, из самого важного:


  • Нельзя настроить шаблоны для удаляемых файлов
  • Нельзя прогнать в тестовом режиме и узнать, что ты удаляешь
  • Нельзя залогировать, что ты удалил
Ну вот с первым пунктом не соглашусь точно. Исходники перед глазами, даже первокурсник сможет поправить.
Остальные можно реализовать, под свои нужды.
  1. Зачем тащить ещё и Go на свои сервера? Даже если в вида бинарника. Кстати, архив бинарника весит 640 килобайт, а разархивированный — 2 метра.
  2. Зачем править исходники на Go, когда есть внятная кастомизация на уровне модулей и опций cli?

А как вы оптимизируете update-notifier, если он у вас вот здесь закомменчен?

Очень сурово оптимизирую, о чём честно написал в посте.


Уведомление об апдейтах я оттуда полностью выпилил

Будет время — может, соберу для демонстрации человеческую версию update-notifier, которая весит, сколько должна.

Мне почему-то показалось, что ваш тул умеет заменять update-notifier на его упакованную версию без потерь функциональности.


Теперь перечитал повнимательнее, оказалось, что вы просто удалили update-notifier из зависимостей совсем. Так неитересно, npm таким образом похудеть не заставишь.

Хотел его оптимизировать, но это оказалось небыстро — в бандл его не соберёшь, надо форкать и править. Будет время — обязательно это сделаю.
НЛО прилетело и опубликовало эту надпись здесь
Вы правда ничего не поняли.
Выкачать зависимости без включаемого в них мусора нельзя.
Удаляется оно перед сборкой артефакта, который потом будет раскатан по серверам.
Экономия в 100 мегабайт для каждого собираемого билда, с учётом, что мы собираем этак по 300 билдов в сутки — 30 гигабайт в сутки (на самом деле больше, так как это только для одного проекта). Плюс более быстрый деплой засчёт меньшего размера артефакта.
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории