refactor server into nuxt

This commit is contained in:
Pooya Parsa 2017-06-20 16:14:47 +04:30
parent bf379fc0fd
commit daa50e4efb
13 changed files with 139 additions and 169 deletions

View File

@ -8,7 +8,7 @@ const debug = require('debug')('nuxt:build')
debug.color = 2 // force green color debug.color = 2 // force green color
const fs = require('fs') const fs = require('fs')
const parseArgs = require('minimist') const parseArgs = require('minimist')
const { Nuxt, Server, Builder } = require('../') const { Nuxt, Builder } = require('../')
const chokidar = require('chokidar') const chokidar = require('chokidar')
const resolve = require('path').resolve const resolve = require('path').resolve
@ -50,64 +50,64 @@ if (argv.help) {
const rootDir = resolve(argv._[0] || '.') const rootDir = resolve(argv._[0] || '.')
const nuxtConfigFile = resolve(rootDir, argv['config-file']) const nuxtConfigFile = resolve(rootDir, argv['config-file'])
var options = {} // Load config once for chokidar
if (fs.existsSync(nuxtConfigFile)) { const nuxtConfig = loadNuxtConfig()
options = require(nuxtConfigFile) _.defaultsDeep(nuxtConfig, { watchers: { chokidar: { ignoreInitial: true } } })
} else if (argv['config-file'] !== 'nuxt.config.js') {
console.error(`> Could not load config file ${argv['config-file']}`)
process.exit(1)
}
if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir
}
// Force development mode: add hot reloading and watching changes
options.dev = true
const nuxt = new Nuxt(options) // Start dev
const builder = new Builder(nuxt) let dev = startDev()
const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port // Start watching for nuxt.config.js changes
const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host chokidar
const server = new Server(nuxt) .watch(nuxtConfigFile, nuxtConfig.watchers.chokidar)
server.listen(port, host) .on('all', _.debounce(() => {
builder.build().then(() => {
listenOnConfigChanges(nuxt, server)
})
function listenOnConfigChanges (nuxt, server) {
// Listen on nuxt.config.js changes
const build = _.debounce(() => {
debug('[nuxt.config.js] changed') debug('[nuxt.config.js] changed')
delete require.cache[nuxtConfigFile] debug('Rebuilding the app...')
var options = {} dev = dev.then(startDev)
if (fs.existsSync(nuxtConfigFile)) { }), 2500)
try {
options = require(nuxtConfigFile)
} catch (e) {
return console.error(e) // eslint-disable-line no-console
}
}
if (typeof options.rootDir !== 'string') { function startDev (oldNuxt) {
options.rootDir = rootDir // Get latest environment variables
} const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port
const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host
nuxt.close() // Load options
.then(() => { let options = {}
debug('Rebuilding the app...') try {
const nuxt = new Nuxt(options) options = loadNuxtConfig()
const builder = new Builder(nuxt) } catch (err) {
server.nuxt = nuxt console.error(err)
return builder.build() return // Wait for next reload
}) }
.catch((error) => {
console.error('Error while rebuild the app:', error) // eslint-disable-line no-console // Create nuxt and builder instance
process.exit(1) const nuxt = new Nuxt(options)
}) const builder = new Builder(nuxt)
}, 200)
chokidar.watch(nuxtConfigFile, Object.assign({}, nuxt.options.watchers.chokidar, { ignoreInitial: true })) return Promise.resolve()
.on('all', build) .then(() => builder.build()) // 1- Start build
.then(() => oldNuxt ? oldNuxt.close() : Promise.resolve()) // 2- Close old nuxt after successful build
.then(() => nuxt.listen(port, host)) // 3- Start listening
.then(() => nuxt) // 4- Pass new nuxt to watch chain
} }
module.exports = nuxt function loadNuxtConfig () {
let options = {}
if (fs.existsSync(nuxtConfigFile)) {
delete require.cache[nuxtConfigFile]
options = require(nuxtConfigFile)
} else if (argv['config-file'] !== 'nuxt.config.js') {
console.error(`> Could not load config file ${argv['config-file']}`)
process.exit(1)
}
if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir
}
// Force development mode for add hot reloading and watching changes
options.dev = true
return options
}

View File

@ -43,17 +43,21 @@ if (argv.help) {
const rootDir = resolve(argv._[0] || '.') const rootDir = resolve(argv._[0] || '.')
const nuxtConfigFile = resolve(rootDir, argv['config-file']) const nuxtConfigFile = resolve(rootDir, argv['config-file'])
var options = {} let options = {}
if (fs.existsSync(nuxtConfigFile)) { if (fs.existsSync(nuxtConfigFile)) {
options = require(nuxtConfigFile) options = require(nuxtConfigFile)
} else if (argv['config-file'] !== 'nuxt.config.js') { } else if (argv['config-file'] !== 'nuxt.config.js') {
console.error(`> Could not load config file ${argv['config-file']}`) console.error(`> Could not load config file ${argv['config-file']}`)
process.exit(1) process.exit(1)
} }
if (typeof options.rootDir !== 'string') { if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir options.rootDir = rootDir
} }
options.dev = false // Force production mode (no webpack middleware called)
// Force production mode (no webpack middleware called)
options.dev = false
// Check if project is built for production // Check if project is built for production
const distDir = join(options.rootDir, options.buildDir || '.nuxt', 'dist' ) const distDir = join(options.rootDir, options.buildDir || '.nuxt', 'dist' )
@ -65,6 +69,4 @@ if (!fs.existsSync(join(distDir, 'server-bundle.json'))) {
const nuxt = new Nuxt(options) const nuxt = new Nuxt(options)
const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port
const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host
new Server(nuxt).listen(port, host) nuxt.listen(port, host)
module.exports = nuxt

View File

@ -2,7 +2,6 @@ import Options from './options'
import ModuleContainer from './module' import ModuleContainer from './module'
import Nuxt from './nuxt' import Nuxt from './nuxt'
import Renderer from './renderer' import Renderer from './renderer'
import Server from './server'
import * as Utils from 'utils' import * as Utils from 'utils'
export default { export default {
@ -10,6 +9,5 @@ export default {
ModuleContainer, ModuleContainer,
Nuxt, Nuxt,
Renderer, Renderer,
Server,
Utils Utils
} }

View File

@ -1,7 +1,12 @@
import Tapable from 'tappable' import Tapable from 'tappable'
import chalk from 'chalk'
import ModuleContainer from './module' import ModuleContainer from './module'
import Renderer from './renderer' import Renderer from './renderer'
import Options from './options' import Options from './options'
import Debug from 'debug'
const debug = Debug('nuxt:')
debug.color = 5
export default class Nuxt extends Tapable { export default class Nuxt extends Tapable {
constructor (_options = {}) { constructor (_options = {}) {
@ -38,6 +43,34 @@ export default class Nuxt extends Tapable {
return this return this
} }
listen (port = 3000, host = 'localhost') {
return new Promise((resolve, reject) => {
const server = this.renderer.app.listen({ port, host, exclusive: false }, err => {
if (err) {
return reject(err)
}
// Show Open URL
let _host = host === '0.0.0.0' ? 'localhost' : host
// eslint-disable-next-line no-console
console.log('\n' + chalk.bold(chalk.bgBlue.black(' OPEN ') + chalk.blue(` http://${_host}:${port}\n`)))
// Close server on nuxt close
this.plugin('close', () => new Promise((_resolve, _reject) => {
server.close(_err => {
debug('server closed')
if (_err) {
return _reject(err)
}
_resolve()
})
}))
resolve()
})
})
}
errorHandler /* istanbul ignore next */ () { errorHandler /* istanbul ignore next */ () {
// Silent // Silent
if (this.options.errorHandler === false) { if (this.options.errorHandler === false) {
@ -54,7 +87,6 @@ export default class Nuxt extends Tapable {
} }
async close (callback) { async close (callback) {
// Call for close
await this.applyPluginsAsync('close') await this.applyPluginsAsync('close')
if (typeof callback === 'function') { if (typeof callback === 'function') {

View File

@ -21,31 +21,6 @@ setAnsiColors(ansiHTML)
let jsdom = null let jsdom = null
const parseTemplate = templateStr => _.template(templateStr, {
interpolate: /{{([\s\S]+?)}}/g
})
const resourceMap = [
{
key: 'clientManifest',
fileName: 'vue-ssr-client-manifest.json',
transform: JSON.parse
},
{
key: 'serverBundle',
fileName: 'server-bundle.json',
transform: JSON.parse
},
{
key: 'appTemplate',
fileName: 'index.html',
transform: parseTemplate
}
]
// Protector utility against request to SSR bundle files
const ssrResourceRegex = new RegExp(resourceMap.map(resource => resource.fileName).join('|'), 'i')
export default class Renderer extends Tapable { export default class Renderer extends Tapable {
constructor (nuxt) { constructor (nuxt) {
super() super()
@ -403,3 +378,28 @@ export default class Renderer extends Tapable {
return window return window
} }
} }
const parseTemplate = templateStr => _.template(templateStr, {
interpolate: /{{([\s\S]+?)}}/g
})
const resourceMap = [
{
key: 'clientManifest',
fileName: 'vue-ssr-client-manifest.json',
transform: JSON.parse
},
{
key: 'serverBundle',
fileName: 'server-bundle.json',
transform: JSON.parse
},
{
key: 'appTemplate',
fileName: 'index.html',
transform: parseTemplate
}
]
// Protector utility against request to SSR bundle files
const ssrResourceRegex = new RegExp(resourceMap.map(resource => resource.fileName).join('|'), 'i')

View File

@ -1,62 +0,0 @@
import http from 'http'
import chalk from 'chalk'
class Server {
constructor (nuxt) {
this.nuxt = nuxt
this.options = nuxt.options
// Initialize
/* istanbul ignore if */
if (nuxt.initialized) {
// If nuxt already initialized
this._ready = this.ready().catch(this.nuxt.errorHandler)
} else {
// Wait for hook
this.nuxt.plugin('afterInit', () => {
this._ready = this.ready()
return this._ready
})
}
// Stop server on nuxt.close()
this.nuxt.plugin('close', () => this.close())
}
async ready () {
/* istanbul ignore if */
if (this._ready) {
return this._ready
}
this.server = http.createServer(this.nuxt.render)
return this
}
listen (port, host) {
host = host || 'localhost'
port = port || 3000
return this.ready()
.then(() => {
this.server.listen(port, host, () => {
let _host = host === '0.0.0.0' ? 'localhost' : host
// eslint-disable-next-line no-console
console.log('\n' + chalk.bold(chalk.bgBlue.black(' OPEN ') + chalk.blue(` http://${_host}:${port}\n`)))
})
}).catch(this.nuxt.errorHandler)
}
close () {
return new Promise((resolve, reject) => {
this.server.close(err => {
if (err) {
return reject(err)
}
resolve()
})
})
}
}
export default Server

View File

@ -1,7 +1,7 @@
import test from 'ava' import test from 'ava'
import { resolve } from 'path' import { resolve } from 'path'
import rp from 'request-promise-native' import rp from 'request-promise-native'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4001 const port = 4001
const url = (route) => 'http://localhost:' + port + route const url = (route) => 'http://localhost:' + port + route
@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => {
} }
nuxt = new Nuxt(options) nuxt = new Nuxt(options)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('/stateless', async t => { test('/stateless', async t => {

View File

@ -30,7 +30,7 @@ test.before('Init Nuxt.js', async t => {
server = http.createServer((req, res) => { server = http.createServer((req, res) => {
serve(req, res, finalhandler(req, res)) serve(req, res, finalhandler(req, res))
}) })
server.listen(port) await nuxt.listen(port)
}) })
test('/stateless', async t => { test('/stateless', async t => {

View File

@ -2,7 +2,7 @@ import test from 'ava'
import { resolve } from 'path' import { resolve } from 'path'
import rp from 'request-promise-native' import rp from 'request-promise-native'
import stdMocks from 'std-mocks' import stdMocks from 'std-mocks'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4003 const port = 4003
const url = (route) => 'http://localhost:' + port + route const url = (route) => 'http://localhost:' + port + route
@ -19,8 +19,8 @@ test.before('Init Nuxt.js', async t => {
} }
nuxt = new Nuxt(options) nuxt = new Nuxt(options)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('/stateless', async t => { test('/stateless', async t => {

View File

@ -1,6 +1,6 @@
import test from 'ava' import test from 'ava'
import { resolve } from 'path' import { resolve } from 'path'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4004 const port = 4004
// const url = (route) => 'http://localhost:' + port + route // const url = (route) => 'http://localhost:' + port + route
@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => {
} }
nuxt = new Nuxt(options) nuxt = new Nuxt(options)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('/parent', async t => { test('/parent', async t => {

View File

@ -1,6 +1,6 @@
import test from 'ava' import test from 'ava'
import { resolve } from 'path' import { resolve } from 'path'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4005 const port = 4005
const url = (route) => 'http://localhost:' + port + route const url = (route) => 'http://localhost:' + port + route
@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => {
} }
nuxt = new Nuxt(options) nuxt = new Nuxt(options)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('/ should display an error', async t => { test('/ should display an error', async t => {

View File

@ -1,7 +1,7 @@
import test from 'ava' import test from 'ava'
import { resolve, normalize } from 'path' import { resolve, normalize } from 'path'
import rp from 'request-promise-native' import rp from 'request-promise-native'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4006 const port = 4006
const url = (route) => 'http://localhost:' + port + route const url = (route) => 'http://localhost:' + port + route
@ -18,8 +18,8 @@ test.before('Init Nuxt.js', async t => {
config.runBuild = true config.runBuild = true
nuxt = new Nuxt(config) nuxt = new Nuxt(config)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('Vendor', async t => { test('Vendor', async t => {

View File

@ -1,7 +1,7 @@
import test from 'ava' import test from 'ava'
import { resolve } from 'path' import { resolve } from 'path'
import rp from 'request-promise-native' import rp from 'request-promise-native'
import { Nuxt, Server, Builder } from '../index.js' import { Nuxt, Builder } from '../index.js'
const port = 4007 const port = 4007
const url = (route) => 'http://localhost:' + port + route const url = (route) => 'http://localhost:' + port + route
@ -18,8 +18,8 @@ test.before('Init Nuxt.js', async t => {
config.runBuild = true config.runBuild = true
nuxt = new Nuxt(config) nuxt = new Nuxt(config)
await new Builder(nuxt).build() await new Builder(nuxt).build()
server = new Server(nuxt)
server.listen(port, 'localhost') await nuxt.listen(port, 'localhost')
}) })
test('/', async t => { test('/', async t => {