Devinora
@Devinora
Front-end web development

Как использовать шаблоны в Webpack для HTML?

Необходимо внедрить куски страницы через шаблонизатор или иным способом.
Я использую HtmlWebpackPlugin и html-loader.
У HtmlWebpackPlugin есть пример, который работает: <%= require('html-loader!./templates/base/footer.h... Проблема в том, что html-loader работает только в таком варианте, но когда использую в своей конфигурации, то получаю это:

HTML уже обработанный webpack
// Модуль path предоставляет утилиты для работы с путями к файлам и каталогам. Доступ к нему можно получить, используя:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// Источник: https://github.com/jantimon/html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

// Пользовательские зависимости.

// Объект с путями.
const projectPath = require('./modules/projectPath');
// Метод для поиска файлов.
const fileFilter = require('./modules/fileFilter');
// Временная переменная, которая определяет режим сборки.
const { NODE_ENV } = process.env;
// ОбЪект с рабочими файлами
// js: {
//   expansion: '.js',
//   names: ['cart', 'index', 'profile'],
// };
const fileList = fileFilter([
  {
    source: path.join(projectPath.context, projectPath.entry),
    fileExtension: '.js',
  },
  {
    source: projectPath.context,
    fileExtension: '.html',
  },
]);

const setChunksName = function (module, chunks, cacheGroupKey) {
  let moduleName = module.identifier();

  function getStr(str, start, end) {
    const strStart = str.lastIndexOf(start) + 1;
    const strEnd = str.lastIndexOf(end);
    return str.slice(strStart, strEnd);
  }

  moduleName = getStr(moduleName, '\\', '.');

  const allChunksNames = chunks.map((item) => item.name).join('~');
  return `${cacheGroupKey}~${allChunksNames}~${moduleName}`;
};

module.exports = {
  context: projectPath.context,
  stats: {
    children: true,
  },
  entry: () => {
    // Объект в котором будут сгенерированы точки входа.
    const entryPoints = {};
    // Цикл для автоматической генерации точек входа.
    fileList.js.names.forEach((element) => {
      // Расширение файла
      const { expansion } = fileList.js;
      // Присваивание имени файла
      entryPoints[element] = `${projectPath.entry}${element}${expansion}`;
    });
    return entryPoints;
  },
  output: {
    path: projectPath.output,
    filename: (pathData) => {
      if (NODE_ENV === 'production') {
        return `${projectPath.outputJs}[name]~[chunkhash:8].js`;
      }
      return `${projectPath.outputJs}[name].js`;
    },
    clean: true,
  },
  optimization: {
    minimize: false,
    splitChunks: {
        modules: {
          test: /[\\/]js[\\/]modules[\\/]/,
          chunks: 'all',
          minSize: 0,
          name: setChunksName,
        },
      },
    },
  },
  module: {
    // Загрузчики оцениваются / выполняются справа налево (или снизу вверх).
    // По моим догадкам, это работает внутри каждого элемента массива - rules (непосредственно внутри объекта).
    rules: [
      // Babel START
      {
        // "test" аналог "include". это две одинаковые команды(свойства), но есть соглашение что "test" используется для проверки разрешения (регулярное выражение), а "include" используется для проверки путей.
        test: /\.js$/,
        // Исключение, к которым не будет применяться "loader".
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            // Пример для браузеров
            // presets: [
            //   ['@babel/preset-env', { targets: 'ie 11' }]
            // ]
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime'],
          },
        },
      },
      // Babel END
      // HTML START
      {
        test: /\.html$/i,
        use: [
          {
            loader: 'html-loader',
            options: {
              // esModule: false,
            },
          },
          // {
          //   loader: 'underscore-template-loader',
          //   options: {
          //     attributes: [],
          //   },
          // },
        ],
      },
      // HTML END
      // Sass START
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            // Ждя Dev использовать style loader, или разобраться с тем, который есть
            loader: MiniCssExtractPlugin.loader,
            // options: {
            //   hmr: NODE_ENV === "development",
            //   reloadAll: true,
            // },
          },
          // {
          //   loader: 'style-loader',
          // },
          {
            loader: 'css-loader',
            options: {
              // sourceMap: true,
              // importLoaders: 1,
            },
          },
          {
            loader: 'sass-loader',
            // options: {
            //   sourceMap: true,
            // },
          },
        ],
      },
      // Sass END
      // Image END
      {
        test: /[\\]img[\\].*(gif|png|jpe?g|svg)$/i,
        loader: 'image-webpack-loader',
        generator: {
          filename: 'img/[name]~[contenthash:8].[ext]',
        },
        options: {
          mozjpeg: {
            progressive: true,
          },
          // optipng.enabled: false will disable optipng
          optipng: {
            enabled: false,
          },
          pngquant: {
            quality: [0.65, 0.9],
            speed: 4,
          },
          gifsicle: {
            interlaced: false,
          },
          // the webp option will enable WEBP
          webp: {
            quality: 75,
          },
        },
      },
      // Image END
      // Fonts START
      {
        test: /[\\]fonts[\\].*(png|woff|woff2|eot|ttf|svg)$/,
        // type: 'asset/resource',
        generator: {
          filename: 'fonts/[name]~[contenthash:8].[ext]',
        },
      },
      // Fonts END
    ],
  },
  resolve: {
    extensions: ['.js', '.json', '.jsx', '.css', '.sass', '.scss', '.html'],
  },
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: 'css/[name]~[chunkhash:8].css',
      chunkFilename: 'css/[name]~[chunkhash:8].css',
    }),
    // Динамическое создание файлов HTML
    ...fileList.html.names.map((page) => {
      // Расширение файла
      const { expansion } = fileList.html;
      return new HtmlWebpackPlugin({
        filename: `${page}${expansion}`,
        template: `${projectPath.context}/${page}${expansion}`,
        inject: 'body',
        // Отвечает за подключение JS файлов
        chunks: [page],
      });
    }),
  ],
};

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="utf-8" />
    <title>Webpack: Home</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,shrink-to-fit=no"
    />
    <link
      rel="shortcut icon"
      type="image/png"
      href="img/favicon~6a4b5400..png"
    />
    <link href="css/index~8e108267.css" rel="stylesheet" />
  </head>
  <body class="page">
    <div class="page__w">
      <header class="header">
        <ul class="nav header__nav">
          <h1>Маргоша</h1>
          <li class="nav__item">Test</li>
          <li class="nav__item">Test</li>
          <li class="nav__item">Test</li>
          <li class="nav__item">Test</li>
          <li class="nav__item">Test</li>
          <li class="nav__item">Test</li>
        </ul>
        <div class="img-w">
          <img src="img/two~a7efde2e..jpg" alt="" class="img-w__img" />
        </div>
      </header>
      <%= require('./templates/base/footer.html').default %>
    </div>
    <script
      defer="defer"
      src="js/modules~cart~index~profile~global~eccab143.js"
    ></script>
    <script defer="defer" src="js/modules~cart~index~test~a902f87e.js"></script>
    <script defer="defer" src="js/index~8e108267.js"></script>
  </body>
</html>


Так же пытался использовать underscore-template-loader, но в связке с html-loader работает не корректно. Не могу ставить, ибо много текста.

1. html-loader работает только inline, но меня это не устраивает, так как я использую его в конфиге.
2. underscore-template-loader тоже работает, но когда он является единственным лоадером.

P.S: Я использую чистый HTML, и не хотел бы прибегать к использованию других шаблонизаторов. Мне просто нужно интегрировать части страниц. Буду благодарен, если подскажите как это реализовать по простому. Так же встречалось, что вроде можно использоваться синтаксис lodash или underscore, но не пойму как заставить это работать.

Мой шаблон(код) webpack сборки на github: webpack-template
  • Вопрос задан
  • 810 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы