1
0
Fork 0
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:
Tim Neutkens 2018-09-27 21:10:53 +02:00 committed by GitHub
parent 20f3b6b284
commit fb0b485299
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 51 additions and 131 deletions

View file

@ -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: {

View file

@ -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}`)
}
})
.catch((err) => {
if (err.code === 'EADDRINUSE') {

View file

@ -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: {

View file

@ -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}`)
}
})
.catch((err) => {
console.error(err)

View file

@ -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`)
}
})

View file

@ -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

View file

@ -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} />)
}
}

View file

@ -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,15 +212,16 @@ export default class Router {
}
changeState (method, url, as, options = {}) {
if (process.env.NODE_ENV !== 'production') {
if (typeof window.history === 'undefined') {
historyUnavailableWarning()
console.error(`Warning: window.history is not available.`)
return
}
if (typeof window.history[method] === 'undefined') {
historyMethodWarning(method)
console.error(`Warning: window.history.${method} is not available`)
return
}
}
if (method !== 'pushState' || getURL() !== as) {
window.history[method]({ url, as, options }, null, as)

View file

@ -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

View file

@ -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')
}
}

View 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
View file

@ -0,0 +1,9 @@
export function printAndExit (message, code = 1) {
if (code === 0) {
console.log(message)
} else {
console.error(message)
}
process.exit(code)
}

View file

@ -1,5 +1,6 @@
import Server from './'
// This file is used for when users run `require('next')`
module.exports = (opts) => {
return new Server(opts)
}