mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Move out start method from server (#5315)
- This makes sure the Next.js renderer / server doesn't have a dependency on the `http` module. - Splits out util functions for SSR only - Removes obsolete methods / methods that weren't being tree-shaken
This commit is contained in:
parent
20f3b6b284
commit
fb0b485299
|
@ -3,7 +3,7 @@ import { resolve, join } from 'path'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import parseArgs from 'minimist'
|
import parseArgs from 'minimist'
|
||||||
import build from '../build'
|
import build from '../build'
|
||||||
import { printAndExit } from '../lib/utils'
|
import { printAndExit } from '../server/lib/utils'
|
||||||
|
|
||||||
const argv = parseArgs(process.argv.slice(2), {
|
const argv = parseArgs(process.argv.slice(2), {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
11
bin/next-dev
11
bin/next-dev
|
@ -2,8 +2,8 @@
|
||||||
import { resolve, join } from 'path'
|
import { resolve, join } from 'path'
|
||||||
import parseArgs from 'minimist'
|
import parseArgs from 'minimist'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import Server from '../server'
|
import startServer from '../server/lib/start-server'
|
||||||
import { printAndExit } from '../lib/utils'
|
import { printAndExit } from '../server/lib/utils'
|
||||||
|
|
||||||
const argv = parseArgs(process.argv.slice(2), {
|
const argv = parseArgs(process.argv.slice(2), {
|
||||||
alias: {
|
alias: {
|
||||||
|
@ -52,12 +52,9 @@ if (!existsSync(join(dir, 'pages'))) {
|
||||||
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
||||||
}
|
}
|
||||||
|
|
||||||
const srv = new Server({ dir, dev: true })
|
startServer({dir, dev: true}, argv.port, argv.hostname)
|
||||||
srv.start(argv.port, argv.hostname)
|
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
if (!process.env.NOW) {
|
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err.code === 'EADDRINUSE') {
|
if (err.code === 'EADDRINUSE') {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { resolve, join } from 'path'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import parseArgs from 'minimist'
|
import parseArgs from 'minimist'
|
||||||
import exportApp from '../export'
|
import exportApp from '../export'
|
||||||
import { printAndExit } from '../lib/utils'
|
import { printAndExit } from '../server/lib/utils'
|
||||||
|
|
||||||
const argv = parseArgs(process.argv.slice(2), {
|
const argv = parseArgs(process.argv.slice(2), {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
import parseArgs from 'minimist'
|
import parseArgs from 'minimist'
|
||||||
import Server from '../server'
|
import startServer from '../server/lib/start-server'
|
||||||
|
|
||||||
const argv = parseArgs(process.argv.slice(2), {
|
const argv = parseArgs(process.argv.slice(2), {
|
||||||
alias: {
|
alias: {
|
||||||
|
@ -44,12 +44,9 @@ if (argv.help) {
|
||||||
|
|
||||||
const dir = resolve(argv._[0] || '.')
|
const dir = resolve(argv._[0] || '.')
|
||||||
|
|
||||||
const srv = new Server({ dir })
|
startServer({dir}, argv.port, argv.hostname)
|
||||||
srv.start(argv.port, argv.hostname)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (!process.env.NOW) {
|
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import shallowEquals from './shallow-equals'
|
import shallowEquals from './shallow-equals'
|
||||||
import { execOnce, warn, loadGetInitialProps } from './utils'
|
import { execOnce, loadGetInitialProps } from './utils'
|
||||||
import { makePublicRouterInstance } from './router'
|
import { makePublicRouterInstance } from './router'
|
||||||
|
|
||||||
export default class App extends Component {
|
export default class App extends Component {
|
||||||
|
@ -79,7 +79,7 @@ export class Container extends Component {
|
||||||
|
|
||||||
const warnUrl = execOnce(() => {
|
const warnUrl = execOnce(() => {
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
warn(`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`)
|
console.error(`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { resolve, format, parse } from 'url'
|
||||||
import React, { Component, Children } from 'react'
|
import React, { Component, Children } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Router, { _rewriteUrlForNextExport } from './router'
|
import Router, { _rewriteUrlForNextExport } from './router'
|
||||||
import { warn, execOnce, getLocationOrigin } from './utils'
|
import { execOnce, getLocationOrigin } from './utils'
|
||||||
|
|
||||||
function isLocal (href) {
|
function isLocal (href) {
|
||||||
const url = parse(href, false, true)
|
const url = parse(href, false, true)
|
||||||
|
@ -14,8 +14,6 @@ function isLocal (href) {
|
||||||
(url.protocol === origin.protocol && url.host === origin.host)
|
(url.protocol === origin.protocol && url.host === origin.host)
|
||||||
}
|
}
|
||||||
|
|
||||||
const warnLink = execOnce(warn)
|
|
||||||
|
|
||||||
function memoizedFormatUrl (formatUrl) {
|
function memoizedFormatUrl (formatUrl) {
|
||||||
let lastHref = null
|
let lastHref = null
|
||||||
let lastAs = null
|
let lastAs = null
|
||||||
|
@ -155,6 +153,8 @@ class Link extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
const warn = execOnce(console.error)
|
||||||
|
|
||||||
// This module gets removed by webpack.IgnorePlugin
|
// This module gets removed by webpack.IgnorePlugin
|
||||||
const exact = require('prop-types-exact')
|
const exact = require('prop-types-exact')
|
||||||
Link.propTypes = exact({
|
Link.propTypes = exact({
|
||||||
|
@ -171,7 +171,7 @@ if (process.env.NODE_ENV === 'development') {
|
||||||
const value = props[propName]
|
const value = props[propName]
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
warnLink(`Warning: You're using a string directly inside <Link>. This usage has been deprecated. Please add an <a> tag as child of <Link>`)
|
warn(`Warning: You're using a string directly inside <Link>. This usage has been deprecated. Please add an <a> tag as child of <Link>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import Link from './link'
|
|
||||||
import Router from './router'
|
|
||||||
import { warn, execOnce } from './utils'
|
|
||||||
|
|
||||||
const warnImperativePrefetch = execOnce(() => {
|
|
||||||
const message = '> You are using deprecated "next/prefetch". It will be removed with Next.js 2.0.\n' +
|
|
||||||
'> Use "Router.prefetch(href)" instead.'
|
|
||||||
warn(message)
|
|
||||||
})
|
|
||||||
|
|
||||||
const wantLinkPrefetch = execOnce(() => {
|
|
||||||
const message = '> You are using deprecated "next/prefetch". It will be removed with Next.js 2.0.\n' +
|
|
||||||
'> Use "<Link prefetch />" instead.'
|
|
||||||
warn(message)
|
|
||||||
})
|
|
||||||
|
|
||||||
export function prefetch (href) {
|
|
||||||
warnImperativePrefetch()
|
|
||||||
return Router.prefetch(href)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class LinkPrefetch extends React.Component {
|
|
||||||
render () {
|
|
||||||
wantLinkPrefetch()
|
|
||||||
const props = {
|
|
||||||
...this.props,
|
|
||||||
prefetch: this.props.prefetch !== false
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<Link {...props} />)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,16 +4,9 @@ import { parse, format } from 'url'
|
||||||
import EventEmitter from '../EventEmitter'
|
import EventEmitter from '../EventEmitter'
|
||||||
import shallowEquals from '../shallow-equals'
|
import shallowEquals from '../shallow-equals'
|
||||||
import PQueue from '../p-queue'
|
import PQueue from '../p-queue'
|
||||||
import { loadGetInitialProps, getURL, warn, execOnce } from '../utils'
|
import { loadGetInitialProps, getURL } from '../utils'
|
||||||
import { _rewriteUrlForNextExport } from './'
|
import { _rewriteUrlForNextExport } from './'
|
||||||
|
|
||||||
const historyUnavailableWarning = execOnce(() => {
|
|
||||||
warn(`Warning: window.history is not available.`)
|
|
||||||
})
|
|
||||||
const historyMethodWarning = execOnce((method) => {
|
|
||||||
warn(`Warning: window.history.${method} is not available`)
|
|
||||||
})
|
|
||||||
|
|
||||||
export default class Router {
|
export default class Router {
|
||||||
static events = new EventEmitter()
|
static events = new EventEmitter()
|
||||||
|
|
||||||
|
@ -219,14 +212,15 @@ export default class Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
changeState (method, url, as, options = {}) {
|
changeState (method, url, as, options = {}) {
|
||||||
if (typeof window.history === 'undefined') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
historyUnavailableWarning()
|
if (typeof window.history === 'undefined') {
|
||||||
return
|
console.error(`Warning: window.history is not available.`)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
if (typeof window.history[method] === 'undefined') {
|
if (typeof window.history[method] === 'undefined') {
|
||||||
historyMethodWarning(method)
|
console.error(`Warning: window.history.${method} is not available`)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method !== 'pushState' || getURL() !== as) {
|
if (method !== 'pushState' || getURL() !== as) {
|
||||||
|
|
37
lib/utils.js
37
lib/utils.js
|
@ -1,9 +1,3 @@
|
||||||
export function warn (message) {
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
console.error(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function execOnce (fn) {
|
export function execOnce (fn) {
|
||||||
let used = false
|
let used = false
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
|
@ -14,37 +8,6 @@ export function execOnce (fn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deprecated (fn, message) {
|
|
||||||
// else is used here so that webpack/uglify will remove the code block depending on the build environment
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
return fn
|
|
||||||
} else {
|
|
||||||
let warned = false
|
|
||||||
const newFn = function (...args) {
|
|
||||||
if (!warned) {
|
|
||||||
warned = true
|
|
||||||
console.error(message)
|
|
||||||
}
|
|
||||||
return fn.apply(this, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy all properties
|
|
||||||
Object.assign(newFn, fn)
|
|
||||||
|
|
||||||
return newFn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function printAndExit (message, code = 1) {
|
|
||||||
if (code === 0) {
|
|
||||||
console.log(message)
|
|
||||||
} else {
|
|
||||||
console.error(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.exit(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDisplayName (Component) {
|
export function getDisplayName (Component) {
|
||||||
if (typeof Component === 'string') {
|
if (typeof Component === 'string') {
|
||||||
return Component
|
return Component
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { resolve, join, sep } from 'path'
|
||||||
import { parse as parseUrl } from 'url'
|
import { parse as parseUrl } from 'url'
|
||||||
import { parse as parseQs } from 'querystring'
|
import { parse as parseQs } from 'querystring'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import http, { STATUS_CODES } from 'http'
|
|
||||||
import {
|
import {
|
||||||
renderToHTML,
|
renderToHTML,
|
||||||
renderErrorToHTML,
|
renderErrorToHTML,
|
||||||
|
@ -27,7 +26,6 @@ export default class Server {
|
||||||
this.dev = dev
|
this.dev = dev
|
||||||
this.quiet = quiet
|
this.quiet = quiet
|
||||||
this.router = new Router()
|
this.router = new Router()
|
||||||
this.http = null
|
|
||||||
const phase = dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER
|
const phase = dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER
|
||||||
this.nextConfig = loadConfig(phase, this.dir, conf)
|
this.nextConfig = loadConfig(phase, this.dir, conf)
|
||||||
this.distDir = join(this.dir, this.nextConfig.distDir)
|
this.distDir = join(this.dir, this.nextConfig.distDir)
|
||||||
|
@ -87,7 +85,7 @@ export default class Server {
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (!this.quiet) console.error(err)
|
if (!this.quiet) console.error(err)
|
||||||
res.statusCode = 500
|
res.statusCode = 500
|
||||||
res.end(STATUS_CODES[500])
|
res.end('Internal Server Error')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,15 +109,6 @@ export default class Server {
|
||||||
if (this.hotReloader) {
|
if (this.hotReloader) {
|
||||||
await this.hotReloader.stop()
|
await this.hotReloader.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.http) {
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
this.http.close((err) => {
|
|
||||||
if (err) return reject(err)
|
|
||||||
return resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async defineRoutes () {
|
async defineRoutes () {
|
||||||
|
@ -203,17 +192,6 @@ export default class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async start (port, hostname) {
|
|
||||||
await this.prepare()
|
|
||||||
this.http = http.createServer(this.getRequestHandler())
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
// This code catches EADDRINUSE error if the port is already in use
|
|
||||||
this.http.on('error', reject)
|
|
||||||
this.http.on('listening', () => resolve())
|
|
||||||
this.http.listen(port, hostname)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async run (req, res, parsedUrl) {
|
async run (req, res, parsedUrl) {
|
||||||
if (this.hotReloader) {
|
if (this.hotReloader) {
|
||||||
const {finished} = await this.hotReloader.run(req, res, parsedUrl)
|
const {finished} = await this.hotReloader.run(req, res, parsedUrl)
|
||||||
|
@ -232,7 +210,7 @@ export default class Server {
|
||||||
await this.render404(req, res, parsedUrl)
|
await this.render404(req, res, parsedUrl)
|
||||||
} else {
|
} else {
|
||||||
res.statusCode = 501
|
res.statusCode = 501
|
||||||
res.end(STATUS_CODES[501])
|
res.end('Not Implemented')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
server/lib/start-server.js
Normal file
14
server/lib/start-server.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import http from 'http'
|
||||||
|
import Server from '../index'
|
||||||
|
|
||||||
|
export default async function start (serverOptions, port, hostname) {
|
||||||
|
const app = new Server(serverOptions)
|
||||||
|
await app.prepare()
|
||||||
|
const srv = http.createServer(app.getRequestHandler())
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
// This code catches EADDRINUSE error if the port is already in use
|
||||||
|
srv.on('error', reject)
|
||||||
|
srv.on('listening', () => resolve())
|
||||||
|
srv.listen(port, hostname)
|
||||||
|
})
|
||||||
|
}
|
9
server/lib/utils.js
Normal file
9
server/lib/utils.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export function printAndExit (message, code = 1) {
|
||||||
|
if (code === 0) {
|
||||||
|
console.log(message)
|
||||||
|
} else {
|
||||||
|
console.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(code)
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import Server from './'
|
import Server from './'
|
||||||
|
|
||||||
|
// This file is used for when users run `require('next')`
|
||||||
module.exports = (opts) => {
|
module.exports = (opts) => {
|
||||||
return new Server(opts)
|
return new Server(opts)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue