I'm trying to configure webpack to generate HtmlWebpackPlugin
instances according to how many .handlebars
files I have in the Source folder.
The problem here is that even though inside the function everything comes back correctly, (names, file directories etc), when I try to call the function in the plugins section of webpack, I get nothing. By nothing, I mean I get no errors but when the server starts (the dev server), I get 'Cannot get' on the pages.
I'm pretty sure I am doing (or thinking something wrong) here, but why doesn't it generate the instances for me as it should?
webpack config:
var path = require('path');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var fs = require('file-system');
const templateFiles = fs.readdirSync(path.resolve(__dirname, "./Source/"));
//const devMode = process.env.NODE_ENV !== 'production'
const generateHtml = () => {
templateFiles.forEach((file) => {
if (file.indexOf(".handlebars") > -1) {
const name = file.split(".")[0];
const fileName = '.Source/' + file;
console.log("the file name@");
console.log(fileName);
return new HtmlWebpackPlugin({
title: name,
fileName: name + ".html",
template: fileName
});
}
});
};
const publicPath = '/';
module.exports = {
// set this to your entry point - make sure you go in there and request the css file that you need to be built
entry: {
index: "./Source/js/index.js"
},
output: {
//destination (dist) folder
path: path.resolve(path.join(__dirname, 'Build')),
filename: path.join('js', "bundle-[name].js"),
//folder where there actual server will throw files in
publicPath: publicPath,
},
// create a map file for debugging
devtool: 'source-map',
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
exclude: /node_modules/,
use: [{
loader: MiniCssExtractPlugin.loader,
},
{
loader: "css-loader", options: {
sourceMap: true
}
}, {
loader: "sass-loader", options: {
sourceMap: true
}
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
{
test: /\.handlebars$/,
loader: "handlebars-loader"
}
],
},
watch: false, // change this to true to keep webpack running
plugins: [
new MiniCssExtractPlugin({
//define actual folder structure to your style.css (the output)
//the scss file will be automatically retrieved from your index.js (or whatever the entry point you defined is)
filename: path.join('css', "style.css"),
}),
//serve my own html template and define where it is. Css injection implied.
generateHtml()
],
//open the dev server on command 'npm start' or 'npm run start:dev'
devServer: {
contentBase: path.join('index.handlebars'),
compress: true,
port: 3000
}
};`
Long story short: webpack cares what kind of object you give it to chew on. So, by default it won't let you execute functions inside the module.exports object that you give it.
Which brings me to my next point. And the answer:
So, I declared my config as a const, then generated a final object that webpack can read (the one with the multiple instances of HtmlWebpackPlugin) and then I fed that to Webpack and voila, final webpack.config:
var path = require('path');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var fs = require('file-system');
const templateFiles = fs.readdirSync(path.resolve(__dirname, "./Source/"));
//const devMode = process.env.NODE_ENV !== 'production'
const generateHtml = (config) => {
templateFiles.forEach((file) => {
if (file.indexOf(".handlebars") > -1) {
const name = file.split(".")[0];
const fileName = 'Source/' + file;
config.plugins.push(new HtmlWebpackPlugin({
title: name,
filename: name + ".html",
template: fileName
}));
}
});
return config
};
const publicPath = '/';
const baseConfig = {
// set this to your entry point - make sure you go in there and request the css file that you need to be built
entry: {
index: "./Source/js/index.js"
},
// change this to your dist folder - Build in this case.
output: {
path: path.resolve(path.join(__dirname, 'Build')),
filename: path.join('js', "bundle-[name].js"),
//folder where there actual server will throw files in
publicPath: publicPath,
},
// create a map file for debugging
devtool: 'source-map',
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
exclude: /node_modules/,
use: [{
loader: MiniCssExtractPlugin.loader,
},
{
loader: "css-loader", options: {
sourceMap: true
}
}, {
loader: "sass-loader", options: {
sourceMap: true
}
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
{
test: /\.handlebars$/,
loader: "handlebars-loader"
}
],
},
watch: false, // change this to true to keep webpack running
plugins: [
new MiniCssExtractPlugin({
//define actual folder structure to your style.css (the output)
//the scss file will be automatically retrieved from your index.js (or whatever the entry point you defined is)
filename: path.join('css', "style.css"),
}),
//serve my own html template and define where it is. Css injection implied.
],
//open the dev server on command 'npm start' or 'npm run start:dev'
devServer: {
contentBase: path.join('index.handlebars'),
compress: true,
port: 3000
}
};
console.log(baseConfig)
const config = generateHtml(baseConfig)
//feed new config object to webpack
module.exports = config