Правильный способ использования Webpack для объединения HTML-страницы с CSS и JS

Правильный способ использования 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 лет и могут содержать устаревшие версии этих шаблонизаторов. Это означает, что вы не можете использовать функции (или исправления) последней версии шаблонизатора.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE