How to use gzip in Angular 8 and NodeJS?

Viewed 2425

I was trying to use gzip to reduce the size of the bundle of my current angular project. The bundle report claims that after using gzip it would reduce my product-build's size to about 30% or less. But I don't know how to make that work.

Currently, my project is built in Angular and is sent to a port through Node.js Express.js server. Guess we would need config both Angular and NodeJS to make it work?

What I have tried so far:

It looks like the gzip can be applied in Angular 5- until Google disabled the ng eject. Also, I found a lot of Nginx tutorials with gzip but none of Node.js by now. So guess I don't quite understand either of them.

I tried to add the following code in my node server, but it doesn't seem to affect the performance of the project with or without the compression.

const express = require('express');
const http = require('http');
const https = require('https');
const compression = require('compression');

const app = express();

const port = 4201;

app.use(compression());
app.use(express.static(__dirname + '/dist'));

Edit: After testing with http://www.gidnetwork.com/tools/gzip-test.php, my site has been compressed into gzip. But the performance in Google Page Insight doesn't change. Perhaps only the index.html is compressed?

3 Answers

I use node version 16.13.2 and it has a built-in compression package.

So, all you need is to use the below server.ts file as your node server

import 'zone.js/dist/zone-node';

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';

import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';

const compression = require('compression');

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
    const server = express();
    const distFolder = join(process.cwd(), 'dist/your-project-name/browser');
    const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

    server.use(compression());

    // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
    server.engine('html', ngExpressEngine({
        bootstrap: AppServerModule,
    }));

    server.set('view engine', 'html');
    server.set('views', distFolder);

    // Example Express Rest API endpoints
    // server.get('/api/**', (req, res) => { });
    // Serve static files from /browser
    server.get('*.*', express.static(distFolder, {
        maxAge: '1y'
    }));

    // All regular routes use the Universal engine
    server.get('*', (req, res) => {
        res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
    });

    return server;
}

function run(): void {
    const port = process.env['PORT'] || 4000;

    // Start up the Node server
    const server = app();

    server.listen(port, () => {
        console.log(`Node Express server listening on http://localhost:${port}`);
    });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
    run();
}

export * from './src/main.server';

Try zlib, nodejs has a stable support in core now. An example (taken from the docs):

// server example
// Running a gzip operation on every request is quite expensive.
// It would be much more efficient to cache the compressed buffer.
var zlib = require('zlib');
var http = require('http');
var fs = require('fs');
http.createServer(function(request, response) {
  var raw = fs.createReadStream('index.html');
  var acceptEncoding = request.headers['accept-encoding'];
  if (!acceptEncoding) {
    acceptEncoding = '';
  }

  // Note: this is not a conformant accept-encoding parser.
  // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
  if (acceptEncoding.match(/\bdeflate\b/)) {
    response.writeHead(200, { 'content-encoding': 'deflate' });
    raw.pipe(zlib.createDeflate()).pipe(response);
  } else if (acceptEncoding.match(/\bgzip\b/)) {
    response.writeHead(200, { 'content-encoding': 'gzip' });
    raw.pipe(zlib.createGzip()).pipe(response);
  } else {
    response.writeHead(200, {});
    raw.pipe(response);
  }
}).listen(1337);

for angular you have to install gzip-all

npm i gzip-all

and on your package.json file

package.json

"scripts": {
    "build": "ng build --prod --no-delete-output-path --aot --base-href /app/ && gzip-all \Project file.....\" ",
},
Related