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

Merge branch 'canary'

# Conflicts:
#	examples/with-apollo-and-redux/README.md
#	examples/with-sentry/README.md
#	examples/with-sentry/package.json
#	examples/with-sentry/pages/_app.js
#	package.json
#	packages/next/build/webpack-config.js
#	packages/next/client/index.js
#	server/document.js
#	server/render.js
#	test/integration/production/test/index.test.js
This commit is contained in:
Tim Neutkens 2019-02-11 08:22:31 +01:00
commit 163830c026
1106 changed files with 28630 additions and 10683 deletions

View file

@ -1,18 +0,0 @@
module.exports = {
'presets': [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-flow'
],
'plugins': [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-class-properties',
['@babel/plugin-transform-runtime', {
'corejs': 2
}],
['babel-plugin-transform-define', {
'process.env.NEXT_VERSION': require('./package.json').version
}]
]
}

View file

@ -6,5 +6,29 @@ jobs:
working_directory: ~/repo
steps:
- checkout
- run: yarn install
- run: yarn test
- run:
name: Installing dependencies
command: yarn install
- run:
name: Bootstrapping
command: yarn bootstrap
- run:
name: Linting
command: yarn lint
- run:
name: Tests
command: yarn test
- run:
name: Potentially save npm token
command: "([[ ! -z $NPM_TOKEN ]] && echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> ~/.npmrc) || echo \"Did not write npm token\""
- run:
name: Potentially publish canary release
command: "if ls ~/.npmrc >/dev/null 2>&1 && [[ $(git describe --exact-match 2> /dev/null || :) =~ -canary ]]; then yarn run lerna publish from-git --npm-tag canary --yes; else echo \"Did not publish\"; fi"
- run:
name: Potentially publish stable release
command: "if ls ~/.npmrc >/dev/null 2>&1 && [[ ! $(git describe --exact-match 2> /dev/null || :) =~ -canary ]]; then yarn run lerna publish from-git --yes; else echo \"Did not publish\"; fi"
workflows:
version: 2
build-and-deploy:
jobs:
- build

View file

@ -1,3 +0,0 @@
[ignore]
<PROJECT_ROOT>/examples/.*
<PROJECT_ROOT>/.*.json

View file

@ -1,11 +0,0 @@
---
name: Request to be added to the showcase on nextjs.org
about: Apply for your project to be added to nextjs.org
---
# Request to be added to the showcase on nextjs.org
- Name of company:
- Url:
- Testimonial about Next.js (optional):

4
.gitignore vendored
View file

@ -6,6 +6,7 @@ dist
node_modules
package-lock.json
yarn.lock
!/yarn.lock
test/node_modules
# logs & pids
@ -19,3 +20,6 @@ coverage
# test output
test/**/out
.DS_Store
# Editors
**/.idea

1
.npmrc
View file

@ -1 +1,2 @@
save-exact = true
tag-version-prefix=""

View file

@ -8,7 +8,7 @@
}
},
language: "node_js",
node_js: ["8"],
node_js: ["8", "10"],
cache: {
directories: ["node_modules"]
},
@ -20,17 +20,6 @@
before_cache: [
"rm -rf node_modules/.cache"
],
after_script: ["npm run coveralls"],
deploy: {
provider: "npm",
email: "leo@zeit.co",
tag: "canary",
api_key: {
secure: "MJfpcAJC1IvPL01NiGRLYAAgb7TZz5K0ukM1n+E+QcoF9+L1gn4WcP056ECchuohEFSwvO/ZcTZM5yhpp10cd72RZykeat/YYgRXFyUDkD3up2FHr4hYdcv/tBHCkeUMJZwt1ZNH4xM69Y02KAmpRBWZGKe6qETlZqxUg79Gi1g6W5PdhbsKedTp2tJJzG58nevKsSRP01S97K7kDC5oJNwuO+cbLwtzX5cB6Rd8hGx6lMetWLzSmSS689N0flfm/R9pxY/WjgBBQ0iYZkosb1VO2NhJMnrHtdr/Wfrkvnz8KSO/KD2n7RrOnSzUQBJSNxx35kr7HU4pKreMxEiOnEbOog4HZmWsM0UyRlbYeREfXLBvIjlnYoWCblZdVbdIl4R7NflVBSeK2eDkZQt2iCqP0fHvJ7kyLQx9J2janlr+96dKSudalercfmV9aXtbCeweqim5l4AZywSggpZAvopE6uN6KtFafO0JM760flbQfDVEQWHrHGvZvu05NrzJvZa6CN47rDHbaO6IibMXakogVz+AIuTZ3t/2bynetkericV8MGdOrwb807DLWTdqNKCj2wTmHgDiX8n3FF7VisLS54mKFfuuzzALdWtlBPbwS+bZ0235/35rs2EUidC5eunryWp4Y150xWfCK2swxM9xR0iCE0KSXrsdGDGyrvE="
},
skip_cleanup: true,
on: {
tags: true
}
}
before_script: ["npm run bootstrap"],
after_script: ["npm run coveralls"]
}

1792
README-zh-CN.md Normal file

File diff suppressed because it is too large Load diff

1
app.js
View file

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

View file

@ -1,23 +0,0 @@
environment:
matrix:
- nodejs_version: "8"
# Install scripts. (runs after repo cloning)
install:
# Install Google Chrome for e2e testing
- choco install --ignore-checksums googlechrome
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version x64
# install modules
- npm install
# Post-install test scripts.
test_script:
# Output useful info for debugging.
- node --version
- npm --version
# run tests
- npm test
# Don't actually build.
build: off

View file

@ -1 +0,0 @@
module.exports = require('./dist/lib/asset')

28
azure-pipelines.yml Normal file
View file

@ -0,0 +1,28 @@
pool:
vmImage: 'vs2017-win2016'
strategy:
maxParallel: 10
matrix:
node-10:
node_version: ^10.10.0
node-8:
node_version: ^8.12.0
steps:
- task: NodeTool@0
inputs:
versionSpec: $(node_version)
displayName: 'Install Node.js'
- script: |
yarn install
displayName: 'Install dependencies'
- script: |
yarn bootstrap
displayName: 'Lerna bootstrap'
- script: |
yarn test
displayName: 'Run tests'

111
bin/next
View file

@ -1,111 +0,0 @@
#!/usr/bin/env node
import { join } from 'path'
import { spawn } from 'cross-spawn'
import pkg from '../../package.json'
import {CONFIG_FILE} from '../lib/constants'
if (pkg.peerDependencies) {
Object.keys(pkg.peerDependencies).forEach(dependency => {
try {
// When 'npm link' is used it checks the clone location. Not the project.
require.resolve(dependency)
} catch (err) {
console.warn(`The module '${dependency}' was not found. Next.js requires that you include it in 'dependencies' of your 'package.json'. To add it, run 'npm install --save ${dependency}'`)
}
})
}
const defaultCommand = 'dev'
const commands = new Set([
'init',
'build',
'start',
'export',
defaultCommand
])
let cmd = process.argv[2]
let args = []
let nodeArgs = []
if (new Set(['--version', '-v']).has(cmd)) {
console.log(`next.js v${pkg.version}`)
process.exit(0)
}
const inspectArg = process.argv.find(arg => arg.includes('--inspect'))
if (inspectArg) {
nodeArgs.push(inspectArg)
}
if (new Set(['--help', '-h']).has(cmd)) {
console.log(`
Usage
$ next <command>
Available commands
${Array.from(commands).join(', ')}
For more information run a command with the --help flag
$ next init --help
`)
process.exit(0)
}
if (commands.has(cmd)) {
args = process.argv.slice(3)
} else {
cmd = defaultCommand
args = process.argv.slice(2)
}
const defaultEnv = cmd === 'dev' ? 'development' : 'production'
process.env.NODE_ENV = process.env.NODE_ENV || defaultEnv
const bin = join(__dirname, 'next-' + cmd)
const startProcess = () => {
const proc = spawn('node', [...nodeArgs, ...[bin], ...args], { stdio: 'inherit', customFds: [0, 1, 2] })
proc.on('close', (code, signal) => {
if (code !== null) {
process.exit(code)
}
if (signal) {
if (signal === 'SIGKILL') {
process.exit(137)
}
console.log(`got signal ${signal}, exiting`)
process.exit(signal === 'SIGINT' ? 0 : 1)
}
process.exit(0)
})
proc.on('error', (err) => {
console.error(err)
process.exit(1)
})
return proc
}
let proc = startProcess()
const wrapper = () => {
if (proc) {
proc.kill()
}
}
process.on('SIGINT', wrapper)
process.on('SIGTERM', wrapper)
process.on('exit', wrapper)
if (cmd === 'dev') {
const {watchFile} = require('fs')
watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur, prev) => {
if (cur.size > 0 || prev.size > 0) {
console.log(`\n> Found a change in ${CONFIG_FILE}, restarting the server...`)
// Don't listen to 'close' now since otherwise parent gets killed by listener
proc.removeAllListeners('close')
proc.kill()
proc = startProcess()
}
})
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env node
console.log('`next init` is not supported anymore. These community projects provide the same functionality as `next init` with additional features: http://npmjs.com/next-init and http://npmjs.com/create-next-app.')
process.exit(0)

View file

@ -1,60 +0,0 @@
const env = process.env.NODE_ENV
const isProduction = env === 'production'
const isDevelopment = env === 'development'
const isTest = env === 'test'
// Resolve styled-jsx plugins
function styledJsxOptions (opts) {
if (!opts) {
return {}
}
if (!Array.isArray(opts.plugins)) {
return opts
}
opts.plugins = opts.plugins.map(plugin => {
if (Array.isArray(plugin)) {
const [name, options] = plugin
return [
require.resolve(name),
options
]
}
return require.resolve(plugin)
})
return opts
}
module.exports = (context, opts = {}) => ({
presets: [
[require('@babel/preset-env').default, {
// In the test environment `modules` is often needed to be set to true, babel figures that out by itself using the `'auto'` option
// In production/development this option is set to `false` so that webpack can handle import/export with tree-shaking
modules: isDevelopment || isProduction ? false : 'auto',
...opts['preset-env']
}],
[require('@babel/preset-react'), {
// This adds @babel/plugin-transform-react-jsx-source and
// @babel/plugin-transform-react-jsx-self automatically in development
development: isDevelopment || isTest,
...opts['preset-react']
}]
],
plugins: [
require('babel-plugin-react-require'),
require('@babel/plugin-syntax-dynamic-import'),
require('./plugins/react-loadable-plugin'),
[require('@babel/plugin-proposal-class-properties'), opts['class-properties'] || {}],
require('@babel/plugin-proposal-object-rest-spread'),
[require('@babel/plugin-transform-runtime'), {
helpers: false,
regenerator: true,
...opts['transform-runtime']
}],
[require('styled-jsx/babel'), styledJsxOptions(opts['styled-jsx'])],
process.env.NODE_ENV === 'production' && require('babel-plugin-transform-react-remove-prop-types')
].filter(Boolean)
})

View file

@ -1,62 +0,0 @@
import { join } from 'path'
import promisify from '../lib/promisify'
import fs from 'fs'
import webpack from 'webpack'
import loadConfig from '../server/config'
import { PHASE_PRODUCTION_BUILD, BUILD_ID_FILE } from '../lib/constants'
import getBaseWebpackConfig from './webpack'
const access = promisify(fs.access)
const writeFile = promisify(fs.writeFile)
export default async function build (dir, conf = null) {
const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf)
const buildId = await config.generateBuildId() // defaults to a uuid
const distDir = join(dir, config.distDir)
try {
await access(dir, (fs.constants || fs).W_OK)
} catch (err) {
console.error(`> Failed, build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable`)
throw err
}
try {
const configs = await Promise.all([
getBaseWebpackConfig(dir, { buildId, isServer: false, config }),
getBaseWebpackConfig(dir, { buildId, isServer: true, config })
])
await runCompiler(configs)
await writeBuildId(distDir, buildId)
} catch (err) {
console.error(`> Failed to build`)
throw err
}
}
function runCompiler (compiler) {
return new Promise(async (resolve, reject) => {
const webpackCompiler = await webpack(await compiler)
webpackCompiler.run((err, stats) => {
if (err) return reject(err)
const jsonStats = stats.toJson('errors-only')
if (jsonStats.errors.length > 0) {
const error = new Error(jsonStats.errors[0])
error.errors = jsonStats.errors
error.warnings = jsonStats.warnings
return reject(error)
}
resolve()
})
})
}
async function writeBuildId (distDir, buildId) {
const buildIdPath = join(distDir, BUILD_ID_FILE)
await writeFile(buildIdPath, buildId, 'utf8')
}

View file

@ -1,56 +0,0 @@
// @flow
import { relative } from 'path'
import loaderUtils from 'loader-utils'
type Options = {|
extensions: RegExp,
include: Array<string>
|}
module.exports = function (content: string, sourceMap: any) {
this.cacheable()
const options: Options = loaderUtils.getOptions(this)
if (!options.extensions) {
throw new Error('extensions is not provided to hot-self-accept-loader. Please upgrade all next-plugins to the latest version.')
}
if (!options.include) {
throw new Error('include option is not provided to hot-self-accept-loader. Please upgrade all next-plugins to the latest version.')
}
const route = getRoute(this.resourcePath, options)
// Webpack has a built in system to prevent default from colliding, giving it a random letter per export.
// We can safely check if Component is undefined since all other pages imported into the entrypoint don't have __webpack_exports__.default
this.callback(null, `${content}
(function (Component, route) {
if(!Component) return
if (!module.hot) return
module.hot.accept()
Component.__route = route
if (module.hot.status() === 'idle') return
var components = next.router.components
for (var r in components) {
if (!components.hasOwnProperty(r)) continue
if (components[r].Component.__route === route) {
next.router.update(r, Component)
}
}
})(typeof __webpack_exports__ !== 'undefined' ? __webpack_exports__.default : (module.exports.default || module.exports), ${JSON.stringify(route)})
`, sourceMap)
}
function getRoute (resourcePath: string, options: Options) {
const dir = options.include.find((d) => resourcePath.indexOf(d) === 0)
if (!dir) {
throw new Error(`'hot-self-accept-loader' was called on a file that isn't a page.`)
}
const path = relative(dir, resourcePath).replace(options.extensions, '.js')
return '/' + path.replace(/((^|\/)index)?\.js$/, '')
}

View file

@ -1,54 +0,0 @@
// @flow
import { ConcatSource } from 'webpack-sources'
import {
IS_BUNDLED_PAGE_REGEX,
ROUTE_NAME_REGEX
} from '../../../lib/constants'
export default class PagesPlugin {
apply (compiler: any) {
compiler.hooks.compilation.tap('PagesPlugin', (compilation) => {
// This hook is triggered right before a module gets wrapped into it's initializing function,
// For example when you look at the source of a bundle you'll see an object holding `'pages/_app.js': function(module, etc, etc)`
// This hook triggers right before that code is added and wraps the module into `__NEXT_REGISTER_PAGE` when the module is a page
// The reason we're doing this is that we don't want to execute the page code which has potential side effects before switching to a route
compilation.moduleTemplates.javascript.hooks.render.tap('PagesPluginRenderPageRegister', (moduleSourcePostModule, module, options) => {
const {chunk} = options
// check if the current module is the entry module, we only want to wrap the topmost module
if (chunk.entryModule !== module) {
return moduleSourcePostModule
}
// Check if the chunk is a page
if (!IS_BUNDLED_PAGE_REGEX.test(chunk.name)) {
return moduleSourcePostModule
}
// Match the route the chunk belongs to
let routeName = ROUTE_NAME_REGEX.exec(chunk.name)[1]
// We need to convert \ into / when we are in windows
// to get the proper route name
// Here we need to do windows check because it's possible
// to have "\" in the filename in unix.
// Anyway if someone did that, he'll be having issues here.
// But that's something we cannot avoid.
if (/^win/.test(process.platform)) {
routeName = routeName.replace(/\\/g, '/')
}
routeName = `/${routeName.replace(/(^|\/)index$/, '')}`
const source = new ConcatSource(
`__NEXT_REGISTER_PAGE('${routeName}', function() {\n`,
moduleSourcePostModule,
'\nreturn { page: module.exports.default }',
'});'
)
return source
})
})
}
}

View file

@ -1,80 +0,0 @@
import path from 'path'
import promisify from '../../lib/promisify'
import globModule from 'glob'
import {CLIENT_STATIC_FILES_PATH} from '../../lib/constants'
const glob = promisify(globModule)
export async function getPages (dir, {nextPagesDir, dev, buildId, isServer, pageExtensions}) {
const pageFiles = await getPagePaths(dir, {dev, isServer, pageExtensions})
return getPageEntries(pageFiles, {nextPagesDir, buildId, isServer, pageExtensions})
}
export async function getPagePaths (dir, {dev, isServer, pageExtensions}) {
let pages
if (dev) {
// In development we only compile _document.js, _error.js and _app.js when starting, since they're always needed. All other pages are compiled with on demand entries
pages = await glob(isServer ? `pages/+(_document|_app|_error).+(${pageExtensions})` : `pages/+(_app|_error).+(${pageExtensions})`, { cwd: dir })
} else {
// In production get all pages from the pages directory
pages = await glob(isServer ? `pages/**/*.+(${pageExtensions})` : `pages/**/!(_document)*.+(${pageExtensions})`, { cwd: dir })
}
return pages
}
// Convert page path into single entry
export function createEntry (filePath, {buildId = '', name, pageExtensions} = {}) {
const parsedPath = path.parse(filePath)
let entryName = name || filePath
// This makes sure we compile `pages/blog/index.js` to `pages/blog.js`.
// Excludes `pages/index.js` from this rule since we do want `/` to route to `pages/index.js`
if (parsedPath.dir !== 'pages' && parsedPath.name === 'index') {
entryName = `${parsedPath.dir}.js`
}
// Makes sure supported extensions are stripped off. The outputted file should always be `.js`
if (pageExtensions) {
entryName = entryName.replace(new RegExp(`\\.+(${pageExtensions})$`), '.js')
}
return {
name: path.join(CLIENT_STATIC_FILES_PATH, buildId, entryName),
files: [parsedPath.root ? filePath : `./${filePath}`] // The entry always has to be an array.
}
}
// Convert page paths into entries
export function getPageEntries (pagePaths, {nextPagesDir, buildId, isServer = false, pageExtensions} = {}) {
const entries = {}
for (const filePath of pagePaths) {
const entry = createEntry(filePath, {pageExtensions, buildId})
entries[entry.name] = entry.files
}
const appPagePath = path.join(nextPagesDir, '_app.js')
const appPageEntry = createEntry(appPagePath, {buildId, name: 'pages/_app.js'}) // default app.js
if (!entries[appPageEntry.name]) {
entries[appPageEntry.name] = appPageEntry.files
}
const errorPagePath = path.join(nextPagesDir, '_error.js')
const errorPageEntry = createEntry(errorPagePath, {buildId, name: 'pages/_error.js'}) // default error.js
if (!entries[errorPageEntry.name]) {
entries[errorPageEntry.name] = errorPageEntry.files
}
if (isServer) {
const documentPagePath = path.join(nextPagesDir, '_document.js')
const documentPageEntry = createEntry(documentPagePath, {buildId, name: 'pages/_document.js'}) // default _document.js
if (!entries[documentPageEntry.name]) {
entries[documentPageEntry.name] = documentPageEntry.files
}
}
return entries
}

View file

@ -1,25 +0,0 @@
// @flow
import * as React from 'react'
type ComponentDidCatchInfo = {
componentStack: string
}
type Props = {|
onError: (error: Error, info: ComponentDidCatchInfo) => void,
children: React.ComponentType<*>
|}
class ErrorBoundary extends React.Component<Props> {
componentDidCatch (error: Error, info: ComponentDidCatchInfo) {
const {onError} = this.props
// onError is required
onError(error, info)
}
render () {
const {children} = this.props
return React.Children.only(children)
}
}
export default ErrorBoundary

View file

@ -1,60 +0,0 @@
/* global location */
import Router from '../lib/router'
import fetch from 'unfetch'
export default ({assetPrefix}) => {
Router.ready(() => {
Router.events.on('routeChangeComplete', ping)
})
async function ping () {
try {
const url = `${assetPrefix || ''}/_next/on-demand-entries-ping?page=${Router.pathname}`
const res = await fetch(url, {
credentials: 'same-origin'
})
const payload = await res.json()
if (payload.invalid) {
// Payload can be invalid even if the page is not exists.
// So, we need to make sure it's exists before reloading.
const pageRes = await fetch(location.href, {
credentials: 'same-origin'
})
if (pageRes.status === 200) {
location.reload()
}
}
} catch (err) {
console.error(`Error with on-demand-entries-ping: ${err.message}`)
}
}
let pingerTimeout
async function runPinger () {
// Will restart on the visibilitychange API below. For older browsers, this
// will always be true and will always run, but support is fairly prevalent
// at this point.
while (!document.hidden) {
await ping()
await new Promise((resolve) => {
pingerTimeout = setTimeout(resolve, 5000)
})
}
}
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
runPinger()
} else {
clearTimeout(pingerTimeout)
}
}, false)
setTimeout(() => {
runPinger()
.catch((err) => {
console.error(err)
})
}, 10000)
}

View file

@ -1,81 +0,0 @@
import 'event-source-polyfill'
import connect from './dev-error-overlay/hot-dev-client'
import Router from '../lib/router'
const handlers = {
reload (route) {
// If the App component changes we have to reload the current route, this is handled by hot-self-accept-loader
// So we just return
if (route === '/_app') {
return
}
if (route === '/_error') {
for (const r of Object.keys(Router.components)) {
const { err } = Router.components[r]
if (err) {
// reload all error routes
// which are expected to be errors of '/_error' routes
Router.reload(r)
}
}
return
}
// Since _document is server only we need to reload the full page when it changes.
if (route === '/_document') {
window.location.reload()
return
}
Router.reload(route)
},
change (route) {
// If the App component changes we have to reload the current route, this is handled by hot-self-accept-loader
// So we just return
if (route === '/_app') {
return
}
const { err, Component } = Router.components[route] || {}
if (err) {
// reload to recover from runtime errors
Router.reload(route)
}
if (Router.route !== route) {
// If this is a not a change for a currently viewing page.
// We don't need to worry about it.
return
}
if (!Component) {
// This only happens when we create a new page without a default export.
// If you removed a default export from a exising viewing page, this has no effect.
console.warn(`Hard reloading due to no default component in page: ${route}`)
window.location.reload()
}
}
}
export default ({assetPrefix}) => {
const options = {
path: `${assetPrefix}/_next/webpack-hmr`
}
const devClient = connect(options)
devClient.subscribeToHmrEvent((obj) => {
const fn = handlers[obj.action]
if (fn) {
const data = obj.data || []
fn(...data)
} else {
throw new Error('Unexpected action ' + obj.action)
}
})
return devClient
}

View file

@ -3,8 +3,58 @@
Our Commitment to Open Source can be found [here](https://zeit.co/blog/oss)
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Install the dependencies: `npm install`
3. Run `npm link` to link the local repo to NPM
4. Run `npm run build` to build and watch for code changes
5. Then npm link this repo inside any example app with `npm link next`
6. Then you can run your example app with the local version of Next.js (You may need to re-run the example app as you change server side code in the Next.js repository)
2. Install yarn: `npm install -g yarn`
3. Install the dependencies: `yarn`
4. Run `yarn run bootstrap`, which will link all repositories locally
5. Run `yarn run dev` to build and watch for code changes
## To run tests
Running all tests:
```
yarn testonly
```
Running a specific test suite inside of the `test/integration` directory:
```
yarn testonly --testPathPattern "production"
```
Running just one test in the `production` test suite:
```
yarn testonly --testPathPattern "production" -t "should allow etag header support"
```
## Running the integration test apps without running tests
```
./node_modules/.bin/next ./test/integration/basic
```
## Testing in your own app
First `next-server` needs to be linked:
```
cd packages/next-server
npm link
```
Then `next` needs to link to `next-server`, and be linked itself:
```
cd packages/next
npm link
npm link next-server
```
And finally, link the `next` package inside your app:
```
npm link next
```
Then you can run your app with the local version of Next.js (You may need to re-run the example app as you change server side code in the Next.js repository).

View file

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

View file

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

View file

@ -0,0 +1,11 @@
# Circular structure in "getInitialProps" result
#### Why This Error Occurred
`getInitialProps` is serialized to JSON using `JSON.stringify` and sent to the client side for hydrating the page.
However, the result returned from `getInitialProps` can't be serialized when it has a circular structure.
#### Possible Ways to Fix It
Circular structures are not supported, so the way to fix this error is removing the circular structure from the object that is returned from `getInitialProps`.

View file

@ -0,0 +1,20 @@
# `Head` or `NextScript` attribute `crossOrigin` is deprecated
#### Why This Error Occurred
This option has been moved to `next.config.js`.
#### Possible Ways to Fix It
Add the config option:
```js
// next.config.js
module.exports = {
crossOrigin: 'anonymous'
}
```
### Useful Links
- [The issue this was reported in: #5674](https://github.com/zeit/next.js/issues/5674)

View file

@ -0,0 +1,9 @@
# generateBuildId did not return a string
#### Why This Error Occurred
The most common cause for this issue is a custom `next.config.js` with the `generateBuildId` method defined, but it does not return a string.
#### Possible Ways to Fix It
Always return a string from generateBuildId.

View file

@ -0,0 +1,9 @@
# Using `next start` with `target` not set to `server`
#### Why This Error Occurred
Next.js can only handle running a server when the `target` is set to `server` (this is the default value). A serverless build, for instance, has no handler for requeststhis is usually implemented by a hosting provider.
#### Possible Ways to Fix It
Use a different handler than `next start` when testing a serverless **production** build, otherwise just use `next dev`.

View file

@ -27,12 +27,15 @@ export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return <Container>
return (
<Container>
<Head>
<title>My new cool app</title>
</Head>
<Component {...pageProps} />
</Container>
)
}
}
```

View file

@ -0,0 +1,22 @@
# Using `publicRuntimeConfig` with `target` set to `serverless`
#### Why This Error Occurred
In the `serverless` target environment `next.config.js` is not loaded, so we don't support `publicRuntimeConfig`.
#### Possible Ways to Fix It
Use config option `env` to set **build time** variables like such:
```js
// next.config.js
module.exports = {
env: {
special: "value"
}
}
```
```js
// pages/index.js
console.log(process.env.special) // value
```

View file

@ -1,3 +0,0 @@
{
"presets": ["../babel"]
}

1
examples/.gitignore vendored
View file

@ -1 +0,0 @@
**/yarn.lock

View file

@ -7,7 +7,9 @@ const ActiveLink = ({ router, children, ...props }) => {
let className = child.props.className || null
if (router.pathname === props.href && props.activeClassName) {
className = `${className !== null ? className : ''} ${props.activeClassName}`.trim()
className = `${className !== null ? className : ''} ${
props.activeClassName
}`.trim()
}
delete props.activeClassName

View file

@ -9,8 +9,8 @@
"author": "Remy Sharp <remy@leftlogic.com>",
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC"
}

View file

@ -0,0 +1,50 @@
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/analyze-bundles)
# Analyzer Bundles example
## How to use
### Using `create-next-app`
Execute [`create-next-app`](https://github.com/segmentio/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example:
```bash
npx create-next-app --example analyze-bundles analyze-bundles-app
# or
yarn create next-app --example analyze-bundles analyze-bundles-app
```
### Download manually
Download the example:
```bash
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/analyze-bundles
cd analyze-bundles
```
Install it
```bash
npm install
npm run dev
# or
yarn
yarn dev
```
## The idea behind the example
This example shows how to analyze the output bundles using [@zeit/next-bundle-analyzer](https://github.com/zeit/next-plugins/tree/master/packages/next-bundle-analyzer)
To analyze your webpack output, invoke the following command:
```bash
npm run analyze
npm run analyze:server
npm run analyze:browser
# or
yarn analyze
yarn analyze:server
yarn analyze:browser
```

View file

@ -0,0 +1,21 @@
const withBundleAnalyzer = require('@zeit/next-bundle-analyzer')
const nextConfig = {
analyzeServer: ['server', 'both'].includes(process.env.BUNDLE_ANALYZE),
analyzeBrowser: ['browser', 'both'].includes(process.env.BUNDLE_ANALYZE),
bundleAnalyzerConfig: {
server: {
analyzerMode: 'static',
reportFilename: '../bundles/server.html'
},
browser: {
analyzerMode: 'static',
reportFilename: '../bundles/client.html'
}
},
webpack (config) {
return config
}
}
module.exports = withBundleAnalyzer(nextConfig)

View file

@ -0,0 +1,20 @@
{
"name": "with-webpack-bundle-analyzer",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"analyze": "BUNDLE_ANALYZE=both next build",
"analyze:server": "BUNDLE_ANALYZE=server next build",
"analyze:browser": "BUNDLE_ANALYZE=browser next build"
},
"dependencies": {
"@zeit/next-bundle-analyzer": "^0.1.2",
"faker": "^4.1.0",
"next": "latest",
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC"
}

View file

@ -0,0 +1 @@
export default () => <div>About us</div>

View file

@ -0,0 +1 @@
export default () => <div>This is the contact page.</div>

View file

@ -21,7 +21,9 @@ export default class Index extends React.Component {
<h1>Home Page</h1>
<p>Welcome, {name}</p>
<div>
<Link href='/about'><a>About Page</a></Link>
<Link href='/about'>
<a>About Page</a>
</Link>
</div>
</div>
)

View file

@ -8,8 +8,8 @@
},
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC"
}

View file

@ -9,8 +9,8 @@
},
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC"
}

View file

@ -1,3 +1 @@
export default () => (
<div>About us</div>
)
export default () => <div>About us</div>

View file

@ -1,3 +1 @@
export default () => (
<div>About 2</div>
)
export default () => <div>About 2</div>

View file

@ -1,3 +1 @@
export default () => (
<div>Hello Day</div>
)
export default () => <div>Hello Day</div>

View file

@ -1,4 +1,9 @@
import Link from 'next/link'
export default () => (
<div>Hello World. <Link href='/about'><a>About</a></Link></div>
<div>
Hello World.{' '}
<Link href='/about'>
<a>About</a>
</Link>
</div>
)

View file

@ -8,7 +8,7 @@
},
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -7,14 +7,12 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
res.setHeader('Content-Type', 'text/html; charset=iso-8859-2')
handle(req, res, parsedUrl)
})
.listen(port, (err) => {
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})

View file

@ -3,7 +3,7 @@
const path = require('path')
exports['default'] = {
general: (api) => {
general: api => {
const packageJSON = require(api.projectRoot + path.sep + 'package.json')
return {
@ -46,16 +46,16 @@ exports['default'] = {
cliIncludeInternal: true,
// configuration for your actionhero project structure
paths: {
'action': [path.join(__dirname, '/../actions')],
'task': [path.join(__dirname, '/../tasks')],
'public': [path.join(__dirname, '/../static')],
'pid': [path.join(__dirname, '/../pids')],
'log': [path.join(__dirname, '/../log')],
'server': [path.join(__dirname, '/../servers')],
'cli': [path.join(__dirname, '/../bin')],
'initializer': [path.join(__dirname, '/../initializers')],
'plugin': [path.join(__dirname, '/../node_modules')],
'locale': [path.join(__dirname, '/../locales')]
action: [path.join(__dirname, '/../actions')],
task: [path.join(__dirname, '/../tasks')],
public: [path.join(__dirname, '/../static')],
pid: [path.join(__dirname, '/../pids')],
log: [path.join(__dirname, '/../log')],
server: [path.join(__dirname, '/../servers')],
cli: [path.join(__dirname, '/../bin')],
initializer: [path.join(__dirname, '/../initializers')],
plugin: [path.join(__dirname, '/../node_modules')],
locale: [path.join(__dirname, '/../locales')]
},
// hash containing chat rooms you wish to be created at server boot
startingChatRooms: {
@ -67,17 +67,17 @@ exports['default'] = {
}
exports.test = {
general: (api) => {
general: api => {
return {
id: 'test-server-' + process.pid,
serverToken: 'serverToken-' + process.pid,
developmentMode: true,
startingChatRooms: {
'defaultRoom': {},
'otherRoom': {}
defaultRoom: {},
otherRoom: {}
},
paths: {
'locale': [
locale: [
// require('os').tmpdir() + require('path').sep + 'locales',
path.join(__dirname, '/../locales')
]
@ -88,7 +88,7 @@ exports.test = {
}
exports.production = {
general: (api) => {
general: api => {
return {
fileRequestLogLevel: 'debug',
developmentMode: false

View file

@ -2,9 +2,9 @@
// error messages can be strings of objects
exports['default'] = {
errors: (api) => {
errors: api => {
return {
'_toExpand': false,
_toExpand: false,
// ///////////////
// SERIALIZERS //
@ -12,28 +12,28 @@ exports['default'] = {
serializers: {
servers: {
web: (error) => {
web: error => {
if (error.message) {
return String(error.message)
} else {
return error
}
},
websocket: (error) => {
websocket: error => {
if (error.message) {
return String(error.message)
} else {
return error
}
},
socket: (error) => {
socket: error => {
if (error.message) {
return String(error.message)
} else {
return error
}
},
specHelper: (error) => {
specHelper: error => {
if (error.message) {
return 'Error: ' + String(error.message)
} else {
@ -49,38 +49,51 @@ exports['default'] = {
// When a params for an action is invalid
invalidParams: (data, validationErrors) => {
if (validationErrors.length >= 0) { return validationErrors[0] }
if (validationErrors.length >= 0) {
return validationErrors[0]
}
return data.connection.localize('actionhero.errors.invalidParams')
},
// When a required param for an action is not provided
missingParams: (data, missingParams) => {
return data.connection.localize(['actionhero.errors.missingParams', {param: missingParams[0]}])
return data.connection.localize([
'actionhero.errors.missingParams',
{ param: missingParams[0] }
])
},
// user requested an unknown action
unknownAction: (data) => {
unknownAction: data => {
return data.connection.localize('actionhero.errors.unknownAction')
},
// action not useable by this client/server type
unsupportedServerType: (data) => {
return data.connection.localize(['actionhero.errors.unsupportedServerType', {type: data.connection.type}])
unsupportedServerType: data => {
return data.connection.localize([
'actionhero.errors.unsupportedServerType',
{ type: data.connection.type }
])
},
// action failed because server is mid-shutdown
serverShuttingDown: (data) => {
serverShuttingDown: data => {
return data.connection.localize('actionhero.errors.serverShuttingDown')
},
// action failed because this client already has too many pending acitons
// limit defined in api.config.general.simultaneousActions
tooManyPendingActions: (data) => {
return data.connection.localize('actionhero.errors.tooManyPendingActions')
tooManyPendingActions: data => {
return data.connection.localize(
'actionhero.errors.tooManyPendingActions'
)
},
dataLengthTooLarge: (maxLength, receivedLength) => {
return api.i18n.localize(['actionhero.errors.dataLengthTooLarge', {maxLength: maxLength, receivedLength: receivedLength}])
return api.i18n.localize([
'actionhero.errors.dataLengthTooLarge',
{ maxLength: maxLength, receivedLength: receivedLength }
])
},
// ///////////////
@ -89,18 +102,21 @@ exports['default'] = {
// The body message to accompany 404 (file not found) errors regarding flat files
// You may want to load in the contnet of 404.html or similar
fileNotFound: (connection) => {
fileNotFound: connection => {
return connection.localize(['actionhero.errors.fileNotFound'])
},
// user didn't request a file
fileNotProvided: (connection) => {
fileNotProvided: connection => {
return connection.localize('actionhero.errors.fileNotProvided')
},
// something went wrong trying to read the file
fileReadError: (connection, error) => {
return connection.localize(['actionhero.errors.fileReadError', {error: String(error)}])
return connection.localize([
'actionhero.errors.fileReadError',
{ error: String(error) }
])
},
// ///////////////
@ -108,41 +124,54 @@ exports['default'] = {
// ///////////////
verbNotFound: (connection, verb) => {
return connection.localize(['actionhero.errors.verbNotFound', {verb: verb}])
return connection.localize([
'actionhero.errors.verbNotFound',
{ verb: verb }
])
},
verbNotAllowed: (connection, verb) => {
return connection.localize(['actionhero.errors.verbNotAllowed', {verb: verb}])
return connection.localize([
'actionhero.errors.verbNotAllowed',
{ verb: verb }
])
},
connectionRoomAndMessage: (connection) => {
connectionRoomAndMessage: connection => {
return connection.localize('actionhero.errors.connectionRoomAndMessage')
},
connectionNotInRoom: (connection, room) => {
return connection.localize(['actionhero.errors.connectionNotInRoom', {room: room}])
return connection.localize([
'actionhero.errors.connectionNotInRoom',
{ room: room }
])
},
connectionAlreadyInRoom: (connection, room) => {
return connection.localize(['actionhero.errors.connectionAlreadyInRoom', {room: room}])
return connection.localize([
'actionhero.errors.connectionAlreadyInRoom',
{ room: room }
])
},
connectionRoomHasBeenDeleted: (room) => {
return api.i18n.localize('actionhero.errors.connectionRoomHasBeenDeleted')
connectionRoomHasBeenDeleted: room => {
return api.i18n.localize(
'actionhero.errors.connectionRoomHasBeenDeleted'
)
},
connectionRoomNotExist: (room) => {
connectionRoomNotExist: room => {
return api.i18n.localize('actionhero.errors.connectionRoomNotExist')
},
connectionRoomExists: (room) => {
connectionRoomExists: room => {
return api.i18n.localize('actionhero.errors.connectionRoomExists')
},
connectionRoomRequired: (room) => {
connectionRoomRequired: room => {
return api.i18n.localize('actionhero.errors.connectionRoomRequired')
}
}
}
}

View file

@ -1,5 +1,5 @@
exports['default'] = {
i18n: (api) => {
i18n: api => {
return {
// visit https://github.com/mashpie/i18n-node to see all configuration options
// locale path can be configired from within ./config/api.js
@ -28,7 +28,7 @@ exports['default'] = {
}
exports.test = {
i18n: (api) => {
i18n: api => {
return {
updateFiles: true
}

View file

@ -4,16 +4,18 @@ const fs = require('fs')
const cluster = require('cluster')
exports['default'] = {
logger: (api) => {
logger: api => {
let logger = { transports: [] }
// console logger
if (cluster.isMaster) {
logger.transports.push(function (api, winston) {
return new (winston.transports.Console)({
return new winston.transports.Console({
colorize: true,
level: 'info',
timestamp: function () { return api.id + ' @ ' + new Date().toISOString() }
timestamp: function () {
return api.id + ' @ ' + new Date().toISOString()
}
})
})
}
@ -26,15 +28,18 @@ exports['default'] = {
fs.mkdirSync(logDirectory)
} catch (e) {
if (e.code !== 'EEXIST') {
throw (new Error('Cannot create log directory @ ' + logDirectory))
throw new Error('Cannot create log directory @ ' + logDirectory)
}
}
}
return new (winston.transports.File)({
filename: api.config.general.paths.log[0] + '/' + api.pids.title + '.log',
return new winston.transports.File({
filename:
api.config.general.paths.log[0] + '/' + api.pids.title + '.log',
level: 'info',
timestamp: function () { return api.id + ' @ ' + new Date().toISOString() }
timestamp: function () {
return api.id + ' @ ' + new Date().toISOString()
}
})
})
@ -52,7 +57,7 @@ exports['default'] = {
}
exports.test = {
logger: (api) => {
logger: api => {
return {
transports: null
}

View file

@ -1,5 +1,5 @@
exports['default'] = {
plugins: (api) => {
plugins: api => {
/*
If you want to use plugins in your application, include them here:

View file

@ -11,15 +11,20 @@ if (process.env.REDIS_URL) {
}
exports['default'] = {
redis: (api) => {
redis: api => {
// konstructor: The redis client constructor method. All redis methods must be promises
// args: The arguments to pass to the constructor
// buildNew: is it `new konstructor()` or just `konstructor()`?
function retryStrategy (times) {
if (times === 1) {
const error = 'Unable to connect to Redis - please check your Redis config!'
if (process.env.NODE_ENV === 'test') { console.error(error) } else { api.log(error, 'error') }
const error =
'Unable to connect to Redis - please check your Redis config!'
if (process.env.NODE_ENV === 'test') {
console.error(error)
} else {
api.log(error, 'error')
}
return 5000
}
return Math.min(times * 50, maxBackoff)
@ -28,20 +33,44 @@ exports['default'] = {
return {
enabled: true,
'_toExpand': false,
_toExpand: false,
client: {
konstructor: require('ioredis'),
args: [{ port: port, host: host, password: password, db: db, retryStrategy: retryStrategy }],
args: [
{
port: port,
host: host,
password: password,
db: db,
retryStrategy: retryStrategy
}
],
buildNew: true
},
subscriber: {
konstructor: require('ioredis'),
args: [{ port: port, host: host, password: password, db: db, retryStrategy: retryStrategy }],
args: [
{
port: port,
host: host,
password: password,
db: db,
retryStrategy: retryStrategy
}
],
buildNew: true
},
tasks: {
konstructor: require('ioredis'),
args: [{ port: port, host: host, password: password, db: db, retryStrategy: retryStrategy }],
args: [
{
port: port,
host: host,
password: password,
db: db,
retryStrategy: retryStrategy
}
],
buildNew: true
}
}

View file

@ -1,9 +1,7 @@
exports['default'] = {
routes: (api) => {
routes: api => {
return {
get: [
{ path: '/', matchTrailingPathParts: true, action: 'render' }
]
get: [{ path: '/', matchTrailingPathParts: true, action: 'render' }]
}
}
}

View file

@ -2,9 +2,9 @@
exports['default'] = {
servers: {
socket: (api) => {
socket: api => {
return {
enabled: (process.env.ENABLE_TCP_SERVER !== undefined),
enabled: process.env.ENABLE_TCP_SERVER !== undefined,
// TCP or TLS?
secure: false,
// Passed to tls.createServer if secure=true. Should contain SSL certificates
@ -26,7 +26,7 @@ exports['default'] = {
exports.test = {
servers: {
socket: (api) => {
socket: api => {
return {
enabled: true,
port: 1001 + (process.pid % 64535),

View file

@ -4,7 +4,7 @@ const os = require('os')
exports['default'] = {
servers: {
web: (api) => {
web: api => {
return {
enabled: true,
// HTTP or HTTPS?
@ -13,7 +13,9 @@ exports['default'] = {
serverOptions: {},
// Should we redirect all traffic to the first host in this array if hte request header doesn't match?
// i.e.: [ 'https://www.site.com' ]
allowedRequestHosts: process.env.ALLOWED_HOSTS ? process.env.ALLOWED_HOSTS.split(',') : [],
allowedRequestHosts: process.env.ALLOWED_HOSTS
? process.env.ALLOWED_HOSTS.split(',')
: [],
// Port or Socket Path
port: process.env.PORT || 8080,
// Which IP to listen on (use '0.0.0.0' for all; '::' for all on ipv4 and ipv6)
@ -23,7 +25,8 @@ exports['default'] = {
httpHeaders: {
'X-Powered-By': api.config.general.serverName,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS, TRACE',
'Access-Control-Allow-Methods':
'HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS, TRACE',
'Access-Control-Allow-Headers': 'Content-Type'
},
// Route that actions will be served from; secondary route against this route will be treated as actions,
@ -92,7 +95,7 @@ exports['default'] = {
exports.production = {
servers: {
web: (api) => {
web: api => {
return {
padding: null,
metadataOptions: {
@ -106,7 +109,7 @@ exports.production = {
exports.test = {
servers: {
web: (api) => {
web: api => {
return {
secure: false,
port: process.env.PORT || 1000 + (process.pid % 64535),

View file

@ -4,7 +4,7 @@
exports['default'] = {
servers: {
websocket: (api) => {
websocket: api => {
return {
enabled: true,
// you can pass a FQDN (string) here or 'window.location.origin'
@ -55,7 +55,7 @@ exports['default'] = {
exports['test'] = {
servers: {
websocket: (api) => {
websocket: api => {
return { clientUrl: null }
}
}

View file

@ -1,5 +1,5 @@
exports['default'] = {
tasks: (api) => {
tasks: api => {
return {
// Should this node run a scheduler to promote delayed tasks?
scheduler: false,
@ -52,7 +52,7 @@ exports['default'] = {
}
exports.test = {
tasks: (api) => {
tasks: api => {
return {
timeout: 100,
checkTimeout: 50

View file

@ -10,16 +10,20 @@ module.exports = class NextInitializer extends Initializer {
async initialize () {
api.next = {
render: async (connection) => {
if (connection.type !== 'web') { throw new Error('Connections for NEXT apps must be of type "web"') }
render: async connection => {
if (connection.type !== 'web') {
throw new Error('Connections for NEXT apps must be of type "web"')
}
const req = connection.rawConnection.req
const res = connection.rawConnection.res
return api.next.handle(req, res)
}
}
api.next.dev = (api.env === 'development')
if (api.next.dev) { api.log('Running next in development mode...') }
api.next.dev = api.env === 'development'
if (api.next.dev) {
api.log('Running next in development mode...')
}
api.next.app = next({ dev: api.next.dev })
api.next.handle = api.next.app.getRequestHandler()

View file

@ -7,8 +7,8 @@
"ioredis": "^3.2.2",
"isomorphic-fetch": "^2.2.1",
"next": "^5.0.1-canary.9",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"ws": "^4.1.0"
},
"scripts": {

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -9,7 +9,7 @@
"dependencies": {
"express": "^4.14.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -3,13 +3,18 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link
href={{pathname: '/posts', query: { id: '2' }}}
as='/posts/2'
>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
<li>
<Link href={{ pathname: '/posts', query: { id: '2' } }} as='/posts/2'>
<a>post #2</a>
</Link>
</li>

View file

@ -6,12 +6,14 @@ export default class extends Component {
}
render () {
return <div>
return (
<div>
<h1>My blog post #{this.props.postId}</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</div>
)
}
}

View file

@ -6,8 +6,7 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
app.prepare().then(() => {
const server = express()
server.get('/a', (req, res) => {
@ -26,7 +25,7 @@ app.prepare()
return handle(req, res)
})
server.listen(port, (err) => {
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})

View file

@ -9,7 +9,7 @@
"dependencies": {
"fastify": "1.8.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -6,51 +6,47 @@ const dev = process.env.NODE_ENV !== 'production'
fastify.register((fastify, opts, next) => {
const app = Next({ dev })
app.prepare()
app
.prepare()
.then(() => {
if (dev) {
fastify.get('/_next/*', (req, reply) => {
return app.handleRequest(req.req, reply.res)
.then(() => {
return app.handleRequest(req.req, reply.res).then(() => {
reply.sent = true
})
})
}
fastify.get('/a', (req, reply) => {
return app.render(req.req, reply.res, '/b', req.query)
.then(() => {
return app.render(req.req, reply.res, '/b', req.query).then(() => {
reply.sent = true
})
})
fastify.get('/b', (req, reply) => {
return app.render(req.req, reply.res, '/a', req.query)
.then(() => {
return app.render(req.req, reply.res, '/a', req.query).then(() => {
reply.sent = true
})
})
fastify.get('/*', (req, reply) => {
return app.handleRequest(req.req, reply.res)
.then(() => {
return app.handleRequest(req.req, reply.res).then(() => {
reply.sent = true
})
})
fastify.setNotFoundHandler((request, reply) => {
return app.render404(request.req, reply.res)
.then(() => {
return app.render404(request.req, reply.res).then(() => {
reply.sent = true
})
})
next()
})
.catch((err) => next(err))
.catch(err => next(err))
})
fastify.listen(port, (err) => {
fastify.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})

View file

@ -13,7 +13,13 @@ const defaultHandlerWrapper = app => async ({ raw: { req, res }, url }) => {
}
const pathWrapper = (app, pathName, opts) => async ({ raw, query, params }) => {
return app.renderToHTML(raw.req, raw.res, pathName, { ...query, ...params }, opts)
return app.renderToHTML(
raw.req,
raw.res,
pathName,
{ ...query, ...params },
opts
)
}
module.exports = { pathWrapper, defaultHandlerWrapper, nextHandlerWrapper }

View file

@ -9,7 +9,7 @@
"dependencies": {
"hapi": "^17.1.1",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -1,6 +1,10 @@
const next = require('next')
const Hapi = require('hapi')
const { pathWrapper, defaultHandlerWrapper, nextHandlerWrapper } = require('./next-wrapper')
const {
pathWrapper,
defaultHandlerWrapper,
nextHandlerWrapper
} = require('./next-wrapper')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
@ -9,9 +13,7 @@ const server = new Hapi.Server({
port
})
app
.prepare()
.then(async () => {
app.prepare().then(async () => {
server.route({
method: 'GET',
path: '/a',
@ -26,13 +28,13 @@ app
server.route({
method: 'GET',
path: '/_next/{p*}', /* next specific routes */
path: '/_next/{p*}' /* next specific routes */,
handler: nextHandlerWrapper(app)
})
server.route({
method: 'GET',
path: '/{p*}', /* catch all route */
path: '/{p*}' /* catch all route */,
handler: defaultHandlerWrapper(app)
})

View file

@ -10,7 +10,7 @@
"koa": "^2.0.1",
"koa-router": "^7.1.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -7,8 +7,7 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
app.prepare().then(() => {
const server = new Koa()
const router = new Router()

View file

@ -9,8 +9,8 @@
"micro": "^9.1.0",
"micro-route": "^2.4.0",
"next": "latest",
"react": "^16.1.1",
"react-dom": "^16.1.1"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"devDependencies": {
"micro-dev": "^2.2.0"

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -6,8 +6,8 @@
},
"dependencies": {
"next": "latest",
"react": "^16.2.0",
"react-dom": "^16.2.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"devDependencies": {
"nodemon": "^1.12.1"

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -7,8 +7,7 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
@ -20,8 +19,7 @@ app.prepare()
} else {
handle(req, res, parsedUrl)
}
})
.listen(port, (err) => {
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})

View file

@ -8,8 +8,8 @@
},
"dependencies": {
"next": "latest",
"polka": "0.2.3",
"react": "16.2.0",
"react-dom": "16.2.0"
"polka": "0.5.1",
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -15,7 +15,8 @@ app.prepare().then(() => {
server.get('*', (req, res) => handle(req, res))
server
.listen(port)
.then(() => console.log(`> Ready on http://localhost:${port}`))
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})

View file

@ -0,0 +1,8 @@
# Dependency directories
node_modules/
# next.js build output
.next
# typescript build output
dist

View file

@ -1,6 +1,4 @@
{
"watch": ["server/**/*.ts"],
"execMap": {
"ts": "ts-node --typeCheck --compilerOptions '{\"module\":\"commonjs\"}'"
}
"exec": "ts-node --project tsconfig.server.json server/index.ts"
}

View file

@ -1,23 +1,21 @@
{
"scripts": {
"dev": "nodemon server/index.ts",
"dev": "nodemon",
"build": "next build && tsc --project tsconfig.server.json",
"start": "NODE_ENV=production node .next/production-server/index.js"
"start": "cross-env NODE_ENV=production node dist/index.js"
},
"dependencies": {
"@babel/core": "^7.0.0-rc.1",
"@zeit/next-typescript": "1.1.0",
"babel-loader": "^7.1.4",
"next": "latest",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"typescript": "latest",
"typescript-babel-jest": "^1.0.5"
"@zeit/next-typescript": "^1.1.0",
"next": "^7.0.0",
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"devDependencies": {
"@types/next": "^2.4.11",
"@types/react": "^16.0.36",
"nodemon": "^1.17.5",
"ts-node": "^4.1.0"
"@types/next": "^7.0.0",
"@types/react": "^16.6.0",
"cross-env": "^5.2.0",
"nodemon": "^1.18.8",
"ts-node": "^7.0.1",
"typescript": "^3.2.0"
}
}

View file

@ -2,7 +2,11 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": ".next/production-server/"
"outDir": "dist",
"target": "es2017",
"lib": [
"es2017"
]
},
"include": ["server/**/*.ts"]
}

View file

@ -8,7 +8,7 @@
},
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
}
}

View file

@ -3,7 +3,15 @@ import Link from 'next/link'
export default () => (
<ul>
<li><Link href='/b' as='/a'><a>a</a></Link></li>
<li><Link href='/a' as='/b'><a>b</a></Link></li>
<li>
<Link href='/b' as='/a'>
<a>a</a>
</Link>
</li>
<li>
<Link href='/a' as='/b'>
<a>b</a>
</Link>
</li>
</ul>
)

View file

@ -7,8 +7,7 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
@ -20,8 +19,7 @@ app.prepare()
} else {
handle(req, res, parsedUrl)
}
})
.listen(port, (err) => {
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})

View file

@ -9,8 +9,8 @@
"dependencies": {
"isomorphic-unfetch": "^2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC"
}

View file

@ -14,7 +14,9 @@ export default class Index extends React.Component {
return (
<div>
<p>Next.js has {this.props.stars} </p>
<Link prefetch href='/preact'><a>How about preact?</a></Link>
<Link prefetch href='/preact'>
<a>How about preact?</a>
</Link>
</div>
)
}

View file

@ -14,7 +14,9 @@ export default class Preact extends React.Component {
return (
<div>
<p>Preact has {this.props.stars} </p>
<Link prefetch href='/'><a>I bet next has more stars (?)</a></Link>
<Link prefetch href='/'>
<a>I bet next has more stars (?)</a>
</Link>
</div>
)
}

View file

@ -16,7 +16,12 @@ const UserForm = () => {
<Input controlLabel='Email' type='email' title='user' name='email' />
</Col>
<Col lg={8} lgOffset={4}>
<Input controlLabel='Password' type='password' title='user' name='password' />
<Input
controlLabel='Password'
type='password'
title='user'
name='password'
/>
</Col>
</Row>
</div>

View file

@ -14,7 +14,10 @@ class Main extends Component {
<div>
<Head>
<title>Form Handler</title>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css' />
<link
rel='stylesheet'
href='https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css'
/>
</Head>
<Header />
<DisplayForm />

View file

@ -6,7 +6,7 @@ import { bindActionCreators } from 'redux'
import { inputChange } from '../actions'
class Input extends Component {
inputChange = (e) => {
inputChange = e => {
const { inputChange, title, name } = this.props
inputChange(title, name, e.target.value)
}
@ -35,4 +35,7 @@ const mapDispatchToProps = dispatch => {
}
}
export default connect(null, mapDispatchToProps)(Input)
export default connect(
null,
mapDispatchToProps
)(Input)

View file

@ -15,8 +15,8 @@
"dependencies": {
"express": "^4.15.4",
"next": "latest",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"next-redux-wrapper": "^1.3.2",
"react-bootstrap": "^0.31.3",
"react-redux": "^5.0.6",

View file

@ -3,11 +3,9 @@ import { INPUT_VALUE } from '../constants'
export default (state = {}, action) => {
switch (action.type) {
case INPUT_VALUE:
return { ...state,
[action.title]:
{ ...state[action.title],
[action.name]: action.val
}
return {
...state,
[action.title]: { ...state[action.title], [action.name]: action.val }
}
default:
return state

View file

@ -5,7 +5,8 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
app
.prepare()
.then(() => {
const server = express()
@ -17,12 +18,12 @@ app.prepare()
return handle(req, res)
})
server.listen(3000, (err) => {
server.listen(3000, err => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
.catch(ex => {
console.error(ex.stack)
process.exit(1)
})

Some files were not shown because too many files have changed in this diff Show more