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:
commit
163830c026
18
.babelrc.js
18
.babelrc.js
|
@ -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
|
||||
}]
|
||||
]
|
||||
}
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
[ignore]
|
||||
<PROJECT_ROOT>/examples/.*
|
||||
<PROJECT_ROOT>/.*.json
|
11
.github/ISSUE_TEMPLATE/9.Nextjs.org_showcase.md
vendored
11
.github/ISSUE_TEMPLATE/9.Nextjs.org_showcase.md
vendored
|
@ -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
4
.gitignore
vendored
|
@ -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
|
||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -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
1792
README-zh-CN.md
Normal file
File diff suppressed because it is too large
Load diff
23
appveyor.yml
23
appveyor.yml
|
@ -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
|
28
azure-pipelines.yml
Normal file
28
azure-pipelines.yml
Normal 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
111
bin/next
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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)
|
|
@ -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)
|
||||
})
|
|
@ -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')
|
||||
}
|
|
@ -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$/, '')
|
||||
}
|
|
@ -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
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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).
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('./dist/server/document')
|
11
errors/circular-structure.md
Normal file
11
errors/circular-structure.md
Normal 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`.
|
20
errors/doc-crossorigin-deprecated.md
Normal file
20
errors/doc-crossorigin-deprecated.md
Normal 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)
|
9
errors/generatebuildid-not-a-string.md
Normal file
9
errors/generatebuildid-not-a-string.md
Normal 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.
|
9
errors/next-start-serverless.md
Normal file
9
errors/next-start-serverless.md
Normal 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 requests–this 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`.
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
22
errors/serverless-publicRuntimeConfig.md
Normal file
22
errors/serverless-publicRuntimeConfig.md
Normal 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
|
||||
```
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"presets": ["../babel"]
|
||||
}
|
1
examples/.gitignore
vendored
1
examples/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
**/yarn.lock
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
50
examples/analyze-bundles/README.md
Normal file
50
examples/analyze-bundles/README.md
Normal 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
|
||||
```
|
21
examples/analyze-bundles/next.config.js
Normal file
21
examples/analyze-bundles/next.config.js
Normal 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)
|
20
examples/analyze-bundles/package.json
Normal file
20
examples/analyze-bundles/package.json
Normal 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"
|
||||
}
|
1
examples/analyze-bundles/pages/about.js
Normal file
1
examples/analyze-bundles/pages/about.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default () => <div>About us</div>
|
1
examples/analyze-bundles/pages/contact.js
Normal file
1
examples/analyze-bundles/pages/contact.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default () => <div>This is the contact page.</div>
|
|
@ -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>
|
||||
)
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
export default () => (
|
||||
<div>About us</div>
|
||||
)
|
||||
export default () => <div>About us</div>
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
export default () => (
|
||||
<div>About 2</div>
|
||||
)
|
||||
export default () => <div>About 2</div>
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
export default () => (
|
||||
<div>Hello Day</div>
|
||||
)
|
||||
export default () => <div>Hello Day</div>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
'use strict'
|
||||
const {Action, api} = require('actionhero')
|
||||
const { Action, api } = require('actionhero')
|
||||
|
||||
module.exports = class CreateChatRoom extends Action {
|
||||
constructor () {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
exports['default'] = {
|
||||
plugins: (api) => {
|
||||
plugins: api => {
|
||||
/*
|
||||
If you want to use plugins in your application, include them here:
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
exports['default'] = {
|
||||
routes: (api) => {
|
||||
routes: api => {
|
||||
return {
|
||||
get: [
|
||||
{ path: '/', matchTrailingPathParts: true, action: 'render' }
|
||||
]
|
||||
get: [{ path: '/', matchTrailingPathParts: true, action: 'render' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
8
examples/custom-server-typescript/.gitignore
vendored
Normal file
8
examples/custom-server-typescript/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# typescript build output
|
||||
dist
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": ".next/production-server/"
|
||||
"outDir": "dist",
|
||||
"target": "es2017",
|
||||
"lib": [
|
||||
"es2017"
|
||||
]
|
||||
},
|
||||
"include": ["server/**/*.ts"]
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue