1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Add missing dependencies to server (#5369)

- compile default pages correctly into `.next`
- add missing runtime dependencies
This commit is contained in:
Tim Neutkens 2018-10-03 00:08:57 +02:00 committed by GitHub
parent de6d394d73
commit 785377d3c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 431 additions and 426 deletions

View file

@ -24,10 +24,12 @@
]
},
"dependencies": {
"@babel/runtime-corejs2": "^7.1.2",
"ansi-html": "0.0.7",
"etag": "1.8.1",
"find-up": "3.0.0",
"fresh": "0.5.2",
"hoist-non-react-statics": "^3.0.1",
"htmlescape": "1.1.1",
"http-errors": "1.6.2",
"path-to-regexp": "2.1.0",

View file

@ -1 +1 @@
module.exports = require('./dist/lib/app')
module.exports = require('./dist/pages/_app')

View file

@ -32,14 +32,20 @@ function externalsConfig (dir, isServer) {
return externals
}
const notExternalModules = ['next/app', 'next/document', 'next/error']
externals.push((context, request, callback) => {
resolve(request, { basedir: dir, preserveSymlinks: true }, (err, res) => {
if (notExternalModules.indexOf(request) !== -1) {
return callback()
}
resolve(request, { basedir: context, preserveSymlinks: true }, (err, res) => {
if (err) {
return callback()
}
// Default pages have to be transpiled
if (res.match(/node_modules[/\\]next[/\\]dist[/\\]pages/)) {
if (res.match(/next[/\\]dist[/\\]pages/)) {
return callback()
}

View file

@ -1 +1 @@
module.exports = require('./dist/server/document')
module.exports = require('./dist/pages/_document')

View file

@ -1 +1 @@
module.exports = require('./dist/lib/error')
module.exports = require('./dist/pages/_error')

View file

@ -1,116 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { execOnce, loadGetInitialProps } from 'next-server/dist/lib/utils'
import { makePublicRouterInstance } from 'next-server/router'
export default class App extends Component {
static childContextTypes = {
headManager: PropTypes.object,
router: PropTypes.object
}
static async getInitialProps ({ Component, router, ctx }) {
const pageProps = await loadGetInitialProps(Component, ctx)
return {pageProps}
}
getChildContext () {
const { headManager } = this.props
return {
headManager,
router: makePublicRouterInstance(this.props.router)
}
}
// Kept here for backwards compatibility.
// When someone ended App they could call `super.componentDidCatch`. This is now deprecated.
componentDidCatch (err) {
throw err
}
render () {
const {router, Component, pageProps} = this.props
const url = createUrl(router)
return <Container>
<Component {...pageProps} url={url} />
</Container>
}
}
export class Container extends Component {
componentDidMount () {
this.scrollToHash()
}
componentDidUpdate () {
this.scrollToHash()
}
scrollToHash () {
let { hash } = window.location
hash = hash ? hash.substring(1) : false
if (!hash) return
const el = document.getElementById(hash)
if (!el) return
// If we call scrollIntoView() in here without a setTimeout
// it won't scroll properly.
setTimeout(() => el.scrollIntoView(), 0)
}
render () {
return this.props.children
}
}
const warnUrl = execOnce(() => {
if (process.env.NODE_ENV !== 'production') {
console.error(`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`)
}
})
export function createUrl (router) {
// This is to make sure we don't references the router object at call time
const {pathname, asPath, query} = router
return {
get query () {
warnUrl()
return query
},
get pathname () {
warnUrl()
return pathname
},
get asPath () {
warnUrl()
return asPath
},
back: () => {
warnUrl()
router.back()
},
push: (url, as) => {
warnUrl()
return router.push(url, as)
},
pushTo: (href, as) => {
warnUrl()
const pushRoute = as ? href : null
const pushUrl = as || href
return router.push(pushRoute, pushUrl)
},
replace: (url, as) => {
warnUrl()
return router.replace(url, as)
},
replaceTo: (href, as) => {
warnUrl()
const replaceRoute = as ? href : null
const replaceUrl = as || href
return router.replace(replaceRoute, replaceUrl)
}
}
}

View file

@ -1,79 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import HTTPStatus from 'http-status'
import Head from 'next-server/head'
export default class Error extends React.Component {
static getInitialProps ({ res, err }) {
const statusCode = res ? res.statusCode : (err ? err.statusCode : null)
return { statusCode }
}
render () {
const { statusCode } = this.props
const title = statusCode === 404
? 'This page could not be found'
: HTTPStatus[statusCode] || 'An unexpected error has occurred'
return <div style={styles.error}>
<Head>
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<title>{statusCode}: {title}</title>
</Head>
<div>
<style dangerouslySetInnerHTML={{ __html: 'body { margin: 0 }' }} />
{statusCode ? <h1 style={styles.h1}>{statusCode}</h1> : null}
<div style={styles.desc}>
<h2 style={styles.h2}>{title}.</h2>
</div>
</div>
</div>
}
}
if (process.env.NODE_ENV !== 'production') {
Error.propTypes = {
statusCode: PropTypes.number
}
}
const styles = {
error: {
color: '#000',
background: '#fff',
fontFamily: '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif',
height: '100vh',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
},
desc: {
display: 'inline-block',
textAlign: 'left',
lineHeight: '49px',
height: '49px',
verticalAlign: 'middle'
},
h1: {
display: 'inline-block',
borderRight: '1px solid rgba(0, 0, 0,.3)',
margin: 0,
marginRight: '20px',
padding: '10px 23px 10px 0',
fontSize: '24px',
fontWeight: 500,
verticalAlign: 'top'
},
h2: {
fontSize: '14px',
fontWeight: 'normal',
lineHeight: 'inherit',
margin: 0,
padding: 0
}
}

View file

@ -1 +1,116 @@
module.exports = require('next/app')
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { execOnce, loadGetInitialProps } from 'next-server/dist/lib/utils'
import { makePublicRouterInstance } from 'next-server/router'
export default class App extends Component {
static childContextTypes = {
headManager: PropTypes.object,
router: PropTypes.object
}
static async getInitialProps ({ Component, router, ctx }) {
const pageProps = await loadGetInitialProps(Component, ctx)
return {pageProps}
}
getChildContext () {
const { headManager } = this.props
return {
headManager,
router: makePublicRouterInstance(this.props.router)
}
}
// Kept here for backwards compatibility.
// When someone ended App they could call `super.componentDidCatch`. This is now deprecated.
componentDidCatch (err) {
throw err
}
render () {
const {router, Component, pageProps} = this.props
const url = createUrl(router)
return <Container>
<Component {...pageProps} url={url} />
</Container>
}
}
export class Container extends Component {
componentDidMount () {
this.scrollToHash()
}
componentDidUpdate () {
this.scrollToHash()
}
scrollToHash () {
let { hash } = window.location
hash = hash ? hash.substring(1) : false
if (!hash) return
const el = document.getElementById(hash)
if (!el) return
// If we call scrollIntoView() in here without a setTimeout
// it won't scroll properly.
setTimeout(() => el.scrollIntoView(), 0)
}
render () {
return this.props.children
}
}
const warnUrl = execOnce(() => {
if (process.env.NODE_ENV !== 'production') {
console.error(`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`)
}
})
export function createUrl (router) {
// This is to make sure we don't references the router object at call time
const {pathname, asPath, query} = router
return {
get query () {
warnUrl()
return query
},
get pathname () {
warnUrl()
return pathname
},
get asPath () {
warnUrl()
return asPath
},
back: () => {
warnUrl()
router.back()
},
push: (url, as) => {
warnUrl()
return router.push(url, as)
},
pushTo: (href, as) => {
warnUrl()
const pushRoute = as ? href : null
const pushUrl = as || href
return router.push(pushRoute, pushUrl)
},
replace: (url, as) => {
warnUrl()
return router.replace(url, as)
},
replaceTo: (href, as) => {
warnUrl()
const replaceRoute = as ? href : null
const replaceUrl = as || href
return router.replace(replaceRoute, replaceUrl)
}
}
}

View file

@ -1 +1,218 @@
module.exports = require('next/document')
/* eslint-disable */
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import htmlescape from 'htmlescape'
import flush from 'styled-jsx/server'
const Fragment = React.Fragment || function Fragment ({ children }) {
return <div>{children}</div>
}
export default class Document extends Component {
static childContextTypes = {
_documentProps: PropTypes.any
}
static getInitialProps ({ renderPage }) {
const { html, head, buildManifest } = renderPage()
const styles = flush()
return { html, head, styles, buildManifest }
}
getChildContext () {
return { _documentProps: this.props }
}
render () {
return <html>
<Head />
<body>
<Main />
<NextScript />
</body>
</html>
}
}
export class Head extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
static propTypes = {
nonce: PropTypes.string
}
getCssLinks () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .css files here
if(!/\.css$/.exec(file)) {
return null
}
return <link
key={file}
nonce={this.props.nonce}
rel='stylesheet'
href={`${assetPrefix}/_next/${file}`}
/>
})
}
getPreloadDynamicChunks () {
const { dynamicImports, assetPrefix } = this.context._documentProps
return dynamicImports.map((bundle) => {
return <link
rel='preload'
key={bundle.file}
href={`${assetPrefix}/_next/${bundle.file}`}
as='script'
nonce={this.props.nonce}
/>
})
}
getPreloadMainLinks () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .js files here
if(!/\.js$/.exec(file)) {
return null
}
return <link
key={file}
nonce={this.props.nonce}
rel='preload'
href={`${assetPrefix}/_next/${file}`}
as='script'
/>
})
}
render () {
const { head, styles, assetPrefix, __NEXT_DATA__ } = this.context._documentProps
const { page, pathname, buildId } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname)
let children = this.props.children
// show a warning if Head contains <title> (only in development)
if (process.env.NODE_ENV !== 'production') {
children = React.Children.map(children, (child) => {
if (child && child.type === 'title') {
console.warn("Warning: <title> should not be used in _document.js's <Head>. https://err.sh/next.js/no-document-title")
}
return child
})
}
return <head {...this.props}>
{head}
{page !== '/_error' && <link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}`} as='script' nonce={this.props.nonce} />}
<link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} as='script' nonce={this.props.nonce} />
<link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages/_error.js`} as='script' nonce={this.props.nonce} />
{this.getPreloadDynamicChunks()}
{this.getPreloadMainLinks()}
{this.getCssLinks()}
{styles || null}
{children}
</head>
}
}
export class Main extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
render () {
const { html } = this.context._documentProps
return (
<div id='__next' dangerouslySetInnerHTML={{ __html: html }} />
)
}
}
export class NextScript extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
static propTypes = {
nonce: PropTypes.string
}
getDynamicChunks () {
const { dynamicImports, assetPrefix } = this.context._documentProps
return dynamicImports.map((bundle) => {
return <script
async
key={bundle.file}
src={`${assetPrefix}/_next/${bundle.file}`}
nonce={this.props.nonce}
/>
})
}
getScripts () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .js files here
if(!/\.js$/.exec(file)) {
return null
}
return <script
key={file}
src={`${assetPrefix}/_next/${file}`}
nonce={this.props.nonce}
async
/>
})
}
static getInlineScriptSource (documentProps) {
const { __NEXT_DATA__ } = documentProps
const { page, pathname } = __NEXT_DATA__
return `__NEXT_DATA__ = ${htmlescape(__NEXT_DATA__)};__NEXT_LOADED_PAGES__=[];__NEXT_REGISTER_PAGE=function(r,f){__NEXT_LOADED_PAGES__.push([r, f])}${page === '/_error' ? `;__NEXT_REGISTER_PAGE(${htmlescape(pathname)},function(){var e = new Error('Page does not exist: ${htmlescape(pathname)}');e.statusCode=404;return {error:e}})`:''}`
}
render () {
const { staticMarkup, assetPrefix, devFiles, __NEXT_DATA__ } = this.context._documentProps
const { page, pathname, buildId } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname)
return <Fragment>
{devFiles ? devFiles.map((file) => <script key={file} src={`${assetPrefix}/_next/${file}`} nonce={this.props.nonce} />) : null}
{staticMarkup ? null : <script nonce={this.props.nonce} dangerouslySetInnerHTML={{
__html: NextScript.getInlineScriptSource(this.context._documentProps)
}} />}
{page !== '/_error' && <script async id={`__NEXT_PAGE__${pathname}`} src={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}`} nonce={this.props.nonce} />}
<script async id={`__NEXT_PAGE__/_app`} src={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} nonce={this.props.nonce} />
<script async id={`__NEXT_PAGE__/_error`} src={`${assetPrefix}/_next/static/${buildId}/pages/_error.js`} nonce={this.props.nonce} />
{staticMarkup ? null : this.getDynamicChunks()}
{staticMarkup ? null : this.getScripts()}
</Fragment>
}
}
function getPagePathname (pathname) {
if (pathname === '/') {
return '/index.js'
}
return `${pathname}.js`
}

View file

@ -1 +1,79 @@
module.exports = require('next/error')
import React from 'react'
import PropTypes from 'prop-types'
import HTTPStatus from 'http-status'
import Head from 'next-server/head'
export default class Error extends React.Component {
static getInitialProps ({ res, err }) {
const statusCode = res ? res.statusCode : (err ? err.statusCode : null)
return { statusCode }
}
render () {
const { statusCode } = this.props
const title = statusCode === 404
? 'This page could not be found'
: HTTPStatus[statusCode] || 'An unexpected error has occurred'
return <div style={styles.error}>
<Head>
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<title>{statusCode}: {title}</title>
</Head>
<div>
<style dangerouslySetInnerHTML={{ __html: 'body { margin: 0 }' }} />
{statusCode ? <h1 style={styles.h1}>{statusCode}</h1> : null}
<div style={styles.desc}>
<h2 style={styles.h2}>{title}.</h2>
</div>
</div>
</div>
}
}
if (process.env.NODE_ENV !== 'production') {
Error.propTypes = {
statusCode: PropTypes.number
}
}
const styles = {
error: {
color: '#000',
background: '#fff',
fontFamily: '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif',
height: '100vh',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
},
desc: {
display: 'inline-block',
textAlign: 'left',
lineHeight: '49px',
height: '49px',
verticalAlign: 'middle'
},
h1: {
display: 'inline-block',
borderRight: '1px solid rgba(0, 0, 0,.3)',
margin: 0,
marginRight: '20px',
padding: '10px 23px 10px 0',
fontSize: '24px',
fontWeight: 500,
verticalAlign: 'top'
},
h2: {
fontSize: '14px',
fontWeight: 'normal',
lineHeight: 'inherit',
margin: 0,
padding: 0
}
}

View file

@ -1,218 +0,0 @@
/* eslint-disable */
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import htmlescape from 'htmlescape'
import flush from 'styled-jsx/server'
const Fragment = React.Fragment || function Fragment ({ children }) {
return <div>{children}</div>
}
export default class Document extends Component {
static childContextTypes = {
_documentProps: PropTypes.any
}
static getInitialProps ({ renderPage }) {
const { html, head, buildManifest } = renderPage()
const styles = flush()
return { html, head, styles, buildManifest }
}
getChildContext () {
return { _documentProps: this.props }
}
render () {
return <html>
<Head />
<body>
<Main />
<NextScript />
</body>
</html>
}
}
export class Head extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
static propTypes = {
nonce: PropTypes.string
}
getCssLinks () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .css files here
if(!/\.css$/.exec(file)) {
return null
}
return <link
key={file}
nonce={this.props.nonce}
rel='stylesheet'
href={`${assetPrefix}/_next/${file}`}
/>
})
}
getPreloadDynamicChunks () {
const { dynamicImports, assetPrefix } = this.context._documentProps
return dynamicImports.map((bundle) => {
return <link
rel='preload'
key={bundle.file}
href={`${assetPrefix}/_next/${bundle.file}`}
as='script'
nonce={this.props.nonce}
/>
})
}
getPreloadMainLinks () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .js files here
if(!/\.js$/.exec(file)) {
return null
}
return <link
key={file}
nonce={this.props.nonce}
rel='preload'
href={`${assetPrefix}/_next/${file}`}
as='script'
/>
})
}
render () {
const { head, styles, assetPrefix, __NEXT_DATA__ } = this.context._documentProps
const { page, pathname, buildId } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname)
let children = this.props.children
// show a warning if Head contains <title> (only in development)
if (process.env.NODE_ENV !== 'production') {
children = React.Children.map(children, (child) => {
if (child && child.type === 'title') {
console.warn("Warning: <title> should not be used in _document.js's <Head>. https://err.sh/next.js/no-document-title")
}
return child
})
}
return <head {...this.props}>
{head}
{page !== '/_error' && <link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}`} as='script' nonce={this.props.nonce} />}
<link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} as='script' nonce={this.props.nonce} />
<link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages/_error.js`} as='script' nonce={this.props.nonce} />
{this.getPreloadDynamicChunks()}
{this.getPreloadMainLinks()}
{this.getCssLinks()}
{styles || null}
{children}
</head>
}
}
export class Main extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
render () {
const { html } = this.context._documentProps
return (
<div id='__next' dangerouslySetInnerHTML={{ __html: html }} />
)
}
}
export class NextScript extends Component {
static contextTypes = {
_documentProps: PropTypes.any
}
static propTypes = {
nonce: PropTypes.string
}
getDynamicChunks () {
const { dynamicImports, assetPrefix } = this.context._documentProps
return dynamicImports.map((bundle) => {
return <script
async
key={bundle.file}
src={`${assetPrefix}/_next/${bundle.file}`}
nonce={this.props.nonce}
/>
})
}
getScripts () {
const { assetPrefix, files } = this.context._documentProps
if(!files || files.length === 0) {
return null
}
return files.map((file) => {
// Only render .js files here
if(!/\.js$/.exec(file)) {
return null
}
return <script
key={file}
src={`${assetPrefix}/_next/${file}`}
nonce={this.props.nonce}
async
/>
})
}
static getInlineScriptSource (documentProps) {
const { __NEXT_DATA__ } = documentProps
const { page, pathname } = __NEXT_DATA__
return `__NEXT_DATA__ = ${htmlescape(__NEXT_DATA__)};__NEXT_LOADED_PAGES__=[];__NEXT_REGISTER_PAGE=function(r,f){__NEXT_LOADED_PAGES__.push([r, f])}${page === '/_error' ? `;__NEXT_REGISTER_PAGE(${htmlescape(pathname)},function(){var e = new Error('Page does not exist: ${htmlescape(pathname)}');e.statusCode=404;return {error:e}})`:''}`
}
render () {
const { staticMarkup, assetPrefix, devFiles, __NEXT_DATA__ } = this.context._documentProps
const { page, pathname, buildId } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname)
return <Fragment>
{devFiles ? devFiles.map((file) => <script key={file} src={`${assetPrefix}/_next/${file}`} nonce={this.props.nonce} />) : null}
{staticMarkup ? null : <script nonce={this.props.nonce} dangerouslySetInnerHTML={{
__html: NextScript.getInlineScriptSource(this.context._documentProps)
}} />}
{page !== '/_error' && <script async id={`__NEXT_PAGE__${pathname}`} src={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}`} nonce={this.props.nonce} />}
<script async id={`__NEXT_PAGE__/_app`} src={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} nonce={this.props.nonce} />
<script async id={`__NEXT_PAGE__/_error`} src={`${assetPrefix}/_next/static/${buildId}/pages/_error.js`} nonce={this.props.nonce} />
{staticMarkup ? null : this.getDynamicChunks()}
{staticMarkup ? null : this.getScripts()}
</Fragment>
}
}
function getPagePathname (pathname) {
if (pathname === '/') {
return '/index.js'
}
return `${pathname}.js`
}

View file

@ -1,7 +1,7 @@
const notifier = require('node-notifier')
export async function compile (task) {
await task.parallel(['bin', 'server', 'nextbuild', 'nextbuildstatic', 'lib', 'client'])
await task.parallel(['bin', 'server', 'nextbuild', 'nextbuildstatic', 'pages', 'lib', 'client'])
}
export async function bin (task, opts) {
@ -35,18 +35,18 @@ export async function nextbuildstatic (task, opts) {
notify('Compiled export files')
}
export async function copy (task) {
await task.source('pages/**/*.js').target('dist/pages')
export async function pages (task, opts) {
await task.source(opts.src || 'pages/**/*.js').babel().target('dist/pages')
}
export async function build (task) {
await task.serial(['copy', 'compile'])
await task.serial(['compile'])
}
export default async function (task) {
await task.start('build')
await task.watch('bin/*', 'bin')
await task.watch('pages/**/*.js', 'copy')
await task.watch('pages/**/*.js', 'pages')
await task.watch('server/**/*.js', 'server')
await task.watch('build/**/*.js', 'nextbuild')
await task.watch('export/**/*.js', 'nextexport')