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 <timer150@gmail.com> * Pin compression types Co-Authored-By: Joe Haddad <timer150@gmail.com> * lockfile update for locked compression deps * simplify compression middleware application * add test for compression
This commit is contained in:
parent
df213f7aab
commit
9659b4b555
6 changed files with 139 additions and 2 deletions
|
@ -18,6 +18,7 @@ const defaultConfig: { [key: string]: any } = {
|
|||
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
|
||||
target: process.env.__NEXT_BUILDER_EXPERIMENTAL_TARGET || 'server',
|
||||
poweredByHeader: true,
|
||||
compress: true,
|
||||
onDemandEntries: {
|
||||
maxInactiveAge: 60 * 1000,
|
||||
pagesBufferLength: 2,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { IncomingMessage, ServerResponse } from 'http'
|
|||
import { join, resolve, sep } from 'path'
|
||||
import { parse as parseQs, ParsedUrlQuery } from 'querystring'
|
||||
import { parse as parseUrl, UrlWithParsedQuery } from 'url'
|
||||
import compression from 'compression'
|
||||
|
||||
import {
|
||||
BUILD_ID_FILE,
|
||||
|
@ -36,6 +37,12 @@ import { isBlockedPage, isInternalUrl } from './utils'
|
|||
|
||||
type NextConfig = any
|
||||
|
||||
type Middleware = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: (err?: Error) => void
|
||||
) => void
|
||||
|
||||
export type ServerConstructor = {
|
||||
/**
|
||||
* Where the Next project is located - @default '.'
|
||||
|
@ -72,6 +79,7 @@ export default class Server {
|
|||
documentMiddlewareEnabled: boolean
|
||||
dev?: boolean
|
||||
}
|
||||
private compression?: Middleware
|
||||
router: Router
|
||||
private dynamicRoutes?: Array<{ page: string; match: RouteMatch }>
|
||||
|
||||
|
@ -101,6 +109,7 @@ export default class Server {
|
|||
publicRuntimeConfig,
|
||||
assetPrefix,
|
||||
generateEtags,
|
||||
compress,
|
||||
} = this.nextConfig
|
||||
|
||||
this.buildId = this.readBuildId()
|
||||
|
@ -122,6 +131,10 @@ export default class Server {
|
|||
this.renderOpts.runtimeConfig = publicRuntimeConfig
|
||||
}
|
||||
|
||||
if (compress && this.nextConfig.target !== 'serverless') {
|
||||
this.compression = compression() as Middleware
|
||||
}
|
||||
|
||||
// Initialize next/config with the environment configuration
|
||||
envConfig.setConfig({
|
||||
serverRuntimeConfig,
|
||||
|
@ -371,11 +384,19 @@ export default class Server {
|
|||
}))
|
||||
}
|
||||
|
||||
private handleCompression(req: IncomingMessage, res: ServerResponse) {
|
||||
if (this.compression) {
|
||||
this.compression(req, res, () => {})
|
||||
}
|
||||
}
|
||||
|
||||
private async run(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
parsedUrl: UrlWithParsedQuery
|
||||
) {
|
||||
this.handleCompression(req, res)
|
||||
|
||||
try {
|
||||
const fn = this.router.match(req, res, parsedUrl)
|
||||
if (fn) {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"babel-plugin-transform-async-to-promises": "0.8.10",
|
||||
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
|
||||
"chalk": "2.4.2",
|
||||
"compression": "1.7.4",
|
||||
"find-up": "4.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "1.3.4",
|
||||
"fresh": "0.5.2",
|
||||
|
@ -119,6 +120,7 @@
|
|||
"@types/babel__template": "7.0.2",
|
||||
"@types/babel__traverse": "7.0.6",
|
||||
"@types/cross-spawn": "6.0.0",
|
||||
"@types/compression": "0.0.36",
|
||||
"@types/etag": "1.8.0",
|
||||
"@types/find-up": "2.1.1",
|
||||
"@types/fresh": "0.5.0",
|
||||
|
|
1
test/integration/compression/pages/index.js
Normal file
1
test/integration/compression/pages/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default () => <div id='hello'>OK</div>
|
30
test/integration/compression/test/index.test.js
Normal file
30
test/integration/compression/test/index.test.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* eslint-env jest */
|
||||
/* global jasmine */
|
||||
import { join } from 'path'
|
||||
import {
|
||||
fetchViaHTTP,
|
||||
renderViaHTTP,
|
||||
findPort,
|
||||
launchApp,
|
||||
killApp
|
||||
} from 'next-test-utils'
|
||||
|
||||
const context = {}
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||
|
||||
describe('Compression', () => {
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
context.server = await launchApp(join(__dirname, '../'), context.appPort)
|
||||
|
||||
// pre-build page at the start
|
||||
await renderViaHTTP(context.appPort, '/')
|
||||
})
|
||||
afterAll(() => killApp(context.server))
|
||||
|
||||
it('should compress responses by default', async () => {
|
||||
const res = await fetchViaHTTP(context.appPort, '/')
|
||||
|
||||
expect(res.headers.get('content-encoding')).toMatch(/gzip/)
|
||||
})
|
||||
})
|
86
yarn.lock
86
yarn.lock
|
@ -1800,6 +1800,28 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.3.0"
|
||||
|
||||
"@types/body-parser@*":
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
|
||||
integrity sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==
|
||||
dependencies:
|
||||
"@types/connect" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/compression@0.0.36":
|
||||
version "0.0.36"
|
||||
resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.36.tgz#7646602ffbfc43ea48a8bf0b2f1d5e5f9d75c0d0"
|
||||
integrity sha512-B66iZCIcD2eB2F8e8YDIVtCUKgfiseOR5YOIbmMN2tM57Wu55j1xSdxdSw78aVzsPmbZ6G+hINc+1xe1tt4NBg==
|
||||
dependencies:
|
||||
"@types/express" "*"
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28"
|
||||
integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/content-type@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
|
||||
|
@ -1829,6 +1851,23 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||
|
||||
"@types/express-serve-static-core@*":
|
||||
version "4.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.7.tgz#50ba6f8a691c08a3dd9fa7fba25ef3133d298049"
|
||||
integrity sha512-847KvL8Q1y3TtFLRTXcVakErLJQgdpFSaq+k043xefz9raEf0C7HalpSY7OW5PyjCnY8P7bPW5t/Co9qqp+USg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/range-parser" "*"
|
||||
|
||||
"@types/express@*":
|
||||
version "4.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.0.tgz#49eaedb209582a86f12ed9b725160f12d04ef287"
|
||||
integrity sha512-CjaMu57cjgjuZbh9DpkloeGxV45CnMGlVd+XpG7Gm9QgVrd7KFq+X4HY0vM+2v0bczS48Wg7bvnMY5TN+Xmcfw==
|
||||
dependencies:
|
||||
"@types/body-parser" "*"
|
||||
"@types/express-serve-static-core" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/find-up@2.1.1":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/find-up/-/find-up-2.1.1.tgz#1cd2d240f1ad1f48d32346074724dc3107248a11"
|
||||
|
@ -1960,6 +1999,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
|
||||
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
|
||||
|
||||
"@types/range-parser@*":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
|
||||
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
|
||||
|
||||
"@types/react-dom@16.8.4":
|
||||
version "16.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.4.tgz#7fb7ba368857c7aa0f4e4511c4710ca2c5a12a88"
|
||||
|
@ -1997,6 +2041,14 @@
|
|||
"@types/mime" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/serve-static@*":
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"
|
||||
integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==
|
||||
dependencies:
|
||||
"@types/express-serve-static-core" "*"
|
||||
"@types/mime" "*"
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
|
@ -2315,7 +2367,7 @@ abort-controller@3.0.0:
|
|||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
accepts@~1.3.7:
|
||||
accepts@~1.3.5, accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
||||
|
@ -3250,6 +3302,11 @@ byte-size@^4.0.3:
|
|||
resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.4.tgz#29d381709f41aae0d89c631f1c81aec88cd40b23"
|
||||
integrity sha512-82RPeneC6nqCdSwCX2hZUz3JPOvN5at/nTEw/CMf05Smu3Hrpo9Psb7LjN+k+XndNArG1EY8L4+BM3aTM4BCvw==
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||
|
||||
bytes@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
|
@ -3848,6 +3905,26 @@ compress-commons@^1.2.0:
|
|||
normalize-path "^2.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
compressible@~2.0.16:
|
||||
version "2.0.17"
|
||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
|
||||
integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
|
||||
dependencies:
|
||||
mime-db ">= 1.40.0 < 2"
|
||||
|
||||
compression@1.7.4:
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
|
||||
integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
|
||||
dependencies:
|
||||
accepts "~1.3.5"
|
||||
bytes "3.0.0"
|
||||
compressible "~2.0.16"
|
||||
debug "2.6.9"
|
||||
on-headers "~1.0.2"
|
||||
safe-buffer "5.1.2"
|
||||
vary "~1.1.2"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
@ -8781,7 +8858,7 @@ miller-rabin@^4.0.0:
|
|||
bn.js "^4.0.0"
|
||||
brorand "^1.0.1"
|
||||
|
||||
mime-db@1.40.0:
|
||||
mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
|
||||
version "1.40.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
|
||||
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
|
||||
|
@ -9480,6 +9557,11 @@ on-finished@~2.3.0:
|
|||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
on-headers@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
||||
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
|
|
Loading…
Reference in a new issue