Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compression webpack plugin

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 ?

like image 322
Flint Avatar asked May 21 '18 04:05

Flint


3 Answers

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/

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#text_compression_with_gzip

like image 63
pldg Avatar answered Sep 29 '22 16:09

pldg


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:

  1. Create a vue.config.js file if not already present

  2. 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.

like image 29
HalfWebDev Avatar answered Sep 29 '22 16:09

HalfWebDev


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.

  • Using the argument '*.js' at the beginning means that this app.get works for every endpoint that is fired to fetch a JS file.
  • Inside the callback, I attach .br to the URL of the request. Furthermore, the Content-Encoding response header is set to br.
  • The Content-Type header is set to application/javascript; charset=UTF-8 to specify the MIME type.
  • At the end and very important, next() makes possible to continue to any callback that may be next.
  • Do not forget to provide the folder where your compressed bundle is placed. I used app.use(express.static('public')) in my case.
like image 25
Paul M. Avatar answered Sep 29 '22 15:09

Paul M.