From fb0b485299268bff4e59e11c278156d7562cc0f6 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 27 Sep 2018 21:10:53 +0200 Subject: [PATCH] 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 --- bin/next-build | 2 +- bin/next-dev | 11 ++++------- bin/next-export | 2 +- bin/next-start | 9 +++------ lib/app.js | 4 ++-- lib/link.js | 8 ++++---- lib/prefetch.js | 33 --------------------------------- lib/router/router.js | 26 ++++++++++---------------- lib/utils.js | 37 ------------------------------------- server/index.js | 26 ++------------------------ server/lib/start-server.js | 14 ++++++++++++++ server/lib/utils.js | 9 +++++++++ server/next.js | 1 + 13 files changed, 51 insertions(+), 131 deletions(-) delete mode 100644 lib/prefetch.js create mode 100644 server/lib/start-server.js create mode 100644 server/lib/utils.js diff --git a/bin/next-build b/bin/next-build index 7d518777..59931230 100755 --- a/bin/next-build +++ b/bin/next-build @@ -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: { diff --git a/bin/next-dev b/bin/next-dev index 89227ae5..80dddb14 100755 --- a/bin/next-dev +++ b/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') { diff --git a/bin/next-export b/bin/next-export index efebbb1e..a012be4d 100755 --- a/bin/next-export +++ b/bin/next-export @@ -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: { diff --git a/bin/next-start b/bin/next-start index 19832a17..cce686e6 100755 --- a/bin/next-start +++ b/bin/next-start @@ -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) diff --git a/lib/app.js b/lib/app.js index ce57c0e9..80899ab0 100644 --- a/lib/app.js +++ b/lib/app.js @@ -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`) } }) diff --git a/lib/link.js b/lib/link.js index edf986ab..ef66030b 100644 --- a/lib/link.js +++ b/lib/link.js @@ -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 . This usage has been deprecated. Please add an tag as child of `) + warn(`Warning: You're using a string directly inside . This usage has been deprecated. Please add an tag as child of `) } return null diff --git a/lib/prefetch.js b/lib/prefetch.js deleted file mode 100644 index ef667173..00000000 --- a/lib/prefetch.js +++ /dev/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 "" 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 () - } -} diff --git a/lib/router/router.js b/lib/router/router.js index bc63716d..c0e9ff1d 100644 --- a/lib/router/router.js +++ b/lib/router/router.js @@ -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) { diff --git a/lib/utils.js b/lib/utils.js index 8fea5122..89304aee 100644 --- a/lib/utils.js +++ b/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 diff --git a/server/index.js b/server/index.js index e7d7862e..d39e8ec2 100644 --- a/server/index.js +++ b/server/index.js @@ -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') } } diff --git a/server/lib/start-server.js b/server/lib/start-server.js new file mode 100644 index 00000000..e32429c1 --- /dev/null +++ b/server/lib/start-server.js @@ -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) + }) +} diff --git a/server/lib/utils.js b/server/lib/utils.js new file mode 100644 index 00000000..4242a1b7 --- /dev/null +++ b/server/lib/utils.js @@ -0,0 +1,9 @@ +export function printAndExit (message, code = 1) { + if (code === 0) { + console.log(message) + } else { + console.error(message) + } + + process.exit(code) +} diff --git a/server/next.js b/server/next.js index d680668a..7ab70e59 100644 --- a/server/next.js +++ b/server/next.js @@ -1,5 +1,6 @@ import Server from './' +// This file is used for when users run `require('next')` module.exports = (opts) => { return new Server(opts) }