jantimon / html-webpack-plugin

Simplifies creation of HTML files to serve your webpack bundles
MIT License
10.69k stars 1.31k forks source link

File does not render correctly / cannot get variable from options #1839

Open mateusz-grek opened 7 months ago

mateusz-grek commented 7 months ago

Current behaviour πŸ’£

I currently have the following file structure: emodelle.html locatedΒ in the de folder takes the element from de/components/02_footer_section/index.html and injects its contents into itself.

de/emodelle.html
de/components/02_footer_section/index.html
de/emodelle.html

DATA FROM FOOTER: <%= require('html-loader!./components/02_footer_section/index.html').default %> DATA STRAIGHT FROM EMODELLE: <%= htmlWebpackPlugin.options.newVariable %>

de/components/02_footer_section/index.html

<%= htmlWebpackPlugin.options.newVariable %>

This dynamic variable newVariable comes from webpack.config.js

const htmlPluginEntries = templateFiles.map((template) => new HTMLWebpackPlugin({
  inject: true,
  hash: false,
  filename: template.output,
  template: path.resolve(environment.paths.source, template.input),
  favicon: path.resolve(environment.paths.source, 'images', 'favicon.ico'),
  newVariable: 'New Variable test'
}));

Webpack.config.js

/**
 * Webpack main configuration file
 */

const path = require('path');
const fs = require('fs');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const SitemapPlugin = require('sitemap-webpack-plugin').default;
const Glob = require('glob');

let filesToIncludeArr = [];
let filesToIncludeArrSitemap = [];
const filesToInclude = Glob.sync('src/**/*.html').map(function(file) {

    filesToIncludeArr.push(file.replace('src/', ''));
    filesToIncludeArrSitemap.push(file.replace('src/', '').replace('.html', '').replace('index', ''));

  // filesToIncludeArr[entryKey] = file;
})
console.log(filesToIncludeArr);

// Example of simple string paths
const paths = filesToIncludeArrSitemap;

const environment = require('./configuration/environment');

const templateFiles = filesToIncludeArr
  .filter((file) => ['.html', '.ejs'].includes(path.extname(file).toLowerCase())).map((filename) => ({
    input: filename,
    output: filename.replace(/\.ejs$/, '.html'),
}));

const htmlPluginEntries = templateFiles.map((template) => new HTMLWebpackPlugin({
  inject: true,
  hash: false,
  filename: template.output,
  template: path.resolve(environment.paths.source, template.input),
  favicon: path.resolve(environment.paths.source, 'images', 'favicon.ico'),
  newVariable: 'New Variable test'
}));

module.exports = {
  entry: {
    app: path.resolve(environment.paths.source, 'js', 'app.js'),
  },
  output: {
    filename: 'js/[name].js',
    path: environment.paths.output,
  },
  module: {
    rules: [
      {
        test: /\.((c|sa|sc)ss)$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.(png|gif|jpe?g|svg|webp)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: environment.limits.images,
          },
        },
        generator: {
          filename: 'images/design/[name].[hash:6][ext]',
        },
      },
      {
        test: /\.(eot|ttf|woff|woff2)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: environment.limits.images,
          },
        },
        generator: {
          filename: 'images/design/[name].[hash:6][ext]',
        },
      },

    ],
  },
  optimization: {
    minimizer: [
      '...',
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminMinify,
          options: {
            // Lossless optimization with custom option
            // Feel free to experiment with options for better result for you
            plugins: [
              ['gifsicle', { interlaced: true }],
              ['jpegtran', { progressive: true }],
              ['optipng', { optimizationLevel: 5 }],
              // Svgo configuration here https://github.com/svg/svgo#configuration
              [
                'svgo',
                {
                  plugins: [
                    {
                      name: 'removeViewBox',
                      active: false,
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].css',
    }),
    new CleanWebpackPlugin({
      verbose: true,
      cleanOnceBeforeBuildPatterns: ['**/*', '!stats.json'],
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(environment.paths.source, 'images', 'content'),
          to: path.resolve(environment.paths.output, 'images', 'content'),
          toType: 'dir',
          globOptions: {
            ignore: ['*.DS_Store', 'Thumbs.db'],
          },
        },
        { from: "src/.htaccess"},
        { from: "src/robots.txt"},
        {
          from: path.resolve(environment.paths.source, 'videos'),
          to: path.resolve(environment.paths.output, 'videos'),
          toType: 'dir',
          globOptions: {
            ignore: ['*.DS_Store', 'Thumbs.db'],
          },
        },
      ],
    }),
    new SitemapPlugin({
      base: 'https://citroenist-mag.ch/',
      paths,
      options: {
        filename: 'sitemap.xml'
      }
    })

  ].concat(htmlPluginEntries),
  target: 'web',
};

Expected behaviour β˜€οΈ

When using the npm run dev command, the newVariable variable appears correctly from emodelle.html, but not from footer, but when I go directly to the footer file in the browser, I see the rendered variable.

It seems that when compiling, webpack only renders emodelle and takes its variables, while from footer it does not render anything, it only shows pure html as a string in emodelle.html

GOAL TO ACHIEVE

I would like to be able to add dynamic variables to the file de/components/02_footer_section/index.html which will then be rendered when compiling to emodelle.html

Reproduction Example πŸ‘Ύ

Environment πŸ–₯

Node.js v21.5.0
linux 6.5.0-15-generic

npm version: 10.2.4

npm ls webpack 
@weareathlon/frontend-webpack-boilerplate@5.16.0 /home/mateusz/Developer/xxx/xxx
β”œβ”€β”¬ babel-loader@9.1.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ clean-webpack-plugin@4.0.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ copy-webpack-plugin@11.0.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ css-loader@6.7.3
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ css-minimizer-webpack-plugin@4.2.2
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ html-loader@4.2.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ html-webpack-plugin@5.5.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ image-minimizer-webpack-plugin@3.8.1
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ mini-css-extract-plugin@2.7.2
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ postcss-loader@7.0.2
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ sass-loader@13.2.0
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ terser-webpack-plugin@5.3.6
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ webpack-cli@5.0.1
β”‚ β”œβ”€β”¬ @webpack-cli/configtest@2.0.1
β”‚ β”‚ └── webpack@5.75.0 deduped
β”‚ β”œβ”€β”¬ @webpack-cli/info@2.0.1
β”‚ β”‚ └── webpack@5.75.0 deduped
β”‚ β”œβ”€β”¬ @webpack-cli/serve@2.0.1
β”‚ β”‚ └── webpack@5.75.0 deduped
β”‚ └── webpack@5.75.0 deduped
β”œβ”€β”¬ webpack-dev-server@4.11.1
β”‚ β”œβ”€β”¬ webpack-dev-middleware@5.3.3
β”‚ β”‚ └── webpack@5.75.0 deduped
β”‚ └── webpack@5.75.0 deduped
└── webpack@5.75.0

npm ls html-webpack-plugin 

@weareathlon/frontend-webpack-boilerplate@5.16.0 /home/mateusz/Developer/xxx/xxx
└── html-webpack-plugin@5.5.0
alexander-akait commented 7 months ago

Please create reproducible test repo using github, thank you

mateusz-grek commented 7 months ago

Please see reproducible test repo as requested https://github.com/mateusz-grek/html-webpack-plugin-issue

alexander-akait commented 7 months ago

Because html-loader doesn't support variables, it is a future of html-webpack-plugin, you need to pass variables into <%= require('html-loader!./components/02_footer_section/index.html').default %>

There is an old issue - https://github.com/webpack-contrib/html-loader/issues/291, I recommend to use template engine for such purposes, we are still not sure it is a right solution to allow using require inside HTML files, that is why it is not finished and don't work in some cases