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 parseArgs from 'minimist'
|
||||
import build from '../build'
|
||||
import { printAndExit } from '../lib/utils'
|
||||
import { printAndExit } from '../server/lib/utils'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
|
|
11
bin/next-dev
11
bin/next-dev
|
@ -2,8 +2,8 @@
|
|||
import { resolve, join } from 'path'
|
||||
import parseArgs from 'minimist'
|
||||
import { existsSync } from 'fs'
|
||||
import Server from '../server'
|
||||
import { printAndExit } from '../lib/utils'
|
||||
import startServer from '../server/lib/start-server'
|
||||
import { printAndExit } from '../server/lib/utils'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
|
@ -52,12 +52,9 @@ if (!existsSync(join(dir, 'pages'))) {
|
|||
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
||||
}
|
||||
|
||||
const srv = new Server({ dir, dev: true })
|
||||
srv.start(argv.port, argv.hostname)
|
||||
startServer({dir, dev: true}, argv.port, argv.hostname)
|
||||
.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) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { resolve, join } from 'path'
|
|||
import { existsSync } from 'fs'
|
||||
import parseArgs from 'minimist'
|
||||
import exportApp from '../export'
|
||||
import { printAndExit } from '../lib/utils'
|
||||
import { printAndExit } from '../server/lib/utils'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { resolve } from 'path'
|
||||
import parseArgs from 'minimist'
|
||||
import Server from '../server'
|
||||
import startServer from '../server/lib/start-server'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
|
@ -44,12 +44,9 @@ if (argv.help) {
|
|||
|
||||
const dir = resolve(argv._[0] || '.')
|
||||
|
||||
const srv = new Server({ dir })
|
||||
srv.start(argv.port, argv.hostname)
|
||||
startServer({dir}, argv.port, argv.hostname)
|
||||
.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) => {
|
||||
console.error(err)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import shallowEquals from './shallow-equals'
|
||||
import { execOnce, warn, loadGetInitialProps } from './utils'
|
||||
import { execOnce, loadGetInitialProps } from './utils'
|
||||
import { makePublicRouterInstance } from './router'
|
||||
|
||||
export default class App extends Component {
|
||||
|
@ -79,7 +79,7 @@ export class Container extends Component {
|
|||
|
||||
const warnUrl = execOnce(() => {
|
||||
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 PropTypes from 'prop-types'
|
||||
import Router, { _rewriteUrlForNextExport } from './router'
|
||||
import { warn, execOnce, getLocationOrigin } from './utils'
|
||||
import { execOnce, getLocationOrigin } from './utils'
|
||||
|
||||
function isLocal (href) {
|
||||
const url = parse(href, false, true)
|
||||
|
@ -14,8 +14,6 @@ function isLocal (href) {
|
|||
(url.protocol === origin.protocol && url.host === origin.host)
|
||||
}
|
||||
|
||||
const warnLink = execOnce(warn)
|
||||
|
||||
function memoizedFormatUrl (formatUrl) {
|
||||
let lastHref = null
|
||||
let lastAs = null
|
||||
|
@ -155,6 +153,8 @@ class Link extends Component {
|
|||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const warn = execOnce(console.error)
|
||||
|
||||
// This module gets removed by webpack.IgnorePlugin
|
||||
const exact = require('prop-types-exact')
|
||||
Link.propTypes = exact({
|
||||
|
@ -171,7 +171,7 @@ if (process.env.NODE_ENV === 'development') {
|
|||
const value = props[propName]
|
||||
|
||||
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
|
||||
|
|
|
@ -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 shallowEquals from '../shallow-equals'
|
||||
import PQueue from '../p-queue'
|
||||
import { loadGetInitialProps, getURL, warn, execOnce } from '../utils'
|
||||
import { loadGetInitialProps, getURL } from '../utils'
|
||||
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 {
|
||||
static events = new EventEmitter()
|
||||
|
||||
|
@ -219,14 +212,15 @@ export default class Router {
|
|||
}
|
||||
|
||||
changeState (method, url, as, options = {}) {
|
||||
if (typeof window.history === 'undefined') {
|
||||
historyUnavailableWarning()
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof window.history[method] === 'undefined') {
|
||||
historyMethodWarning(method)
|
||||
return
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof window.history === 'undefined') {
|
||||
console.error(`Warning: window.history is not available.`)
|
||||
return
|
||||
}
|
||||
if (typeof window.history[method] === 'undefined') {
|
||||
console.error(`Warning: window.history.${method} is not available`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let used = false
|
||||
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) {
|
||||
if (typeof Component === 'string') {
|
||||
return Component
|
||||
|
|
|
@ -3,7 +3,6 @@ import { resolve, join, sep } from 'path'
|
|||
import { parse as parseUrl } from 'url'
|
||||
import { parse as parseQs } from 'querystring'
|
||||
import fs from 'fs'
|
||||
import http, { STATUS_CODES } from 'http'
|
||||
import {
|
||||
renderToHTML,
|
||||
renderErrorToHTML,
|
||||
|
@ -27,7 +26,6 @@ export default class Server {
|
|||
this.dev = dev
|
||||
this.quiet = quiet
|
||||
this.router = new Router()
|
||||
this.http = null
|
||||
const phase = dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER
|
||||
this.nextConfig = loadConfig(phase, this.dir, conf)
|
||||
this.distDir = join(this.dir, this.nextConfig.distDir)
|
||||
|
@ -87,7 +85,7 @@ export default class Server {
|
|||
.catch((err) => {
|
||||
if (!this.quiet) console.error(err)
|
||||
res.statusCode = 500
|
||||
res.end(STATUS_CODES[500])
|
||||
res.end('Internal Server Error')
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,15 +109,6 @@ export default class Server {
|
|||
if (this.hotReloader) {
|
||||
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 () {
|
||||
|
@ -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) {
|
||||
if (this.hotReloader) {
|
||||
const {finished} = await this.hotReloader.run(req, res, parsedUrl)
|
||||
|
@ -232,7 +210,7 @@ export default class Server {
|
|||
await this.render404(req, res, parsedUrl)
|
||||
} else {
|
||||
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 './'
|
||||
|
||||
// This file is used for when users run `require('next')`
|
||||
module.exports = (opts) => {
|
||||
return new Server(opts)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue