Have you ever wondered how to build multiple-page website with webpack? If that's your case - either due to maintaining a legacy page, or some current architectural decisions - the materials focused on single-page-app (SPA) can leave you with some doubts.
Define dynamically an entry for each page
In our case, we need to define one entry for each page. Assuming we have a list of pages in an array pages = ['a', 'b']
, the entry:
section of webpack config can look like:
entry: pages.reduce((config, page) => {
config[page] = `./src/${page}.js`;
return config;
}, {}),
with just a bit of functional programming, we turned the pages
list into:
{
a: '.src/a.js',
b: '.src/b.js'
}
that we can set to entry
. Because of doing it this way, the next time when we add a new page, it will be just adding one element to the list, without copy&pasting code.
Inject all the necessary code to html
Same as with SPAs, we want to inject the imports dynamically into your html. For that we useHtmlWebpackPlugin
. Again, we want to use our pages
array, so we avoid repeating code when we add new pages. So we will build our plugins:
dynamically & we will leave a place to add some other, unrelated plugins there too.
plugins: [].concat(
pages.map(
(page) =>
new HtmlWebpackPlugin({
inject: true,
template: `./${page}.html`,
filename: `${page}.html`,
chunks: [page],
})
),
// <- here goes array(s) of other plugins
),
Optimization
To get the most out of our architecture, we need to split built code into chunks. That will allow us to reuse portions of code if they are big enough and used across multiple pages. Luckily, we can achieve that by just adding:
optimization: {
splitChunks: {
chunks: "all",
},
},
Complete configuration & example app
The complete, working configuration:
const path = require("path"),
HtmlWebpackPlugin = require("html-webpack-plugin");
const pages = ["a", "b"];
module.exports = {
entry: pages.reduce((config, page) => {
config[page] = `./src/${page}.js`;
return config;
}, {}),
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
},
optimization: {
splitChunks: {
chunks: "all",
},
},
plugins: [].concat(
pages.map(
(page) =>
new HtmlWebpackPlugin({
inject: true,
template: `./${page}.html`,
filename: `${page}.html`,
chunks: [page],
})
)
),
};
To play with it, the easiest way is to check out the repo of an example app:
https://github.com/marcin-wosinek/webpack-multipage-example
Links
Want's more?
Here you can find me going through the example with details:
Top comments (14)
Thank You so much for sharing your knowlage. Your solution is almost perfect for my needs. I just wounder if You have any idea how to use it in dot.net MVC applications?
I have one layout template and my partial views have @Sripts sections where I would like to push chunks that webpack creates for me auto-magic :-) My views lives in Views map and I'm not really sure how to approach that problem.
Any ideas?
I have seen some dot.net applications using modern JS, but the integration was done on the dot.net side. No idea how webpack can be used in that scenario, I guess there should be one of those options possible:
I was able to solve it with HtmlWebpackPlugin and templates that building my script/style secion into partial views.
Had to add cutom html extension (found here: [stackoverflow.com/questions/543353...] ) to could render those sections in my partial, it is not allowed by default.
Working great. Thank You for the idea with HtmlWebpackPlugin, wouldn't come so far without that.
Thank You.
So far so good but I am stuck as to how I can add database content at a pre-render stage so that ejs templating can be used? I don't want to do DOM manipulation.
sounds more like a job for a tool like NextJs. Doing it with webpack will be probably doable - the is plenty of loaders etc. but I'm afraid you will get to uncharted territory pretty fast.
I am a plain vanilla user so I don't think NextJs is my cup of tea.
What DB you want to connect to? Is it something that could be replaced with flat MD or text files in the repo?
actually I am using fetch to connect to the url which links to a MS-SQL database. It's a large db and the site I am converting from a Delphi based program to a microservice.
For me it sounds you are more in static page generation area, and less in the JS applications where webpack thrives.
You can consider:
Hi Thanks for the nicely engineered code, not what i used in my project but I have a little problem while it works its a bit mess I guess it's my fault somewhere and I can't find the problem. I'm building small web for my photography only 2 html's.
This msg in console and functionality makes me headache , webpack-internal:///./src/imgslide.js:12 Uncaught TypeError: Cannot read properties of null (reading 'classList') at nextImg (imgslide.js:12:13) ,
obviously it can not read the 'classList' coz it doesn't exist in contact.html , it's different then index.html, can I ask you for some suggestions what might went wrong.
Gracias :)
how can use access the page in brower after config ? Dont need to change dev server config? but this so i can not see page?
I'm not sure if I understand the question. Do you want to start a dev server & access the website form the browser? Can you see any URLs the the output of the command that started the dev server?
yes it is my question. I fixed it. set dev open brower auto then accecss the page.