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

@ -6,7 +6,7 @@ Adding `<title>` in `pages/_document.js` will lead to unexpected results with `n
#### Possible Ways to Fix It
Set `<title>` in `pages/_app.js` instead :
Set `<title>` in `pages/_app.js` instead:
```js
// pages/_app.js
@ -22,17 +22,20 @@ export default class MyApp extends App {
pageProps = await Component.getInitialProps(ctx)
}
return {pageProps}
return { pageProps }
}
render () {
const {Component, pageProps} = this.props
return <Container>
<Head>
<title>My new cool app</title>
</Head>
<Component {...pageProps} />
</Container>
const { Component, pageProps } = this.props
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,15 +7,13 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
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) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
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 => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})

View file

@ -1,5 +1,5 @@
'use strict'
const {Action, api} = require('actionhero')
const { Action, api } = require('actionhero')
module.exports = class CreateChatRoom extends Action {
constructor () {

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) => {
let logger = {transports: []}
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

@ -1,5 +1,5 @@
'use strict'
const {Initializer, api} = require('actionhero')
const { Initializer, api } = require('actionhero')
const next = require('next')
module.exports = class NextInitializer extends Initializer {
@ -10,18 +10,22 @@ 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.app = next({ dev: api.next.dev })
api.next.handle = api.next.app.getRequestHandler()
await api.next.app.prepare()
}

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>
<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.
</p>
</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.
</p>
</div>
)
}
}

View file

@ -6,28 +6,27 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
app.prepare().then(() => {
const server = express()
server.get('/a', (req, res) => {
return app.render(req, res, '/b', req.query)
})
server.get('/b', (req, res) => {
return app.render(req, res, '/a', req.query)
})
server.get('/posts/:id', (req, res) => {
return app.render(req, res, '/posts', { id: req.params.id })
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
server.get('/a', (req, res) => {
return app.render(req, res, '/b', req.query)
})
server.get('/b', (req, res) => {
return app.render(req, res, '/a', req.query)
})
server.get('/posts/:id', (req, res) => {
return app.render(req, res, '/posts', { id: req.params.id })
})
server.get('*', (req, res) => {
return handle(req, res)
})
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(() => {
reply.sent = true
})
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(() => {
reply.sent = true
})
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(() => {
reply.sent = true
})
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(() => {
reply.sent = true
})
return app.handleRequest(req.req, reply.res).then(() => {
reply.sent = true
})
})
fastify.setNotFoundHandler((request, reply) => {
return app.render404(request.req, reply.res)
.then(() => {
reply.sent = true
})
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,38 +13,36 @@ const server = new Hapi.Server({
port
})
app
.prepare()
.then(async () => {
server.route({
method: 'GET',
path: '/a',
handler: pathWrapper(app, '/a')
})
server.route({
method: 'GET',
path: '/b',
handler: pathWrapper(app, '/b')
})
server.route({
method: 'GET',
path: '/_next/{p*}', /* next specific routes */
handler: nextHandlerWrapper(app)
})
server.route({
method: 'GET',
path: '/{p*}', /* catch all route */
handler: defaultHandlerWrapper(app)
})
try {
await server.start()
console.log(`> Ready on http://localhost:${port}`)
} catch (error) {
console.log('Error starting server')
console.log(error)
}
app.prepare().then(async () => {
server.route({
method: 'GET',
path: '/a',
handler: pathWrapper(app, '/a')
})
server.route({
method: 'GET',
path: '/b',
handler: pathWrapper(app, '/b')
})
server.route({
method: 'GET',
path: '/_next/{p*}' /* next specific routes */,
handler: nextHandlerWrapper(app)
})
server.route({
method: 'GET',
path: '/{p*}' /* catch all route */,
handler: defaultHandlerWrapper(app)
})
try {
await server.start()
console.log(`> Ready on http://localhost:${port}`)
} catch (error) {
console.log('Error starting server')
console.log(error)
}
})

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,33 +7,32 @@ const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = new Koa()
const router = new Router()
app.prepare().then(() => {
const server = new Koa()
const router = new Router()
router.get('/a', async ctx => {
await app.render(ctx.req, ctx.res, '/b', ctx.query)
ctx.respond = false
})
router.get('/b', async ctx => {
await app.render(ctx.req, ctx.res, '/a', ctx.query)
ctx.respond = false
})
router.get('*', async ctx => {
await handle(ctx.req, ctx.res)
ctx.respond = false
})
server.use(async (ctx, next) => {
ctx.res.statusCode = 200
await next()
})
server.use(router.routes())
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
router.get('/a', async ctx => {
await app.render(ctx.req, ctx.res, '/b', ctx.query)
ctx.respond = false
})
router.get('/b', async ctx => {
await app.render(ctx.req, ctx.res, '/a', ctx.query)
ctx.respond = false
})
router.get('*', async ctx => {
await handle(ctx.req, ctx.res)
ctx.respond = false
})
server.use(async (ctx, next) => {
ctx.res.statusCode = 200
await next()
})
server.use(router.routes())
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
})

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

@ -1,5 +1,5 @@
import { INPUT_VALUE } from '../constants'
export const inputChange = (title, name, val) => dispatch => {
return dispatch({type: INPUT_VALUE, title, name, val})
return dispatch({ type: INPUT_VALUE, title, name, val })
}

View file

@ -1,4 +1,4 @@
import React, {Component} from 'react'
import React, { Component } from 'react'
import { Col, Row } from 'react-bootstrap'
import { connect } from 'react-redux'
@ -9,7 +9,7 @@ class DisplayForm extends Component {
<div>
<Row>
<Col lg={8} lgOffset={2}>
<pre>{JSON.stringify(state, null, 2) }</pre>
<pre>{JSON.stringify(state, null, 2)}</pre>
</Col>
</Row>
</div>

View file

@ -6,7 +6,7 @@ const Header = () => {
<Row style={{ marginTop: '10px' }}>
<Col lg={8} lgOffset={2}>
<Jumbotron style={{ borderRadius: '15px' }}>
<h1 style={{textAlign: 'center'}}>Form Handler</h1>
<h1 style={{ textAlign: 'center' }}>Form Handler</h1>
</Jumbotron>
</Col>
</Row>

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

@ -1,4 +1,4 @@
import React, {Component} from 'react'
import React, { Component } from 'react'
import Head from 'next/head'
import { Col, Row } from 'react-bootstrap'
@ -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 />

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