diff --git a/bin/common/utils.js b/bin/common/utils.js index 52862c5261..b55e5ee48d 100644 --- a/bin/common/utils.js +++ b/bin/common/utils.js @@ -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 } +} diff --git a/bin/nuxt-dev b/bin/nuxt-dev index 722a99c846..ffb856d18f 100755 --- a/bin/nuxt-dev +++ b/bin/nuxt-dev @@ -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()) diff --git a/bin/nuxt-start b/bin/nuxt-start index 2fba86cd42..fc0cbedfe5 100755 --- a/bin/nuxt-start +++ b/bin/nuxt-start @@ -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) }) diff --git a/lib/common/nuxt.config.js b/lib/common/nuxt.config.js index 7e8b11de69..bf25274f3b 100644 --- a/lib/common/nuxt.config.js +++ b/lib/common/nuxt.config.js @@ -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, diff --git a/lib/core/nuxt.js b/lib/core/nuxt.js index b55fd4511b..60546cd527 100644 --- a/lib/core/nuxt.js +++ b/lib/core/nuxt.js @@ -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) + } } ) diff --git a/test/fixtures/https/https.test.js b/test/fixtures/https/https.test.js new file mode 100644 index 0000000000..0f1ba45df1 --- /dev/null +++ b/test/fixtures/https/https.test.js @@ -0,0 +1,3 @@ +import { buildFixture } from '../../utils/build' + +buildFixture('https') diff --git a/test/fixtures/https/nuxt.config.js b/test/fixtures/https/nuxt.config.js new file mode 100644 index 0000000000..a9dad76109 --- /dev/null +++ b/test/fixtures/https/nuxt.config.js @@ -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')) + } + } +} diff --git a/test/fixtures/https/pages/index.vue b/test/fixtures/https/pages/index.vue new file mode 100644 index 0000000000..6156839c56 --- /dev/null +++ b/test/fixtures/https/pages/index.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/https/server.crt b/test/fixtures/https/server.crt new file mode 100644 index 0000000000..4aad81cae2 --- /dev/null +++ b/test/fixtures/https/server.crt @@ -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----- diff --git a/test/fixtures/https/server.key b/test/fixtures/https/server.key new file mode 100644 index 0000000000..4eea4ca5aa --- /dev/null +++ b/test/fixtures/https/server.key @@ -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----- diff --git a/test/fixtures/sockets/nuxt.config.js b/test/fixtures/sockets/nuxt.config.js new file mode 100644 index 0000000000..0d36c2a012 --- /dev/null +++ b/test/fixtures/sockets/nuxt.config.js @@ -0,0 +1,7 @@ +import path from 'path' + +export default { + server: { + socket: path.resolve(__dirname, 'nuxt.socket') + } +} diff --git a/test/fixtures/sockets/pages/index.vue b/test/fixtures/sockets/pages/index.vue new file mode 100644 index 0000000000..a96dbe7181 --- /dev/null +++ b/test/fixtures/sockets/pages/index.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/sockets/sockets.test.js b/test/fixtures/sockets/sockets.test.js new file mode 100644 index 0000000000..39ca9e6907 --- /dev/null +++ b/test/fixtures/sockets/sockets.test.js @@ -0,0 +1,3 @@ +import { buildFixture } from '../../utils/build' + +buildFixture('sockets') diff --git a/test/unit/https.test.js b/test/unit/https.test.js new file mode 100644 index 0000000000..1168a920d3 --- /dev/null +++ b/test/unit/https.test.js @@ -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('

Served over HTTPS!

')).toBe(true) + }) + + // Close server and ask nuxt to stop listening to file changes + afterAll(async () => { + await nuxt.close() + }) +}) diff --git a/test/unit/sockets.test.js b/test/unit/sockets.test.js new file mode 100644 index 0000000000..df5551fdbe --- /dev/null +++ b/test/unit/sockets.test.js @@ -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('

Served over sockets!

')).toBe(true) + }) + + // Close server and ask nuxt to stop listening to file changes + afterAll(async () => { + await nuxt.close() + }) +})