Reputation: 1691
I'm trying to figure out how to properly use webpack-html-plugin with the compression plugin, the documentation of latter is a bit scarce.
My webpack configuration declares :
output: {
filename: 'js/[name]-[hash].js',
The compression plugin is run at last
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip"
})
In the end the scripts are correctly produced and compressed.
js/app-caf3b4b3.js.gz 382 kB [emitted] [big]
I can declare the preloading of the gzipped file in the index.html
template
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>.gz" as="script">
But webpack is in charge for the insertion of this line :
<script type="text/javascript" src="/js/app-caf3b4b3.js">
inside of <body></body>
How can I ask webpack to use the compressed script ?
Upvotes: 11
Views: 20820
Reputation: 411
#webpack #compression #express #node
It was challenging to group all the information to achieve what I wanted to do; here, I leave you how I created the webpack and related it to express.
this is the plugin section on webpack file: webpack.config.js
example (array of obj)
plugins: [confi1, config2, confi3]
plugins: [
new CompressionPlugin({
filename: '[path][base].gz',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8
}),
new CompressionPlugin({
filename: '[path][base].br',
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
compressionOptions: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 11
}
},
threshold: 10240,
minRatio: 0.8
})
]
If you notice, I am using only two compressions, there are more, but I think that with those two, we are fine.
Also, if you want to learn how to modify the opction you can take a look at this page : https://webpack.js.org/plugins/compression-webpack-plugin/
br = Brotli is a lossless data compression algorithm developed by Google)
gzip = is a software library used for data compression (STANDAR). zlib was written by Jean-loup Gailly
I use both for the case that supports br we send br; in case it does not support it we send gzip, and in the worst case we send .js file: we will see it now
How to send the correct file to the client with express: below...
app.use(
'/static',
expressStaticGzip(path.join('dist', 'frontend'), {
enableBrotli: true,
customCompressions: [
{
encodingName: 'deflate',
fileExtension: 'zz'
}
],
orderPreference: ['br', 'gz'],
setHeaders: function (res, path) {
res.setHeader('Cache-Control', 'public, max-age=0');
}
})
);
look at the files in the image: if you compile with webpack, note the plugins for your JS (br, gz). In this case, bundle.js has a bundle.js.br & bundle.js.gz, and for the CSS, we have the same; if a client makes a request to the folder Static where the files that will be sent to the express client are located, they decide what to send based on the headers in the request. For example, if you use chrome express will send you 'br', but if you use Safari express will send you 'gz'
example for Crome and Safari:
example fo safari:
with this, we send the HTML file to the client, and then the client is going to request the js file, but the server will send the js file compress
app.get('/*', function (req, res) {
let pathServer = process.env.subDOMAIN == "true" ? "" : "/scheduler_app";
res.render('pages/index', { App: "stringApp", script: `<script src="${pathServer}/static/bundle.js"></script>`, css: `<link rel="stylesheet" href="${pathServer}/static/main.css">` });
});
Upvotes: 2
Reputation: 318
My approach is a bit different but it served the purpose in the and and I can save a lot of data send to the client! I was also struggling with serving the compressed version with my React SSR app; in my case the brotli type with js.br extension > "bundle.js.br". The following snippet changed it in the end to serve it properly. I reduced my client-side uncompressed bundle in development mode from 1.7 MB to 0.27 MB. Try and figure it out for you. There is no extra plugin needed to serve the file. Of course, the compressed version must be generated first with webpack. For webpack brotli compression I use the npmjs packages compression-webpack-plugin in conjunction with zlib.
var express = require('express');
var app = express();
app.get('*.js', (req, res, next) => {
if (req.header('Accept-Encoding').includes('br')) {
req.url = req.url + '.br';
console.log(req.header('Accept-Encoding'));
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
}
next();
});
app.use(express.static('public'));
Now let me explain my snippet above which I use for my SSR React app to serve the compressed file.
Upvotes: 1
Reputation: 7648
You can do that via Webpack Compression Plugin from you SPA app or also from server side. I'll answer for the Vue.js spa that I tested it on for config. React and Angular webpacks will not be different except for the config file names.
Steps:
Create a vue.config.js
file if not already present
Add something along these lines
const CompressionWebpackPlugin = require("compression-webpack-plugin");
module.exports = {
configureWebpack: {
plugins: [
new CompressionWebpackPlugin({
filename: "[path].gz[query]",
algorithm: "gzip",
test: /\.(js|css)$/,
...
})
]
}
};
More options available in plugin docs.
Upvotes: 7
Reputation: 2588
You don't need to link a compressed file in html. You must do this server-side. You can also gzip css and html files.
Set your server to send a file using gzip compression, you'll also need proper headers to tell the browser how to interpret that compressed file.
If you are using an Apache server you can enable gzip compression with an .htaccess file.
I use this for my Apache server:
# enable the rewrite capabilities
RewriteEngine On
# prevents the rule from being overrided by .htaccess files in subdirectories
RewriteOptions InheritDownBefore
# provide a URL-path base (not a file-path base) for any relative paths in the rule's target
RewriteBase /
# GZIP
## allows you to have certain browsers uncompress information on the fly
AddEncoding gzip .gz
## serve gzip .css files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
## serve gzip .js files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
## serve gzip .html files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.html $1\.html\.gz [QSA]
## serve correct content types, and prevent mod_deflate double gzip
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.html\.gz$ - [T=text/html,E=no-gzip:1,E=is_gzip:1]
Header set Content-Encoding "gzip" env=is_gzip
You can google for more information on how to optimize a website with gzip compression.
https://gtmetrix.com/enable-gzip-compression.html
https://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/
Upvotes: 7