Output file does not contain markup. its more like a webpack js file that outputs markup
My html output contains webpack js, instead of html markup
webpack config:
new HtmlBundlerPlugin({
entry: {
article: "/src/views/article.html"
},
})
article.html:
<%~ include('/src/views/partials/_markup-top.html',{pageTitle: 'article', bodyClass: 'tier'}) %>
<main>main stuff for articles here.... </main>
<%~ include('/src/views/partials/_markup-bottom.html') %>
I would expect the html output to be something like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<title>article</title>
<meta name="description" content="test" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://fonts.googleapis.com/css?family=Roboto:400,500,700" rel="stylesheet">
</head>
<body class="tier">
<!-- Skip Nav -->
<div id="skip-nav">
<a href="#main">Skip Navigation</a>
</div>
<!-- Main Container -->
<main class="main-container" id="content">
<!-- markup -->
</main>
</body>
</html>
Actual output:
/******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/views/article.html":
/*!********************************!*\
!*** ./src/views/article.html ***!
\********************************/
/***/ (function(module) {
module.exports='<!DOCTYPE html>\n<html lang="en">\n\n<head>\n <meta charset="UTF-8" />\n <link
...
it's like it's treating this like a js file.
Environment: Mac OS node v16.13.2
webpack.config:
// Plugins
const path = require("path");
const glob = require("glob");
const TerserPlugin = require("terser-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const FileManagerPlugin = require("filemanager-webpack-plugin");
// const FileManagerPlugin = require("filemanager-plugin").WebpackFilemanager;
const HtmlBundlerPlugin = require("html-bundler-webpack-plugin");
const isHot = path.basename(require.main.filename) === "webpack-dev-server.js";
// Handle nested html partials
const INCLUDE_PATTERN = /<include src="(.+)"\s*\/?>(?:<\/include>)?/gi;
class CurrentTimePlugin {
constructor() {
// You can add any options you might want to pass to the plugin here
}
apply(compiler) {
compiler.hooks.done.tap("CurrentTimePlugin", (stats) => {
setTimeout(() => {
const currentTime = new Date().toLocaleString();
console.log("\n\n" + "=========================================================");
console.log("\t" + `Webpack compiled at: ${currentTime}`);
console.log("=========================================================");
}, 100);
});
}
}
const processNestedHtml = (content, loaderContext, dir = null) =>
!INCLUDE_PATTERN.test(content)
? content
: content.replace(INCLUDE_PATTERN, (m, src) => {
const filePath = path.resolve(dir || loaderContext.context, src);
loaderContext.dependency(filePath);
return processNestedHtml(loaderContext.fs.readFileSync(filePath, "utf8"), loaderContext, path.dirname(filePath));
});
module.exports = {
entry: {
app: [path.join(__dirname, "../src/js/app.js")]
},
devServer: {
static: {
directory: path.resolve(__dirname, "../dist"),
serveIndex: true,
watch: true
}
},
output: {
path: path.resolve(__dirname, "../dist"),
filename: "js/[name].js"
},
optimization: {
minimize: false,
minimizer: [
new TerserPlugin({
parallel: true
}),
new CssMinimizerPlugin()
]
},
resolve: {
extensions: [".js", ".css", ".scss"],
modules: ["node_modules"],
alias: {
request$: "xhr",
fonts: path.resolve(__dirname, "../src/fonts"),
components: path.resolve(__dirname, "../src/components"),
modules: path.resolve(__dirname, "../src/modules"),
styles: path.resolve(__dirname, "../src/styles")
}
},
module: {
rules: [
{
// babel-loader
test: /\.js$/,
exclude: /node_modules/,
rules: [
{
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true,
babelrc: false,
rootMode: "upward"
}
}
]
}
]
},
{
// json loader
test: /\.json$/,
loader: "json-loader"
},
{
// style loaders
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2,
esModule: false
}
},
{
loader: "postcss-loader",
options: {
sourceMap: true
}
},
{
loader: "resolve-url-loader"
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
},
{
// Loads fonts
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: "url-loader",
options: {
limit: true,
esModule: false
}
},
{
// Load images
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
generator: {
filename: "assets/[name][ext]"
}
},
{
// Allow partials in html pages.
test: /\.(html)$/,
// exclude: /node_modules/,
include: [path.resolve(__dirname, "../src/views/partials"), path.resolve(__dirname, "../src/components/icon-font/")],
use: {
loader: "html-loader",
options: {
preprocessor: processNestedHtml
}
}
}
]
},
stats: {
children: true
},
plugins: [
new FileManagerPlugin({
events: {
onEnd: [
{delete: ["./dist/images"]},
{delete: [path.join(__dirname, "../wp/wp-content/themes/2019-redesign/assets/*")]},
{
copy: [
{
source: path.join(__dirname, "../src/images"),
destination: path.join(__dirname, "../dist/images")
}
]
},
{
copy: [
{
source: path.join(__dirname, "../dist/images"),
destination: path.join(__dirname, "../wp/wp-content/themes/2019-redesign/assets/images")
}
]
},
{
copy: [
{
source: path.join(__dirname, "../dist/js"),
destination: path.join(__dirname, "../wp/wp-content/themes/2019-redesign/assets/js")
}
]
},
{
copy: [
{
source: path.join(__dirname, "../dist/css"),
destination: path.join(__dirname, "../wp/wp-content/themes/2019-redesign/assets/css")
}
]
}
]
}
}),
// MiniCssExtractPlugin
new MiniCssExtractPlugin({
filename: isHot ? "[name].css" : "css/[name].css",
chunkFilename: "[id].css"
}),
new ESLintPlugin(),
new CurrentTimePlugin(),
new HtmlBundlerPlugin({
entry: {
article: "/src/views/article.html"
},
})
]
};
@scott-primacy
please read the manual Install and Quick Start.
- delete the loader - MiniCssExtractPlugin.loader
- delete the plugin - MiniCssExtractPlugin
- delete the loader -
html-loader
Please create a small repository with reproducible issue, then I can help you.
@scott-primacy
the correct webpack config:
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
class CurrentTimePlugin {
constructor() {
// You can add any options you might want to pass to the plugin here
}
apply(compiler) {
compiler.hooks.done.tap('CurrentTimePlugin', (stats) => {
setTimeout(() => {
const currentTime = new Date().toLocaleString();
console.log('\n\n' + '=========================================================');
console.log('\t' + `Webpack compiled at: ${currentTime}`);
console.log('=========================================================');
}, 100);
});
}
}
module.exports = {
// NOTE: add the source JS file directly in the template using <script src="scripts/app.js"> tag, NOT here
// entry: {
// app: [path.join(__dirname, '../src/js/app.js')],
// },
devServer: {
static: {
directory: path.resolve(__dirname, '../dist'),
serveIndex: true,
watch: true,
},
},
output: {
path: path.resolve(__dirname, '../dist'),
//filename: 'js/[name].js', // <= MOVE into `js.filename` bundler plugin option
},
optimization: {
minimize: false,
minimizer: [
new TerserPlugin({
parallel: true,
}),
new CssMinimizerPlugin(),
],
},
resolve: {
//extensions: ['.js', '.css', '.scss'], // DON'T mix JS and SCSS extensions
extensions: ['.js'],
modules: ['node_modules'],
alias: {
request$: 'xhr',
fonts: path.resolve(__dirname, '../src/fonts'),
components: path.resolve(__dirname, '../src/components'),
modules: path.resolve(__dirname, '../src/modules'),
styles: path.resolve(__dirname, '../src/styles'),
scripts: path.resolve(__dirname, '../src/js'), // <= use alias to define JS in the template
images: path.join(__dirname, '../wp/wp-content/themes/2019-redesign/assets/images'), // <= use alias to define source image files
},
},
module: {
rules: [
{
// babel-loader
test: /\.js$/,
exclude: /node_modules/,
rules: [
{
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
babelrc: false,
rootMode: 'upward',
},
},
],
},
],
},
{
// json loader
test: /\.json$/,
loader: 'json-loader',
},
{
// style loaders
test: /\.(css|sass|scss)$/,
use: [
// MiniCssExtractPlugin.loader, // <= DELETE it
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
esModule: false,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
// Loads fonts
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: 'url-loader',
options: {
limit: true,
esModule: false,
},
},
{
// Load images
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'assets/[name][ext]',
},
},
// DELETE the html rule, DON'T use the `html-loader`
// {
// // Allow partials in html pages.
// test: /\.(html)$/,
// // exclude: /node_modules/,
// include: [
// path.resolve(__dirname, '../src/views/partials'),
// path.resolve(__dirname, '../src/components/icon-font/'),
// ],
// use: {
// loader: 'html-loader',
// options: {
// preprocessor: processNestedHtml,
// },
// },
// },
],
},
stats: {
children: true,
},
plugins: [
// NOTE: you can define source image files directly in template using the webpack alias to the image directory,
// then you don't need to copy source images into dist
new FileManagerPlugin({
events: {
onEnd: [
{ delete: ['./dist/images'] },
{
delete: [path.join(__dirname, '../wp/wp-content/themes/2019-redesign/assets/*')],
},
{
copy: [
{
source: path.join(__dirname, '../src/images'),
destination: path.join(__dirname, '../dist/images'),
},
],
},
{
copy: [
{
source: path.join(__dirname, '../dist/images'),
destination: path.join(__dirname, '../wp/wp-content/themes/2019-redesign/assets/images'),
},
],
},
{
copy: [
{
source: path.join(__dirname, '../dist/js'),
destination: path.join(__dirname, '../wp/wp-content/themes/2019-redesign/assets/js'),
},
],
},
{
copy: [
{
source: path.join(__dirname, '../dist/css'),
destination: path.join(__dirname, '../wp/wp-content/themes/2019-redesign/assets/css'),
},
],
},
],
},
}),
// MiniCssExtractPlugin // <= DELETE it
// new MiniCssExtractPlugin({
// filename: isHot ? '[name].css' : 'css/[name].css',
// chunkFilename: '[id].css',
// }),
new ESLintPlugin(),
new CurrentTimePlugin(),
new HtmlBundlerPlugin({
entry: {
article: './src/views/article.html',
},
js: {
filename: 'js/[name].js',
},
css: {
filename: 'css/[name].css',
chunkFilename: 'css/[name].chunk.css',
},
}),
],
};
Please create a repo, then I can help you more.
Thanks so much for your help. I created this little repo to help me get this working: https://github.com/scott-primacy/webpack
Unfortunately, it can't compile the html page tho.
Module build failed (from ./node_modules/html-bundler-webpack-plugin/src/Loader/index.js):
LoaderException:
HTML Bundler Plugin Resolving of source files in the template file failed.
File: src/views/article.html
Error: Cannot find module '/Users/scottr/work/webpack-testing/src/styles/app.css'
@scott-primacy
Cannot find module '/Users/scottr/work/webpack-testing/src/styles/app.css'
of course is not found. Did you see my PR? Firstly merge my PR into your demo and see how it works.
You should load the source SCSS file, not CSS, because css not exists and will be generate by the bundler plugin.
Just add the source SCSS file into HTML:
<link href="@styles/app.scss" rel="stylesheet">
and remove this file from JS.
@stylesis the webpack alias to/Users/scottr/work/webpack-testing/src/styles/
@scott-primacy is the issue still actual?