Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
HTTP2 server with compression and caching
const http2 = require('http2');
const fs = require('fs');
const path = require('path');
const zlib = require('zlib');
const brotli = require('brotli'); // npm package
const PORT = 3032;
const BROTLI_QUALITY = 11; // slow, but we're caching so who cares
const STATIC_DIRECTORY = path.resolve(__dirname, '../dist/');
const cache = {};
/*
-- To generate keys --
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
-keyout localhost-privkey.pem -out localhost-cert.pem
*/
const server = http2.createSecureServer({
key: fs.readFileSync(path.resolve(__dirname, './localhost-privkey.pem')),
cert: fs.readFileSync(path.resolve(__dirname, './localhost-cert.pem')),
});
const getStaticFile = (fileName, useBrotli) => {
const cacheKey = `${fileName}-${useBrotli}`; // we must cache gzipped and brotli responses separately
if (cacheKey in cache) return cache[cacheKey];
const fileBuffer = fs.readFileSync(path.resolve(STATIC_DIRECTORY, fileName.replace(/^\//, '')));
const compressedFile = useBrotli
? brotli.compress(fileBuffer, { quality: BROTLI_QUALITY })
: zlib.gzipSync(fileBuffer.toString());
cache[cacheKey] = compressedFile;
return compressedFile;
};
const getItemAtPath = ({ path, useBrotli }) => {
const notFoundResponse = {
body: `<h1>No ${path} for you!</h1>`,
responseHeader: {
':status': 404,
},
};
try {
const commonHeader = {
'Content-Encoding': useBrotli ? 'br' : 'gzip',
':status': 200,
};
if (path === '/') {
return {
body: getStaticFile('index.html', useBrotli),
responseHeader: {
...commonHeader,
'content-type': 'text/html',
},
};
}
if (path.endsWith('.js')) {
return {
body: getStaticFile(path, useBrotli),
responseHeader: {
...commonHeader,
'Cache-Control': 'max-age=31536000',
'content-type': 'application/javascript',
},
};
}
if (path.endsWith('.css')) {
return {
body: getStaticFile(path, useBrotli),
responseHeader: {
...commonHeader,
'Cache-Control': 'max-age=31536000',
'content-type': 'text/css',
},
};
}
return notFoundResponse;
} catch (err) {
return notFoundResponse;
}
}
server.on('stream', (stream, headers) => {
const { body, responseHeader } = getItemAtPath({
path: headers[':path'],
useBrotli: headers['accept-encoding'].includes('br'),
})
stream.respond(responseHeader);
stream.end(body);
});
server.listen(PORT);
console.info(`Server is probably ready on https://localhost:${PORT}`);
@mike-boddin

This comment has been minimized.

Copy link

commented Dec 23, 2018

I just wanted to star this gist on my mobile but I didn't find the button to do so.
So I guess I will find it again later through my comment...

Great article!
“The 100% correct way to split your chunks with Webpack” by David Gilbertson https://link.medium.com/VHcUdzDCSS

@soundyogi

This comment has been minimized.

Copy link

commented Dec 28, 2018

Great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.