diff --git a/package.json b/package.json index fa30e67580..a2ffce6139 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "debug": "2.3.3", "element-resize-detector": "1.1.9", "express": "4.14.0", + "express-static-gzip": "0.2.1", "fluxible": "1.2.0", "fluxible-addons-react": "0.2.8", "foundation-apps": "1.2.0", @@ -109,6 +110,8 @@ "babel-plugin-transform-react-remove-prop-types": "0.2.11", "babel-plugin-transform-runtime": "6.15.0", "babel-runtime": "6.18.0", + "brotli-webpack-plugin": "0.1.1", + "compression-webpack-plugin": "0.3.2", "css-loader": "0.26.1", "csswring": "5.1.0", "eslint": "3.11.1", diff --git a/server/server.js b/server/server.js index f51c775d84..bd6e90b9f2 100644 --- a/server/server.js +++ b/server/server.js @@ -31,6 +31,7 @@ if (process.env.NODE_ENV === 'production') { /* ********* Server **********/ const express = require('express'); +const expressStaticGzip = require('express-static-gzip'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); @@ -43,7 +44,8 @@ function setUpStaticFolders() { const staticFolder = path.join(process.cwd(), '_static'); // Sert cache for 1 week const oneDay = 86400000; - app.use(config.APP_PATH, express.static(staticFolder, { + app.use(config.APP_PATH, expressStaticGzip(staticFolder, { + enableBrotli: true, maxAge: 30 * oneDay, setHeaders(res, reqPath) { if ( diff --git a/webpack.config.js b/webpack.config.js index d57670bd97..8a0355473d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,6 +11,8 @@ const StatsPlugin = require('stats-webpack-plugin'); // const OptimizeJsPlugin = require('optimize-js-plugin'); const OfflinePlugin = require('offline-plugin'); const WebpackMd5Hash = require('webpack-md5-hash'); +const GzipCompressionPlugin = require('compression-webpack-plugin'); +const BrotliCompressionPlugin = require('brotli-webpack-plugin'); const fs = require('fs'); require('babel-core/register')({ @@ -161,7 +163,7 @@ function getPluginsConfig(env) { names: ['common', 'leaflet', 'manifest'], }), new webpack.optimize.AggressiveMergingPlugin(), - new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 20000 }), + new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 60000 }), new StatsPlugin('../stats.json', { chunkModules: true }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, @@ -193,6 +195,17 @@ function getPluginsConfig(env) { }, safeToUseOptionalCaches: true, }), + new GzipCompressionPlugin({ + asset: '[path].gz[query]', + algorithm: 'zopfli', + test: /\.(js|css|html|svg)$/, + minRatio: 0.95, + }), + new BrotliCompressionPlugin({ + asset: '[path].br[query]', + test: /\.(js|css|html|svg)$/, + minRatio: 0.95, + }), new webpack.NoErrorsPlugin(), ]); } diff --git a/yarn.lock b/yarn.lock index d1d5619073..607c3a89ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -294,6 +294,10 @@ async-foreach@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" +async@0.2.x, async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + async@2.0.0-rc.4: version "2.0.0-rc.4" resolved "https://registry.yarnpkg.com/async/-/async-2.0.0-rc.4.tgz#9b7f60724c17962a973f787419e0ebc5571dbad8" @@ -310,10 +314,6 @@ async@^1.4.0, async@^1.5.0, async@^1.5.2, async@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@~0.2.6: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" @@ -1183,6 +1183,14 @@ brorand@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" +brotli-webpack-plugin@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/brotli-webpack-plugin/-/brotli-webpack-plugin-0.1.1.tgz#a42bb2a4ac62d1972996edd46162cc900c275024" + dependencies: + async "0.2.x" + iltorb "^1.0.12" + webpack-sources "^0.1.0" + browser-pack@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531" @@ -1699,6 +1707,15 @@ compressible@~2.0.8: dependencies: mime-db ">= 1.24.0 < 2" +compression-webpack-plugin@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-0.3.2.tgz#1edfb0e749d7366d3e701670c463359b2c0cf704" + dependencies: + async "0.2.x" + webpack-sources "^0.1.0" + optionalDependencies: + node-zopfli "^2.0.0" + compression@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" @@ -2063,6 +2080,12 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +defaults@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -2642,7 +2665,14 @@ exports-loader@0.6.3: loader-utils "0.2.x" source-map "0.1.x" -express@4.14.0, express@^4.13.3, express@^4.4.4: +express-static-gzip@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/express-static-gzip/-/express-static-gzip-0.2.1.tgz#c077d4501c7c07565d24f3ba382d1e7f9eb88f1b" + dependencies: + express "^4.14.0" + mime "^1.3.4" + +express@4.14.0, express@^4.13.3, express@^4.14.0, express@^4.4.4: version "4.14.0" resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" dependencies: @@ -3651,6 +3681,12 @@ ignore@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" +iltorb@^1.0.12: + version "1.0.13" + resolved "https://registry.yarnpkg.com/iltorb/-/iltorb-1.0.13.tgz#9913538457bf39d3dac223ebb4d9990dbda1354f" + dependencies: + nan "^2.4.0" + imports-loader@0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.6.5.tgz#ae74653031d59e37b3c2fb2544ac61aeae3530a6" @@ -4858,7 +4894,7 @@ named-placeholders@1.1.1: dependencies: lru-cache "2.5.0" -nan@^2.0.4, nan@^2.3.0, nan@^2.3.2: +nan@^2.0.0, nan@^2.0.4, nan@^2.3.0, nan@^2.3.2, nan@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" @@ -4957,7 +4993,7 @@ node-libs-browser@^1.0.0: util "^0.10.3" vm-browserify "0.0.4" -node-pre-gyp@^0.6.29: +node-pre-gyp@^0.6.29, node-pre-gyp@^0.6.4: version "0.6.32" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" dependencies: @@ -4996,6 +5032,15 @@ node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" +node-zopfli@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-zopfli/-/node-zopfli-2.0.2.tgz#a7a473ae92aaea85d4c68d45bbf2c944c46116b8" + dependencies: + commander "^2.8.1" + defaults "^1.0.2" + nan "^2.0.0" + node-pre-gyp "^0.6.4" + nodemon@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c"