diff --git a/package-lock.json b/package-lock.json index 0a72720bf..7f60226b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4321,6 +4321,12 @@ "pify": "^4.0.1", "semver": "^5.6.0" } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true } } }, @@ -4570,12 +4576,6 @@ } } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "optional": true - }, "mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", diff --git a/server.js b/server.js index c149e113a..92a17c301 100644 --- a/server.js +++ b/server.js @@ -1,18 +1,13 @@ const _ = require('lodash'); const jwt = require('jwt-simple'); -const expressStaticGzip = require('express-static-gzip'); const express = require('express'); const app = express(); const homebrewApi = require('./server/homebrew.api.js'); const GoogleActions = require('./server/googleActions.js'); +const serveCompressedStaticAssets = require('./server/static-assets.mv.js'); -// Serve brotli-compressed static files if available -app.use('/', expressStaticGzip(`${__dirname}/build`, { - enableBrotli : true, - orderPreference : ['br'], - index : false -})); +app.use('/', serveCompressedStaticAssets(`${__dirname}/build`)); process.chdir(__dirname); diff --git a/server/static-assets.mv.js b/server/static-assets.mv.js new file mode 100644 index 000000000..732420d46 --- /dev/null +++ b/server/static-assets.mv.js @@ -0,0 +1,31 @@ +const expressStaticGzip = require('express-static-gzip'); + +// Serve brotli-compressed static files if available +const customCacheControlHandler=(response, path)=>{ + if(path.endsWith('.br')) { + // Drop .br suffix to help mime understand the actual type of the file + path = path.slice(0, -3); + } + if(path.endsWith('.js') || path.endsWith('.css')) { + // .js and .css files are allowed to be cached up to 12 hours, but then + // they must be revalidated to see if there are any updates + response.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); + } else { + // Everything else is cached up to a months as we don't update our images + // or fonts frequently + response.setHeader('Cache-Control', 'public, max-age=2592000, must-revalidate'); + } +}; + +const init=(pathToAssets)=>{ + return expressStaticGzip(pathToAssets, { + enableBrotli : true, + orderPreference : ['br'], + index : false, + serveStatic : { + cacheControl : false, // we are going to use custom cache-control + setHeaders : customCacheControlHandler + } }); +}; + +module.exports = init;