Skip to content

How to use templates? #43

@Devinora

Description

@Devinora

I am using html-loader and underscore-template-loader. Together they don't work properly. I just need to port the repetitive parts of the page.

webpack.config

// Модуль 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`;
    },
    // pathinfo: 'verbose',
    // assetModuleFilename: 'images/[hash][ext][query]',
    clean: true,
    // Добавляет URL в тег script: ./js/index.js
    // publicPath: './js/',
    // chunkFilename: `${projectPath.outputJs}[name]~[chunkhash:8].js`,
  },
  optimization: {
    minimize: false,
    // chunkIds: 'named',
    // Разобраться с именами чанков. в output перестал работать chunkFilename, из-за splitChunks. https://github.com/webpack/webpack/issues/9297
    splitChunks: {
      // test: /[\\]js[\\]pages[\\]/,
      // chunks: 'all',
      // minSize: 0,
      // name: setChunksName,
      cacheGroups: {
        // common: {
        //   test: /[\\]js[\\]pages[\\]/,
        // },
        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: {
    // Сообщите webpack, в каких каталогах следует искать при разрешении модулей.
    modules: ['node_modules'],
    // alias: {
    //   // mdl: path.resolve(__dirname, 'src/js/modules')
    // },
    // позволяет пользователям не использовать расширение при импорте:
    // import File from '../path/to/file';
    // Базовые настройки
    // extensions: ['.wasm', '.mjs', '.js', '.json'],
    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',
    }),
    // Плагин игнорирует файлы.
    // new IgnoreEmitPlugin(/^.+?styles.+?\.js$/),
    // // Не добавляет файл в HTML
    // new HtmlWebpackSkipAssetsPlugin({
    //   excludeAssets: [/^.+?styles.+?\.js$/],
    // }),
    // Динамическое создание файлов 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],
      });
    }),
  ],
};

Compiled HTML

<body class="page">
  module.exports = function(obj) { obj || (obj = {}); var __t, __p = ''; with
  (obj) { __p += '\r\n\r\n\r\n\r\n\r\n <meta charset="utf-8" />\r\n
  <title>Webpack: Home</title>\r\n
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />\r\n
  <meta
    name="viewport"
    \r\n=""
    content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,shrink-to-fit=no"
  />\r\n
  <link
    rel="shortcut icon"
    type="image/png"
    href="img/favicon~6a4b5400..png"
  />\r\n <link href="css/index~8e108267.css" rel="stylesheet" />\r\n\r\n\r\n
  <div class="page__w">
    \r\n
    <header class="header">
      \r\n
      <ul class="nav header__nav">
        \r\n
        <h1>Маргоша</h1>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
        <li class="nav__item">Test</li>
        \r\n
      </ul>
      \r\n
      <div class="img-w">
        \r\n <img src="img/two~a7efde2e..jpg" alt="" class="img-w__img" />\r\n
      </div>
      \r\n
    </header>
    \r\n ' + require("./templates/base/footer.html").apply(null,arguments) +
    '\r\n
  </div>
  \r\n
  <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>
  \r\n'; } return __p };
</body>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions