feat(server): timing option for Server-Timing header (#4800)

This commit is contained in:
Xin Du (Clark) 2019-01-19 18:14:54 +00:00 committed by Pooya Parsa
parent a7ba73ed13
commit b23f5c9b4b
12 changed files with 122 additions and 17 deletions

View File

@ -10,6 +10,9 @@ module.exports = {
extends: [ extends: [
'@nuxtjs' '@nuxtjs'
], ],
"globals": {
"BigInt": true
},
overrides: [{ overrides: [{
files: [ 'test/fixtures/*/.nuxt*/**' ], files: [ 'test/fixtures/*/.nuxt*/**' ],
rules: { rules: {

View File

@ -9,5 +9,6 @@ export default ({ env = {} } = {}) => ({
env.npm_package_config_nuxt_host || env.npm_package_config_nuxt_host ||
'localhost', 'localhost',
socket: env.UNIX_SOCKET || socket: env.UNIX_SOCKET ||
env.npm_package_config_unix_socket env.npm_package_config_unix_socket,
timing: false
}) })

View File

@ -306,6 +306,7 @@ Object {
"https": false, "https": false,
"port": 3000, "port": 3000,
"socket": undefined, "socket": undefined,
"timing": false,
}, },
"serverMiddleware": Array [], "serverMiddleware": Array [],
"srcDir": "/var/nuxt/test", "srcDir": "/var/nuxt/test",

View File

@ -282,6 +282,7 @@ Object {
"https": false, "https": false,
"port": 3000, "port": 3000,
"socket": undefined, "socket": undefined,
"timing": false,
}, },
"serverMiddleware": Array [], "serverMiddleware": Array [],
"srcDir": undefined, "srcDir": undefined,
@ -605,6 +606,7 @@ Object {
"https": false, "https": false,
"port": "3001", "port": "3001",
"socket": "/var/run/nuxt.sock", "socket": "/var/run/nuxt.sock",
"timing": false,
}, },
"serverMiddleware": Array [], "serverMiddleware": Array [],
"srcDir": undefined, "srcDir": undefined,

View File

@ -1,25 +1,17 @@
import serverConfig from '../../src/config/server' import serverConfig from '../../src/config/server'
describe('config: server', () => { const serverDefaults = serverConfig()
test('should return default server configurations', () => {
expect(serverConfig()).toEqual({
https: false,
port: 3000,
host: 'localhost',
socket: undefined
})
})
describe('config: server', () => {
test('should return server configurations with NUXT_* env', () => { test('should return server configurations with NUXT_* env', () => {
const env = { const env = {
NUXT_PORT: 3001, NUXT_PORT: 3001,
NUXT_HOST: '127.0.0.1' NUXT_HOST: '127.0.0.1'
} }
expect(serverConfig({ env })).toEqual({ expect(serverConfig({ env })).toEqual({
https: false, ...serverDefaults,
port: env.NUXT_PORT, port: env.NUXT_PORT,
host: env.NUXT_HOST, host: env.NUXT_HOST
socket: undefined
}) })
}) })
@ -30,7 +22,7 @@ describe('config: server', () => {
UNIX_SOCKET: '/var/run/env.sock' UNIX_SOCKET: '/var/run/env.sock'
} }
expect(serverConfig({ env })).toEqual({ expect(serverConfig({ env })).toEqual({
https: false, ...serverDefaults,
port: env.PORT, port: env.PORT,
host: env.HOST, host: env.HOST,
socket: env.UNIX_SOCKET socket: env.UNIX_SOCKET
@ -44,7 +36,7 @@ describe('config: server', () => {
npm_package_config_unix_socket: '/var/run/env.npm.sock' npm_package_config_unix_socket: '/var/run/env.npm.sock'
} }
expect(serverConfig({ env })).toEqual({ expect(serverConfig({ env })).toEqual({
https: false, ...serverDefaults,
port: env.npm_package_config_nuxt_port, port: env.npm_package_config_nuxt_port,
host: env.npm_package_config_nuxt_host, host: env.npm_package_config_nuxt_host,
socket: env.npm_package_config_unix_socket socket: env.npm_package_config_unix_socket

View File

@ -20,6 +20,7 @@
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"ip": "^1.1.5", "ip": "^1.1.5",
"launch-editor-middleware": "^2.2.1", "launch-editor-middleware": "^2.2.1",
"on-headers": "^1.0.1",
"pify": "^4.0.1", "pify": "^4.0.1",
"semver": "^5.6.0", "semver": "^5.6.0",
"serve-placeholder": "^1.1.0", "serve-placeholder": "^1.1.0",

View File

@ -0,0 +1,51 @@
import consola from 'consola'
import onHeaders from 'on-headers'
import { Timer } from '@nuxt/utils'
export default options => (req, res, next) => {
if (res.timing) {
consola.warn('server-timing is already registered.')
}
res.timing = new ServerTiming()
if (options && options.total) {
res.timing.start('total', 'Nuxt Server Time')
}
onHeaders(res, () => {
res.timing.end('total')
res.setHeader(
'Server-Timing',
[]
.concat(res.getHeader('Server-Timing') || [])
.concat(res.timing.headers)
.join(', ')
)
})
next()
}
class ServerTiming extends Timer {
constructor(...args) {
super(...args)
this.headers = []
}
end(...args) {
const time = super.end(...args)
this.headers.push(this.formatHeader(time))
return time
}
clear() {
super.clear()
this.headers.length = 0
}
formatHeader(time) {
const desc = time.description ? `;desc="${time.description}"` : ''
return `${time.name};dur=${time.duration}${desc}`
}
}

View File

@ -12,6 +12,7 @@ import nuxtMiddleware from './middleware/nuxt'
import errorMiddleware from './middleware/error' import errorMiddleware from './middleware/error'
import Listener from './listener' import Listener from './listener'
import createModernMiddleware from './middleware/modern' import createModernMiddleware from './middleware/modern'
import createTimingMiddleware from './middleware/timing'
export default class Server { export default class Server {
constructor(nuxt) { constructor(nuxt) {
@ -75,6 +76,10 @@ export default class Server {
} }
} }
if (this.options.server.timing) {
this.useMiddleware(createTimingMiddleware(this.options.server.timing))
}
const modernMiddleware = createModernMiddleware({ const modernMiddleware = createModernMiddleware({
context: this.renderer.context context: this.renderer.context
}) })

View File

@ -24,3 +24,42 @@ export const timeout = function timeout(fn, ms, msg) {
export const waitFor = function waitFor(ms) { export const waitFor = function waitFor(ms) {
return new Promise(resolve => setTimeout(resolve, ms || 0)) return new Promise(resolve => setTimeout(resolve, ms || 0))
} }
export class Timer {
constructor() {
this._times = new Map()
}
start(name, description) {
const time = {
name,
description,
start: this.hrtime()
}
this._times.set(name, time)
return time
}
end(name) {
if (this._times.has(name)) {
const time = this._times.get(name)
time.duration = this.hrtime(time.start)
this._times.delete(name)
return time
}
}
hrtime(start) {
const useBigInt = typeof process.hrtime.bigint === 'function'
if (start) {
const end = useBigInt ? process.hrtime.bigint() : process.hrtime(start)
return useBigInt
? (end - start) / BigInt(1000000)
: (end[0] * 1e3) + (end[1] * 1e-6)
}
return useBigInt ? process.hrtime.bigint() : process.hrtime()
}
clear() {
this._times.clear()
}
}

View File

@ -6,7 +6,10 @@ export default {
srcDir: __dirname, srcDir: __dirname,
server: { server: {
port: 8000, port: 8000,
host: '0.0.0.0' host: '0.0.0.0',
timing: {
total: true
}
}, },
router: { router: {
base: '/test/', base: '/test/',

View File

@ -197,6 +197,13 @@ describe('with-config', () => {
expect(fakeErrorLog).toHaveBeenCalled() expect(fakeErrorLog).toHaveBeenCalled()
}) })
test('/ with Server-Timing header', async () => {
const { headers } = await rp(url('/test'), {
resolveWithFullResponse: true
})
expect(headers['server-timing']).toMatch(/total;dur=\d+;desc="Nuxt Server Time"/)
})
// Close server and ask nuxt to stop listening to file changes // Close server and ask nuxt to stop listening to file changes
afterAll(async () => { afterAll(async () => {
await nuxt.close() await nuxt.close()

View File

@ -7771,7 +7771,7 @@ on-finished@~2.3.0:
dependencies: dependencies:
ee-first "1.1.1" ee-first "1.1.1"
on-headers@~1.0.1: on-headers@^1.0.1, on-headers@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=