feat(core, cli): builtin support of https and unix sockets (#3831)

Co-authored-by: Aurélien Chrétien <aurelien@manager.one>
Co-authored-by: Rémy Sanchez <remy.sanchez@hyperthese.net>
This commit is contained in:
Jonas Galvez 2018-09-02 06:20:25 -03:00 committed by Pooya Parsa
parent 4f6a048a4b
commit 72479687d9
15 changed files with 190 additions and 19 deletions

View File

@ -52,3 +52,22 @@ exports.loadNuxtConfig = (argv) => {
return options
}
exports.getLatestHost = (argv) => {
const port =
argv.port ||
process.env.NUXT_PORT ||
process.env.PORT ||
process.env.npm_package_config_nuxt_port
const host =
argv.hostname ||
process.env.NUXT_HOST ||
process.env.HOST ||
process.env.npm_package_config_nuxt_host
const socket =
argv['unix-socket'] ||
process.env.UNIX_SOCKET ||
process.env.npm_package_config_unix_socket
return { port, host, socket }
}

View File

@ -3,7 +3,7 @@ const parseArgs = require('minimist')
const consola = require('consola')
const { version } = require('../package.json')
const { Nuxt, Builder } = require('..')
const { loadNuxtConfig } = require('./common/utils')
const { loadNuxtConfig, getLatestHost } = require('./common/utils')
const argv = parseArgs(process.argv.slice(2), {
alias: {
@ -75,7 +75,7 @@ const errorHandler = (err, instance) => {
}
// Get latest environment variables
const { port, host } = nuxt.options.server
const { port, host, socket } = getLatestHost(argv)
return (
Promise.resolve()
@ -91,7 +91,7 @@ const errorHandler = (err, instance) => {
})
.then(() => oldInstance && oldInstance.nuxt.close())
// Start listening
.then(() => nuxt.listen(port, host))
.then(() => nuxt.listen(port, host, socket))
// Show ready message first time, others will be shown through WebpackBar
.then(() => !oldInstance && nuxt.showReady(false))
.then(() => builder.watchServer())

View File

@ -4,19 +4,20 @@ const { resolve } = require('path')
const parseArgs = require('minimist')
const consola = require('consola')
const { Nuxt } = require('../dist/nuxt-start')
const { loadNuxtConfig } = require('./common/utils')
const { loadNuxtConfig, getLatestHost } = require('./common/utils')
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help',
H: 'hostname',
p: 'port',
n: 'unix-socket',
c: 'config-file',
s: 'spa',
u: 'universal'
},
boolean: ['h', 's', 'u'],
string: ['H', 'c'],
string: ['H', 'c', 'n'],
default: {
c: 'nuxt.config.js'
}
@ -36,6 +37,7 @@ if (argv.help) {
Options
--port, -p A port number on which to start the application
--hostname, -H Hostname on which to start the application
--unix-socket, -n Path to a UNIX socket
--spa Launch in SPA mode
--universal Launch in Universal mode (default)
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
@ -77,8 +79,8 @@ if (nuxt.options.render.ssr === true) {
}
}
const { port, host } = nuxt.options.server
const { port, host, socket } = getLatestHost(argv)
nuxt.listen(port, host).then(() => {
nuxt.listen(port, host, socket).then(() => {
nuxt.showReady(false)
})

View File

@ -16,6 +16,7 @@ export default {
// Server options
server: {
https: false,
port: process.env.NUXT_PORT ||
process.env.PORT ||
process.env.npm_package_config_nuxt_port,

View File

@ -1,5 +1,6 @@
import Module from 'module'
import { resolve, join } from 'path'
import https from 'https'
import enableDestroy from 'server-destroy'
import _ from 'lodash'
@ -141,25 +142,62 @@ export default class Nuxt {
this.readyMessage = null
}
listen(port = 3000, host = 'localhost') {
listen(port = 3000, host = 'localhost', socket = null) {
return this.ready().then(() => new Promise((resolve, reject) => {
const server = this.renderer.app.listen(
{ port, host, exclusive: false },
if (!socket && typeof this.options.server.socket === 'string') {
socket = this.options.server.socket
}
const args = { exclusive: false }
if (socket) {
args.path = socket
} else {
args.port = port
args.host = host
}
let appServer
const isHttps = Boolean(this.options.server.https)
if (isHttps) {
let httpsOptions
if (this.options.server.https === true) {
httpsOptions = {}
} else {
httpsOptions = this.options.server.https
}
appServer = https.createServer(httpsOptions, this.renderer.app)
} else {
appServer = this.renderer.app
}
const server = appServer.listen(
args,
(err) => {
/* istanbul ignore if */
if (err) {
return reject(err)
}
({ address: host, port } = server.address())
if (host === '127.0.0.1') {
host = 'localhost'
} else if (host === '0.0.0.0') {
host = ip.address()
}
let listenURL
const listenURL = chalk.underline.blue(`http://${host}:${port}`)
this.readyMessage = `Listening on ${listenURL}`
if (!socket) {
({ address: host, port } = server.address())
if (host === '127.0.0.1') {
host = 'localhost'
} else if (host === '0.0.0.0') {
host = ip.address()
}
listenURL = chalk.underline.blue(`http${isHttps ? 's' : ''}://${host}:${port}`)
this.readyMessage = `Listening on ${listenURL}`
} else {
listenURL = chalk.underline.blue(`unix+http://${socket}`)
this.readyMessage = `Listening on ${listenURL}`
}
// Close server on nuxt close
this.hook(
@ -178,7 +216,11 @@ export default class Nuxt {
})
)
this.callHook('listen', server, { port, host }).then(resolve)
if (socket) {
this.callHook('listen', server, { path: socket }).then(resolve)
} else {
this.callHook('listen', server, { port, host }).then(resolve)
}
}
)

3
test/fixtures/https/https.test.js vendored Normal file
View File

@ -0,0 +1,3 @@
import { buildFixture } from '../../utils/build'
buildFixture('https')

11
test/fixtures/https/nuxt.config.js vendored Normal file
View File

@ -0,0 +1,11 @@
import fs from 'fs'
import path from 'path'
export default {
server: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
}
}
}

3
test/fixtures/https/pages/index.vue vendored Normal file
View File

@ -0,0 +1,3 @@
<template>
<h1>Served over HTTPS!</h1>
</template>

19
test/fixtures/https/server.crt vendored Normal file
View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDIjCCAougAwIBAgIJALww5SutcTujMA0GCSqGSIb3DQEBCwUAMGoxCzAJBgNV
BAYTAkJSMRIwEAYDVQQIEwlTYW8gUGF1bG8xETAPBgNVBAcTCEJhcnJldG9zMQ0w
CwYDVQQKEwROdXh0MREwDwYDVQQLEwhGaXh0dXJlczESMBAGA1UEAxMJbG9jYWxo
b3N0MB4XDTE4MDkwMTIzMTk0OVoXDTE4MTAwMTIzMTk0OVowajELMAkGA1UEBhMC
QlIxEjAQBgNVBAgTCVNhbyBQYXVsbzERMA8GA1UEBxMIQmFycmV0b3MxDTALBgNV
BAoTBE51eHQxETAPBgNVBAsTCEZpeHR1cmVzMRIwEAYDVQQDEwlsb2NhbGhvc3Qw
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALoFJlquH9KNTPS3E0jbdKWLVw+N
oQaV+yPGPJb/IEAtg2cgMy62UlBS8eMTnMAv6JntuSuqS9wWdrvrTvcJkbbCRnKp
P13OTPpzhXO8R9pgzsopaO0DfLM8mTpFi1UPhzRm5riRCVIcg/KYH5JybI7LVzVu
v6LT3DhOtqp3tufRAgMBAAGjgc8wgcwwHQYDVR0OBBYEFIHCFtBMyB2w+os85zPR
AkI05z4FMIGcBgNVHSMEgZQwgZGAFIHCFtBMyB2w+os85zPRAkI05z4FoW6kbDBq
MQswCQYDVQQGEwJCUjESMBAGA1UECBMJU2FvIFBhdWxvMREwDwYDVQQHEwhCYXJy
ZXRvczENMAsGA1UEChMETnV4dDERMA8GA1UECxMIRml4dHVyZXMxEjAQBgNVBAMT
CWxvY2FsaG9zdIIJALww5SutcTujMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADgYEARaylCmK13yfaARc3utZLmD+vW7P1S4CO25skgaaQasKsKtABTURz92Ju
fShBFvP6d8AQH3yvHEC2+QBUibg6tc9oT1hE1GXYczp11AvYry3hcbalB+V1vqN+
/vMAWDmg5Y0cE/QnJ8YZi2fHFoxkxJdDIfx5/w19vvE5h18IMro=
-----END CERTIFICATE-----

15
test/fixtures/https/server.key vendored Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC6BSZarh/SjUz0txNI23Sli1cPjaEGlfsjxjyW/yBALYNnIDMu
tlJQUvHjE5zAL+iZ7bkrqkvcFna76073CZG2wkZyqT9dzkz6c4VzvEfaYM7KKWjt
A3yzPJk6RYtVD4c0Zua4kQlSHIPymB+ScmyOy1c1br+i09w4Traqd7bn0QIDAQAB
AoGAWZpBb0yQZ4tIllfZIi8TcOo9dXBzMAjuf7ztUo5xqnhB41rPTKDl5WsOuKKp
zqlFEWBA4ZeWEt1/M+WUk8o4NU2M03Q5N7cubw2T6/q43pZkCjvdTScsP6sJgGK9
zR0o4+Owu9J5j+X9e7ChfZFVeZa3WCX6dCB17AVfUdCh7EECQQDpPdkLirOsiu5x
/b42+/dLpL4gq+mnAqLzaeHI0Eb2Gt9A8RyxPicdjZGOJ3bmGZPFWcu2xUbmEsic
pSbAmZujAkEAzCvBLokZ2ETJN1pZJgT3luUDmd6LsaW8BJoJ42ECM/k8ARKMJfIS
/tqZPJhdkZ6JhYc36m4lNwPaY7x4Cbxl+wJBAM1WBZ6DnWppZUI1gSAm8q9FeZyJ
vEmrqIlizcNcmRxQy/sASaJAdW8vEtVzKNmp6s3zH8ToKGKkZriBLHyivsECQALF
zVfOcNVpCbqAtZk4lAwui//477i34XfGh7/Yv2jpR5FUKScSxINFgLM79nlVx9RS
Y8YBPOwkV0DnfFHVhyUCQFYYp2B8XgghJGapOcWvp7QogkDWqCra5mrSlI+jzi5W
b1LjJqCCCq4kGK6nKEzT7gd75lb2LbcUdc5JfFHbcE0=
-----END RSA PRIVATE KEY-----

7
test/fixtures/sockets/nuxt.config.js vendored Normal file
View File

@ -0,0 +1,7 @@
import path from 'path'
export default {
server: {
socket: path.resolve(__dirname, 'nuxt.socket')
}
}

3
test/fixtures/sockets/pages/index.vue vendored Normal file
View File

@ -0,0 +1,3 @@
<template>
<h1>Served over sockets!</h1>
</template>

3
test/fixtures/sockets/sockets.test.js vendored Normal file
View File

@ -0,0 +1,3 @@
import { buildFixture } from '../../utils/build'
buildFixture('sockets')

22
test/unit/https.test.js Normal file
View File

@ -0,0 +1,22 @@
import { loadFixture, getPort, Nuxt } from '../utils'
let nuxt = null
describe('basic https', () => {
beforeAll(async () => {
const options = await loadFixture('https')
nuxt = new Nuxt(options)
const port = await getPort()
await nuxt.listen(port, '0.0.0.0')
})
test('/', async () => {
const { html } = await nuxt.renderRoute('/')
expect(html.includes('<h1>Served over HTTPS!</h1>')).toBe(true)
})
// Close server and ask nuxt to stop listening to file changes
afterAll(async () => {
await nuxt.close()
})
})

21
test/unit/sockets.test.js Normal file
View File

@ -0,0 +1,21 @@
import { loadFixture, Nuxt } from '../utils'
let nuxt = null
describe.skip.appveyor('basic sockets', () => {
beforeAll(async () => {
const options = await loadFixture('sockets')
nuxt = new Nuxt(options)
await nuxt.listen()
})
test('/', async () => {
const { html } = await nuxt.renderRoute('/')
expect(html.includes('<h1>Served over sockets!</h1>')).toBe(true)
})
// Close server and ask nuxt to stop listening to file changes
afterAll(async () => {
await nuxt.close()
})
})