Сегодня мы поговорим о сборщиках проектов (о бандлерах), об инструментах, которые облегчают жизнь разработчиков. Суть работы бандлеров заключается в том, что они берут JavaScript-код, содержащийся во множестве файлов, и упаковывают его в один или несколько файлов, определённым образом упорядочивая и подготавливая к работе в браузерах. Более того, благодаря различным подключаемым модулям (плагинам) и загрузчикам, код можно минифицировать, можно упаковывать, помимо кода, и другие ресурсы (вроде CSS-файлов и изображений). Бандлеры позволяют использовать препроцессоры, умеют разделять код на фрагменты, загружающиеся тогда, когда в них возникнет необходимость. Но их возможности этим не ограничиваются. Фактически, речь идёт о том, что они помогают организовывать процесс разработки.

image

Существует множество бандлеров. Например — Browserify и webpack. Хотя эти сборщики проектов представляют собой замечательные инструменты, лично я обнаружил, что их сложно настраивать. С чего начать настройку? Этот вопрос особенно актуален для новичков, для тех, кого может немного испугать такое понятие, как «конфигурационный файл».

Именно поэтому я, как правило, пользуюсь сборщиком проектов Parcel. Я наткнулся на этот бандлер случайно, когда смотрел одно учебное видео на YouTube. Там давались советы по ускорению разработки. Показанная в этом видео рабочая среда была сильно завязана на Parcel. После этого я решил, что и мне стоит попробовать этот бандлер.

Особенности Parcel


Мне в Parcel больше всего нравится то, что он совершенно не требует настройки. Именно так: конфигурировать его не нужно. В этом плане Parcel выигрывает у webpack, где настройки могут быть разбросаны по нескольким файлам и представлять собой целые «простыни» кода. Разработчик, настраивая webpack, возможно, взял что-то из конфигурационных файлов других программистов. Возможно, что настройки попросту целиком скопированы из других проектов. Ясно, что сложность конфигурации зависит от разработчика, но даже при настройке webpack для небольшого проекта требуется задействовать некий набор плагинов и установить определённые опции.

Именно поэтому использование Parcel и кажется мне удачным ходом. Например, если разработчик планирует стилизовать свой проект с помощью SCSS или LESS, то он может, без лишних движений, просто написать соответствующий код. Хочется использовать самые свежие возможности JavaScript? Если так — можно, ни о чём не задумываясь, писать код с использованием этих возможностей. Нужен сервер для разработки? У того, кто пользуется Parcel, есть такой сервер. На самом деле, тут мы лишь едва коснулись верхушки айсберга обширных возможностей Parcel.

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

Сфера использования Parcel


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

Я уже говорил о том, насколько быстро Parcel позволяет выйти на функционирующий проект. Благодаря этому он идеально подходит для работы в условиях жёстких временных рамок и для создания прототипов. Речь идёт о ситуациях, когда время дорого, и когда целью разработчиков является как можно более быстрое создание работающего приложения.

Это не значит, что Parcel не подходит для сложных приложений, или для проектов, в работе над которыми участвуют большие команды программистов. Parcel хорошо показывает себя и в таких условиях. Однако я понял, что крупномасштабным проектам может пойти на пользу ручная настройка рабочих процессов.

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

Я работал над одним многостраничным сайтом, в недрах которого имелось много JavaScript-кода. Parcel отлично показал себя в этом проекте. Он дал мне сервер, он компилировал Sass в CSS, добавлял в код, при необходимости, префиксы производителей браузеров, позволял, без каких-либо настроек, использовать в JavaScript-файлах команды экспорта и импорта. Всё это значительно облегчило мне работу над проектом.

Создание простого сайта с использованием Parcel


Давайте устроим Parcel тест-драйв. Это позволит нам увидеть то, что создать что-то с помощью этого бандлера сравнительно просто. Вот страничка, над которой мы будем работать.


Страница экспериментального проекта

Мы собираемся создать простой сайт, в котором будет использоваться Sass и немного JavaScript. Мы будем выводить на страницу сайта сведения о текущем дне недели и случайное изображение, загруженное с Unsplash Source.

?Базовая структура проекта


Проект, в котором планируется использовать Parcel, не нуждается в особой структуре файлов и папок. В нём необязательно использовать некий фреймворк. Базовая структура проекта будет представлять собой три файла, имена которых говорят сами за себя. Это — index.html, style.scss и index.js. Создать их можно так, как вам удобно. Например — с помощью командной строки:

mkdir simple-site
cd simple-site
touch index.html && touch style.scss && touch index.js

Добавим в файл index.html немного шаблонного кода и разметку, на которой будет основан функционал проекта:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link href="https://fonts.googleapis.com/css?family=Lato&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.scss">
  <title>Parcel Tutorial</title>
</head>
<body>
  <div class="container">
    <h1>Today is:</h1>
    <span class="today"></span>
    <h2><font color="#3AC1EF">and the image of the day:</font></h2>
    <img align="center" src="https://source.unsplash.com/random/600x400" alt="unsplash random image">
</div>
<script src="index.js"></script>
</body>
</html>

Вы могли заметить, что тут я загружаю веб-шрифт (Lato) из Google Fonts. Использование загружаемых шрифтов — это дело добровольное. Здесь стоит обратить внимание на подключение CSS и JavaScript-файлов, и на HTML-код тела документа, в котором предусмотрено место для вывода сведений о дне недели, и место для вывода случайного изображения из Unsplash. Собственно говоря, на этом работа над базовой структурой проекта завершена.

?Чудо быстрой подготовки Parcel к работе


Теперь, прежде чем перейти к стилизации и к написанию скриптов, попробуем запустить наш проект с помощью Parcel. В установке Parcel ничего необычного нет:

npm install -g parcel-bundler
# или
yarn global add parcel-bundler

Теперь инициализируем проект с помощью npm или yarn, что приведёт к созданию файла package.json:

npm init -y
# или
yarn init -y

Вот и всё! Больше никаких настроек выполнять не нужно. Всё, что нам осталось сделать — это сообщить Parcel о том, какой файл является входной точкой проекта. Это позволит бандлеру узнать о том, что его серверу нужно отдавать клиентам.

В нашем случае таким файлом будет index.html:

parcel index.html

В консоли, после успешного запуска сервера, будет выведено примерно следующее:

Server running at http://localhost:1234
v  Built in 13ms.

Сервер Parcel поддерживает «горячую» перезагрузку. Бандлер выполняет пересборку приложения каждый раз, когда сохраняются изменения, внесённые в файлы проекта.

Вернёмся в папку проекта. Здесь можно увидеть новые папки и файлы, созданные бандлером.


Новые папки и файлы, созданные бандлером

Нас здесь особенно интересует папка dist. Она содержит весь скомпилированный код, включая карты кода для CSS и JavaScript.

?Продолжение работы над проектом


Перейдём в файл style.scss и ознакомимся с тем, как Parcel обрабатывает Sass-код. Я создал тут несколько переменных, используемых для хранения цветов и ширины контейнера, в котором размещается содержимое страницы:

$container-size: 768px;
$bg: #000;
$text: #fff;
$primary-yellow: #f9f929;

Теперь, в тот же файл, добавим описания стилей. Тут вы можете создать то, что вам нравится. Я, например, поступил так:

*, *::after, *::before {
  box-sizing: border-box;
}

body {
  background: $bg;
  color: $text;
  font-family: 'Lato', sans-serif;
  margin: 0;
  padding: 0;
}

.container {
  margin: 0 auto;
  max-width: $container-size;
  text-align: center;

  h1 {
    display: inline-block;
    font-size: 36px;
  }

  span {
    color: $primary-yellow;
    font-size: 36px;
    margin-left: 10px;
  }
}

Как только этот файл будет сохранён — Parcel примется за работу, всё скомпилирует, и перезагрузит страницу в браузере. Нам ничего, кроме сохранения файла, делать не требуется. Parcel, по умолчанию, наблюдает за изменениями файлов.

Вот как будет выглядеть страница после стилизации.


Стилизованная страница

Осталось лишь вывести здесь название текущего дня недели. Мы, в ходе решения этой задачи, будем использовать команды импорта и экспорта. Это позволит проверить возможности Parcel по работе с современными механизмами JavaScript.

Создадим файл today.js и экспортируем из него функцию, которая возвращает, пользуясь массивом с названиями дней недели, название текущего дня:

export function getDay() {
  const today = new Date();
  const daysArr = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  return daysArr[today.getDay()];
}

Обратите внимание на то, что функция getDay первым днём недели считает воскресенье (Sunday).

Мы экспортировали из today.js функцию getDay. Теперь перейдём в файл index.js и импортируем в него эту функцию из файла today.js. Это приведёт к тому, что файл today.js будет обработан при сборке проекта.

import { getDay } from './today';

Parcel, без дополнительных настроек, поддерживает синтаксис ES6-модулей, поэтому мы можем пользоваться JS-файлах командами импорта и экспорта.

Теперь нам осталось лишь выбрать соответствующий элемент <span> и передать в него значение, возвращаемое функцией getDay. Добавим в index.html следующий код:

const day = document.querySelector('.today');
day.innerHTML = getDay();

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


Готовый проект

?Сборка проекта для продакшна


Мы создали приложение, а теперь мы хотим куда-нибудь его выложить. Это может быть наш собственный сервер, или что-то вроде Surge или Now, позволяющее максимально просто публиковать веб-проекты. При этом нам нужно, чтобы код проекта был бы скомпилирован и минифицирован.

Для приведения проекта в вид, пригодный для публикации, нам достаточно единственной команды:

parcel build index.html

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


Сборка проекта

Теперь в нашем распоряжении оказываются ресурсы приложения, готовые к развёртыванию его в продакшне. Здесь можно почитать подробности о том, как Parcel собирает продакшн-версии проектов, и найти некоторые советы, которые позволят повысить эффективность работы с этим бандлером.

Итоги


Я говорил это уже несколько раз, но повторюсь снова: Parcel — это отличный инструмент. Он позволяет собирать проекты, компилировать код, даёт в распоряжение программиста сервер разработки, выполняет предварительную обработку и пост-обработку ресурсов, минифицирует код. И этим его способности не ограничиваются. Здесь мы рассмотрели, вероятно, предельно простой пример, но я надеюсь, что он позволил вам ощутить возможности Parcel и помог узнать о том, как использовать этот бандлер в ваших проектах.

Уважаемые читатели! Каким бандлером вы пользуетесь?


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


  1. Zenitchik
    30.10.2019 14:24

    А без index.html нельзя?
    У меня типовой кейс — взять некоторый index.js, подтянуть все его зависимости, сложить вместе с учётом топологической сортировки (попутно выпилив код подключения зависимостей), минимизировать.


    1. casusbelli-dn
      30.10.2019 15:38

      Можно.
      parcel index.js


  1. i360u
    30.10.2019 14:30

    Я тестил Parcel, когда он еще не умел в ESM, и именно по этой причине, не смотря на привлекательность концепции, я не стал его использовать. Видимо, настало время дать ему второй шанс.


    1. JustDont
      30.10.2019 14:59

      Зачем?

      Проблема всех zero-configuration инструментов (а Parcel себя позиционирует именно так) в том, что или у вас в проекте строго то, на что рассчитывали авторы Parcel, или вам придётся натягивать сову на глобус (менять свой проект или дописывать в Parcel код для обработки именно вашего случая).

      Чудес не бывает, zero-configuration работает только тогда, когда предположения сторон друг об друге полностью сходятся.

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


      1. i360u
        30.10.2019 15:58

        Затем, что мне проще написать скрипт на ноде для сложных случаев, с гораздо более широкими возможностями, чем ковыряться в конфигах, обертках и чужих API. И, в этом контексте, гораздо приятнее работать с минималистичными специализированными инструментами на каждом из этапов. Rollup вполне подходит (именно его я и использую сейчас), но почему бы не попробовать альтернативу?


        1. JustDont
          30.10.2019 16:42

          Ну я несколько раз пробовал, но заканчивалось всё всегда одинаково: Parcel или работает, или не работает. Если происходит второе (а у меня всегда этот момент довольно быстро наступал), то проще (zero-configuration же) выкинуть Parcel и взять что-то куда более настраиваемое.


  1. casusbelli-dn
    30.10.2019 15:10

    Внедрил его в древний проект, что бы начать писать со всеми современными плюшками (модули, es6, препроцессор). Классная штука.


  1. Akuma
    30.10.2019 17:09

    Оно прям совсем без конфигурации?
    Может мне в «этом» проекте надо es5, а в «другом» es6?


    1. Metotron0
      30.10.2019 19:47

      Позволяет написать конфиги, если есть необходимость. У него документация маленькая и на русском, там это упомянуто.


  1. Metotron0
    30.10.2019 19:03

    Пользуюсь в основном vue, а в нём webpack. Для простеньких сайтов хотел задействоваь как раз parcel, но задач таких пока что нет. Недавно на работе проводил лекции про сборщикам, искал разные, сперва нашёл brunch, но в нём не понятно, как сделать autoprefixer вместе с scss, я смог только раздельно. Потом нашёл Parcel, но и он оказался не без конфигов — для нормального async/await потребовался .babelrc, и какая-то настройка в .postcssrc, наверное для автопрефиксера как раз. И ещё такую багу заметил, что в live режиме он с первой правки код обновляет, а дальше нет, пробовал на разных компьютерах, но с одним и тем же кодом с модулями и await, он просто не видит моих изменений.


    1. aleki
      31.10.2019 09:09

      Ну так .babelrc и .postcssrc — это не конфиги parcel, их и при использовании других сборщиков надо писать (в дополнение к конфигу самого сборщика).


      1. Metotron0
        01.11.2019 04:23

        Но он мог бы и сам догадаться об автопрефиксере и поддержке async/await. Тем более, что код он минифицирует, так почему не префиксит?
        Не так важно, чьи это конфиги, но их пришлось писать.


        1. aleki
          01.11.2019 11:46

          Эм, как он сам догадается? Вот я делаю себе личный сайт и мне плевать на пользователей старых браузеров, зачем мне autoprefixer?


          Как это не важно чьи это конфиги, может сборщик ещё и код за меня писать должен?


          1. justboris
            02.11.2019 10:50

            Нужно прописать список поддерживаемых браузеров в формате browserslist, все остальные инструменты это подхватят и не будет ни префиксов, ни транспиляции


      1. Free_ze
        01.11.2019 11:16

        В webpack для того же babel отдельный конфиг можно не заводить.


        1. aleki
          01.11.2019 11:47

          Потому что он будет прописан в опциях к loader'у. Не вижу разницы.


          1. Free_ze
            01.11.2019 12:01

            Разница в синтаксисе и отсутствии «обязательного» дополнительного файла-конфига.


            1. aleki
              01.11.2019 12:33

              Так это скорее минус, чем плюс. Лучше держать конфиги в отдельных файлах, потому что все конфиги не запихнёшь в webpack. В противном случае условные конфиги .prettierrc, .eslintrc или .huskyrc будут в отдельных файлах, а конфига .babelrc при этом рядом с ними лежать не будет, что только путает и усложняет навигацию.


              1. Free_ze
                01.11.2019 13:11

                Вы вольны либо всё аналогично пихать в webpack.config.js, либо выносить наружу в стандартные конфиги, хоть вместе, хоть по отдельности. Не вижу смысла об этом спорить.

                Я все же оспаривал с тезис про обязательность отдельных внешних конфигов в отличных от parcel js-бандлерах: это неправда как минимум для webpack, там все можно уложить в общий конфиг, с единым синтаксисом.


                1. aleki
                  01.11.2019 13:22

                  Я все же оспаривал с тезис про обязательность отдельных внешних конфигов в отличных от parcel js-бандлерах

                  Ещё бы знать, где вы увидели здесь такой тезис.


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

                  А вот это вранье. Я уже написал выше, ВСЁ не уложись в конфиг вебпака, поэтому и смысла в этом нет.


                  1. Free_ze
                    01.11.2019 13:33

                    где вы увидели здесь такой тезис.

                    .babelrc и .postcssrc — это не конфиги parcel, их и при использовании других сборщиков _надо_ писать (в дополнение к конфигу самого сборщика).
                    (с)

                    ВСЁ не уложись в конфиг вебпака

                    Из перечисленного:

                    husky, судя по документации, укладывается в и так существующий package.json, что логично, ибо к сборке он не относится.

                    Это всё.


                    1. aleki
                      01.11.2019 14:12

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


                      Из перечисленного:
                      postcss — уложился
                      babel — уложился
                      prettier — уложился
                      eslint — уложился

                      Расскажите-ка мне о поддержке различными редакторами этих конфигов.


                      1. Free_ze
                        01.11.2019 14:18

                        От того, что вы перенесли конфиги этих инструментов в конфиг вебпака, они не перестают быть конфигами

                        Что вы понимаете под конфигом вебпака, если не конфигурацию его лоадеров и плагинов?

                        Расскажите-ка мне о поддержке различными редакторами этих конфигов.

                        Может лучше свежий анекдот? Или любую другую информацию, которая так же не относится к теме обсуждения.


                        1. aleki
                          01.11.2019 14:26

                          Что вы понимаете под конфигом вебпака, если не конфигурацию его лоадеров и плагинов?

                          Сам по себе babel — не лоадер и у него есть свой конфиг, который можно пробросить через лоадер. Очевидно, как по мне. Иными словами, если вы добавили в зависимости babel-loader, то это не отменяет того, что вам также нужно добавить и сам babel. Аналогично и с другими инструментами. Странно, что это приходится по слогам объяснять.


                          Может лучше свежий анекдот? Или любую другую информацию, которая так же не относится к теме обсуждения.

                          Как это не относится? Напрямую относится. Если конфиги будут в отдельных файлах, то редакторы кода их охотно подхватывают, а если в webpack конфиге, то нормальной поддержки не жди.


                          Видимо, опыта у вас очень мало, поэтому продолжать этот разговор смысла дальше не вижу.


                          1. Free_ze
                            01.11.2019 14:33

                            Сам по себе babel — не лоадер и у него есть свой конфиг

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

                            Если конфиги будут в отдельных файлах, то редакторы кода их охотно подхватывают

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


                            1. aleki
                              01.11.2019 14:39

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

                              Действительно, невероятно.


                              Это позволяет вам заявлять, что конфигурировать можно исключительно через отдельные файлы?

                              Лучше научитесь читать и не присваивать другим слов, которых они не говорили, чтобы потом не оправдываться.


  1. Kroid
    31.10.2019 10:15

    В общем-то, в чем основная суть parcel'а — он самостоятельно устанавливает нужные плагины для разных расширений файлов. Добавил, к примеру, .ts файл — сборщик тут же установил пакет для тайпскрипт. Не нужно его перезагружать и что-то там дописывать в конфигах. Для простых проектов штука реально классная!


    Но он пока ещё слишком сырой. К примеру, девелоперский веб сервер не способен понять, что "./index.html" файл нужно отдавать по запросу "/", если хостишь всю папку.


    Ну и для не самых частых юзкейсов всё равно придётся писать конфиги.


  1. kireevmp
    31.10.2019 12:03
    +1

    Помимо всех плюсов, которые даёт этот восхитительный бандлер, есть парочка минусов, которые в статье не были упомянуты:


    • как только нужно подключать различные zero-runtime библиотеки (styled-components или linaria, например), требуются плагины, настроить которые с первого раза не получится. Хорошо, если получится со второго, а не с десятого.
    • иногда бывают проблемы, когда ломается файловый кэш и приходится его руками удалять, а иногда полностью переустанавливать все зависимости
    • бывает, что если в вашем коде была ошибка во время первой сборки parcel index.html, то всё сломается (в папку dist попадет корявый код), и придется заново перезапускать весь parcel.
    • parcel для node js иногда ведёт себя странно, не всегда запихивая зависимости в собранный файл. Поэтому будьте осторожны с этим, особенно, если деплоите на хероку — код, который работал локально может сломаться.

    И всё же, это лучший бандлер (по моему скромному мнению, не претендующему на истинность) для проектов средней и малой величины. Для домашних проектов точно стоит использовать именно его.