Подробное руководство по настройке сборщика Webpack 5, в котором настроены Pug, Sass, JavaScript, React и Markdown.

Содержание

О чем статья

Перед вами подробная инструкция по настройке сборщика Webpack 5 с нуля. Шаг за шагом статья объясняет "что делать" и "зачем это надо".

После выполнения всех шагов вы получите рабочий шаблон, в котором будут настроены Pug, Sass, JavaScript, React и Markdown.

  • Шаблонизатор Pug обладает более широкими возможностями для написания разметки, чем HTML. Разметка Pug преобразуется вебпаком в разметку HTML.

  • Препроцессор Sass имеет больше возможностей для написания стилей, чем CSS. В конечном итоге, вебпак преобразует код SCSS в CSS.

  • Язык JavaScript необходим для создания интерактивности сайта, при этом, сборка позволит использовать последние достижения языка и не переживать, что новую функцию не распознает старый браузер.

  • React - это JavaScript-библиотека для создания пользовательских интерфейсов

  • Разметка Markdown удобна для написания текстов. Разметка Markdown преобразуется в понятный для браузеров HTML.

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

Быстрый запуск Webpack

Для настройки сборки webpack автор статьи использовал операционную систему Ubuntu 20.04, в которой были установлены:

Следующие инструменты
  • NodeJS v16.17.1

  • менеджер пакетов NPM v8.15.0

  • стандартный Терминал

  • стандартный Текстовый редактор (далее по тексту будет называться редактор кода или редактор)

  • браузер FireFox v105.0.

    У вас инструменты могут отличаться.

Чтобы выполнять дальнейшие действия, установим на компьютер Node.js.

Откроем терминал и создадим каталог будущего проекта:

mkdir my-project

Сделаем этот каталог рабочим:

cd my-project

Обратите внимание! С этого момента старайтесь не закрывать окно терминала, так как в нем открыт рабочий каталог my-project и все дальнейшие команды в терминале выполняются в корневом каталоге проекта. Если терминал по какой-то причине будет закрыт, то нужно открыть новый терминал и выполнить команду: cd my-project.

Теперь, если нужна система контроля версий Git, выполним следующее. Сначала инициализируем Git, для этого в терминале введем:

git init

В корне проекта будет создан скрытый каталог .git, в котором хранятся необходимые файлы git-репозитория. Если в менеджере файлов каталог .git не отображается, то нажмем комбинацию клавиш Ctrl+H.

Затем, в корне проекта создадим скрытый файл .gitignore. Для этого, в терминале введем следующее:

touch .gitignore

В этом файле будем указывать имена и шаблоны для файлов и каталогов, которые не нужны в репозитории. С помощью редактора кода откроем файл .gitignore и запишем следующее:

node_modules

Эта запись указывает системе Git, чтобы она не отслеживала и не добавляла каталог node_modules в репозиторий.

Не забывайте сохранять в редакторе кода всё, что изменили. Это забывают делать не только новички, но опытные разработчики. Поэтому, если после очередной правки кода, у вас что-то не работает, обязательно убедитесь, что код сохранен. В дальнейшем, я не буду напоминать об этом. Запомни правило: сделал правку в коде, нажми сочетание клавиш Ctrl+S. Эта комбинация клавиш сохраняет изменения и работает практически в любом редакторе.

С настройками Git в этом проекте закончим. В дальнейшем, не забываем делать коммиты.

Теперь, инициализируем npm, для этого в терминале введем следующую команду:

npm init -y

В корне проекта создается файл package.json с настройками по умолчанию, на что указывает опция -y. Подробно о файле package.json читайте в документации по npm.

Теперь установим webpack и webpack-cli, последний нужен для запуска webpack из командной строки. В терминале введем следующее:

npm i -D webpack webpack-cli

i - это сокращение от install. Опция -D указывает, что установленные пакеты нужны только для режима development (режима разработки) и не будут использоваться в производственной сборке. После установки это фиксируется в фале package.json, пакеты будут прописаны в секции "devDependencies": {...} .

Так как это первые пакеты, которые были установлены в проект, то будут созданы каталог node_modules и файл package-lock.json. Каталог node_modules содержит все устанавливаемые пакеты и их зависимости. Этот каталог не рекомендуется включать в репозиторий, поэтому мы указали это в файле .gitignore. Файл package-lock.json хранит записи о точных версиях установленных зависимостей.

Теперь в корне проекта создадим каталог src, в котором будет хранится исходный код:

mkdir src

В каталоге src создадим файл index.js:

touch src/index.js

В редакторе откроем файл src/index.js и введем следующий код:

function component(text) {
  const element = document.createElement('h1');
  element.textContent = text;
  return element;
}

document.body.prepend(component('Проект собран на Webpack'));

Затем в редакторе откроем package.json и добавим в поле "scripts" следующую строку с именем dev:

"scripts": {
  "dev": "webpack --mode development",
  "test": "echo \"Error: no test specified\" && exit 1"
}

dev - это произвольное сокращенное имя для скрипта webpack --mode development. Подобные скрипты в секции "scripts" файла package.json запускаются в с помощью команды npm run. Так, для запуска скрипта с именем dev, введем в терминале следующую команду:

npm run dev

В результате, в корне проекта должен появиться каталог dist, в который скомпилируется файл main.js. Если сравнить содержимое файла main.js с исходным src/index.js, то увидим отличия, хотя файлы выполняют одно и то же. Итак, мы запустили webpack в режиме разработки, в результате, файл src/index.js был транспилирован в файл dist/main.js.

Перед началом выполнения, webpack будет искать в корне проекта файл настроек webpack.config.js. Так как, файл мы ещё не создали, то webpack применяет настройки по умолчанию.  Он определяет точку входа src/index.js и выводит откомпилированный код в файл dist/main.js. Подробно об изменении настроек смотри ниже в параграфе Настройка в webpack точки входа и выхода.

Чтобы понять некоторые моменты, создадим в выходном каталоге файл dist/index.html. Для этого, в терминале выполним:

touch dist/index.html

Именно этот файл браузер начинает загружать первым, а потом загружает те ресурсы, которые прописаны в этом файле. В редакторе кода откроем файл dist/index.html и запишем следующее:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Быстрый запуск Webpack</title>
  </head>
  <body>
    <p>Файл создан вручную</p>
    <script src="main.js"></script>
  </body>
</html>

В этом файле мы указали ссылку на скрипт. Этот скрипт должен быть загружен и выполнен во время выполнения файла dist/index.html. В браузере откроем файл dist/index.html и увидим следующее:

Проект собран на Webpack 
Файл создан вручную

Первая строка текста создана файлом dist/main.js, а вторая - файлом dist/index.html.

На данный момент, файловая структура нашего проекта должна выглядеть так:

my-project
  |-dist
    index.html
    main.js
  |+node_modules
  |-src
    index.js
  |+.git
  package-lock.json
  package.json
  .gitignore

Установка и настройка html-webpack-plugin

В примере выше, мы добавляли вручную файл index.html в выходной каталог. Теперь, настроим webpack, чтобы этот HTML-файл автоматически создавался в готовой сборке из исходного шаблона. Для этого используем плагин html-webpack-plugin, который установим из терминала:

npm i -D html-webpack-plugin

Теперь настроим html-webpack-plugin в файле webpack.config.js. Но сначала создадим этот файл в корне проекта. Для этого в терминале выполним:

touch webpack.config.js

Затем откроем файл webpack.config.js в редакторе и напишем следующий код:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src', 'template.html'),
      filename: 'index.html',
    }),
  ],
};

Разберемся в коде:

  • Первые две строки импортируют модули html-webpack-plugin и path и определяют эти модули в переменные HtmlWebpackPlugin и path соответственно.

  • module.exports = {} - эта запись означает, что все настройки этого файла помещаются в объект, который экспортируется как модуль по умолчанию.

  • Для плагина html-webpack-plugin создается экземпляр new HtmlWebpackPlugin с двумя заданными свойствами: template - путь к входному файлу и filename - имя выходного файла.

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

В Linux и macOS пути в файловой системе задаются так: /path/to/template.html. В Windows пути выглядят иначе: C:\path\to\template.html. В среде Node.js существует модуль path, который учитывает эти различия. Модуль path мы подключили во второй строке файла webpack.config.js, а затем вызвали в свойстве template. Метод path.join объединяет заданные сегменты пути вместе и применяет необходимый разделитель для конкретной системы. Сегменты пути для метода path.join мы задали тремя аргументами __dirname, 'src' и 'template.html'. Если заранее известно, что этот шаблон будет использоваться только в ОС Linux, то можно вместо такого кода, как template: path.join(__dirname, 'src', 'template.html') указать проще - template: './src/template.html'

  • __dirname - глобальная константа, которая указывает абсолютный путь к каталогу файла, код которого запрашивает эту константу, т. е. в нашем случае, файл, который запрашивает __dirname - это файл webpack.config.js, поэтому __dirname содержит абсолютный путь к корневому каталогу проекта.

Вместо метода path.join часто применяют метод path.resolve.

Файл настроек webpack.config.js нужен вебпаку, чтобы знать, какие плагины и с какими настройками использовать в том или ином случае. Webpack автоматически определит, если файл настроек лежит в корне проекта и имеет имя webpack.config.js. Если имя или расположение файла иное, то необходимо указать это с помощью опции --config в файле package.json, например:

"scripts": {
  "serve": "webpack serve --open --mode development --config dev/serve.config.js"
}

Однако, мы это вносить в файл не будем.

Создадим файл src/template.html:

touch src/template.html

Откроем в редакторе файл src/template.html и создадим в нём такую разметку:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Быстрый запуск Webpack</title>
  </head>
  <body>
    <p>Файл создан плагином html-webpack-plugin</p>
  </body>
</html>

Теперь, удалим каталог dist с двумя файлами, а после в терминале запустим команду:

npm run dev

Каталог dist снова будет создан, а внутри него созданы файлы index.html и main.js. Если откроем в браузере файл dist/index.html, то увидим:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Таким образом, webpack с помощью плагина html-webpack-plugin сделал две вещи:

  • создал файл dist/index.html из файла src/template.html

  • в файле dist/index.html автоматически прописал путь к файлу скрипта main.js.

Минимально возможный вариант сборки webpack собран и настроен. С помощью этого шаблона можно начинать разработку проекта по следующему алгоритму:

  1. Редактируем исходный код в файлах каталога src

  2. Сохраняем результат

  3. Выполняем сборку проекта с помощью команды:

npm run dev
  1. Открываем в браузере файл dist/index.html, либо если этот файл открыт, перезагружаем страницу браузера.

  2. Смотрим на полученный результат в браузере и, если надо, повторяем шаги сначала.

Установка и настройка DevServer

В созданной сборке нужно каждый раз запускать в терминале команду npm run dev и вручную обновлять страницу браузера. Для уменьшения количества рутинных операций, автоматизируем процесс.

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

  1. Режим Watch

  2. webpack-dev-server

  3. webpack-dev-middleware

Здесь мы рассмотрим вариант с веб сервером. С помощью терминала установим webpack-dev-server:

npm i -D webpack-dev-server

В редакторе кода откроем файл webpack.config.js и добавим настройки для веб-сервера, отмеченные знаком +:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');

  module.exports = {
    plugins: [
      new HtmlWebpackPlugin({
        template: path.join(__dirname, 'src', 'template.html'),
        filename: 'index.html',
      }),
    ],
+   devServer: {
+     watchFiles: path.join(__dirname, 'src'),
+     port: 9000,
+   },
  };

Для devServer указали два свойства:

  • watchFiles указывает на каталог src, за которыми будет вестись наблюдение и в случае, если в каталоге произойдут изменения, веб сервер автоматически сделает сборку проекта и перезагрузит страницу браузера.

  • port указывает порт на котором будет работать веб-сервер, по умолчанию - localhost:8080.

Чтобы запускать веб сервер короткой командой, создадим для CLI скрипт "serve" в файле package.json:

{
  "scripts": {
+   "serve": "webpack serve --open --mode development",
    "dev": "webpack --mode development",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}
  • serve означает запустить веб сервер.

  • --open автоматически запускает браузер, который в системе установлен по умолчанию.

  • --mode development включает режим разработки.

Перед тем как запустить веб-сервер, удалим каталог dist. Это делать необязательно, а нужно лишь для понимания работы веб-сервера.

В терминале запустим веб-сервер командой:

npm run serve

В результате, автоматически откроется страница браузера по адресу http://localhost:9000/ и мы увидим те же строки, что и при ручном запуске браузера:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Если по какой-то причине, страница браузера автоматически не откроется, то откройте браузер вручную и перейдите по адресу http://localhost:9000.

Если заглянуть в каталог проекта, когда сервер работает, то мы не увидим каталог dist. Тогда откуда браузер берет данные? Всё просто, DevServer компилирует исходный код, и записывает файлы не на диск, а в оперативную память.

Веб-сервер можно остановить, если в терминале нажать сочетание клавиш Ctrl+C.

Теперь файловая структура нашего проекта будет выглядеть так:

my-project
  |-node_modules
  |-src
    index.js
    template.html
  |+.git
  package-lock.json
  package.json
  webpack.config.js
  .gitignore

Настройка в Webpack точки входа и выхода

В Webpack'е начиная с четвертой версии не требуется задавать точки входа и выхода, а допускается использовать настройки по умолчанию:

  • точка входа - ./src/index.js

  • точка выхода - ./dest/main.js.

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

Точка входа - файл, который Webpack компилирует первым и если в этом файле подключаются зависимости, то эти зависимости тоже обрабатываются.

С помощью настроек, укажем путь и имя точки входа. Для этого в файл webpack.config.js добавим свойство entry:

module.exports = {
  entry: path.join(__dirname, 'src', 'index.js'),
};

Теперь, чтобы изменить точку входа изменяем значение свойства entry. Также, можно задать несколько точек входа. Это нужно при разделении кода на части. Подробно о настройках точки входа читайте в статьях Entry Points и Entry and Context.

Точка выхода - каталог, в который Webpack компилирует точки входа.

Точка выхода настраивается в файле webpack.config.js с помощью свойства output:

module.exports = {
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.[contenthash].js',
  },
};

где:

  • [contenthash] - шаблон, в который подставляется хеш, сгенерированный на основе содержимого файла. Хеширование меняет имя после каждого изменения содержимого файла. Это решает проблему версионирования. Если хеш изменился, то браузер берет не старый файл из кеша, а загружает новый с сервера. Можно сократить 40 знаков хеша до нужного количества символов следующим образом: [contenthash:8]. Хеш будет длиной 8 символов. Подробно о шаблоне хешей читайте в статье Hash vs chunkhash vs ContentHash.

Более подробно о точках выхода описывается в статьях concepts/output и configuration/output.

Теперь файл webpack.config.js выглядит так:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  entry: path.join(__dirname, 'src', 'index.js'),
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.[contenthash].js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src', 'template.html'),
      filename: 'index.html',
    }),
  ],
  devServer: {
    watchFiles: path.join(__dirname, 'src'),
    port: 9000,
  },
};

В терминале остановим сервер клавишами Ctrl+C и запустим следующую команду:

npm run dev

В корне проекта появится каталог dist, в котором будут два файла: index.html и index.[hash].js. Второй файл раньше назывался main.js. Код в имени файла - это и есть хеш, который будет меняться с изменением содержимого файла.

Автоматическая очистка каталогов

При каждом запуске сборки webpack будет создавать новые файлы с хешированными именами. Чтобы ненужные файлы не накапливались, перед каждым запуском вебпака необходимо очищать каталог dist. В этом нам поможет filemanager-webpack-plugin.

Сперва, установим filemanager-webpack-plugin:

npm i -D filemanager-webpack-plugin

Затем, в файле webpack.config.js добавим:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');
+ const FileManagerPlugin = require('filemanager-webpack-plugin');

  module.exports = {
    ...
    plugins: [
      new HtmlWebpackPlugin({
        ...
      }),
+     new FileManagerPlugin({
+       events: {
+         onStart: {
+           delete: ['dist'],
+         },
+       },
+     }),
    ],
    devServer: {
      ...
    },
  };

Каталог dist, если быть точным, не очищается, а удаляется. Плагин filemanager-webpack-plugin может также копировать, создавать, перемещать, архивировать файлы и каталоги перед началом сборки onStart и по окончании onEnd. В дальнейшем, воспользуемся этим плагином для копирования файлов.

Проверим работу пакета filemanager-webpack-plugin, для этого в терминале запустим веб-сервер командой:

npm run serve

В результате, автоматически откроется страница браузера по адресу http://localhost:9000/ и мы увидим тоже, что и в прошлый раз:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Если же проверим корневой каталог проекта, то не увидим каталога dist, что говорит, о правильной работе пакета filemanager-webpack-plugin.

Остановим DevServer, для этого в терминале нажмем Ctrl+C.

Настройка режима production в webpack

До сих пор webpack использовался в режиме разработки. Теперь создадим производственную сборку, чтобы получить готовое приложение, которое размещается на удаленном сервере.

В файле package.json добавим скрипт "build":

  "scripts": {
    "serve": "webpack serve --open --mode development",
    "dev": "webpack --mode development",
+   "build": "webpack --mode production",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

Чтобы понять, чем сборка production отличается от development, проделаем некоторые шаги. Запустим webpack в режиме development:

npm run dev

Oткроем файл dist/index.[hash].js в редакторе кода и посмотрим на него. Видим кучу комментариев, а код находится не в сжатом виде. Размер файла составляет 1418 байт.

Запустим webpack в режиме production:

npm run build

Посмотрим на содержимое файла dist/index.[hash].js, в котором увидим, что отсутствуют комментарии, а код имеет сжатый вид. Размер файла составляет 139 байт. Этим режим production отличается от режима development - код конечного бандла сжимается. То же относится и к файлу index.html, который в режиме development имеет размер 282 байта, а в режиме production размер уменьшается до 259 байт, так как убираются пробелы и ненужные символы.

Babel

Большинство новых браузеров поддерживают все новые возможности JavaScript ES6-ES13. Но, многие из этих возможностей не поддерживаются старыми браузерами, которые до сих пор используются в мире. Поэтому, если важно сохранять поддержку этих браузеров, то самый распространенный способ - применить Babel.

Babel - это компилятор, который адаптирует новые функции JavaScript для устаревших браузеров.

Чтобы посмотреть, какие браузеры поддерживают ту или иную функцию воспользуемся сервисом Can I use. Если в строке Can I use______? ввести es13, то будет выведен список функций, которые ожидаются в 13-ом выпуске ECMAScript. При выборе функции, показывается таблица с браузерами, которые поддерживают или не поддерживают эту функцию.

Babel позволяет писать код с использованием новых возможностей JavaScript ES6-ES13. При этом можно не заботится о том, что функция не будет поддерживаться старым браузером. Babel транспилирует JavaScript код в ES5, а браузеры, которые не поддерживают этот стандарт уже никем не используются.

Для работы Babel требуется два пакета @babel/core и @babel/preset-env, а чтобы Babel работал с Webpack требуется загрузчик babel-loader. Установим эти три пакета одной командой:

npm i -D @babel/core @babel/preset-env babel-loader

Конфигурацию для Babel зададим в файле .babelrc. Из терминала создадим этот файл:

touch .babelrc

В корне проекта будет создан файл .babelrc. Откроем его и внесем следующий код:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ]
  ]
}

Теперь, откроем файл webpack.config.js и добавим настройки для Babel:

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
+   module: {
+     rules: [
+       {
+         test: /\.js$/,
+         use: 'babel-loader',
+         exclude: /node_modules/,
+       },
+     ],
+   },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };

Мы создали объект module, для которого задали правило rules. Для вебпака файл - это модуль, будь то скрипт, стили, шрифт или изображение. Здесь, для всех модулей (читай, файлов) с расширением .js webpack будет применять плагин babel-loader. Правило не действует на каталог node_modules, что указывается в свойстве module.rules.exclude.

Перед тем, как запустить сборку, откроем файл dist/index.[hash].js и посмотрим на код, который выглядит примерно так:

document.body.append((function(e){constt=document.createElement('h1');return (t.textContent='Проект собран на Webpack'),t;})());

В терминале запустим команду:

npm run build

Теперь, откроем файл dist/index.[hash].js и посмотрим на код. Этот код выглядит по-другому:

(()=>{var e;document.body.append(("Проект собран на Webpack",(e=document.createElement("h1")).textContent="Проект собран на Webpack",e))})();

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

Подключение шаблонизатора Pug

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

Шаблонизаторы позволяют:

  • создавать шаблоны, компоненты, блоки

  • работать с данными, подставляя эти данные в код. Например, шаблонизатор может автоматически создать любое количество карточек товара, если подставить данные в компонент из объекта JSON, тогда как в HTML это нужно делать вручную.

  • менять классы элементов в зависимости от данных, что позволяет управлять интерфейсом компонентов.

  • задавать условные выражения и циклы, как в языках программирования.

В этой статье рассмотрим шаблонизатор Pug, который написан на JavaScript и выполняется в среде Node.js. Шаблонизатор Pug использует синтаксис, основанный на отступах и отличается от синтаксиса HTML отсутствием угловых скобок и закрывающихся тегов. После компиляции синтаксис Pug превращается в HTML код.

Чтобы шаблонизатор Pug работал с Webpack, имеется плагин и загрузчик файлов pug-loader.

Загрузчик pug-loader не поддерживает Pug 3-ей версии, поэтому придется довольствоваться второй версией. Кому очень нужен Pug 3, предлагаю два варианта решения:

Сравнительно недавно появился pug-plugin, который работает с Webpack 5 и Pug 3.

Самостоятельно настроить pug-loader для третьей версии Pug, и дождаться, пока разработчики плагина сами это сделают. Это способ, которым пользуется автор этой статьи, об этом способе читайте в статье  Как заставить работать вместе Pug 3, pug-loader и Webpack 5.

Установим pug и pug-loader

npm i -D pug pug-loader

Вебпаку укажем, что используем плагин pug-loader для файлов с расширением .pug. Для этого в файле webpack.config.js добавим:

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        {
          test: /\.js$/,
          use: 'babel-loader',
          exclude: /node_modules/,
        },
+       {
+          test: /\.pug$/,
+          loader: 'pug-loader',
+       },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
+       template: path.join(__dirname, 'src', 'template.pug'),
        filename: 'index.html',
      }),
      new FileManagerPlugin({
        ...
      }),
    ],
    devServer: {
      ...
    },
  };

Теперь, благодаря pug-loader модуль HtmlWebpackPlugin может работать с файлами .pug.

Из терминала создадим файл src/template.pug:

touch src/template.pug

Откроем файл в редакторе и напишем в нем следующее:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug

Обязательно соблюдайте начальные отступы для тегов. Каждый отступ означает вложенность тега в вышестоящий тег.

Теперь удалим файл src/template.html и в терминале запустим команду:

npm run serve

Откроется страница браузера по адресу http://localhost:9000/, на которой увидим:

Проект собран на Webpack
Файл откомпилирован шаблонизатором Pug

Из этого следует, что шаблонизатор Pug работает правильно. Остановим DevServer, для этого в терминале нажмем Ctrl+C.

Загрузка стилей в webpack

Для написания стилей будем использовать препроцессор Sass, который расширяет возможности CSS и упрощает создание CSS-кода, а также преобразует SCSS в понятный браузеру код CSS. Однако, не весь современный код CSS распознают устаревшие браузеры. Поэтому, будем прогонять этот CSS через постпроцессор PostCSS, чтобы большинство браузеров понимало современные стили.

Установим необходимые пакеты:

npm i -D sass-loader postcss-loader postcss-preset-env css-loader style-loader sass

где:

  • sass-loader - загрузчик файлов Sass/SCSS

  • sass компилятор файлов .scss в .css.

  • postcss-loader - загрузчик CSS файлов для пост-обработки. Должен работать с каким нибудь плагином.

  • postcss-preset-env - плагин для PostCSS, который конвертирует современный CSS в код, понятный большинству браузеров, включением необходимых полифилов.

  • css-loader загрузчик CSS-файлов

  • style-loader загрузчик стилей в DOM

Если требуется использовать только CSS и не пользоваться преимуществами SCSS и PostCSS, то установите только css-loader и style-loader.

Создадим файл src/main.scss:

touch src/main.scss

и внесем в него следующее:

$font-size: 1rem;
$font-color: lch(28 99 35);

html {
  font-size: $font-size;
  color: $font-color;
}

В файле используются переменные Sass и LCH цвета, которые поддерживаются не всеми браузерами, но PostCSS транспилирует эти цвета в понятные любому браузеру.

В файле src/index.js сделаем импорт файла main.scss:

import './main.scss';

Такой импорт стилей в скрипте не поддерживается языком JavaScript, а возможен благодаря webpack.

В webpack.config.js настроим пакеты:

...
  module.exports = {
    entry: ... ,
    output: {
      ...
    },
    module: {
      rules: [
        {
          ...
        },
        {
          test: /\.pug$/,
          loader: 'pug-loader',
        },
+       {
+         test: /\.(scss|css)$/,
+         use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
+       },
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };

Указываем вебпаку, какие загрузчики стилей применять. Причем, порядок их перечисления в массиве свойства use важен, так как загрузчики используются вебпаком от последнего к первому:

  • Так что последним в списке должен быть sass-loader, который загружает файлы SCSS и компилирует его в CSS.

  • Затем идет postcss-loader, который с помощью PostCSS транспилирует самые современные фичи CSS (переменные, миксины и многое другое) в то, что понятно большинству браузеров. Также, PostCSS применяет автопрефиксер и линтер к CSS.

  • Следующим идет css-loader, который интерпретирует @import и url() внутри CSS.

  • Последним будет style-loader, который внедряет CSS в DOM

Настройки для PostCSS задаются как в файле webpack.config.js так и в собственном файле настроек postcss.config.js. Воспользуемся вторым способом.

Создадим в корне проекта файл postcss.config.js

touch postcss.config.js

и запишем в файле следующий код:

module.exports = {
  plugins: {
    'postcss-preset-env': {
      browsers: 'last 2 versions',
    },
  },
};

В терминале запустим команду:

npm run serve

Откроется браузер и появится цветной текст.

Проект собран на Webpack
Файл откомпилирован шаблонизатором Pug

Теперь остановим сервер сочетанием клавиш Ctrl+C и введем в терминале команду:

npm run build

Если заглянем в каталог dist, то не обнаружим файла с расширением .css. Это связано с тем, что стили находятся в бандле dist/index.[hash].js.

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

Чтобы сборщик мог извлекать CSS из файлов .js установим и настроим плагин mini-css-extract-plugin. Сначала установим mini-css-extract-plugin:

npm i -D mini-css-extract-plugin

Затем настроим его в файле webpack.config.js:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');
  const FileManagerPlugin = require('filemanager-webpack-plugin');
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        ... ,
        {
          test: /\.(scss|css)$/,
          use: [
+           MiniCssExtractPlugin.loader,
            'css-loader',
            'postcss-loader',
            'sass-loader',
          ],
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        ...
      }),
      new FileManagerPlugin({
        ...
      }),
+     new MiniCssExtractPlugin({
+       filename: '[name].[contenthash].css',
+     }),
    ],
    devServer: {
      ...
    },
  };

Вместо 'style-loader' используем MiniCssExtractPlugin.loader.

Проверим работу плагина, для этого в терминале запустим:

npm run build

В каталоге dist появится файл main.[hash].css.

Загрузка изображений в webpack

Теперь настроим webpack для работы с изображениями в формате PNG, JPG, GIF и SVG. До webpack 5 для работы с изображениями использовались загрузчики raw-loaderurl-loader и file-loader. Начиная с webpack 5, вместо загрузчиков изображений, значков, шрифтов и т. д. используется встроенный Asset Modules.

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

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      path: path.join(__dirname, 'dist'),
      filename: 'index.[contenthash].js',
+     assetModuleFilename: path.join('images', '[name].[contenthash][ext]'),
    },
    module: {
      rules: [
        ...
        {
          test: /\.(scss|css)$/,
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
        },
+       {
+         test: /\.(png|jpg|jpeg|gif)$/i,
+         type: 'asset/resource',
+       },
+       {
+         test: /\.svg$/,
+         type: 'asset/resource',
+         generator: {
+           filename: path.join('icons', '[name].[contenthash][ext]'),
+         },
+       },
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };
  • assetModuleFilename - указывает выходной каталог с именем images  для обработанных изображений и шаблон имени [name].[contenthash][ext] для файлов, которые соответствуют правилу type: 'asset/resource'. Если assetModuleFilename не указан, то, по умолчанию, каталогом будет dist, а имена файлов будут задаваться по шаблону [contenthash][ext].

  • [ext] - шаблон для расширения файла, также, включает точку.

  • generator.filename - переопределяет assetModuleFilename для конкретного asset-правила. Здесь, svg-файлы будут выводиться в каталог dist/icons

  • type имеет четыре типа asset:

    • asset/resource - работает так же, как и загрузчик file-loader. Модули, которые соответствуют правилу type: 'asset/resource' будут выводится в указанный с помощью assetModuleFilename каталог.

    • asset/inline работает как загрузчик url-loader. Модули, соответствующие правилу type: 'asset/inline', встраиваются в код бандла как Data URL.

    • asset/source похож на работу загрузчика raw-loader. Модули, соответствующие правилу type: 'asset/source', встраиваются без преобразований (как есть).

    • asset объединяет asset/resource и asset/inline. Он работает следующим образом: если размер модуля больше 8 КБ, то он работает как asset/resource, в противном случае - как asset/inline. Размер 8 КБ задан по умолчанию, но его можно изменить с помощью свойства parser.dataUrlCondition.maxSize.

Создадим каталог src/images и поместим в него растровое изображения с именем image.png и векторное - logo.svg.

Могу предложить свои рисунки. Перейдем по этой ссылке, наведем курсор на рисунок, нажмем правую кнопку мыши, выберем из контекстного меню "Сохранить изображение как...", выберем каталог src/images нашего проекта, нажмем кнопку сохранить. Тоже самое проделаем для векторного изображения.

Откроем файл src/template.pug и допишем в него классы .logo-png, .logo-svg и теги img:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

В атрибуте src используется require, т. е. изображение запрашивается как модуль.

В терминале запустим команду:

npm run serve

В окне браузера появилось два рисунка:

Изменим размеры изображений через стили, для этого добавим в конец файла src/main.scss следующее:

.logo1 {
  width: 10em;
}
.logo2 {
  width: 10em;
}

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

Оптимизация изображений

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

Векторные изображения, к которым относится формат SVG, можно неограниченно масштабировать без потери качества. SVG - текстовый язык разметки, а SVG-файлы редактируются при помощи текстовых или векторных графических редакторов. Если в SVG изображении не сильно много мелких деталей, то SVG-файлы получаются меньше по размеру, чем сравнимые по качеству изображения в форматах JPEG или GIF. SVG применяется во фронтенде и для него придумано много инструментов. Одним из таких инструментов является svgo - минификатор, который удаляет лишний код в разметке SVG и тем самым уменьшает размер файла.

Установим svgo:

npm i -D svgo

Теперь, чтобы заработало сжатие для SVG файлов, настроим плагин imagemin-svgo для совместной работв svgo и imagemin. Однако, у нас не установлен imagemin.

Минификатор imagemin применяется для оптимизации растровых изображений. Для webpack существует image-minimizer-webpack-plugin - это загрузчик и плагин для оптимизации изображений с помощью imagemin.

Сначала, установим плагин image-minimizer-webpack-plugin и минификатор imagemin:

npm i -D image-minimizer-webpack-plugin imagemin

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

npm i -D imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo

В файл webpack.config.js добавим настройки:

  ...
+ const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        ...
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
+   optimization: {
+     minimizer: [
+       new ImageMinimizerPlugin({
+         minimizer: {
+           implementation: ImageMinimizerPlugin.imageminMinify,
+           options: {
+             plugins: [
+               ['gifsicle', { interlaced: true }],
+               ['jpegtran', { progressive: true }],
+               ['optipng', { optimizationLevel: 5 }],
+               ['svgo', { name: 'preset-default' }],
+             ],
+           },
+         },
+       }),
+     ],
+   },
  };

Для svgo параметры оптимизации установлены по умолчанию { name: 'preset-default' }. Подробно о настройках оптимизации svgo читайте здесь.

В терминале запустим команду:

npm run build

Сравним размеры файлов изображений в каталоге src и dist. Файл image.png был 4,9 КБ, а стал 2,3 КБ, файл logo.svg был 11,4 КБ, а стал 2,5 КБ. Мы видим, заметное сжатие изображений.

Включение синтаксиса Markdown и файлов .md в Pug

Pug является удобным инструментом для замены HTML при написании разметки. Но если необходимо в разметку вставлять большие объемы текста, например, как в статье, которую вы сейчас читаете, то ни Pug, ни HTML не удобны для этого. Для написания текстов придумали разметку Markdown, которая удобна для чтения и написания текстов, и которая в итоге будет преобразована в HTML.

Сравните текст, написанный на Markdown

## Markdown документ

- Написано на **Markdown**

с текстом, написанном на Pug:

h2 Markdown документ

ul
  li Написано на
    b Markdown

и с текстом, написанном на HTML:

<h2>Markdown документ</h2>

<ul>
  <li>Написано на <b>Markdown</b></li>
</ul>

По умолчанию шаблонизатор Pug понимает только свою разметку и разметку HTML. Чтобы в шаблонизаторе Pug использовать Markdown, применим фильтр :markdown-it модуля jstransformer-markdown-it.

Фильтры позволяют использовать в шаблонизаторе Pug другие языки.

Установим модуль jstransformer-markdown-it:

npm i -D jstransformer-markdown-it

Теперь можем в Pug файле использовать синтаксис Markdown. Добавим в конец файла src/template.pug три строки кода:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

    :markdown-it(linkify langPrefix='highlight-')
      ## Markdown документ

      - Написано на **Markdown**

Сохраним файл и в терминале выполним команду:

npm run serve

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

Чтобы не загрязнять код текстом, можно поместить markdown разметку в файл с расширением .md и включить этот файл в pug-шаблон, используя include:markdown-it, например, создадим файл content/article.md:

touch content/article.md

Запишем в него следующее:

## Markdown документ

- Написано на **Markdown**

В файле src/template.pug заменим последние три строки на строку с include:markdown-it content/article.md:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

    include:markdown-it content/article.md

Подключение шрифтов

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

Шрифты нашего проекта разместим в каталоге src/fonts, Создадим этот каталог:

mkdir src/fonts

Затем, создадим в этом каталоге файл fonts.scss

touch src/fonts/fonts.scss

В этом файле будем хранить CSS стили для шрифтов. Импортируем файл fonts.scss в src/index.js:

  import './main.scss';
+ import './fonts/fonts.scss';

  function component(text) {
    const element = document.createElement('h1');
    element.textContent = text;
    return element;
  }

  document.body.prepend(component('Проект собран на Webpack'));

Теперь, скачаем нужные шрифты и код CSS для них.

  1. На странице google-webfonts-helper в списке слева нужно выбрать необходимый шрифт.

  • Справа от списка появится страница для шрифта. На этой странице можно дополнительно указать нужные кодировки и стили, которые планируется использовать в шрифте.

  • В секции Select charsets выберем cyrillic и latin.

  • В секции Select styles выберем regular, italic, 700 и 700italic

  • В секции Copy CSS: в поле Customize folder prefix (optional): укажем префикс пути ./ и скопируем из серого поля CSS-код в файл src/fonts/fonts.scss.

  1. Нажмем на синюю кнопку в секции Download files и скачаем файл с расширением .zip.

  2. Распакуем из zip-архива файлы шрифтов в каталог src/fonts/.

Рекомендуется оптимизировать шрифты на таких сервисах как Font2web или Transfonter, но шрифты Google уже оптимизированы, поэтому этот шаг можно пропустить.

Для обработки шрифтов вебпаком добавим следующие правила в файл webpack.config.js:

  module: {
    rules: [
+     {
+       test: /\.(woff2?|eot|ttf|otf)$/i,
+       type: 'asset/resource',
+     },
    ],
  },

В файле main.scss укажем на используемый шрифт. Так, если это будет шрифт Roboto и мы хотим его использовать по всему нашему проекту, то запишем:

html {
  font-family: 'Roboto';
}

В терминале выполним команду:

npm run serve

Откроется браузер и мы увидим, что весь шрифт отображается без засечек.

Проверить применяемый шрифт для элемента можно с помощью инструментов разработчика. Чтобы быстро открыть инструменты разработчика в браузере, нажмем Ctrl+Shift+I, и включим режим выбора элементов сочетанием клавиш Ctrl+Shift+C. Если у вас браузер Chrome или Yandex, то наведите курсором на любой текст на странице. В контекстной подсказке будет показан применяемый шрифт:

Если у вас браузер Firefox, то на применяемые шрифты нужно смотреть в секции для CSS-кода Инспектора.

Копирование файлов и каталогов

Часто возникает необходимость скопировать в готовую сборку некоторые файлы или каталоги без каких-либо преобразований. Это могут быть файлы PDF, либо файл robots.txt, который используется для ограничения доступа поисковым роботам к некоторым ресурсам сайта, файлы favicon.ico, sitemap.xml и т.п. В исходном коде такие ресурсы, обычно, помещают в каталог static, а из нее эти ресурсы копируют в корень каталога dist.

Создадим каталог src/static:

mkdir src/static

Создадим файл src/static/robots.txt:

touch src/static/robots.txt

Как заполнять файл robots.txt можно узнать в статье Использование файла robots.txt, а пока оставим его пустым.

В параграфе Автоматическая очистка каталогов применялся плагин filemanager-webpack-plugin, который может удалять, копировать, создавать, перемещать и архивировать файлы и каталоги. Применим этот плагин для копирования фалов. Так как плагин в проекте уже установлен, то остается его настроить для копирования. Добавим в файл webpack.config.js следующий код:

* const FileManagerPlugin = require('filemanager-webpack-plugin');
module.exports = {
plugins: [
      ... ,
*     new FileManagerPlugin({
*       events: {
*         onStart: {
*           delete: ['dist'],
*         },
+         onEnd: {
+           copy: [
+             {
+               source: path.join('src', 'static', 'robots.txt'),
+               destination: path.join('dist', 'robots.txt'),
+             },
+           ],
*         },
*       },
*     }),
      ... ,
    ],
  };

Звездочками * отмечены строки, которые для этого плагина были настроены раньше в параграфе Автоматическая очистка каталогов, а знаком + отмечены строки, которые добавлены сейчас.

В терминале выполним команду:

npm run build

В каталоге dist появился файл robots.txt.

Установка и настройка React

Установим react и react-dom в проект. Причем, они должны быть установлены как библиотеки. Для этого запустим установку без опции -D:

npm i react react-dom

В файле package.json эти зависимости должны появиться в секции "dependencies".

Так как в реакте мы будем писать код на JSX, то установим пресет @babel/preset-react:

npm i -D @babel/preset-react
  • babel-preset-react: модуль, преобразующий JSX в JavaScript.

Откроем файл .babelrc и добавим строку @babel/preset-react таким образом:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ],
    "@babel/preset-react"
  ]
}

В каталоге src создадим каталог components, а в нём файл app.js:

mkdir src/components
touch src/components/app.js

Запишем в файл app.js следующий код:

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <>
        <h1 className="h1">Приложение на React</h1>
      </>
    );
  }
}

export default App;

Чтобы показать, что SCSS работает в react, откроем файл main.scss и добавим в конец следующий код:

.h1 {
  color: red;
}

Добавим в файл index.js строки, отмеченные знаком +, а строки, отмеченные знаком - можно удалить, но пока оставим:

+ import React from 'react';
+ import ReactDOM from 'react-dom';
+ import App from './components/app';

  import './main.scss';
  import './fonts/fonts.scss';

- function component(text) {
-   const element = document.createElement('h1');
-   element.textContent = text;
-   return element;
- }

- document.body.prepend(component('Проект собран на Webpack'));

+ ReactDOM.render(<App />, document.getElementById('root'));

Теперь запустим сборку:

npm run serve

Откроется окно браузера и мы увидим следующее:

Полезные ресурсы для настройки webpack

Настройка Webpack заставляет постоянно редактировать файл webpack.config.js. Поэтому, полезно держать под рукой справочник. Официальный сайт Webpack'а предлагает такой справочник, который представляет файл конфигурации с интерактивными опциями, если нажать на название непонятной опции, откроется страница с подробной документацией.

Рекомендую посетить сервис createapp.dev, который поможет создать готовый шаблон проекта с необходимыми настройками. Этот сервис настраивает проект под Webpack, Parcel и Snowpack и полезен для опытных пользователей.

Заключение

В этой статье показано, как настроить сборку webpack для создания фронтенда сайта с использованием шаблонизатора Pug, препроцессора SCSS, языка разметки Markdown и языка JavaScript. Также, добавлены настройки для React. Показаны методы оптимизации изображений, подключения шрифтов, настройки локального сервера. В целом сборка рабочая и полностью справляется с задачами, описанными в этой статье.

Не рассмотрена такая тема, как разделение кода на чанки. Это отдельная тема, касающаяся производительности. Если после очередной сборки бандла вы замечаете, что загрузка сайта начинает ощутимо возрастать, то стоит рассмотреть такие методы, как Code Splitting, Lazy Loading и Tree Shaking.

Весь код из этой статьи находится на Github.

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


  1. DinoZavr2
    25.11.2022 22:06
    -10

    Читаю спокойно, думаю, какой то низкоуровневый пост. "Ааа, так это же из песочницы".


    1. mSnus
      26.11.2022 02:30
      +5

      А вот это вообще не смешно, кстати


  1. HabrUser13
    26.11.2022 20:03
    +1

    Опечатка в предложении: "Вебпаку укажем, что используем плагин pug-plugin для файлов с расширением .pug"

    Скорее всего, имелось в виду:

    "Вебпаку укажем, что используем лоадер pug-loader для файлов с расширением .pug"

    Pug plugin - это новый подход к обработке Pug файлов. Он намного облегчает использование Pug в проекте и имеет функциональность плагинов, таких как:

    Используя Pug plugin, входной точкой является Pug файл. Все исходные файлы скриптов и стилей подключаются непосредственно в самом Pug файле с помощью require(). Это намного удобнее, чем импортировать стили в JavaScript файле. Pug plugin сам заменяет имена исходных файлов на их хешированные версии.

    Взято из  pug-plugin:

    Webpack конфиг:

    const path = require('path');
    const PugPlugin = require('pug-plugin');
    
    module.exports = {
      output: {
        path: path.join(__dirname, 'dist/'),
        // output filename of JS files
        filename: 'assets/js/[name].[contenthash:8].js'
      },
    
      entry: {
        // define Pug files in entry:
        index: './src/views/index.pug',      // => dist/index.html
        about: './src/views/about/index.pug' // => dist/about.html
        // ...
      },
    
      plugins: [
        // enable using Pug files as entry point
        new PugPlugin({
           extractCss: {
            // output filename of CSS files
            filename: 'assets/css/[name].[contenthash:8].css'
          },
        })
      ],
    
      module: {
        rules: [
          {
            test: /\.pug$/,
            loader: PugPlugin.loader, // the Pug loader
          },
          {
            test: /\.(css|sass|scss)$/,
            use: ['css-loader', 'sass-loader']
          },
        ],
      },
    };

    Pug файл:

    html
      head
        link(href=require('./styles.scss') rel='stylesheet')
      body
        h1 Hello Pug!
        script(src=require('./main.js'))

    Сгенерированный HTML:

    <html>
      <head>
        <link href="/assets/css/styles.f57966f4.css" rel="stylesheet">
      </head>
      <body>
        <h1>Hello Pug!</h1>
        <script src="/assets/js/main.b855d8f4.js"></script>
      </body>
    </html>

    Pug плагин также имеет Pug лоадер, который содержит встроенные фильтры для подсветки синтаксиса кода и markdown.

    Для активации встроенного markdown фильтра с highlighting'ом кода в markdown, нужно добавить опции в Pug лоадер:

    {
      test: /.pug$/,
      loader: '@webdiscus/pug-loader',
      options: {
        // enable embedded filters
        embedFilters: {
          // enable :markdown filter
          markdown: {
            // enable highlighting in markdown
            highlight: {
              verbose: true,
              use: 'prismjs',
            },
          },
        },
      },
    },

    В данный момент, для подсветки синтаксиса в markdown поддерживается PrismJS, который должен быть установлен дополнительно:

    npm install -D prismjs

    Теперь в Pug темплейте можно :markdown фильтр с блоками кода, например:

    h1 Markdown with code blocks
    
    :markdown
      _HTML_
      ```html
      <!-- Comment -->
      <div class="container">
        <p>Paragraph</p>
      </div>
      ```
    
      _JavaScript_
      ```js
      const arr = [1, 2, 'banana'];
      ```

    Примеры использования pug-filters встроенных в pug-loader.


    1. injashkin Автор
      26.11.2022 20:06

      Спасибо, исправил.


  1. Wyse
    26.11.2022 20:08

    Скажите, этот гайд достаточен чтобы с 0 начать пользоваться вебпаком как фронт ?
    До этого пользовался готовой сборкой "Фрилансера по жизни"


    1. injashkin Автор
      26.11.2022 20:17
      +1

      Собственно, для этой цели статья и написана. Если выполнять всё по порядку, то настроите рабочую сборку вебпак. Старался ничего не пропустить.


      1. Wyse
        27.11.2022 12:27

        Спасибо, сяду переписывать на днях с 0. А то не по себе пользоваться готовым сборщиком не зная как он устроен под капотом.


    1. lapaduga
      27.11.2022 23:28

      О, брат, я тоже этой сборкой пользуюсь)


  1. Fodoo
    27.11.2022 23:21

    Сборка для реакта подойдет или там по-другому настраивается?


    1. injashkin Автор
      27.11.2022 23:28

      Да, подойдет. Впрочем, я добавил в это руководство главу Установка и настройка React