Anyway to tell webpack in a project with multiple entries to include only respective css for each entry?
Seems like it extracts all css across all entries, puts them under vendor.css
and includes that css into all of the entries. And I can't figure out how to tell it to separate the css per entry.
It's a Vue3 project, but the solution should be webpack specific.
Anyway, my vue.config.js
goes something like this:
module.exports = {
...
pages:{
entry1:{
entry:"./src/entry/entry1.js",
template:"public/entry1.html"
},
entry2:{
entry:"./src/entry/entry2.js",
template:"public/entry2.html"
}
},
...
configureWebpack:{
...
}
}
entry1.js:
import css1.css
...
entry2.js:
import css2.css
...
Now I need to build entry1.html
with only styles from css1.css
included and entry2.html
with only styles from css2.css
included.
Instead webpack combines all styles from both css1.css
and css2.css
into a single file and includes that resulting file into the both htmls.
I was trying to play around with MiniCssExtractPlugin
configs and chunk naming but no luck so far.
Anyway to tell webpack in a project with multiple entries to include only respective css for each entry?
Seems like it extracts all css across all entries, puts them under vendor.css
and includes that css into all of the entries. And I can't figure out how to tell it to separate the css per entry.
It's a Vue3 project, but the solution should be webpack specific.
Anyway, my vue.config.js
goes something like this:
module.exports = {
...
pages:{
entry1:{
entry:"./src/entry/entry1.js",
template:"public/entry1.html"
},
entry2:{
entry:"./src/entry/entry2.js",
template:"public/entry2.html"
}
},
...
configureWebpack:{
...
}
}
entry1.js:
import css1.css
...
entry2.js:
import css2.css
...
Now I need to build entry1.html
with only styles from css1.css
included and entry2.html
with only styles from css2.css
included.
Instead webpack combines all styles from both css1.css
and css2.css
into a single file and includes that resulting file into the both htmls.
I was trying to play around with MiniCssExtractPlugin
configs and chunk naming but no luck so far.
2 Answers
Reset to default 1Ok, the solution was as simple as setting optimization.splitChunks.minChunks = 2
(since I have two entries):
configureWebpack: {
optimization: {
splitChunks: {
...
minChunks: 2, // <- this was the fix. Indicates that modules must be imported at least twice before merging them into a common chunk
}
}
split-chunks-plugin doc reference
You can use the html-bundler-webpack-plugin which allow exactly that you need.
Using the Bundler Plugin, an entry point is an HTML template.
All your source asset files (scripts, styles, images, etc.) can be specified directly in the HTML template using <script>
and <link>
tags.
The plugin resolves source files of assets in templates and replaces them with correct output URLs in the generated HTML.
The resolved assets will be processed via Webpack plugins/loaders and placed into the output directory.
For example, there is the HTML template src/entry/home.html
:
<!DOCTYPE html>
<html>
<head>
<!-- relative path to CSS/SCSS source file src/entry/home.css -->
<link href="./home.css" rel="stylesheet">
<!-- relative path to JS source file src/entry/home.js -->
<script src="./home.js" defer="defer"></script>
</head>
<body>
<h1>Home</h1>
</body>
</html>
there is other HTML template src/entry/about.html
:
<!DOCTYPE html>
<html>
<head>
<!-- relative path to CSS/SCSS source file src/entry/about.css -->
<link href="./about.css" rel="stylesheet">
<!-- relative path to JS source file src/entry/about.js-->
<script src="./about.js" defer="defer"></script>
</head>
<body>
<h1>About</h1>
</body>
</html>
Webpack config:
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new VueLoaderPlugin(),
new HtmlBundlerPlugin({
entry: {
index: 'src/entry/home.html', // save generated HTML into dist/index.html
about: 'src/entry/about.html', // save generated HTML into dist/about.html
},
js: {
filename: 'js/[name].[contenthash:8].js', // JS output filename
},
css: {
filename: 'css/[name].[contenthash:8].css', // CSS output filename
},
}),
],
module: {
rules: [
{
test: /\.vue$/i,
use: ['vue-loader'],
},
{
test: /\.s?css$/,
use: ['css-loader', 'sass-loader'], // you can use both SCSS and CSS
},
],
},
};
The HtmlBundlerPlugin replaces the functionality of many plugins and loaders:
- html-webpack-plugin
- mini-css-extract-plugin
- and many others
The generated HTML contains output URLs:
dist/index.html
:
<!DOCTYPE html>
<html>
<head>
<link href="css/home.1234abcd.css" rel="stylesheet">
<script src="js/home.adbc1234.js" defer="defer"></script>
</head>
<body>
<h1>Home</h1>
</body>
</html>
dist/about.html
:
<!DOCTYPE html>
<html>
<head>
<link href="css/about.1234abcd.css" rel="stylesheet">
<script src="js/about.adbc1234.js" defer="defer"></script>
</head>
<body>
<h1>About</h1>
</body>
</html>