Webpack на практике: с нуля до создания автотестов
Это руководство поможет создать сборку для небольшого веб-приложения, а затем научит вас использовать Webpack для настройки автоматических тестов.
58К открытий58К показов
Язык JavaScript повсеместно используется для создания больших веб-сервисов. Для таких проектов приходится импортировать много стороннего кода (Lodash, React, Angular и др.). Из-за этого код усложняется, и в нём гораздо чаще возникают ошибки. Чем больше в вашем коде будет зависимостей, тем большей головной болью станет подключение тегов <script> в правильном порядке.
Webpack создаёт граф зависимостей для JavaScript, CSS и прочих, выдавая однофайловые сборки кода так, чтобы вы могли импортировать все необходимые ресурсы JavaScript всего одним тегом <script>.
Это руководство поможет создать сборку для небольшого веб-приложения, а затем научит вас использовать Webpack для настройки автоматических тестов.
Создание приложения
В качестве тестового приложения мы сделаем карту для ленивцев, которая поможет найти магазины в Кембридже, где продают травяной чай из гибискуса. Потому что каждый ленивец в кембриджском заповеднике Fresh Pond знает, что чай из гибискуса — лучший чай, чтобы умерить свой горячий темперамент!
%save-sc0%Создайте каталог с именем webpack-mocha-tutorial, в него добавьте другой каталог app/src и запустите пакетный менеджер npm init или yarn init. Исходный код приложения находится здесь. Также в статье будут ссылки на коммиты, чтобы прослеживать изменения кода по ходу чтения.
Основная структура приложения будет выглядеть так:
- У вас есть файл
app/src/distance.js, экспортирующий функцию, которая запускает формулу вычисления расстояния (на самом деле нужно использовать ортодому) и функцию, которая сообщает, какая точка из массива точек ближе всего находится.
- Также у вас есть файл
app/src/page.js, который использует код изdistance.js, чтобы вывести ближайший магазин из списка, а затем отобразить его на странице.
- И, наконец, у вас есть страница
index.html.
Общая структура каталогов такова:
Таким образом, файл distance.js определяет функции расстояния, затем файл page.js запускает их, помещая результат функции sortByDistance() в дерево документов (DOM). Но если посмотреть на зависимость между файлами, то видно, что файл page.js зависит от файла distance.js, а не наоборот (Commit 2).
Добавляем Webpack
Для работы с Webpack необходимо его установить с помощью npm или yarn:
Теперь у вас подключён Webpack и доступна его командная строка. Но прежде, чем можно будет запустить сборку, файл page.js должен импортировать код из distance.js. А distance.js экспортирует свои функции с помощью строки:
И чтобы page.js мог использовать экспортированную функцию sortByDistance(), добавляем строку:
Отлично, теперь все зависимости JavaScript связаны. Используем Webpack для создания приложения. Выполним следующую команду:
Сейчас вы должны увидеть новый файл dist/main.js, который содержит весь ваш код из page.js и distance.js. Далее получаем index.html с импортом dist/main.js вместо всех скриптов из app/src, изменив код страницы следующим образом:
Теперь можете открыть страницу в браузере, код по-прежнему должен работать. Поскольку файл main.js содержит весь код из distance.js и page.js, можно импортировать всё из одного файла.
Это работает так: с помощью команды $ npx webpack app/src/page.js вы указываете, что отправной точкой (в терминологии Webpack — точкой входа в ваш код JavaScript) является page.js. Webpack читает файл page.js и видит в нём строку import {sortByDistance} from ./distance. Теперь он знает, что distance.js является зависимостью к page.js. И из всех зависимостей в вашем коде Webpack строит граф и использует его для построения пакетного JavaScript-файла dist/main.js (Commit 3).
Webpack строит граф зависимостей из точки входа, page.js
Между прочим, это также работает, когда ваш код импортирует сторонние зависимости в каталог node_modules
Прим. перев.: все модули, используемые в npm, по умолчанию подключаются из директории node_modules.
Давайте попробуем выполнить некоторые манипуляции с графом зависимостей с помощью jQuery вместо document.getElementById(). Сначала установим jQuery:
$ yarn add --dev jquery
Затем обновим page.js, чтобы включить в него jQuery:
Теперь граф зависимостей выглядит так:
Ваш новый граф зависимостей, где page.js включает jQuery
И если выполнить $ npx webpack app/src/page.js и перезагрузить index.html (несмотря на то, что размер файла dist/main.js намного больше из-за кода jQuery) приложение по-прежнему работает.
Прежде чем продолжить, перейдите в файл package.json и добавьте эти три строчки:
Теперь, чтобы запустить сборку пакета, можно просто выполнить $ yarn build вместо $ npx webpack app/src/page.js. Если команда для сборки изменится, будет удобнее просто обновить её в файле package.json с помощью новой команды сборки и вы по-прежнему можете выполнять сборку с помощью $ yarn build, вместо того чтобы привыкать к запуску новой команды (Commit 4).
Настройка Webpack с помощью файла webpack.config.js
То, что можно сделать с помощью команды $ npx webpack app/src/page.js, является стандартным режимом работы Webpack. Если выполнить $ webpack [entry-file.js], то он создаст граф зависимостей из входного файла и выдаст пакетный файл dist/main.js. Но задать расположение точек входа и выхода программы можно, настроив файл конфигурации. Поместите следующий код в файл с именем webpack.config.js:
Теперь можно выполнить $ npx webpack или сделать ту же сборку, что и раньше, без указания точки входа в программу в аргументах командной строки, т. к. теперь всё это есть в webpack.config.js. Также это значит, что нужно обновить скрипт файла package.json следующим образом:
Если в файле конфигурации изменить путь вывода на что-то вроде __dirname + "/somewhere_else", то при повторном выполнении команды $ yarn build пакетный файл будет помещён в somewhere_else/main.js (Commit 5).
Файл конфигурации предназначен не только для настройки расположения входных и выходных файлов. Также можно настроить что именно Webpack делает, когда встречает файлы разных типов, используя специальные загрузчики, которые на самом деле являются JavaScript-программами, преобразующими ваш код. Например, в файле конфигурации может быть правило, определяющее, что, если Webpack встречает файл TypeScript в своём графе зависимостей, этот файл отправляется в загрузчик, который преобразует его из TypeScript в обычный JavaScript.
Загрузчик, который будет использоваться далее, — это Babel. Если вы не использовали его раньше, Babel — это инструмент, который берёт код JS, использующий современные функции, и преобразует его в эквивалент, совместимый со старыми версиями JavaScript. Это позволяет вашему приложению работать в старых браузерах или в браузерах, которые ещё не поддерживают некоторые новые функции JavaScript. В конце концов, некоторые ленивцы не обновляли свои браузеры с 2009 года. Некоторая часть написанного кода не будет работать в браузере 2009 года:
Здесь используется стрелочная функция и старые браузеры её не воспринимают. Поэтому используем загрузчик и отправим эту функцию в прошлое. Для начала выполним следующее:
Затем в файле webpack.config.js добавим следующий код в module.exports:
Этот код добавит новое правило в ваш Webpack. Если в дереве зависимостей Webpack встречает файл, который заканчивается на .js (например, distance.js), и этот файл отсутствует в папке node_modules (например, jQuery), то к этому файлу применяется данное правило.
Любой файл, который соответствует этому правилу, проходит через все загрузчики в блоке use (в данном случае только через загрузчик babel). Таким образом, файлы distance.js и page.js пройдут через загрузчик, что приведёт к удалению стрелочной функции в distance.js, а затем Webpack продолжит свой путь сборки. Тем временем, как только Webpack встречает jQuery, он просто загружает этот код как он есть без загрузчиков, поскольку jQuery находится в каталоге node_modules.
Теперь, если выполнить $ yarn build и посмотреть исходный код в dist/main.js, фрагмент, соответствующий вашей функции сортировки, использует ключевое слово function, а не стрелочную функцию (Commit 6).
Подсвеченный код на верхнем изображении — это функция sortByDistance() из dist/main.js до использования загрузчика, а подсвеченный код внизу — та же функция после добавления загрузчика. Обратите внимание на то, как выше мы используем стрелочную функцию, а ниже присутствует уже знакомое браузеру 2009 года ключевое слово function.
Теперь приложение готово к работе на устаревших браузерах. Чтобы этот код был поддерживаемым, следует написать несколько тестов для него.
Добавление тестовых сценариев в сборку
Добавим несколько тестовых сценариев в файл distance.js. Для этого будем использовать Mocha, пакетный инструмент для написания тестов, и Chai в качестве нашей библиотеки установок. Выполните следующую команду:
Затем создайте новый каталог app/test и новый файл app/test/distance.test.js, содержащий следующий фрагмент:
Теперь у вас есть тестовые сценарии для функций distance() и sortByDistance(), устанавливающие, что distance() вычисляет формулу расстояния, а sortByDistance() сортирует массивы координат с помощью формулы расстояния, используя наборы тестов Mocha и установки Chai. Довольно стандартная тестовая настройка.
Однако, если выполнить $ mocha app/test/distance.test.js, будет ошибка “Код JavaScript недопустим”, потому что он содержит ключевое слово import, которое Node в данный момент не поддерживает. Но что если обойти это ограничение, используя Webpack для управления зависимостями тестового кода?
Прим.: это можно легко исправить, просто используя require вместо import в тестовых файлах. Но тестовый код также будет проходить через процесс сборки, если вы тестируете JavaScript-код типа Flow, который использует аннотации, или веб-приложения Vue.js, которые используют файлы .vue. Все они должны быть преобразованы в обычный JavaScript.
Список тестовых инструкций:
- Webpack строит граф зависимостей, начинающийся с тестовых файлов, а не с файлов приложения.
- Webpack создаёт файл JavaScript, содержащий весь тестовый код и его зависимости без ключевого слова
import. - Выполняются тесты, запуская Mocha для этого JavaScript-файла.
Всё это будет выглядеть следующим образом:
Как можно увидеть, будут происходить две отдельные сборки. Одна из которых содержит код приложения в качестве точки входа и папку dist в качестве выходной директории, а другая — тестовые файлы в качестве точки входа и папку test-dist в качестве выходного каталога. Итак, давайте обновим конфигурационный файл, чтобы Webpack поддерживал вторую сборку:
Давайте разберёмся, что этот код делает. В строке 4 есть оператор if, который выполняется, если системная переменная TESTBUILD имеет непустое значение. Так что, если вы выполните $ TESTBUILD=true webpack, то вам придётся вводить оператор if, но это не потребуется, если просто выполнить $ npx webpack.
Внутри оператора if происходит выбор, какой JS-файл является точкой входа. Вместо уже установленного выходного каталога dist будет папка test-dist. А вместо точки входа app/src/path.js — массив файлов, соответствующих глобальному выражению app/test/**/*.test.js. Другими словами, это все файлы, которые находятся в каталоге app/test и имеют путь, заканчивающийся на .test.js.
Новая точка входа и выходной путь передаются в объект module.exports, затем запускается Webpack для создания тестовой сборки. Конфигурация Webpack представляет собой обычный код JavaScript, поэтому можно использовать стандартную библиотеку Node и операторы if для её настройки. Если выполнить $ TESTBUILD=true npx webpack, то можно увидеть каталог test-dist. А если запустить $ npx mocha test-dist/main.js, то можно увидеть, как выполняются ваши тесты.
Наконец, в разделе scripts вашего package.json добавьте следующую строку:
Это означает, что когда вы выполняете $ yarn test, создаётся каталог test-dist (каталог сборки тестирования) с помощью Webpack, затем запускается Mocha для этой сборки, и, наконец, код $ rm -rf test-dist удаляет каталог test-dist, поскольку он больше не используется (Commit 7).
Маппинг исходных файлов тестового кода
Тестовая сборка готова, но есть один нюанс, касающийся тестирования кода. Если запустить Mocha для файла test-dist/main.js и один из этих тестов не пройдёт, как это будет выглядеть? Давайте сделаем тест формулы расстояния в app/test/distance.test.js ошибочным:
Выполните $ yarn test и вот что получится:
Тест провален, но нельзя узнать, в какой строке исходного кода находится ошибка. Если таких тестов для веб-приложения у вас много, то поиски строки с ошибкой затянутся надолго.
Код с ошибкой находится в строке 8 в файле app/test/distance.test.js, но Mocha запускается для файла test-dist/main.js, поэтому, с точки зрения Mocha, ошибка находится в строке 116. К счастью, Webpack поддерживает source maps, которые покажут, какая строка кода соответствует ошибке. Source maps (или карты кода) — это файлы исходного кода, которые показывают точное соответствие элементов готового рабочего кода проекта и вашего кода разработки. Выполняется своего рода проход декодером по пакетному файлу main.js, чтобы получить исходные строки кода, которые соответствуют связному коду. Давайте обновим оператор if в файле webpack.config.js:
Затем в объект module.exports добавим строку:
Теперь в тестировочных сборках каталог test-dist будет содержать файл типа source maps. Выполните $ npx webpack TESTBUILD=true и каталог test-dist будет содержать файл main.js.map в дополнение к пакету main.js.
Чтобы Mocha мог использовать эту source map при запуске тестов, необходимо установить ещё один пакет:
Теперь, чтобы его использовать, нужно обновить скрипт Mocha в разделе scripts.test файла package.json:
Флаг --require source-map-support/register требует пакет source-map-support, это означает, что Mocha будет использовать source map, если она доступна. Теперь, если вы выполните $ yarn test и получите ошибку, вы увидите, в какой строке она находится, и сможете исправить код (Commit 8).
Итак, теперь у вас есть пример настройки обычных и тестовых сборок с использованием маппинга. Существует также множество других способов, которыми вы можете воспользоваться в своих сборках, например, объединение нескольких загрузчиков JavaScript для обработки вашего кода как на конвейере или же запуск Webpack как отладочного сервера, чтобы моментально видеть, как изменения в коде влияют на окончательную сборку Webpack. Продолжайте пробовать различные пакеты для компоновки файла webpack.config.js!
Для более точной настройки Webpack вам может быть полезен следующий материал:
58К открытий58К показов



