Правильный способ использования Webpack для объединения HTML-страницы с CSS и JS
14 февраля 2023 г.Обычно младший веб-разработчик сталкивается с проблемой использования сложной настройки Webpack для создания простой HTML-страницы с помощью JS и CSS. Во-первых, вам нужно знать, где и как соединить исходные стили и скрипты с HTML, и где определить сам HTML-шаблон. Нужно знать, какие плагины и загрузчики для этого нужны и как их настроить. Весь процесс не простой и не интуитивный. Более того, конфигурации происходят в разных местах.
До сих пор приходилось использовать такие плагины и загрузчики, как:
| Пакет | Описание |
|----|----|
| html-webpack-плагин | создает HTML и вставляет тег script
для скомпилированного JS-файла в HTML |
| мини-css-экстракт-плагин | вставляет тег link
для обработанного файла CSS в HTML |
| webpack-удалить-пустые-скрипты | удаляет сгенерированные пустые файлы JS |
| html-загрузчик | экспортирует HTML |
| загрузчик стилей | вставляет встроенный CSS в HTML |
| постhtml-встроенный-SVG | вставляет встроенный значок SVG в HTML |
| разрешение-url-загрузчик | разрешает относительный URL в CSS |
| svg-url-загрузчик | кодирует URL-адрес данных SVG как utf8 |
Наконец появился новый подключаемый модуль HTML Bundler для Webpack, заменивший этот зоопарк. плагинов и делает настройку Webpack невероятно простой, логичной и интуитивно понятной. Что еще? весь конфиг происходит в одном месте.
Этот плагин позволяет вам использовать HTML-шаблон в качестве отправной точки для всех зависимостей, используемых в вашем веб-приложении. Все исходные стили и скрипты, указанные в HTML, обрабатываются, а извлеченные JS и CSS сохраняются в выходной каталог.
Простой пример использования
Например, у вас есть шаблон HTML, содержащий скрипт, стиль и изображение.
Вы можете добавлять исходные файлы сценариев и стилей непосредственно в HTML, используя относительный путь или псевдоним Webpack:
<html>
<head>
<!-- load source style here -->
<link href="./style.scss" rel="stylesheet">
<!-- load source script here -->
<script src="./main.js" defer="defer"></script>
</head>
<body>
<h1>Hello World!</h1>
<!-- @images is Webpack alias for the source images directory -->
<img src="@images/logo.png">
</body>
</html>
Исходные файлы обрабатываются с помощью загрузчиков Webpack, и плагин автоматически подставляет имена выходных файлов в сгенерированный файл HTML:
<html>
<head>
<link href="assets/css/style.05e4dd86.css" rel="stylesheet">
<script src="assets/js/main.f4b855d8.js" defer="defer"></script>
</head>
<body>
<h1>Hello World!</h1>
<img src="assets/img/logo.58b43bd8.png">
</body>
</html>
В конфигурации Webpack определите HTML-шаблон в качестве точки входа в параметре entry
:
const path = require('path');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
module.exports = {
output: {
path: path.join(__dirname, 'dist/'),
},
plugins: [
new HtmlBundlerPlugin({
entry: {
// define HTML files here
// output dist/index.html
index: 'src/views/home/index.html',
// output dist/pages/about.html
'pages/about': 'src/views/about/index.html',
// ...
},
js: {
// output filename of extracted JS
filename: 'assets/js/[name].[contenthash:8].js',
},
css: {
// output filename of extracted CSS
filename: 'assets/css/[name].[contenthash:8].css',
},
}),
],
module: {
rules: [
// HTML templates
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader, // HTML template loader
},
// styles
{
test: /.(css|sass|scss)$/,
use: ['css-loader', 'sass-loader'],
},
// images
{
test: /.(png|jpe?g|ico|svg)$/,
type: 'asset/resource',
generator: {
filename: 'assets/img/[name].[hash:8][ext]',
},
},
],
},
};
Использование механизма шаблонов
Вы можете использовать любой механизм шаблонов, такой как EJS, Handlebars, Nunjucks и другие, без загрузчиков шаблонов.
Например, есть файл шаблона Handlebars index.html:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ headline }}</h1>
<div>
<p>{{ firstname }} {{ lastname }}</p>
</div>
</body>
</html>
Чтобы скомпилировать исходный шаблон в HTML, используйте параметр preprocessor
загрузчика. В препроцессоре
можно использовать любой модуль шаблонов JS. В нашем случае это рули.
// ...
module: {
rules: [
{
test: /.html$/, // must match the files specified in the entry
loader: HtmlBundlerPlugin.loader,
options: {
// add the preprocessor option to compile template into HTML
// - content is a source of a template file
// - data is an object defined in the entry option
preprocessor: (content, { data }) => Handlebars.compile(content)(data),
},
},
],
},
// ...
Подробнее о параметре preprocessor
см. здесь.
Для передачи переменных в шаблон используйте расширенный синтаксис параметра entry
и свойства data
:
new HtmlBundlerPlugin({
entry: {
index: { // => the key is the HTML output filename w/o extension
import: './src/views/home/index.html',
// pass data into the template (via preprocessor)
data: {
// ... variables as key:value
},
},
},
}),
Полная конфигурация Webpack:
const path = require('path');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
const Handlebars = require('handlebars');
module.exports = {
output: {
path: path.join(__dirname, 'dist/'),
},
plugins: [
new HtmlBundlerPlugin({
entry: {
index: {
import: './src/views/home/index.html',
data: {
title: 'Heisenberg',
headline: 'Breaking Bad',
firstname: 'Walter',
lastname: 'White',
},
},
},
}),
],
module: {
rules: [
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: (content, { data }) => Handlebars.compile(content)(data),
},
},
// ... other rules, e.g. for styles, images, fonts, etc.
],
},
};
Сгенерированный HTML:
<html>
<head>
<title>Heisenberg</title>
</head>
<body>
<h1>Breaking Bad</h1>
<div>
<p>Walter White</p>
</div>
</body>
</html>
Вы можете использовать другие шаблоны, вот несколько примеров использования препроцессора
для разных механизмов шаблонов.
Рули
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
const Handlebars = require('handlebars');
module.exports = {
// ...
module: {
rules: [
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: (content, { data }) => Handlebars.compile(content)(data),
},
},
],
},
};
Усы
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
const Mustache = require('mustache');
module.exports = {
// ...
module: {
rules: [
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: (content, { data }) => Mustache.render(content, data),
},
},
],
},
};
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
const Nunjucks = require('nunjucks');
module.exports = {
// ...
module: {
rules: [
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: (content, { data }) => Nunjucks.renderString(content, data),
},
},
],
},
};
EJS
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
const ejs = require('ejs');
module.exports = {
// ...
module: {
rules: [
{
test: /.html$/,
loader: HtmlBundlerPlugin.loader,
options: {
preprocessor: (content, { data }) => ejs.render(content, data),
},
},
],
},
};
Таким образом, вы можете использовать последнюю версию любого механизма шаблонов, независимо от того, существует ли для него загрузчик Webpack и насколько он актуален.
Часто многие оригинальные загрузчики не обновлялись более 2 лет и могут содержать устаревшие версии этих шаблонизаторов. Это означает, что вы не можете использовать функции (или исправления) последней версии шаблонизатора.
Оригинал