Webpack

Что такое Webpack?

Webpack — это инструмент, позволяющий скомпилировать, например, JavaScript модули в единый JS-файл. Webpack также известен как сборщик модулей.

При большом количестве файлов он создает один объемный файл (или несколько файлов) для запуска вашего приложения.

Он также способен выполнять множество иных операций:

  • помогает собрать воедино ваши ресурсы
  • следит за изменениями и повторно выполняет задачи
  • может выполнить транспиляцию JavaScript следующего поколения до более старого стандарта JavaScript (ES5) с помощью Babel, что позволит использовать новейшие функции JavaScript, не беспокоясь о том, поддерживает их браузер или нет
  • может выполнить транспиляцию CoffeeScript в JavaScript
  • может конвертировать встроенные изображения в data:URI
  • позволяет использовать require() для CSS файлов
  • может запустить webpack-dev-server (в нём встроен локальный сервер и livereload (“живая перезагрузка браузера”))
  • может работать с Hot Module Replacement (замена горячего модуля)
  • может разделить выходной файл (output file) на несколько файлов, чтобы избежать медленной загрузки страницы из-за большого размера JS-файла
  • может выполнить Tree Shaking

Webpack не ограничивается одним лишь фронтендом, его также успешно применяют в бэкенд разработке на Node.js.

У Webpack есть предшественники, у которых он перенял многие идеи. Основное различие заключается в том, что те инструменты известны как task runners (такс-раннеры), в то время как Webpack ничто иное, как сборщик модулей.

Webpack — это более целенаправленный инструмент. Вам достаточно указать точку входа в ваше приложение (это может быть даже HTML-файл с тегами <script>), а webpack проанализирует файлы и объединит их в один выходной JavaScript-файл, содержащий все необходимое для запуска приложения.

Установка Webpack

Webpack может быть установлен глобально или локально для каждого проекта.

Глобальная установка

Глобальная установка с помощью Yarn:

yarn global add webpack webpack-cli

с помощью npm:

npm i -g webpack webpack-cli

Теперь мы можем запустить webpack:

webpack-cli

Локальная установка

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

Установка с помощью Yarn:

yarn add webpack webpack-cli -D

с помощью npm:

npm i webpack webpack-cli --save-dev

После этого добавьте эти строчки в свой package.json файл:

{ 
  //... 
  "scripts": { 
    "build": "webpack" 
  } 
}

Как только все будет сделано, вы можете запустить Webpack, набрав:

yarn build

в корневом каталоге проекта.

Настройка Webpack

По умолчанию, Webpack (начиная с 4-й версии) не требует никакой настройки, если вы соблюдаете эти правила:

  • точкой входа вашего приложения является ./src/index.js
  • вывод (output) размещается в ./dist/main.js
  • Webpack работает в production mode (режим производства)

Конечно, если понадобится, вы сможете настроить каждую мельчайшую деталь в Webpack. Конфигурационный файл Webpack —webpack.config.js хранится в корневой директории проекта.

Точка входа

По умолчанию, точкой входа является ./src/index.js. Нижеприведенный пример использует файл ./index.js в качестве входной точки.

module.exports = {
  /*...*/
  entry: './index.js'
  /*...*/
}

Вывод (output)

По умолчанию, вывод размещается в ./dist/main.js. В нижеприведенном примере, результат работы в Webpack генерируется в файле app.js:

module.exports = {
  /*...*/
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'app.js'
  }
  /*...*/
}

С помощью Webpack можно использовать оператор import или require в своем JavaScript коде для того, чтобы подключать файлы любого типа (например, CSS).

В Webpack загрузчики являются аналогами задач (tasks) в Grunt и Gulp. Они принимают содержимое файлов, а затем преобразуют его необходимым образом и включают результат преобразования в общую сборку. Например, они могут компилировать TypeScript, загружать компоненты Vue.js и многое другое.

Например, в своем коде вы можете использовать:

import 'style.css'

указав конфигурацию данного загрузчика в файле webpack.config.js:

module.exports = {
  /*...*/
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
    }]
  }
  /*...*/
}

Регулярное выражение применяет данный загрузчик только к CSS файлам.

У загрузчика есть параметры:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
  /*...*/
}

Для одной и той же задачи может потребоваться несколько загрузчиков:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.css$/,
        use:
          [
            'style-loader',
            'css-loader',
          ]
      }
    ]
  }
  /*...*/
}

В этом примере css-loader интерпретирует директиву import 'style.css' в CSS. Затем style-loader внедряет этот CSS в DOM, используя тег <style>.

Порядок выполнения перевернут (последнее выполняется первым).

Так сколько всего существует загрузчиков? Очень много! Здесь вы сможете найти полный список.

Самым часто используемым загрузчиком является Babel — он используется для транспиляции современного JavaScript в ES5:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
  /*...*/
}

Данный пример заставляет Babel предварительно обрабатывать все наши React/JSX файлы:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  },
  resolve: {
    extensions: [
      '.js',
      '.jsx'
    ]
  }
  /*...*/
}

Здесь вы можете увидеть параметры babel-loader.

Плагины

Плагины —  это почти то же самое, что и загрузчики, но под стероидами. Они могут сделать то, что не могут загрузчики. Ко всему прочему, Webpack построен на системе плагинов, которые вы используете в своем файле конфигурации.

Рассмотрим следующий пример:

module.exports = {
  /*...*/
  plugins: [
    new HTMLWebpackPlugin()
  ]
  /*...*/
}

Плагин HTMLWebpackPlugin автоматически создает HTML-файл с уже подключенным скриптом.

Здесь доступно множество плагинов.

Еще один полезный плагин,CleanWebpackPlugin, мы можем использовать перед перегенерацией файлов, чтобы очистить нашу папку dist/ и получить аккуратный файл с конфигурацией.

module.exports = {
  /*...*/
  plugins: [
    new CleanWebpackPlugin(['dist']),
  ]
  /*...*/
}

Режимы Webpack

Данные режимы (появившиеся в 4-й версии Webpack) настраивают среду, в которой будет работать Webpack. Режим может быть настроен на development или production (по умолчанию стоит production).

module.exports = {
  entry: './index.js',
  mode: 'development',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'app.js'
  }
}

Режим development:

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

Режим production работает медленнее, чем development, так как ему нужно создать более оптимизированный бандл. Полученный JavaScript файл меньше по размеру, поскольку многое из режима development в нем отсутствует.

Я написал небольшое приложение, которое выводит содержимое console.log.

Вот бандл production:

Вот бандл development:

Запуск Webpack

Если Webpack установлен глобально, его можно вручную запустить из командной строки. Но, обычно, вы прописываете скрипт внутри файла package.json, который затем запускаете через npm или yarn.

Например, эти package.json скрипты, которые мы использовали ранее:

"scripts": {
  "build": "webpack"
}

позволяют запускать webpack, набрав:

npm run build

или:

yarn run build

или просто:

yarn build

Просмотр изменений

Webpack может автоматически перестраивать бандл, когда в вашем приложении происходят изменения. Для этого добавьте данный скрипт:

"scripts": {
  "watch": "webpack --watch"
}

и запустите данную функцию:

npm run watch

или:

yarn run watch

или просто:

yarn watch

Одной из приятных особенностей watch mode (режима просмотра) является то, что бандл изменяется только в том случае, если в сборке нет ошибок. Если ошибки присутствуют, watch продолжит следить за изменениями и будет пытаться перестраивать бандл, но текущий, рабочий бандл не зависит от проблемных бандлов.

Обработка изображений

С помощью Webpack можно очень удобно работать с изображениями, используя загрузчик file-loader.

Эта простая конфигурация:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  }
  /*...*/
}

Позволяет импортировать изображения в ваш JavaScript:

import Icon from './icon.png'

const img = new Image()
img.src = Icon
element.appendChild(img)

Где img — это HTMLImageElement. Ознакомьтесь с документацией по Image().

file-loader может обрабатывать и другие типы ассетов, например, шрифты, CSV-файлы, XML и т.д.

Еще одним приятным инструментом для работы с изображениями является url-loader загрузчик.

В этом примере загружается любой PNG-файл размером менее 8 КБ в качестве data:URL.

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.png$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
  /*...*/
}

Обработайте SASS код и преобразуйте его в CSS

Используйте sass-loadercss-loader и style-loader:

module.exports = {
  /*...*/
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  }
  /*...*/
}

Генерация Source Maps

С транспилированным кодом, зачастую, возникают проблемы при отладке кода в браузере или анализе ошибок. Так как транспилированный и трудночитаемый JavaScript, а не оригинальный код, затрудняет поиск и исправление ошибок. Source Map — это JSON-файл, который содержит информацию о том, как транспилировать код обратно в исходный код.

Source Maps можно сгенерировать, используя свойство конфигурации devtool:

module.exports = {
  /*...*/
  devtool: 'inline-source-map',
  /*...*/
}

devtool имеет множество возможных значений, из которых наиболее часто используемые:

  • none: не добавляет Source Maps
  • source-map: идеально подходит для режима production, предоставляет отдельную Source Map, которую можно свернуть и добавляет ссылку в бандл, чтобы инструменты разработки знали о том, что Source Map доступна
  • inline-source-map: идеально подходит для режима development, встраивает Source Maps в качестве data:URL

Перевод статьи Flavio CopesA beginner’s introduction to Webpack