'Multiple html files using webpack
I'm trying to do something in a project that I'm not sure if it is possible, I am in a wrong way or misunderstanding something. We are using webpack, and the idea is to serve more than one html file.
localhost:8181 -> serves index.html
localhost:8181/example.html -> serves example.html
I'm trying to do it by setting multiple entry points, following the documentation:
The folder structure is:
/
|- package.json
|- webpack.config.js
/src
|- index.html
|- example.html
| /js
|- main.js
|- example.js
Webpack.config.js:
...
entry: {
main: './js/main.js',
exampleEntry: './js/example.js'
},
output: {
path: path.resolve(__dirname, 'build', 'target'),
publicPath: '/',
filename: '[name].bundle.js',
chunkFilename: '[id].bundle_[chunkhash].js',
sourceMapFilename: '[file].map'
},
...
index.html
<!DOCTYPE html>
<html
<head>
...
<link type="text/css" href="/style/default.css">
</head>
<body>
<div id="container"></div>
<script src="/main.bundle.js"></script>
</body>
</html>
example.html:
<!DOCTYPE html>
<html
<head>
...
<link type="text/css" href="/style/default.css">
</head>
<body>
...
<script src="/example.bundle.js"></script>
</body>
</html>
Somebody knows what I'm doing wrong?
Thank you.
Solution 1:[1]
To use Multiple HTML files in Webpack using HtmlWebpackPlugin :
Modify the
webpack.config.jsby directly embedding the below code.
const HtmlWebpackPlugin = require('html-webpack-plugin');
let htmlPageNames = ['example1', 'example2', 'example3', 'example4'];
let multipleHtmlPlugins = htmlPageNames.map(name => {
return new HtmlWebpackPlugin({
template: `./src/${name}.html`, // relative path to the HTML files
filename: `${name}.html`, // output HTML files
chunks: [`${name}`] // respective JS files
})
});
module.exports = {
entry: {
main: './js/main.js',
example1: './js/example1.js',
//... repeat until example 4
},
module: {
//.. your rules
};
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
chunks: ['main']
})
].concat(multipleHtmlPlugins)
};
You can add as many HTML pages as required to the htmlPageNames array. Ensure that each HTML and corresponding JS file have the same name (The above code assumes that).
Solution 2:[2]
You can also use Copy Webpack Plugin if you don't need two different builds, i.e., assuming that you just want to serve a different HTML with the same main.bundle.js.
The plugin is really dead simple (only tested in webpack v4):
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
plugins: [
new CopyWebpackPlugin([
{ from: './src/example.html', to: './example.html' }
])
]
}
Then in example.html you can load the build from index.html. E.g.:
<!DOCTYPE html>
<html
<head>
...
<title>Example</title>
</head>
<body>
<div id="container"> Show an example </div>
<script src="main.bundle.js"></script>
</body>
</html>
Solution 3:[3]
RICHARD ABRAHAM's solution worked well for me i also added fsreaddir function for detect html files
let htmlPageNames = [];
const pages = fs.readdirSync('./src')
pages.forEach(page => {
if (page.endsWith('.html')) {
htmlPageNames.push(page.split('.html')[0])
}
})
console.log(htmlPageNames);
Solution 4:[4]
There is another solution, assuming Webpack ^4.44.1. That is, importing the HTML in your JS/TS app.
Sample webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: { app: './src/index.ts' },
mode: 'development',
devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Development',
template: path.join(path.resolve(__dirname, 'src'), 'index.ejs')
}),
],
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
include: [path.resolve(__dirname, 'src')],
exclude: /node_modules/,
},
{
test: /\.html$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
}
],
// this exclude is required
exclude: path.join(path.resolve(__dirname, 'src'), 'index.html')
}
],
},
resolve: {
extensions: ['.ts', '.js'],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 3900
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
Corresponding app
import './about.html';
console.log('this is a test');
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Question</title>
</head>
<body>
<a href="./about.html">About</a>
</body>
</html>
about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>About</title>
</head>
<body>
<p>This is an about page</p>
</body>
</html>
Webpack will copy about.html to the corresponding output folder.
Solution 5:[5]
plugins: [
...templates.map(template => new HtmlWebpackPlugin(template))
]
This code would help if you have a lot of templates :)
Solution 6:[6]
Going back to @andreas-jägle point. Use 'html-webpack-plugin':html-webpack-plugin html-webpack-plugin. However optimise your code to avoid duplication of files:
plugins: ['index', 'page1', 'page2'].map(
(file) =>
new HtmlWebpackPlugin({
template: './src/' + file + '.html',
inject: true,
chunks: ['index', 'main'],
filename: './' + file + '.html' //relative to root of the application
})
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | RICHARD ABRAHAM |
| Solution 2 | F Lekschas |
| Solution 3 | Akif Kara |
| Solution 4 | |
| Solution 5 | Pavel Rodionov |
| Solution 6 | rottitime |
