Pull to refresh

Comments 31

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

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

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

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

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


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

Я об этом

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

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

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

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

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

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

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

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

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


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

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


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


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

UFO just landed and posted this here
Посмотрел, как это делает 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
Для непубличных — да, чуть сложнее — надо подставить свой регистри и передать токен.

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

Но в данном случае, когда у тебя всего полтора варианта запроса — всё именно так, как вы описали — наркомания.
UFO just landed and posted this here
UFO just landed and posted this here

Так если нужны редиректы, 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 и подстановки токена. И не надо никакую библиотеку тащить.

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

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


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

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


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

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

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


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

Хотел его оптимизировать, но это оказалось небыстро — в бандл его не соберёшь, надо форкать и править. Будет время — обязательно это сделаю.
UFO just landed and posted this here
Вы правда ничего не поняли.
Выкачать зависимости без включаемого в них мусора нельзя.
Удаляется оно перед сборкой артефакта, который потом будет раскатан по серверам.
Экономия в 100 мегабайт для каждого собираемого билда, с учётом, что мы собираем этак по 300 билдов в сутки — 30 гигабайт в сутки (на самом деле больше, так как это только для одного проекта). Плюс более быстрый деплой засчёт меньшего размера артефакта.
UFO just landed and posted this here
Sign up to leave a comment.

Articles