I am already building a working web-app with a configuration that has gzip compression deactivated.
I use the HtmlWebpackPlugin
to inject Vue stuff and generated chunks (js and css) into the main index.html
.
The chunks are created by the splitChunks
instruction of Webpack 4.
What I now want is to activate the CompressionWebpackPlugin
in order to get my big output files smaller.
The compression plugin would do a perfect job if there would not be chunks. It creates a *.js.gz
file for every chunk, BUT, it does not update the references in each chunk to other chunks.
Thus, the browser will not be able to find all of the needed files.
E.g. the index.html
has one or two references to chunk1.js.gz
and chunk2.js.gz
, but inside chunk1
and chunk2
are many references to additional chunks, which cannot be found, because the references have the ending .js
and the real files have the ending .js.gz
.
How can I get the CompressionWebpackPlugin
(or any other of the whole webpack settings and plugins) correctly configured, so that they will accordingly update the file references?
How can this be completely dynamic, so that I can even use the compression features of minimum-ratio or minimum-file-size? (Then some output chunks would be .js
and some would be .js.gz
, so some references have to be the first option, some references have to be the second option).
Other answers to similar questions said, one should compress server-side and not with webpack. However, for what reason does there exist the compression plugin then?
The setup is Vue, Webpack (Single page app), nginx, Django, Docker.
Here is my current configuration of Webpack:
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// extract css into its own file
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[hash:7].css'),
chunkFilename: utils.assetsPath('css/[id].[hash:7].css')
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
jsExtension: '.gz'
}),
// keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
]),
],
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
default: false,
vendors: false,
vendor: {
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
priority: 20,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
},
},
common: {
name: 'common',
minChunks: 2,
chunks: 'async',
priority: 10,
reuseExistingChunk: true,
enforce: true
},
},
},
},
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|css)(\?.*)?$/i,
//threshold: 10240,
//minRatio: 0.8,
deleteOriginalAssets: true,
}),
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig