Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use templates? #43

Open
Devinora opened this issue Aug 14, 2022 · 2 comments
Open

How to use templates? #43

Devinora opened this issue Aug 14, 2022 · 2 comments

Comments

@Devinora
Copy link

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>
@emaphp
Copy link
Owner

emaphp commented Aug 17, 2022

Sup. Haven't work on this project for a while. I believe that the thing you're experiencing is normal, as underscore-template-loader works by loading a HTML template and returning a function that can be evaluated with a set of arguments. The code you're seeing is the resulting function of whatever snippet you're loading through html-loader. This loader shines best when you want to set content programatically on runtime.

@Devinora
Copy link
Author

Good afternoon. I don't really understand how it works under the hood, and what needs to be done for full work. Your loader helped to embed parts of pages, but unfortunately it doesn't work with html-loader. Happy to figure it out, but it takes time. It seems that I found a way out through the preprocessor parameter of the html-loader. The guys wrote a simple function that helps to embed fragments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants