Бандлить что это значит
Не агрись, думер! 22 слова, которые помогут понять поколение Z
Выражает одобрение и восхищение, синоним «вау». Часто употребляется в музыке, в том числе в треках рэпера Нурминского и рэпера Sqwoz Bab. «Ауф» вошло в топ новых русских слов по версии «Яндекса» за 2020 год.
Агрошкольник
Дословно — «агрессивный школьник», от слова «агриться» — сердиться. Используется по отношению к хамам, встревающим в чужую беседу без знания контекста.
Ботать
Нет, не по фене. У зумеров это — учиться, зубрить.
Бинджвотчинг
От английского binge watching, дословно — запойный просмотр. Чаще всего используется в контексте сериалов: когда происходящее на экране настолько увлекает, что вы буквально проглатываете серию за серией и сезон за сезоном.
Безумно можно быть первым
Расхожий мем — строчка из трека рэпера Homie. Из-за абсурдности используется в качестве «добивки» или ответа на бессмысленную, псевдо-мудрую или пацанскую цитату.
Войснуть
Отправить голосовое сообщение (оно же — «голосовуха» и «гс»).
Дноклы
Сокращенно от одноклассников.
Думер
Апатичный, депрессивный, склонный к саморазрушению, антисоциальный человек. Так же существуют глумер (просто грустный человек) и блумер (излишне жизнерадостный).
Забайтить
То есть спровоцировать. Происходит от английского bait — «наживка».
Ливнуть
От английского leave, что значит «уйти».
Личинус
Негативно окрашенное слово по отношению к ребенку, пришедшее из сленга групп про «яжематерей». Образовано от слова «личинка».
Слово просочилось из среды геймеров: лут — это ценная вещь, которую может получить игрок за уничтожение врага. У зумеров обычно используется в значении покупки, а залутиться соответственно — закупиться.
Падра
Слово из песни дуэта MiyaGi & Andy Panda «Кассандра» означает подругу.
Пекарня
Производное от ПК — персональный компьютер.
Раффл
RYTP (Russian YouTube Poop, РИТП)
Смешные ролики в русском YouTube, созданные путем монтажа нескольких вирусных мемогенных видео.
Скипнуть
Прогулять. От английского skip — «пропустить».
Стэнить
Означает фанатеть. Слово позаимствовано у Эминема: Стэном зовут персонажа клипа совместного клипа рэпера с Дайдо «Stan». Он безумный фанат Эминема, закидывающий кумира письмами и мечтающий с ним встретиться. Кумир оставляет письма без ответа — Стэн окончательно сходит с ума и убивает свою девушку и себя.
Тащер
Игрок, который в онлайн-игре тянет всю команду на себе. Также — удачливый человек.
Флейм
Неконструктивный спор в сети, переходящий в откровенную ругань. Спор ради спора.
Флексить
Качаться под музыку или хвастаться.
Шипперить, пить чай с шиповником
Сводить людей в романтическом смысле слова без их ведома. Чаще всего применятся поклонниками и авторами фанфиков в отношении любимых артистов, персонажей.
Bundler — менеджер для управления gem’ами
Что такое Bundler?
Установка
Устанавливаем эту утилиту как любой другой gem:
gem install bundler
Для Rails 3.0 ничего больше делать не нужно, потому как он используется по умолчанию. А для Rails.2.3.x нужно выполнить следующие шаги. C начала добавить ниже приведенный код в boot.rb перед Rails.boot!:
class Rails::Boot
def run
load_initializer
extend_environment
Rails::Initializer.run(:set_load_path)
end
def extend_environment
Rails::Initializer.class_eval do
old_load = instance_method(:load_environment)
define_method(:load_environment) do
Bundler.require :default, Rails.env
old_load.bind(self).call
end
end
end
end
Далее создать файл preinitializer.rb в директории config/initializers с содержимым:
begin
# Require the preresolved locked set of gems.
require File.expand_path(‘../../.bundle/environment’, __FILE__)
rescue LoadError
# Fallback on doing the resolve at runtime.
require «rubygems»
require «bundler»
Bundler.setup
end
Конфигурирование
После создании нового Rails приложения в версии 3.0 в корне проекта уже существует файл Gemfile, который является конфигом для Bundler’а. Для версий Rails 2.3.x его нужно создать самому. Для этого нужно перейти в директорию проекта и выполнить команду:
В этом файле задаются все необходимые зависимости gem’ов. Рассмотрим какие именно возможности предоставляет данный конфиг файл.
Сперва задается ресурс откуда по умолчанию будут устанавливаться gem’ы:
Как уже многие знают ресурс gemcutter.org становится неким стандартом для хранения gem’ов, поэтому при создании конфига именно этот ресурс будет установлен по умолчанию. Но вы легко можете его заменить допустим на gems.github.com или добавить столько ресурсов сколько вам нужно:
source ‘http://gemcutter.org’
source ‘http://gems.github.com’
source ‘http://gems.rubyforge.org’
Далее уже идет список gem’ом которые нужны для работы приложения:
gem ‘will_paginate’
gem ‘oauth’
gem ‘money’
Здесь нужно отметить, что gem’ы можно объединять в группы и далее устанавливать только определенные группы:
group :development do
gem ‘rspec’
gem ‘populator’
gem ‘faker’
end
group :production do
gem ‘memcache-client’
end
Доступна и другая форма объединения gem’ов в группы:
gem ‘rspec’, :group => ‘development’
gem ‘populator’, :group => ‘development’
gem ‘memcache-client’, :group => ‘production’
По умолчанию все gem’ы включаются в группу default.
Если нужна именно конкретная версия gem’а то можно задать ее номер:
gem «rack», «1.0.1»
gem «rails», «>=2.3.2»
Есть возможность задать имя файла который будет подключен во время подключения библиотеки Bundler’ом. По умолчанию это имя gem’а поэтому в большинстве случаев ничего задавать не нужно. Опция которая позволяет задать имя файла для подключения называется require, используется она следующим способом:
gem ‘gchartrb’, :require => ‘google_chart’
В случае если нужно указать git репозитория для скачивания gem’а то нужно использовать опцию git:
gem ‘will_paginate’, :git => ‘git://github.com/mislav/will_paginate.git’
Использование
Как тока задали все нужные gem’ы, нужно выполнить команду:
Эта команда решит все зависимости и установит недостающие gem’ы. При этом если выполнить:
То вы там не увидите gem’ы которые были установлены с помощью bundler’а. Все установленные gem’ы находится в директории
/.bundler. Откуда он их и будет подключать.
Посмотреть список установленных gem’ов можно с помощью команды:
Если нужный gem уже установлен в системе, то для него будет создана ссылка. После каждого изменения файла Gemfile, нужно выполнить команду install. Папка
/.bundler не является обязательной, если вы хотите установить gem’ы в другую папку, это легко сделать:
Если помните, то в конфиг файле есть возможность включать все gem’ы в группы, так вот при установки можно указать какие группы gem’ов не устанавливать:
bundle install —without test
Допустим зачем устанавливать gem’ы на production server который нужны только для тестирования.
Если gem имеет исполняемые файлы, то их можно запускать след образом:
bundle exec cassandra_helper cassandra
Как только вы закончили разработку приложения, нужно заблокировать изменение Gemfile:
После выполнения данной команды создастся файл Gemfile.lock, который будет содержать все зависимости на основе установленых gem’ов у вас на компьютере. Это делается для того чтоб зафиксировать версии gem’ов при которых приложение работает корректно. Данный файл будет иметь следующий вид:
—
dependencies:
faker:
group:
— :development
version: «>= 0»
memcache-client:
group:
— :test
version: «>= 0»
sqlite3-ruby:
group:
— :default
version: «>= 0»
oauth:
group:
— :default
version: «>= 0»
specs:
— stomp:
version: 1.1.4
— populator:
version: 0.2.5
— json:
version: 1.2.0
— thrift:
version: 0.2.0
— thrift_client:
version: 0.3.3
— rspec:
version: 1.3.0
— ruby-hmac:
version: 0.4.0
— oauth:
version: 0.3.6
hash: 0ac3c8666943a1e2294be2851316d83791479451
sources:
— Rubygems:
uri: gemcutter.org
В bundler’е предусмотрена возможность упаковки gem’ов:
После выполнения данной команды в директории vendor/cache будут сохранены все нужные gem’ы, впоследствии чего установка gem’ов будет происходить именно с этой директории. Эта опция будет полезна только для тех у кого нет возможности на production server устанавливать gem’ы с публичных репозиториев.
Вот и все, что я хотел вам рассказать об этой удобной утилите. Попробуйте поработать с ней хотя бы час и я думаю, она вам понравится.
Webpack vs Gulp, внятно и понятно. Или для чего мне еще один мощный инструмент?
нужно ли мне использовать webpack с gulp или вовсе, только webpack
Есть конечно «плагины» для webpack добавляющие функциональность таск раннеров но как по мне это уже перебор.
имхо очередное хипстерское (nodejs) веяние.
Каждый год, стабильно, весь мир «внезапно» осознает что их текущий инструмент (выпущенный год назад) стал слишком «фу фу фу», и нужно срочно запилить что-то новое, чтобы все сказали «ах».
Подождем пока лет 5, пока всё это устаканится, и сформируется нормальный стек технологий для разработки.
Вячеслав Лебедев:
>Факты убедительнее для того, чтобы самому решить, стоит ли он времени на изучение.
Какие факты? Что это очередная поделка, от тех кто мыслит как на картинке ниже?
Я пользуюсь gulp. В свое время стоял выбор между gulp и grunt, мне по духу больше пришелся gulp.
Менять его на что-то новое. зачем? Он полностью устраивает по своему функционалу.
А менять инструмент только ради моды. ну вам виднее.
D’ Normalization: я тоже был примерно такого же мнения, webpack смотрится слегка противоестественно. Но по итогу я решил попробовать и пока доволен, так как он решил целую гору моих проблем со сборкой проектов.
А для простого сайтика я бы webpack не брал конечно. Хотя сайтики разные бывают.
Вячеслав Лебедев: решает конечно, у меня все проекты на ES6 за последние пол года (чуть меньше пожалуй).
Пока спасало только то что в ангуляре есть свои модули, но иногда всеравно случаются косяки связанные с ресовом зависимостей и т.д.
Так же щаблоны. С gulp я собирал шаблоны в templateCache и не парился, с webpack я тупо импортирую их внутрь компонентов (шаблоны только для них) и далее с ними орудую. А так как я еще и jade использую то это все просто дико удобно.
webpack выдерет из core-js только те полифилы которые реально мне нужны (так как я явно прописал зависимость от оных). Это как бы и с другими бандлерами работает, тут просто преимущество бандлеров над тупой конкатенацией. С gulp (имею в виду без бандлинга) же мне пришлось бы подключать весь core-js или лепить кастыли.
Сделаем веб снова великим
Современный веб — это сложная динамическая система, которая постоянно находится в движении. Как было замечено во многих статьях, становится очень сложно уследить за всеми изменениями так как новые инструменты и фреймворки появляются чуть ли не каждый день. Знания устаревают еще не успев закрепиться. Конечно, все это очевидный результат быстрого развития и роста, но это неизбежно добавляет сложности веб разработчикам и увеличивает порог входа в профессию.
Доходит до абсурда, чтобы создать простую форму ввода пользовательских данных приходится конфигурировать сначала babel, потом webpack, а затем еще и разбираться с настройками специфичными для выбранного фреймворка… А это пожалуй слишком много новых слов для новичка в команде, которому поручили эту простую на вид задачку. Нет, скорее всего проект уже будет настроен и сконфигурирован и новичка конечно же не бросят одного на произвол судьбы вкратце рассказав ему что по чем. Но стоит признать, что это действительно стало слишком сложно и мы похоже тратим значительную часть времени на все эти системы сборки и борьбу с конфигурацией.
Но давайте попробуем вспомнить — разве так было всегда? Разве о таком будущем мечтали создатели паутины? Нет, черт возьми, и еще раз нет! Ведь какой-никакой, часто неказистый, наполненный трюками и фокусами но веб был другим — простым и понятным! Вот мы добавили скрипт, вот стиль, а тут наша разметка страницы. Так что же пошло не так, неужели все стало на самом деле так плохо? Ведь javascript да и весь веб только рос и улучшался, язык становился сильнее и выразительнее, появилась модульность, стало очевидным преимущество различных архитектурных шаблонов и все же — где та былая простота? Неужели мы потеряли ее навсегда?
(Великолепный человек-паук)
Ответ на самом деле достаточно прост и прямолинеен. Веб действительно вырос и стал сложнее, теперь не редкость встретить мультимедийное приложение полностью написанное под веб технологии или 3д игру в браузере, что было немыслимо еще 10 лет назад. Но главная проблема в том, что мы часто хотим от веба того, что он еще не готов нам дать — новейшие технологии и стандарты, экспериментальные архитектурные шаблоны, все только самое новое и современное и конечно это должно работать везде и у всех, и побыстрее пожалуйста. И тут на сцене появляется дикая банда во главе с webpack и начинает править бал. И вот вы уже обвешаны сложными конфигурациями и ваш проект собирается полторы минуты и весит полсотни мегабайт. Finito la comedia. Начинается борьба с конфигурацией в попытке выжать еще немного производительности и сократить размер. И о какой разработке и воплощении идей тогда может вообще идти речь, если львиную долю времени мы проводим за настройками сборочной линии. Признавайтесь, кто у вас в команде эксперт по webpack?
Мы не то чтобы привыкли к этому, но скорее смирились, что это нормально, ну а и как иначе? Мы обвешались типами и фреймворками, корпоративность, безопасность — даже не придерешься. Но куда же девалась эта легкость и простота эксперимента, для которой был задуман этот слабо типизированный динамичный язык? А все, нет ее, пропала под горами бандлов и энтерпрайза. Но неужели совсем ничего нельзя сделать?
Тут стоит остановиться и задуматься, а что мы вообще делаем и зачем? Ведь если мы используем webpack, rollup, parcel (нужное подчеркнуть) и создаем все эти нечитаемые бандлы которые потом невозможно дебажить даже с source maps, то ведь это точно кому-нибудь нужно, ведь так? Да, все так, для быстрого и эффективного продакшена от бандлов никуда не денешься и даже новомодный HTTP2 не сделал задачу сильно проще. Потому и пакуют разработчики сидя в офисе долгими осенними вечерами, засиживаясь подольше на работе и сжигая сотни тысяч киловатт энергии, пакуют отделами, пакуют компаниями, пакуют всем миром передавая смену с движением солнца. Так уж повелось, и таков закон. Dura lex, sed lex. Так что поистине шекспировский вопрос бандлить или не бандлить — погибает даже не успев сорваться с уст юного Гамлета открывшего visual studio, чтобы сваять очередной шедевр.
(Все в порядке)
Но постойте, вы же сказали, что это все необходимо для продакшена, а что насчет разработки? Почему нельзя комфортно разрабатывать как в старые добрые времена просто запустив сервер и потом уже упаковывать все перед самой отправкой на продакшн? И почему мы вообще пользуемся одними и теми же инструментами для продакшена и разработки? Почему бы не использовать решение заточенное специально для разработки, ведь то что мы делаем выглядит как-то не особо логично.
И это действительно не логично и мы скорее делаем так за отсутствием альтернатив или просто потому, что привыкли. Но что если я скажу, что у вас есть выбор?
Встречайте hq — специализированный сервер для разработки веб приложений. hq — это статический сервер на стероидах, который понимает все то, что обычному серверу не по зубам. Хотите последнюю фишку из стандарта javascript, но ваш браузер ее еще не поддерживает? — пожалуйста! Ваша библиотека использует commonjs формат — нет проблем! Долой разномастные инструменты заточенные для работы с каждым конкретным фреймворком, hq поддерживает их всех, прямо из коробки. hq настолько крут, что не требует никакой конфигурации, он просто работает и делает свое дело. Нет parcel все не так как у тебя, hq НА САМОМ ДЕЛЕ не требует никакой конфигурации, ее просто нет, так что деваться некуда. Установите его единожды
и затем запускайте одной командой в корне проекта, чтобы начать экспериментировать немедленно
Ну скажете вы, примерно то же предлагала нам и старая банда, ну может чуть побольше конфигурации, чуть менее просто, но все примерно очень похоже, так зачем нам этот новый Чак Норрис в мире дев серверов? И тут я отвечу вам новым девизом дома Грейджой — “Мы не бандлим!”. Да, на самом деле, мы не бандлим!
(Дом Грейджой. Мы не сеем бандлим)
Привет, я занимаюсь веб разработкой с 13-ти лет и я начал бандлить когда мне было 19. Меня на это подсадил мой друг, когда я зашел к нему в гараж где он бандлил дни и ночи на пролет. Я спросил, что это ты делаешь? И он сказал, что это новая штука, это теперь очень модно и круто и я обязательно должен попробовать. Сначала я просто клеил файлы, а потом попробовал небольшой бандл с closure compiler и потом уже не смог остановиться. gulp, browserify, а потом и webpack… Мои бандлы становились все тяжелее. Я не знал как остановиться, я попал в круговорот который не давал мне выйти. Каждый раз когда я попадал на новый проект там уже кто-то бандлил и отказаться было просто невозможно. Не бандлить стало не престижно! Люди из профессии и даже близкие друзья отказывались от общения и не перезванивали мне, когда узнавали, что я хочу перестать. Так что деваться было некуда. Но теперь я чист! Я больше не бандлю во время разработки! Со мной перестали бандлить и мои друзья и знакомые, это теперь не принято у нас в компании. И знаете что? Я никогда не чувствовал себя так хорошо! Мир наконец-то заиграл новыми красками и начало находиться время и на работу и на семью.
Серьезно, отсутствие бандлов сильно упрощает жизнь. Вспомните невыносимые ситуации, когда невозможно поставить break point не то что на выражение, а даже на нужную строку! Или эти имена переменных сгенерированных webpack __webpack__@#%^$. При их прочтении не мудрено и сатану вызвать, а писать их в консоль и врагу не пожелаешь, а что самое противное они скрыты за нормальными, человеческими именами, так что их еще поди угадай. В общем отладка частенько превращается в ад, даже с полноценными source maps. Сколько раз в день вы материте код находящийся внутри node_modules? Сколько проклятий сыпятся на голову несчастным разработчикам React и Angular потому, что невозможно понять сообщение об ошибке и где эта ошибка возникает? После того как мы перешли на hq, мы забыли все это как страшный сон. Времени стало реально больше, теперь не приходится ломать голову почему оно не собирается или просто молча не работает и откуда у нас в билде взялась еще вот эта библиотека на десять мегабайт, теперь прекрасно видно откуда! Страданий стало меньше, работа стала проще и получается делать ее в удовольствие.
(Этот человек — Варг или меняющий кожу, он может проникать в сознание животных. Сейчас он парит вместе с орлом, высматривая врага)
Самое приятное, что hq не кажется чем-то новым и сложным, такое ощущение, что он был с нами всегда, настолько все просто и привычно. hq — это статический сервер который просто понимает тебя. Старт нового проекта становится невероятно быстрым, одна команда в консоли и можно начать экспериментировать. Фреймворки, библиотеки, форматы, архитектурные подходы — все это больше не создает барьеров, с hq все просто работает как в старые добрые времена, быстро, просто и логично! Плюс ко всему hq опенсорс проект так что всегда можно что-то улучшить или добавить поддержку какого-нибудь нового формата.
Признаться честно, мы нашли и недостатки. Раньше, когда сборка с webpack занимала несколько минут это было чудесным оправданием чтобы заглянуть на кухню за чашечкой ароматного кофе, теперь же все работает настолько быстро, что времени для этого просто нет. Хотя, нужно ли вообще искать оправдание для хорошего кофе?
Как же это все работает? Тут может сложиться впечатление, что hq это здоровенный монстр сотканный доктором Франкенштейном из множества разнородных и несвязных частей приправленый толикой черной магии. Но на самом деле все достаточно стройно и единообразно. hq раздает каждый файл индивидуально по запросу, так же как, как это делает обычный статический сервер. Это дает нам всего лишь ограниченную возможность избавиться от неиспользуемого кода, без полноценного tree shaking, но зато экономит много времени которое тратилось на анализ зависимостей. Все трансформации происходят мгновенно и на лету. Более того, трансформируется лишь необходимый минимум. Если вы используете современный браузер и придерживаетесь веб стандартов, то ваш код вряд ли будет изменен вообще. В то время когда вы можете уповать на стандарты, нет никакой гарантии, что библиотеки к которым вы так привыкли будут делать то же самое. Большинство из них наверняка будут поставляться в формате commonjs, что не позволяет им работать в браузере как есть. hq заботится и об этом преобразуя commonjs модули в формат ESM, обрабатывает не стандартные, но довольно распространенные импорты (такие как css или json) и деструктуризирует импортируемые объекты, когда это нужно. hq работает в связке с веб браузером, используя его систему кэширования, чтобы ускорить доставку асетов и передавать лишь файлы которые были изменены. Он автоматически перезагрузит страницу когда вы измените свой код, так что вы мгновенно сможете оценить результат изменений. hq может работать с множеством фреймворков, но не зависит от их кода. Вместо этого hq производит серию AST трансформаций с помощью плагинов для babel, которые были специально созданы для hq, чтоб он смог понять и преобразить разнообразие технологий и подходов используемых в разработке к единому стандарту поддерживаемому браузером.
Таким образом не смотря на все сложности и вызовы предъявляемые современным вебом, разработка проектов может оставаться простой и интуитивно понятной, так же как это было на заре веб технологий. Попробуйте hq сейчас, чтобы улучшить опыт разработки в старом проекте, или используйте его, чтобы создать новый захватывающий проект!
Собираем бандл мечты с помощью Webpack
JS-приложения, сайты и другие ресурсы становятся сложнее и инструменты сборки — это реальность веб-разработки. Бандлеры помогают упаковывать, компилировать и организовывать библиотеки. Один из мощных и гибких инструментов с открытым исходным кодом, который можно идеально настроить для сборки клиентского приложения — Webpack.
Максим Соснов (crazymax11) — Frontend Lead в N1.RU внедрил Webpack в несколько больших проектов, на которых до этого была своя кастомная сборка, и контрибьютил с ним несколько проектов. Максим знает, как с Webpack собрать бандл мечты, сделать это быстро и конфигурировать так, чтобы конфиг оставался чистым, поддерживаемым и модульным.
Интеграция Webpack в типичный проект
Обычно порядок внедрения такой: разработчик где-то прочитал статью про Webpack, решает его подключить, начинает встраивать, как-то это получается, все заводится, и какое-то время webpack-config работает — полгода, год, два. Локально все хорошо — солнце, радуга и бабочки. А потом приходят реальные пользователи:
— С мобильных устройств ваш сайт не загружается.
— У нас все работает. Локально все хорошо!
На всякий случай разработчик идет все профилировать и видит, что для мобильных устройств бандл весит 7 Мбайт и грузится 30 секунд. Это никого не устраивает и разработчик начинает искать, как решить проблему — может подключить лоадер или найти волшебный плагин, который решит все проблемы. Чудесным образом такой плагин находится. Наш разработчик идет в webpack-config, пытается установить, но мешает строчка кода:
Строчка переводится так: «Если config собирается для production, то возьми седьмое правило, и поставь там опцию magic = true ». Разработчик не знает, что с этим делать и как решать. Это ситуация, когда нужен бандл мечты.
Как собрать бандл мечты?
Для начала определим, что это такое. Прежде всего, у бандла мечты две основные характеристики:
Оценить размер бандла
Самое популярное решение — это плагин WebpackBundleAnalyzer. Он собирает статистику сборки приложения и рендерит интерактивную страничку, на которой можно посмотреть расположение и вес каждого модуля.
Если этого мало, можно построить граф зависимостей с помощью другого плагина.
Если и этого недостаточно, и вы хотите продать Webpack маркетологам, то можно построить целую вселенную, где каждая точка — это модуль, как звезда во Вселенной.
Инструментов, которые оценивают размер бандла и следят за ним, очень много. Есть опция в конфиге Webpack, которая рушит сборку, если бандл слишком много весит, например. Есть плагин duplicate-package-checker-webpack-plugin который не даст собрать бандл, если у вас 2 npm-пакета разных версий, например, Lodash 4.15 и Lodash 4.14.
Как уменьшить бандл
Выкинуть лишнее
Оказывается, когда вы добавляете в дате день, час или просто хотите поставить ссылку «через 15 минут» с помощью moment.js, вы подключаете целых 230 Кбайт кода! Почему так происходит и как это решается?
Загрузка локали в moment
В moment.js есть функция, которая устанавливает локали:
Из кода видно, что локаль загружается по динамическому пути, т.е. вычисляется в рантайме. Webpack поступает умно и пытается сделать так, чтобы ваш бандл не упал во время выполнения кода: находит все возможные локали в проекте, и бандлит их. Поэтому приложение весит так много.
Решение очень простое — берем стандартный плагин из Webpack и говорим ему: «Если увидишь, что кто-то хочет загрузить много локалей, потому что не может определить какую, — возьми только русскую!»
Webpack возьмет только русскую, а WebpackBundleAnalyzer покажет 54 Кb, что уже на 200 Kb легче.
Dead code elimination
Следующая оптимизация, которая нас интересует — Dead code elimination. Рассмотрим следующий код.
Теперь перейдем к более продвинутому способу Dead code elimination — Tree shaking.
Tree shaking
Допустим, у нас есть приложение, которое использует Lodash. Я сильно сомневаюсь, что кто-то применяет весь Lodash целиком. Скорее всего, эксплуатируется несколько функций типа get, IsEmpty, unionBy или подобных.
Когда мы делаем Tree shaking, мы хотим от Webpack, чтобы он «потряс» ненужные модули и выкинул их, а у нас остались только необходимые. Это и есть Tree shaking.
Как работает Tree shaking в Webpack
Допустим, у вас есть такой код:
Код очень простой: из какого-то модуля импортируете переменную a и выводите ее. Но в этом модуле есть две переменные: a и b. Переменная b нам не нужна, и мы хотим ее убрать.
Когда придет Webpack, он преобразует код с импортом в такой:
Зависимость Webpack преобразует в следующий код:
Webpack оставил экспорт переменной a, и убрал экспорт переменной b, но саму переменную оставил, пометив её специальным комментарием. В преобразованном коде переменная b не используется, и UglifyJS может ее удалить.
Tree shaking в Webpack работает, только если у вас есть какой-нибудь минификатор кода, например, UglifyJS или babel-minify.
Рассмотрим случаи интереснее — когда Tree shaking не работает.
Когда Tree shaking не работает
Кейс № 1. Вы пишете код:
Прогоняете код через Webpack, и он остается таким же. Все потому, что бандлер организует Tree shaking, только если вы используете ES6 модули. Если применяете CommonJS модули, то Tree shaking работать не будет.
Кейс № 2. Вы пишете код с ES6 модулями и именованными экспортами.
Если ваш код прогоняется через Babel и вы не выставили опцию modules в false, то Babel приведет ваши модули к CommonJS, и Webpack опять же не сможет выполнить Tree shaking, ведь он работает только с ES6 модулями.
Соответственно, нам нужно быть уверенными, что никто в нашем пайплане сборки не будет транспайлить ES6 модули.
Когда вы пишете классы и прогоняете их через Babel, они никогда не вырезаются. Как это исправляется? Есть стандартизованный хак — добавить коммент /*#__PURE__*/ перед функцией:
Тогда UglifyJS поверит на слово, что следующая функция чистая. К счастью, сейчас это делает Babel 7, а в Babel 6 до сих пор ничего не удаляется.
Правило: если у вас где-то есть сайд-эффект, то UglifyJS ничего не сделает.
Загружаем только нужный функционал
Эту часть разобьем на две. В первой части загружается только код, который требует пользователь: если пользователь заходит на главную страницу вашего сайта, он не загружает страницы личного кабинета. Во второй, правки в коде приводят к минимально возможной перезагрузке ресурсов.
Загружаем только необходимый код
Рассмотрим структуру воображаемого приложения. В нем есть:
Первая проблема, которую мы хотим решить — это вынесение общего кода. Обозначим красным квадратиком общий код для всех страниц, зеленым кружком — для главной и страницы поиска. Остальные фигуры не особо важны.
Когда пользователь придет на поиск с главной страницы, он будет перезагружать и квадратик, и кружок второй раз, хотя они у него уже есть. В идеале мы хотели бы видеть примерно это.
Хорошо, что в Webpack 4 уже есть встроенный плагин, который это делает за нас — SplitChunksPlugin. Плагин выносит код приложения или код node modules, который используется несколькими чанками в отдельный чанк, при этом гарантирует, что чанк с общим кодом будет больше 30 Kb, а для загрузки страницы требуется загрузить не больше 5 чанков. Стратегия оптимальна: слишком маленькие чанки загружать невыгодно, а загрузка слишком большого количества чанков — долго и не так эффективно, как загрузка меньшего количества чанков даже на http2. Чтобы повторить такое поведение на 2 или 3 версии Webpack, приходилось писать 20–30 строк с не документированными фичами. Сейчас это решается одной строкой.
Вынос CSS
Было бы прекрасно, если бы мы еще вынесли CSS для каждого чанка в отдельный файл. Для этого есть готовое решение — Mini-Css-Extract-Plugin. Плагин появился только в Webpack 4, а до него не было адекватных решений для такой задачи — только хаки, боль и простреленные ноги. Плагин выносит CSS из асинхронных чанков и создан специально для этой задачи, которую выполняет идеально.
Минимально возможная перезагрузка ресурсов
Разберемся, как бы нам сделать так, чтобы при релизе, например, нового промо-блока на главной странице пользователь перезагружал бы минимально возможную часть кода.
Если бы у нас было версионирование — всё было бы хорошо. Вот у нас главная страница версии N, а после релиза промо-блока — версии N+1. Webpack предоставляет подобный механизм прямо из коробки с помощью хэширования. После того, как Webpack соберет все ассеты, — в данном случае app.js, — то посчитает его контент-хэш, и добавит его к имени файла, чтобы получилось app.[hash].js. Это и есть версионирование, которое нам нужно.
Давайте теперь проверим как это работает. Включим хэши, внесем правки на главной странице, и посмотрим — действительно ли изменился код только главной страницы.Мы увидим, что изменились два файла: main и app.js.
Почему так произошло, ведь это нелогично? Чтобы понять почему, давайте разберем app.js. Он состоит из трех частей:
В Webpack 3 и 2 мы бы написали 5-6 строк, вместо одной. Это не сильно больше, но все равно лишнее неудобство.
Все здорово, мы научились выносить ссылки и рантайм! Давайте напишем новый модуль в main, зарелизим, и — оп! — теперь вообще все перезагружается.
Почему так? Давайте разберемся, как работают модули в webpack.
Модули в webpack
Допустим, есть такой код, в котором вы добавляете модули a, b, d и e:
Webpack преобразует импорты в require: a, b, d и e заменились на require(0), require (1), require (2) и require (3).
Представим картину, которая очень часто случается: вы пишете новый модуль c import c from ‘c’; и вставляете его где-то посередине:
Когда Webpack будет все обрабатывать, то преобразует импорт нового модуля в require(2):
Модули d и e, которые были 2 и 3, получат цифры 3 и 4 — новые id. Из этого следует простой вывод: использовать порядковые номера как id немного глупо, но Webpack это делает.
Не используйте порядковый номер как уникальный id
Для исправления проблемы есть встроенное решение Webpack — HashedModuleIdsPlugin:
Этот плагин вместо цифровых id использует 4 символа md4-хэша от абсолютного пути до файла. С ним наши require превратятся в такие:
Вместо цифр появились буквы. Конечно, есть скрытая проблема — это коллизия хэшей. Мы на нее натыкались один раз и можем советовать использовать 8 символов, вместо 4. Настроив хэши правильно, все будет работать так, как мы изначально и хотели.
Мы теперь знаем, как собирать бандл мечты.
Как собрать бандл мечты быстро?
У нас в N1.RU самое большое приложение состоит из 10 000 модулей и без оптимизаций собирается 28 минут. Мы смогли ускорить сборку до двух минут! Как же мы это сделали? Существует 3 способа ускорения любых вычислений, и все три применимы к Webpack.
Параллелизация сборки
Первое, что мы сделали — распараллелили сборку. Для этого у нас есть:
Кэширование результатов сборки
Кэшировать результаты сборки — наиболее эффективный способ ускорения сборки Webpack.
Первое решение, которое у нас есть — cache-loader. Это лоадер, который встает в цепочку лоадеров и сохраняет на файловую систему результат сборки конкретного файла для конкретной цепочки лоадеров. При следующей сборке бандла, если этот файл есть на файловой системе и уже обрабатывался с этой цепочкой, cache-loader возьмет результаты и не будет вызывать те лоадеры, которые стоят за ними, например, Babel-loader или node-sass.
На графике представлено время сборки. Синий столбик — 100% время сборки, без cache-loader, а с ним — на 7% медленнее. Это происходит потому что cache-loader тратит дополнительное время на сохранение кэшей на файловую систему. Уже на а второй сборке мы получили ощутимый профит — сборка прошла в 2 раза быстрее.
Второе решение более навороченное — HardSourcePlugin. Основное отличие: cache-loader — это просто лоадер, который может оперировать только в цепочке лоадеров кодом или файлами, а HardSourcePlugin имеет почти полный доступ к экосистеме Webpack, умеет оперировать другими плагинами и лоадерами, и сам немного расширяет экосистему для кэширования. На графике выше видно, что на первом запуске время сборки увеличилось на 37%, но ко второму запуску со всеми кэшами мы ускорились в 5 раз.
Самое приятное, что можно использовать оба решения вместе, что мы в N1.RU и делаем. Будьте осторожны, потому что с кэшами есть проблемы, о которых я расскажу чуть позже.
В уже используемых вами плагинах/лоадерах могут быть встроенные механизмы кэширования. Например, в babel-loader очень эффективная система кэширования, но почему-то по умолчанию она выключена. Такой же функционал есть в awesome-typeScript-loader. В UglifyJS плагине тоже есть кэширование, которое замечательно работает. Нас он ускорил на несколько минут.
Проблемы кэширования
На чем сэкономить в production?
Последний способ ускорить какой-либо процесс — не делать какие-то части процесса. Давайте подумаем, на чем можно сэкономить в production? Что мы можем не делать? Ответ короткий — мы ничего не можем не делать! Мы не вправе отказаться от чего-то в production, но можем хорошо сэкономить в dev.
Ускорение сборки — это параллелизация, кэширование и отказ от вычислений. Выполнив эти три простых шага, вы можете ускориться очень сильно.
Как конфигурировать Webpack?
Эволюция конфига в проекте
Типичный путь webpack-конфиг в проекте начинается с простого конфига. Сначала вы просто вставляете Webpack, Babel-loader, sass-loader и все хорошо. Потом, неожиданно, появляются какие-то условия на process.env, и вы вставляете условия. Одно, второе, третье, все больше и больше, пока не добавляется условие с «магической» опцией. Вы понимаете, что все уже совсем плохо, и лучше просто продублировать конфиги для dev и production, и сделать правки два раза. Все будет понятнее. Если у вас мелькнула мысль: «Что-то здесь не так?», то единственный работающий совет — держать конфиг в порядке. Расскажу, как мы это делаем.
Держать конфиг в порядке
Мы используем пакет webpack-merge. Это npm-пакет, который создан, чтобы объединять несколько конфигов в один. Если вас не устраивает стратегия объединения по умолчанию, то можно кастомизировать.
Структура проекта с конфигом
У нас есть 4 основные папки:
Plugin/Loader
Это папки, которые содержат файлы для каждого лоадера и плагина, с подробной документацией и более человеческим API, чем тот, что предоставляют разработчики плагинов и лоадеров.
Выглядит это примерно так:
Есть модуль, он экспортирует функцию, которая имеет опции, и есть документация. На словах выглядит хорошо, а в реальности наши доки к url-loader выглядят так:
Мы рассказываем в простой форме, что он делает, как работает, описываем, какие параметры принимают функции, что создает лоадер, и даем ссылку на доки. Я надеюсь, что тот, кто сюда зайдет, точно поймет, как работает url-loader. Сама функция выглядит так:
Мы принимаем два параметра и возвращаем описание от лоадера. Не следует бояться того, что папка Loader будет громоздкой и на каждый лоадер будет по файлу.
Preset
Это набор опций webpack. Они отвечают за одну функциональность, при этом оперируют лоадерами и плагинами, которые мы уже описали, и настройками webpack, которые у него есть. Самый простой пример — это пресет, который говорит, как правильно загружать scss-файлы:
Он использует уже преподготовленные лоадеры.
Части — это то, что уже лежит в самом приложении. Они настраивают точку входа и выхода вашего приложения, и могут регулировать или подключать специфичные плагины, лоадеры и опции. Типичный пример, где мы объявляем точку входа и выхода:
В своей практике мы используем:
Webpack-merge просто выдает нам готовый конфиг. С этим подходом у нас всегда есть документация к конфигурации, в которой достаточно просто разобраться. С webpack-merge мы не лазим по 3-7 конфигам, чтобы поправить везде Babel-loader, потому что у нас есть консистентная конфигурация отдельных частей по всему проекту. А еще интуитивно понятно, где делать правку.
Управление конфигом
Подведем итоги. Используйте готовые инструменты, а не стройте велосипеды. Документируйте решения, потому что webpack конфиги правятся редко и разными людьми — поэтому документация там очень важна. Разделяйте и переиспользуйте то, что пишете.
Теперь вы знаете, как собирать бандл мечты!
Это доклад — один из лучших на Frontend Conf. Понравилось, и хотите больше — подпишитесь на рассылку, в которой мы собираем новые материалы и даем доступ к видео, и приходите на Frontend Conf РИТ++ в мае.
Хотите рассказать миру что-то крутое по фронтенду из своего опыта? Подавайте доклады на FrontenConf РИТ++, который пройдет 27 и 28 мая в Сколково. Присылайте тезисы до 27 марта, а до 15 апреля ПК примет решение о включении доклада в программу конференции. Мы ждем ваш опыт — откликайтесь!