Skip to content

Commit 9659b4b

Browse files
developitTimer
authored andcommitted
Optional Server Compression (#8066)
* Add `compress` option to enable gzip compression in `next start`. * Add compress option, defaulting to true * Disable compression for serverless target * Pin compression dep Co-Authored-By: Joe Haddad <[email protected]> * Pin compression types Co-Authored-By: Joe Haddad <[email protected]> * lockfile update for locked compression deps * simplify compression middleware application * add test for compression
1 parent df213f7 commit 9659b4b

File tree

6 files changed

+139
-2
lines changed

6 files changed

+139
-2
lines changed

packages/next-server/server/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const defaultConfig: { [key: string]: any } = {
1818
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
1919
target: process.env.__NEXT_BUILDER_EXPERIMENTAL_TARGET || 'server',
2020
poweredByHeader: true,
21+
compress: true,
2122
onDemandEntries: {
2223
maxInactiveAge: 60 * 1000,
2324
pagesBufferLength: 2,

packages/next-server/server/next-server.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IncomingMessage, ServerResponse } from 'http'
33
import { join, resolve, sep } from 'path'
44
import { parse as parseQs, ParsedUrlQuery } from 'querystring'
55
import { parse as parseUrl, UrlWithParsedQuery } from 'url'
6+
import compression from 'compression'
67

78
import {
89
BUILD_ID_FILE,
@@ -36,6 +37,12 @@ import { isBlockedPage, isInternalUrl } from './utils'
3637

3738
type NextConfig = any
3839

40+
type Middleware = (
41+
req: IncomingMessage,
42+
res: ServerResponse,
43+
next: (err?: Error) => void
44+
) => void
45+
3946
export type ServerConstructor = {
4047
/**
4148
* Where the Next project is located - @default '.'
@@ -72,6 +79,7 @@ export default class Server {
7279
documentMiddlewareEnabled: boolean
7380
dev?: boolean
7481
}
82+
private compression?: Middleware
7583
router: Router
7684
private dynamicRoutes?: Array<{ page: string; match: RouteMatch }>
7785

@@ -101,6 +109,7 @@ export default class Server {
101109
publicRuntimeConfig,
102110
assetPrefix,
103111
generateEtags,
112+
compress,
104113
} = this.nextConfig
105114

106115
this.buildId = this.readBuildId()
@@ -122,6 +131,10 @@ export default class Server {
122131
this.renderOpts.runtimeConfig = publicRuntimeConfig
123132
}
124133

134+
if (compress && this.nextConfig.target !== 'serverless') {
135+
this.compression = compression() as Middleware
136+
}
137+
125138
// Initialize next/config with the environment configuration
126139
envConfig.setConfig({
127140
serverRuntimeConfig,
@@ -371,11 +384,19 @@ export default class Server {
371384
}))
372385
}
373386

387+
private handleCompression(req: IncomingMessage, res: ServerResponse) {
388+
if (this.compression) {
389+
this.compression(req, res, () => {})
390+
}
391+
}
392+
374393
private async run(
375394
req: IncomingMessage,
376395
res: ServerResponse,
377396
parsedUrl: UrlWithParsedQuery
378397
) {
398+
this.handleCompression(req, res)
399+
379400
try {
380401
const fn = this.router.match(req, res, parsedUrl)
381402
if (fn) {

packages/next/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"babel-plugin-transform-async-to-promises": "0.8.10",
7777
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
7878
"chalk": "2.4.2",
79+
"compression": "1.7.4",
7980
"find-up": "4.0.0",
8081
"fork-ts-checker-webpack-plugin": "1.3.4",
8182
"fresh": "0.5.2",
@@ -119,6 +120,7 @@
119120
"@types/babel__template": "7.0.2",
120121
"@types/babel__traverse": "7.0.6",
121122
"@types/cross-spawn": "6.0.0",
123+
"@types/compression": "0.0.36",
122124
"@types/etag": "1.8.0",
123125
"@types/find-up": "2.1.1",
124126
"@types/fresh": "0.5.0",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default () => <div id='hello'>OK</div>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* eslint-env jest */
2+
/* global jasmine */
3+
import { join } from 'path'
4+
import {
5+
fetchViaHTTP,
6+
renderViaHTTP,
7+
findPort,
8+
launchApp,
9+
killApp
10+
} from 'next-test-utils'
11+
12+
const context = {}
13+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
14+
15+
describe('Compression', () => {
16+
beforeAll(async () => {
17+
context.appPort = await findPort()
18+
context.server = await launchApp(join(__dirname, '../'), context.appPort)
19+
20+
// pre-build page at the start
21+
await renderViaHTTP(context.appPort, '/')
22+
})
23+
afterAll(() => killApp(context.server))
24+
25+
it('should compress responses by default', async () => {
26+
const res = await fetchViaHTTP(context.appPort, '/')
27+
28+
expect(res.headers.get('content-encoding')).toMatch(/gzip/)
29+
})
30+
})

yarn.lock

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,28 @@
18001800
dependencies:
18011801
"@babel/types" "^7.3.0"
18021802

1803+
"@types/body-parser@*":
1804+
version "1.17.0"
1805+
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
1806+
integrity sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==
1807+
dependencies:
1808+
"@types/connect" "*"
1809+
"@types/node" "*"
1810+
1811+
1812+
version "0.0.36"
1813+
resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.36.tgz#7646602ffbfc43ea48a8bf0b2f1d5e5f9d75c0d0"
1814+
integrity sha512-B66iZCIcD2eB2F8e8YDIVtCUKgfiseOR5YOIbmMN2tM57Wu55j1xSdxdSw78aVzsPmbZ6G+hINc+1xe1tt4NBg==
1815+
dependencies:
1816+
"@types/express" "*"
1817+
1818+
"@types/connect@*":
1819+
version "3.4.32"
1820+
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28"
1821+
integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==
1822+
dependencies:
1823+
"@types/node" "*"
1824+
18031825
18041826
version "1.1.3"
18051827
resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
@@ -1829,6 +1851,23 @@
18291851
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
18301852
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
18311853

1854+
"@types/express-serve-static-core@*":
1855+
version "4.16.7"
1856+
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.7.tgz#50ba6f8a691c08a3dd9fa7fba25ef3133d298049"
1857+
integrity sha512-847KvL8Q1y3TtFLRTXcVakErLJQgdpFSaq+k043xefz9raEf0C7HalpSY7OW5PyjCnY8P7bPW5t/Co9qqp+USg==
1858+
dependencies:
1859+
"@types/node" "*"
1860+
"@types/range-parser" "*"
1861+
1862+
"@types/express@*":
1863+
version "4.17.0"
1864+
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.0.tgz#49eaedb209582a86f12ed9b725160f12d04ef287"
1865+
integrity sha512-CjaMu57cjgjuZbh9DpkloeGxV45CnMGlVd+XpG7Gm9QgVrd7KFq+X4HY0vM+2v0bczS48Wg7bvnMY5TN+Xmcfw==
1866+
dependencies:
1867+
"@types/body-parser" "*"
1868+
"@types/express-serve-static-core" "*"
1869+
"@types/serve-static" "*"
1870+
18321871
18331872
version "2.1.1"
18341873
resolved "https://registry.yarnpkg.com/@types/find-up/-/find-up-2.1.1.tgz#1cd2d240f1ad1f48d32346074724dc3107248a11"
@@ -1960,6 +1999,11 @@
19601999
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
19612000
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
19622001

2002+
"@types/range-parser@*":
2003+
version "1.2.3"
2004+
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
2005+
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
2006+
19632007
19642008
version "16.8.4"
19652009
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.4.tgz#7fb7ba368857c7aa0f4e4511c4710ca2c5a12a88"
@@ -1997,6 +2041,14 @@
19972041
"@types/mime" "*"
19982042
"@types/node" "*"
19992043

2044+
"@types/serve-static@*":
2045+
version "1.13.2"
2046+
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"
2047+
integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==
2048+
dependencies:
2049+
"@types/express-serve-static-core" "*"
2050+
"@types/mime" "*"
2051+
20002052
"@types/source-list-map@*":
20012053
version "0.1.2"
20022054
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
@@ -2315,7 +2367,7 @@ [email protected]:
23152367
dependencies:
23162368
event-target-shim "^5.0.0"
23172369

2318-
accepts@~1.3.7:
2370+
accepts@~1.3.5, accepts@~1.3.7:
23192371
version "1.3.7"
23202372
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
23212373
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@@ -3250,6 +3302,11 @@ byte-size@^4.0.3:
32503302
resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.4.tgz#29d381709f41aae0d89c631f1c81aec88cd40b23"
32513303
integrity sha512-82RPeneC6nqCdSwCX2hZUz3JPOvN5at/nTEw/CMf05Smu3Hrpo9Psb7LjN+k+XndNArG1EY8L4+BM3aTM4BCvw==
32523304

3305+
3306+
version "3.0.0"
3307+
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
3308+
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
3309+
32533310
32543311
version "3.1.0"
32553312
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
@@ -3848,6 +3905,26 @@ compress-commons@^1.2.0:
38483905
normalize-path "^2.0.0"
38493906
readable-stream "^2.0.0"
38503907

3908+
compressible@~2.0.16:
3909+
version "2.0.17"
3910+
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
3911+
integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
3912+
dependencies:
3913+
mime-db ">= 1.40.0 < 2"
3914+
3915+
3916+
version "1.7.4"
3917+
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
3918+
integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
3919+
dependencies:
3920+
accepts "~1.3.5"
3921+
bytes "3.0.0"
3922+
compressible "~2.0.16"
3923+
debug "2.6.9"
3924+
on-headers "~1.0.2"
3925+
safe-buffer "5.1.2"
3926+
vary "~1.1.2"
3927+
38513928
38523929
version "0.0.1"
38533930
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -8781,7 +8858,7 @@ miller-rabin@^4.0.0:
87818858
bn.js "^4.0.0"
87828859
brorand "^1.0.1"
87838860

8784-
8861+
[email protected], "mime-db@>= 1.40.0 < 2":
87858862
version "1.40.0"
87868863
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
87878864
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
@@ -9480,6 +9557,11 @@ on-finished@~2.3.0:
94809557
dependencies:
94819558
ee-first "1.1.1"
94829559

9560+
on-headers@~1.0.2:
9561+
version "1.0.2"
9562+
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
9563+
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
9564+
94839565
once@^1.3.0, once@^1.3.1, once@^1.4.0:
94849566
version "1.4.0"
94859567
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"

0 commit comments

Comments
 (0)