mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Merge branch 'canary' of github.com:zeit/next.js into canary
This commit is contained in:
commit
b6b88e5f81
3
.babelrc
3
.babelrc
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"presets": [
|
||||
"env",
|
||||
"react"
|
||||
"react",
|
||||
"flow"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
|
|
2
.flowconfig
Normal file
2
.flowconfig
Normal file
|
@ -0,0 +1,2 @@
|
|||
[ignore]
|
||||
<PROJECT_ROOT>/examples/.*
|
|
@ -43,7 +43,7 @@ if (!existsSync(join(dir, 'pages'))) {
|
|||
}
|
||||
|
||||
build(dir)
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
|
40
bin/next-dev
40
bin/next-dev
|
@ -54,23 +54,23 @@ if (!existsSync(join(dir, 'pages'))) {
|
|||
|
||||
const srv = new Server({ dir, dev: true })
|
||||
srv.start(argv.port, argv.hostname)
|
||||
.then(async () => {
|
||||
if (!process.env.NOW) {
|
||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
let errorMessage = `Port ${argv.port} is already in use.`
|
||||
const pkgAppPath = require('find-up').sync('package.json', {
|
||||
cwd: dir
|
||||
})
|
||||
const appPackage = JSON.parse(readFileSync(pkgAppPath, 'utf8'))
|
||||
const nextScript = Object.entries(appPackage.scripts).find(scriptLine => scriptLine[1] === 'next')
|
||||
if (nextScript) errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p <some other port>\`.`
|
||||
console.error(errorMessage)
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
process.nextTick(() => process.exit(1))
|
||||
})
|
||||
.then(async () => {
|
||||
if (!process.env.NOW) {
|
||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
let errorMessage = `Port ${argv.port} is already in use.`
|
||||
const pkgAppPath = require('find-up').sync('package.json', {
|
||||
cwd: dir
|
||||
})
|
||||
const appPackage = JSON.parse(readFileSync(pkgAppPath, 'utf8'))
|
||||
const nextScript = Object.entries(appPackage.scripts).find(scriptLine => scriptLine[1] === 'next')
|
||||
if (nextScript) errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p <some other port>\`.`
|
||||
console.error(errorMessage)
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
process.nextTick(() => process.exit(1))
|
||||
})
|
||||
|
|
|
@ -46,12 +46,12 @@ const dir = resolve(argv._[0] || '.')
|
|||
|
||||
const srv = new Server({ dir })
|
||||
srv.start(argv.port, argv.hostname)
|
||||
.then(() => {
|
||||
if (!process.env.NOW) {
|
||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
.then(() => {
|
||||
if (!process.env.NOW) {
|
||||
console.log(`> Ready on http://${argv.hostname ? argv.hostname : 'localhost'}:${argv.port}`)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
|
|
@ -8,14 +8,14 @@ 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)
|
||||
.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}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ exports['default'] = {
|
|||
// Logging levels of task workers
|
||||
workerLogging: {
|
||||
failure: 'error', // task failure
|
||||
success: 'info', // task success
|
||||
success: 'info', // task success
|
||||
start: 'info',
|
||||
end: 'info',
|
||||
cleaning_worker: 'info',
|
||||
|
|
|
@ -7,27 +7,27 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
server.get('/a', (req, res) => {
|
||||
return app.render(req, res, '/b', req.query)
|
||||
})
|
||||
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('/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('/posts/:id', (req, res) => {
|
||||
return app.render(req, res, '/posts', { id: req.params.id })
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -7,23 +7,23 @@ const app = Next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = fastify()
|
||||
.then(() => {
|
||||
const server = fastify()
|
||||
|
||||
server.get('/a', (req, res) => {
|
||||
return app.render(req.req, res.res, '/a', req.query)
|
||||
})
|
||||
server.get('/a', (req, res) => {
|
||||
return app.render(req.req, res.res, '/a', req.query)
|
||||
})
|
||||
|
||||
server.get('/b', (req, res) => {
|
||||
return app.render(req.req, res.res, '/b', req.query)
|
||||
})
|
||||
server.get('/b', (req, res) => {
|
||||
return app.render(req.req, res.res, '/b', req.query)
|
||||
})
|
||||
|
||||
server.get('/*', (req, res) => {
|
||||
return handle(req.req, res.res)
|
||||
})
|
||||
server.get('/*', (req, res) => {
|
||||
return handle(req.req, res.res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,37 +10,37 @@ const server = new Hapi.Server({
|
|||
})
|
||||
|
||||
app
|
||||
.prepare()
|
||||
.then(async () => {
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: '/a',
|
||||
handler: pathWrapper(app, '/a')
|
||||
})
|
||||
.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: '/b',
|
||||
handler: pathWrapper(app, '/b')
|
||||
})
|
||||
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: '/_next/{p*}', /* next specific routes */
|
||||
handler: nextHandlerWrapper(app)
|
||||
})
|
||||
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)
|
||||
})
|
||||
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)
|
||||
}
|
||||
})
|
||||
try {
|
||||
await server.start()
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
} catch (error) {
|
||||
console.log('Error starting server')
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -8,32 +8,32 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = new Koa()
|
||||
const router = new Router()
|
||||
.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('/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('/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
|
||||
})
|
||||
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(async (ctx, next) => {
|
||||
ctx.res.statusCode = 200
|
||||
await next()
|
||||
})
|
||||
|
||||
server.use(router.routes())
|
||||
server.listen(port, () => {
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
server.use(router.routes())
|
||||
server.listen(port, () => {
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,21 +8,21 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const { pathname, query } = parsedUrl
|
||||
.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)
|
||||
}
|
||||
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}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0"
|
||||
"react-dom": "^16.2.0",
|
||||
"@zeit/next-typescript": "0.0.11",
|
||||
"typescript": "^2.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/next": "^2.4.7",
|
||||
"@types/react": "^16.0.36",
|
||||
"@zeit/next-typescript": "^0.0.8",
|
||||
"nodemon": "^1.12.1",
|
||||
"ts-node": "^4.1.0",
|
||||
"typescript": "^2.7.1"
|
||||
"ts-node": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,21 +8,21 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const { pathname, query } = parsedUrl
|
||||
.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)
|
||||
}
|
||||
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}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -6,23 +6,23 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
server.get('/', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
server.get('/', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(3000, (err) => {
|
||||
if (err) throw err
|
||||
console.log('> Ready on http://localhost:3000')
|
||||
server.listen(3000, (err) => {
|
||||
if (err) throw err
|
||||
console.log('> Ready on http://localhost:3000')
|
||||
})
|
||||
})
|
||||
.catch((ex) => {
|
||||
console.error(ex.stack)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
.catch((ex) => {
|
||||
console.error(ex.stack)
|
||||
process.exit(1)
|
||||
})
|
||||
|
|
|
@ -11,21 +11,21 @@ const route = pathMatch()
|
|||
const match = route('/blog/:id')
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const { pathname, query } = parse(req.url, true)
|
||||
const params = match(pathname)
|
||||
if (params === false) {
|
||||
handle(req, res)
|
||||
return
|
||||
}
|
||||
// assigning `query` into the params means that we still
|
||||
// get the query string passed to our application
|
||||
// i.e. /blog/foo?show-comments=true
|
||||
app.render(req, res, '/blog', Object.assign(params, query))
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const { pathname, query } = parse(req.url, true)
|
||||
const params = match(pathname)
|
||||
if (params === false) {
|
||||
handle(req, res)
|
||||
return
|
||||
}
|
||||
// assigning `query` into the params means that we still
|
||||
// get the query string passed to our application
|
||||
// i.e. /blog/foo?show-comments=true
|
||||
app.render(req, res, '/blog', Object.assign(params, query))
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -9,23 +9,23 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const rootStaticFiles = [
|
||||
'/robots.txt',
|
||||
'/sitemap.xml',
|
||||
'/favicon.ico'
|
||||
]
|
||||
if (rootStaticFiles.indexOf(parsedUrl.pathname) > -1) {
|
||||
const path = join(__dirname, 'static', parsedUrl.pathname)
|
||||
app.serveStatic(req, res, path)
|
||||
} else {
|
||||
handle(req, res, parsedUrl)
|
||||
}
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const rootStaticFiles = [
|
||||
'/robots.txt',
|
||||
'/sitemap.xml',
|
||||
'/favicon.ico'
|
||||
]
|
||||
if (rootStaticFiles.indexOf(parsedUrl.pathname) > -1) {
|
||||
const path = join(__dirname, 'static', parsedUrl.pathname)
|
||||
app.serveStatic(req, res, path)
|
||||
} else {
|
||||
handle(req, res, parsedUrl)
|
||||
}
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -14,28 +14,28 @@ const ssrCache = new LRUCache({
|
|||
})
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
// Use the `renderAndCache` utility defined below to serve pages
|
||||
server.get('/', (req, res) => {
|
||||
renderAndCache(req, res, '/')
|
||||
})
|
||||
// Use the `renderAndCache` utility defined below to serve pages
|
||||
server.get('/', (req, res) => {
|
||||
renderAndCache(req, res, '/')
|
||||
})
|
||||
|
||||
server.get('/blog/:id', (req, res) => {
|
||||
const queryParams = { id: req.params.id }
|
||||
renderAndCache(req, res, '/blog', queryParams)
|
||||
})
|
||||
server.get('/blog/:id', (req, res) => {
|
||||
const queryParams = { id: req.params.id }
|
||||
renderAndCache(req, res, '/blog', queryParams)
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
* NB: make sure to modify this to take into account anything that should trigger
|
||||
|
|
|
@ -18,13 +18,13 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -17,13 +17,13 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -11,13 +11,13 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
handle(req, res, parsedUrl)
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable */
|
||||
const withCss = require('@zeit/next-css')
|
||||
|
||||
// fix: prevents error when .css files are required by node
|
||||
|
|
|
@ -49,3 +49,6 @@ export default withReduxSaga(connect(mapStateToProps, null)(Index));
|
|||
```
|
||||
|
||||
`connect` must go inside `withReduxSaga` otherwise `connect` will not be able to find the store.
|
||||
|
||||
### Note:
|
||||
In these *with-apollo* examples, the ```withData()``` HOC must wrap a top-level component from within the ```pages``` directory. Wrapping a child component with the HOC will result in a ```Warning: Failed prop type: The prop 'serverState' is marked as required in 'WithData(Apollo(Component))', but its value is 'undefined'``` error. Down-tree child components will have access to Apollo, and can be wrapped with any other sort of ```graphql()```, ```compose()```, etc HOC's.
|
||||
|
|
|
@ -48,4 +48,7 @@ const mapStateToProps = state => ({
|
|||
});
|
||||
|
||||
export default withRedux(connect(mapStateToProps, null)(Index));
|
||||
```
|
||||
```
|
||||
|
||||
### Note:
|
||||
In these *with-apollo* examples, the ```withData()``` HOC must wrap a top-level component from within the ```pages``` directory. Wrapping a child component with the HOC will result in a ```Warning: Failed prop type: The prop 'serverState' is marked as required in 'WithData(Apollo(Component))', but its value is 'undefined'``` error. Down-tree child components will have access to Apollo, and can be wrapped with any other sort of ```graphql()```, ```compose()```, etc HOC's.
|
||||
|
|
|
@ -66,3 +66,7 @@ It is important to note the use of Apollo's `resetStore()` method after signing
|
|||
|
||||
To get this example running locally, you will need to create a graph.cool
|
||||
account, and provide [the `project.graphcool` schema](https://github.com/zeit/next.js/blob/master/examples/with-apollo-auth/project.graphcool).
|
||||
|
||||
|
||||
### Note:
|
||||
In these *with-apollo* examples, the ```withData()``` HOC must wrap a top-level component from within the ```pages``` directory. Wrapping a child component with the HOC will result in a ```Warning: Failed prop type: The prop 'serverState' is marked as required in 'WithData(Apollo(Component))', but its value is 'undefined'``` error. Down-tree child components will have access to Apollo, and can be wrapped with any other sort of ```graphql()```, ```compose()```, etc HOC's.
|
||||
|
|
|
@ -48,3 +48,6 @@ In this simple example, we integrate Apollo seamlessly with Next by wrapping our
|
|||
On initial page load, while on the server and inside `getInitialProps`, we invoke the Apollo method, [`getDataFromTree`](http://dev.apollodata.com/react/server-side-rendering.html#getDataFromTree). This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.
|
||||
|
||||
This example relies on [graph.cool](https://www.graph.cool) for its GraphQL backend.
|
||||
|
||||
### Note:
|
||||
In these *with-apollo* examples, the ```withData()``` HOC must wrap a top-level component from within the ```pages``` directory. Wrapping a child component with the HOC will result in a ```Warning: Failed prop type: The prop 'serverState' is marked as required in 'WithData(Apollo(Component))', but its value is 'undefined'``` error. Down-tree child components will have access to Apollo, and can be wrapped with any other sort of ```graphql()```, ```compose()```, etc HOC's.
|
||||
|
|
|
@ -32,9 +32,16 @@ export default ComposedComponent => {
|
|||
// and extract the resulting data
|
||||
const apollo = initApollo()
|
||||
try {
|
||||
// create the url prop which is passed to every page
|
||||
const url = {
|
||||
query: ctx.query,
|
||||
asPath: ctx.asPath,
|
||||
pathname: ctx.pathname,
|
||||
};
|
||||
|
||||
// Run all GraphQL queries
|
||||
await getDataFromTree(
|
||||
<ComposedComponent ctx={ctx} {...composedInitialProps} />,
|
||||
<ComposedComponent ctx={ctx} url={url} {...composedInitialProps} />,
|
||||
{
|
||||
router: {
|
||||
asPath: ctx.asPath,
|
||||
|
|
|
@ -10,24 +10,24 @@ export default connect({
|
|||
mounted: signal`clock.mounted`,
|
||||
unMounted: signal`clock.unMounted`
|
||||
},
|
||||
class Page extends React.Component {
|
||||
componentDidMount () {
|
||||
this.props.mounted()
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.unMounted()
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<h1>{this.props.title}</h1>
|
||||
<Clock lastUpdate={this.props.lastUpdate} light={this.props.light} />
|
||||
<nav>
|
||||
<Link href={this.props.linkTo}><a>Navigate</a></Link>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
class Page extends React.Component {
|
||||
componentDidMount () {
|
||||
this.props.mounted()
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.unMounted()
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<h1>{this.props.title}</h1>
|
||||
<Clock lastUpdate={this.props.lastUpdate} light={this.props.light} />
|
||||
<nav>
|
||||
<Link href={this.props.linkTo}><a>Navigate</a></Link>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
RichUtils,
|
||||
convertToRaw,
|
||||
convertFromRaw
|
||||
} from 'draft-js'
|
||||
} from 'draft-js'
|
||||
|
||||
export default class App extends React.Component {
|
||||
constructor (props) {
|
||||
|
@ -62,7 +62,7 @@ export default class App extends React.Component {
|
|||
setSelectionXY = () => {
|
||||
var r = window.getSelection().getRangeAt(0).getBoundingClientRect()
|
||||
var relative = document.body.parentNode.getBoundingClientRect()
|
||||
// 2-a Set the selection coordinates in the state
|
||||
// 2-a Set the selection coordinates in the state
|
||||
this.setState({
|
||||
selectionCoordinates: r,
|
||||
windowWidth: relative.width,
|
||||
|
@ -176,7 +176,7 @@ export default class App extends React.Component {
|
|||
this.elemHeight = elem ? elem.clientHeight : 0
|
||||
}}
|
||||
style={toolbarStyle}
|
||||
>
|
||||
>
|
||||
<ToolBar
|
||||
editorState={editorState}
|
||||
onToggle={this.toggleToolbar}
|
||||
|
@ -261,8 +261,8 @@ const ToolBar = (props) => {
|
|||
label={toolbarItem.label}
|
||||
onToggle={props.onToggle}
|
||||
style={toolbarItem.style}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = {
|
||||
// TODO firebase client config
|
||||
// TODO firebase client config
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = {
|
||||
// TODO firebase server config
|
||||
// TODO firebase server config
|
||||
}
|
||||
|
|
|
@ -90,8 +90,8 @@ export default class Index extends Component {
|
|||
return <div>
|
||||
{
|
||||
user
|
||||
? <button onClick={this.handleLogout}>Logout</button>
|
||||
: <button onClick={this.handleLogin}>Login</button>
|
||||
? <button onClick={this.handleLogout}>Logout</button>
|
||||
: <button onClick={this.handleLogin}>Login</button>
|
||||
}
|
||||
{
|
||||
user &&
|
||||
|
|
|
@ -16,49 +16,49 @@ const firebase = admin.initializeApp({
|
|||
}, 'server')
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
server.use(bodyParser.json())
|
||||
server.use(session({
|
||||
secret: 'geheimnis',
|
||||
saveUninitialized: true,
|
||||
store: new FileStore({path: '/tmp/sessions', secret: 'geheimnis'}),
|
||||
resave: false,
|
||||
rolling: true,
|
||||
httpOnly: true,
|
||||
cookie: { maxAge: 604800000 } // week
|
||||
}))
|
||||
server.use(bodyParser.json())
|
||||
server.use(session({
|
||||
secret: 'geheimnis',
|
||||
saveUninitialized: true,
|
||||
store: new FileStore({path: '/tmp/sessions', secret: 'geheimnis'}),
|
||||
resave: false,
|
||||
rolling: true,
|
||||
httpOnly: true,
|
||||
cookie: { maxAge: 604800000 } // week
|
||||
}))
|
||||
|
||||
server.use((req, res, next) => {
|
||||
req.firebaseServer = firebase
|
||||
next()
|
||||
server.use((req, res, next) => {
|
||||
req.firebaseServer = firebase
|
||||
next()
|
||||
})
|
||||
|
||||
server.post('/api/login', (req, res) => {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
|
||||
const token = req.body.token
|
||||
firebase.auth().verifyIdToken(token)
|
||||
.then((decodedToken) => {
|
||||
req.session.decodedToken = decodedToken
|
||||
return decodedToken
|
||||
})
|
||||
.then((decodedToken) => res.json({ status: true, decodedToken }))
|
||||
.catch((error) => res.json({ error }))
|
||||
})
|
||||
|
||||
server.post('/api/logout', (req, res) => {
|
||||
req.session.decodedToken = null
|
||||
res.json({ status: true })
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
||||
server.post('/api/login', (req, res) => {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
|
||||
const token = req.body.token
|
||||
firebase.auth().verifyIdToken(token)
|
||||
.then((decodedToken) => {
|
||||
req.session.decodedToken = decodedToken
|
||||
return decodedToken
|
||||
})
|
||||
.then((decodedToken) => res.json({ status: true, decodedToken }))
|
||||
.catch((error) => res.json({ error }))
|
||||
})
|
||||
|
||||
server.post('/api/logout', (req, res) => {
|
||||
req.session.decodedToken = null
|
||||
res.json({ status: true })
|
||||
})
|
||||
|
||||
server.get('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -11,12 +11,12 @@ module.exports = {
|
|||
name: 'dist/[path][name].[ext]'
|
||||
}
|
||||
}
|
||||
,
|
||||
,
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['babel-loader', 'raw-loader', 'postcss-loader']
|
||||
}
|
||||
,
|
||||
,
|
||||
{
|
||||
test: /\.s(a|c)ss$/,
|
||||
use: ['babel-loader', 'raw-loader', 'postcss-loader',
|
||||
|
|
41
examples/with-google-analytics/README.md
Normal file
41
examples/with-google-analytics/README.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-google-analytics)
|
||||
|
||||
# Example app with analytics
|
||||
|
||||
## How to use
|
||||
|
||||
### Using `create-next-app`
|
||||
|
||||
Download [`create-next-app`](https://github.com/segmentio/create-next-app) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-google-analytics with-google-analytics-app
|
||||
# or
|
||||
yarn create next-app --example with-google-analytics with-google-analytics-app
|
||||
```
|
||||
|
||||
### Download manually
|
||||
|
||||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-google-analytics
|
||||
cd with-google-analytics
|
||||
```
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
yarn
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
## The idea behind the example
|
||||
|
||||
This example shows how to use [Next.js](https://github.com/zeit/next.js) along with [Google Analytics](https://developers.google.com/analytics/devguides/collection/gtagjs/). A custom [\_document](https://github.com/zeit/next.js/#custom-document) is used to inject [tracking snippet](https://developers.google.com/analytics/devguides/collection/gtagjs/) and track [pageviews](https://developers.google.com/analytics/devguides/collection/gtagjs/pages) and [event](https://developers.google.com/analytics/devguides/collection/gtagjs/events).
|
26
examples/with-google-analytics/components/Header.js
Normal file
26
examples/with-google-analytics/components/Header.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default () => (
|
||||
<header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<Link href='/'>
|
||||
<a>Home</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href='/about'>
|
||||
<a>About</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href='/contact'>
|
||||
<a>Contact</a>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
16
examples/with-google-analytics/components/Page.js
Normal file
16
examples/with-google-analytics/components/Page.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
import Router from 'next/router'
|
||||
import Header from './Header'
|
||||
|
||||
import * as gtag from '../lib/gtag'
|
||||
|
||||
Router.onRouteChangeComplete = url => {
|
||||
gtag.pageview(url)
|
||||
}
|
||||
|
||||
export default ({ children }) => (
|
||||
<div>
|
||||
<Header />
|
||||
{children}
|
||||
</div>
|
||||
)
|
17
examples/with-google-analytics/lib/gtag.js
Normal file
17
examples/with-google-analytics/lib/gtag.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
export const GA_TRACKING_ID = '<YOUR_GA_TRACKING_ID>'
|
||||
|
||||
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
|
||||
export const pageview = url => {
|
||||
window.gtag('config', GA_TRACKING_ID, {
|
||||
page_location: url,
|
||||
})
|
||||
}
|
||||
|
||||
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
|
||||
export const event = ({ action, category, label, value }) => {
|
||||
window.gtag('event', action, {
|
||||
event_category: category,
|
||||
event_label: label,
|
||||
value: value,
|
||||
})
|
||||
}
|
13
examples/with-google-analytics/package.json
Normal file
13
examples/with-google-analytics/package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "with-google-analytics",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0"
|
||||
}
|
||||
}
|
41
examples/with-google-analytics/pages/_document.js
Normal file
41
examples/with-google-analytics/pages/_document.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import React from 'react'
|
||||
import Document, { Head, Main, NextScript } from 'next/document'
|
||||
import flush from 'styled-jsx/server'
|
||||
|
||||
import { GA_TRACKING_ID } from '../lib/gtag'
|
||||
|
||||
export default class extends Document {
|
||||
static getInitialProps ({ renderPage }) {
|
||||
const { html, head, errorHtml, chunks } = renderPage()
|
||||
const styles = flush()
|
||||
return { html, head, errorHtml, chunks, styles }
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<html>
|
||||
<Head>
|
||||
{/* Global Site Tag (gtag.js) - Google Analytics */}
|
||||
<script
|
||||
async
|
||||
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
|
||||
/>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '${GA_TRACKING_ID}');
|
||||
`}}
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
}
|
8
examples/with-google-analytics/pages/about.js
Normal file
8
examples/with-google-analytics/pages/about.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import Page from '../components/Page'
|
||||
|
||||
export default () => (
|
||||
<Page>
|
||||
<h1>This is the About page</h1>
|
||||
</Page>
|
||||
)
|
39
examples/with-google-analytics/pages/contact.js
Normal file
39
examples/with-google-analytics/pages/contact.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import React, { Component } from 'react'
|
||||
import Page from '../components/Page'
|
||||
|
||||
import * as gtag from '../lib/gtag'
|
||||
|
||||
export default class extends Component {
|
||||
state = { message: '' }
|
||||
|
||||
handleInput = e => {
|
||||
this.setState({ message: e.target.value })
|
||||
}
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault()
|
||||
|
||||
gtag.event({
|
||||
action: 'submit_form',
|
||||
category: 'Contact',
|
||||
label: this.state.message
|
||||
})
|
||||
|
||||
this.setState({ message: '' })
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<Page>
|
||||
<h1>This is the Contact page</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<label>
|
||||
<span>Message:</span>
|
||||
<textarea onInput={this.handleInput} value={this.state.message} />
|
||||
</label>
|
||||
<button type='submit'>submit</button>
|
||||
</form>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
}
|
8
examples/with-google-analytics/pages/index.js
Normal file
8
examples/with-google-analytics/pages/index.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import Page from '../components/Page'
|
||||
|
||||
export default () => (
|
||||
<Page>
|
||||
<h1>This is the Home page</h1>
|
||||
</Page>
|
||||
)
|
|
@ -8,10 +8,10 @@ const app = next({ dev })
|
|||
const handler = routes.getRequestHandler(app)
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer(handler)
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
.then(() => {
|
||||
createServer(handler)
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,10 +8,10 @@ const app = next({ dev })
|
|||
const handler = routes.getRequestHandler(app)
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer(handler)
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
.then(() => {
|
||||
createServer(handler)
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
43
examples/with-now-env/README.md
Normal file
43
examples/with-now-env/README.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-now-env)
|
||||
|
||||
# Now-env example
|
||||
|
||||
## How to use
|
||||
|
||||
### Using `create-next-app`
|
||||
|
||||
Download [`create-next-app`](https://github.com/segmentio/create-next-app) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-now-env with-now-env-app
|
||||
# or
|
||||
yarn create next-app --example with-now-env with-now-env-app
|
||||
```
|
||||
|
||||
### Download manually
|
||||
|
||||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-now-env
|
||||
cd with-now-env
|
||||
```
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
keep in mind that in order to deploy the app to `now` the env [secrets](https://zeit.co/docs/getting-started/secrets) defined in `now.json` should be listed in your account
|
||||
|
||||
## The idea behind the example
|
||||
|
||||
This example shows the usage of [now-env](https://github.com/zeit/now-env), it allows to use secrets in development that will be replaced in production by the secrets defined with [now](https://zeit.co/docs/getting-started/secrets)
|
27
examples/with-now-env/next.config.js
Normal file
27
examples/with-now-env/next.config.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* After the next require you can use process.env to get your secrets
|
||||
*/
|
||||
require('now-env')
|
||||
|
||||
console.log({
|
||||
SECRET: process.env.SECRET,
|
||||
ANOTHER_SECRET: process.env.ANOTHER_SECRET,
|
||||
SECRET_FAIL: process.env.SECRET_FAIL
|
||||
})
|
||||
|
||||
/**
|
||||
* If some of the envs are public, like a google maps key, but you still
|
||||
* want to keep them secret from the repo, the following code will allow you
|
||||
* to share some variables with the client, configured at compile time.
|
||||
*/
|
||||
module.exports = {
|
||||
webpack: config => {
|
||||
config.plugins.forEach(plugin => {
|
||||
if (plugin.constructor.name === 'DefinePlugin') {
|
||||
plugin.definitions['process.env.SECRET'] = JSON.stringify(process.env.SECRET)
|
||||
}
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
}
|
4
examples/with-now-env/now-secrets.json
Normal file
4
examples/with-now-env/now-secrets.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"@my-secret-key": "keep-it-secret",
|
||||
"@my-other-secret-key": "keep-it-secret-too"
|
||||
}
|
7
examples/with-now-env/now.json
Normal file
7
examples/with-now-env/now.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"env": {
|
||||
"SECRET": "@my-secret-key",
|
||||
"ANOTHER_SECRET": "@my-other-secret-key",
|
||||
"SECRET_FAIL": "@this-is-not-defined"
|
||||
}
|
||||
}
|
17
examples/with-now-env/package.json
Normal file
17
examples/with-now-env/package.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "with-now-env",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"now-env": "^3.0.4"
|
||||
}
|
||||
}
|
22
examples/with-now-env/pages/index.js
Normal file
22
examples/with-now-env/pages/index.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
export default () => (
|
||||
<div className='hello'>
|
||||
<p>
|
||||
Hello World! Here's a secret shared with the client using webpack
|
||||
DefinePlugin: <strong>{process.env.SECRET}</strong>, the secret is shared
|
||||
at compile time, which means every reference to the secret is replaced
|
||||
with its value
|
||||
</p>
|
||||
<style jsx>{`
|
||||
.hello {
|
||||
font: 15px Helvetica, Arial, sans-serif;
|
||||
background: #eee;
|
||||
padding: 100px;
|
||||
text-align: center;
|
||||
transition: 100ms ease-in background;
|
||||
}
|
||||
.hello:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
|
@ -8,10 +8,10 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => handle(req, res, parse(req.url, true).pathname))
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
.then(() => {
|
||||
createServer((req, res) => handle(req, res, parse(req.url, true).pathname))
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
/* eslint no-extend-native: 0 */
|
||||
|
||||
// Add your polyfills
|
||||
// This files runs at the very beginning (even before React and Next.js core)
|
||||
|
||||
console.log('Load your polyfills')
|
||||
|
||||
// core-js comes with Next.js. So, you can import it like below
|
||||
import includes from 'core-js/library/fn/string/virtual/includes'
|
||||
import repeat from 'core-js/library/fn/string/virtual/repeat'
|
||||
|
||||
// Add your polyfills
|
||||
// This files runs at the very beginning (even before React and Next.js core)
|
||||
console.log('Load your polyfills')
|
||||
|
||||
String.prototype.includes = includes
|
||||
String.prototype.repeat = repeat
|
||||
|
|
|
@ -8,13 +8,13 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
Router.forEachPattern((page, pattern, defaultParams) => server.get(pattern, (req, res) =>
|
||||
app.render(req, res, `/${page}`, Object.assign({}, defaultParams, req.query, req.params))
|
||||
))
|
||||
Router.forEachPattern((page, pattern, defaultParams) => server.get(pattern, (req, res) =>
|
||||
app.render(req, res, `/${page}`, Object.assign({}, defaultParams, req.query, req.params))
|
||||
))
|
||||
|
||||
server.get('*', (req, res) => handle(req, res))
|
||||
server.listen(port)
|
||||
})
|
||||
server.get('*', (req, res) => handle(req, res))
|
||||
server.listen(port)
|
||||
})
|
||||
|
|
|
@ -22,8 +22,8 @@ export default class extends Document {
|
|||
// should render on <head>
|
||||
get helmetHeadComponents () {
|
||||
return Object.keys(this.props.helmet)
|
||||
.filter(el => el !== 'htmlAttributes' && el !== 'bodyAttributes')
|
||||
.map(el => this.props.helmet[el].toComponent())
|
||||
.filter(el => el !== 'htmlAttributes' && el !== 'bodyAttributes')
|
||||
.map(el => this.props.helmet[el].toComponent())
|
||||
}
|
||||
|
||||
get helmetJsx () {
|
||||
|
|
|
@ -39,5 +39,5 @@ export default connect(
|
|||
character: state.character,
|
||||
error: state.error,
|
||||
isFetchedOnServer: state.isFetchedOnServer
|
||||
}),
|
||||
})
|
||||
)(CharacterInfo)
|
||||
|
|
|
@ -46,5 +46,5 @@ export default withRedux(
|
|||
{
|
||||
startFetchingCharacters: actions.startFetchingCharacters,
|
||||
stopFetchingCharacters: actions.stopFetchingCharacters
|
||||
},
|
||||
}
|
||||
)(Counter)
|
||||
|
|
|
@ -7,7 +7,7 @@ import { rootEpic } from './epics'
|
|||
|
||||
export default function initStore (initialState) {
|
||||
const epicMiddleware = createEpicMiddleware(rootEpic)
|
||||
const logger = createLogger({ collapsed: true }) // log every action to see what's happening behind the scenes.
|
||||
const logger = createLogger({ collapsed: true }) // log every action to see what's happening behind the scenes.
|
||||
const reduxMiddleware = applyMiddleware(thunkMiddleware, epicMiddleware, logger)
|
||||
|
||||
return createStore(reducer, initialState, reduxMiddleware)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-analytics)
|
||||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-segment-analytics)
|
||||
|
||||
# Example app with analytics
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
|||
Download [`create-next-app`](https://github.com/segmentio/create-next-app) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-analytics with-analytics-app
|
||||
npx create-next-app --example with-segment-analytics with-segment-analytics-app
|
||||
# or
|
||||
yarn create next-app --example with-analytics with-analytics-app
|
||||
yarn create next-app --example with-segment-analytics with-segment-analytics-app
|
||||
```
|
||||
|
||||
### Download manually
|
||||
|
@ -19,8 +19,8 @@ yarn create next-app --example with-analytics with-analytics-app
|
|||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-analytics
|
||||
cd with-analytics
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-segment-analytics
|
||||
cd with-segment-analytics
|
||||
```
|
||||
|
||||
Install it and run:
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "with-analytics",
|
||||
"name": "with-segment-analytics",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
|
@ -15,7 +15,7 @@ module.exports = {
|
|||
query: { id: post.id }
|
||||
}
|
||||
}),
|
||||
{},
|
||||
{}
|
||||
)
|
||||
|
||||
// combine the map of post pages with the home
|
||||
|
|
|
@ -7,22 +7,22 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
.then(() => {
|
||||
const server = express()
|
||||
|
||||
// custom route for posts
|
||||
server.get('/post/:id', (req, res) => {
|
||||
return app.render(req, res, '/post', {
|
||||
id: req.params.id
|
||||
// custom route for posts
|
||||
server.get('/post/:id', (req, res) => {
|
||||
return app.render(req, res, '/post', {
|
||||
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('*', (req, res) => {
|
||||
return handle(req, res)
|
||||
})
|
||||
|
||||
server.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -9,20 +9,20 @@ const app = next({ dev })
|
|||
const handle = app.getRequestHandler()
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const { pathname } = parsedUrl
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const { pathname } = parsedUrl
|
||||
|
||||
if (pathname === '/service-worker.js') {
|
||||
const filePath = join(__dirname, '.next', pathname)
|
||||
app.serveStatic(req, res, filePath)
|
||||
} else {
|
||||
handle(req, res, parsedUrl)
|
||||
}
|
||||
if (pathname === '/service-worker.js') {
|
||||
const filePath = join(__dirname, '.next', pathname)
|
||||
app.serveStatic(req, res, filePath)
|
||||
} else {
|
||||
handle(req, res, parsedUrl)
|
||||
}
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -244,15 +244,15 @@ module.exports = {
|
|||
*/
|
||||
|
||||
textSizes: {
|
||||
'xs': '.75rem', // 12px
|
||||
'sm': '.875rem', // 14px
|
||||
'base': '1rem', // 16px
|
||||
'lg': '1.125rem', // 18px
|
||||
'xl': '1.25rem', // 20px
|
||||
'2xl': '1.5rem', // 24px
|
||||
'3xl': '1.875rem', // 30px
|
||||
'4xl': '2.25rem', // 36px
|
||||
'5xl': '3rem' // 48px
|
||||
'xs': '.75rem', // 12px
|
||||
'sm': '.875rem', // 14px
|
||||
'base': '1rem', // 16px
|
||||
'lg': '1.125rem', // 18px
|
||||
'xl': '1.25rem', // 20px
|
||||
'2xl': '1.5rem', // 24px
|
||||
'3xl': '1.875rem', // 30px
|
||||
'4xl': '2.25rem', // 36px
|
||||
'5xl': '3rem' // 48px
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"devDependencies": {
|
||||
"@types/next": "^2.4.7",
|
||||
"@types/react": "^16.0.36",
|
||||
"@zeit/next-typescript": "0.0.8",
|
||||
"@zeit/next-typescript": "0.0.11",
|
||||
"typescript": "^2.7.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ const {API_URL} = env
|
|||
|
||||
export default class extends React.Component {
|
||||
static async getInitialProps () {
|
||||
// fetch(`${API_URL}/some-path`)
|
||||
// fetch(`${API_URL}/some-path`)
|
||||
return {}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,19 +11,19 @@ const route = pathMatch()
|
|||
const match = route('/about/:name')
|
||||
|
||||
app.prepare()
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const { pathname } = parse(req.url)
|
||||
const params = match(pathname)
|
||||
if (params === false) {
|
||||
handle(req, res)
|
||||
return
|
||||
}
|
||||
.then(() => {
|
||||
createServer((req, res) => {
|
||||
const { pathname } = parse(req.url)
|
||||
const params = match(pathname)
|
||||
if (params === false) {
|
||||
handle(req, res)
|
||||
return
|
||||
}
|
||||
|
||||
app.render(req, res, '/about', params)
|
||||
app.render(req, res, '/about', params)
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
.listen(port, (err) => {
|
||||
if (err) throw err
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -15,7 +15,7 @@ export default class EventEmitter {
|
|||
|
||||
emit (event, ...data) {
|
||||
if (!this.listeners[event]) return
|
||||
this.listeners[event].forEach(cb => cb(...data))
|
||||
this.listeners[event].forEach(cb => cb(...data)) // eslint-disable-line standard/no-callback-literal
|
||||
}
|
||||
|
||||
off (event, cb) {
|
||||
|
|
|
@ -2,3 +2,4 @@ export const PHASE_EXPORT = 'phase-export'
|
|||
export const PHASE_PRODUCTION_BUILD = 'phase-production-build'
|
||||
export const PHASE_PRODUCTION_SERVER = 'phase-production-server'
|
||||
export const PHASE_DEVELOPMENT_SERVER = 'phase-development-server'
|
||||
export const PAGES_MANIFEST = 'pages-manifest.json'
|
||||
|
|
|
@ -10,8 +10,8 @@ export default ({ error, error: { name, message, module } }) => (
|
|||
{module ? <h1 style={styles.heading}>Error in {module.rawRequest}</h1> : null}
|
||||
{
|
||||
name === 'ModuleBuildError'
|
||||
? <pre style={styles.stack} dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} />
|
||||
: <StackTrace error={error} />
|
||||
? <pre style={styles.stack} dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} />
|
||||
: <StackTrace error={error} />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
|
36
lib/head.js
36
lib/head.js
|
@ -18,24 +18,24 @@ export function defaultHead () {
|
|||
|
||||
function reduceComponents (components) {
|
||||
return components
|
||||
.map((c) => c.props.children)
|
||||
.map((children) => React.Children.toArray(children))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.reduce((a, b) => {
|
||||
if (React.Fragment && b.type === React.Fragment) {
|
||||
return a.concat(React.Children.toArray(b.props.children))
|
||||
}
|
||||
return a.concat(b)
|
||||
}, [])
|
||||
.reverse()
|
||||
.concat(...defaultHead())
|
||||
.filter((c) => !!c)
|
||||
.filter(unique())
|
||||
.reverse()
|
||||
.map((c) => {
|
||||
const className = (c.props && c.props.className ? c.props.className + ' ' : '') + 'next-head'
|
||||
return React.cloneElement(c, { className })
|
||||
})
|
||||
.map((c) => c.props.children)
|
||||
.map((children) => React.Children.toArray(children))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.reduce((a, b) => {
|
||||
if (React.Fragment && b.type === React.Fragment) {
|
||||
return a.concat(React.Children.toArray(b.props.children))
|
||||
}
|
||||
return a.concat(b)
|
||||
}, [])
|
||||
.reverse()
|
||||
.concat(...defaultHead())
|
||||
.filter((c) => !!c)
|
||||
.filter(unique())
|
||||
.reverse()
|
||||
.map((c) => {
|
||||
const className = (c.props && c.props.className ? c.props.className + ' ' : '') + 'next-head'
|
||||
return React.cloneElement(c, { className })
|
||||
})
|
||||
}
|
||||
|
||||
function mapOnServer (head) {
|
||||
|
|
|
@ -355,7 +355,7 @@ export default class Router {
|
|||
}
|
||||
|
||||
async fetchRoute (route) {
|
||||
return await this.pageLoader.loadPage(route)
|
||||
return this.pageLoader.loadPage(route)
|
||||
}
|
||||
|
||||
abortComponentLoad (as) {
|
||||
|
|
|
@ -113,11 +113,12 @@
|
|||
"@taskr/esnext": "1.1.0",
|
||||
"@taskr/watch": "1.1.0",
|
||||
"@zeit/next-css": "0.0.7",
|
||||
"babel-eslint": "8.0.1",
|
||||
"babel-eslint": "8.2.2",
|
||||
"babel-jest": "21.2.0",
|
||||
"babel-plugin-istanbul": "4.1.5",
|
||||
"babel-plugin-transform-remove-strict-mode": "0.0.2",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-preset-flow": "6.23.0",
|
||||
"benchmark": "2.1.4",
|
||||
"cheerio": "0.22.0",
|
||||
"chromedriver": "2.32.3",
|
||||
|
@ -139,7 +140,7 @@
|
|||
"react": "16.2.0",
|
||||
"react-dom": "16.2.0",
|
||||
"rimraf": "2.6.2",
|
||||
"standard": "9.0.2",
|
||||
"standard": "11.0.1",
|
||||
"taskr": "1.1.0",
|
||||
"wd": "1.4.1"
|
||||
},
|
||||
|
|
|
@ -1012,7 +1012,7 @@ module.exports = {
|
|||
Or use a function:
|
||||
|
||||
```js
|
||||
module.exports = (phase, {defaultConfig}){
|
||||
module.exports = (phase, {defaultConfig}) => {
|
||||
//
|
||||
// https://github.com/zeit/
|
||||
return {
|
||||
|
@ -1185,6 +1185,7 @@ module.exports = {
|
|||
```js
|
||||
// pages/index.js
|
||||
import getConfig from 'next/config'
|
||||
// Only holds serverRuntimeConfig and publicRuntimeConfig from next.config.js nothing else.
|
||||
const {serverRuntimeConfig, publicRuntimeConfig} = getConfig()
|
||||
|
||||
console.log(serverRuntimeConfig.mySecret) // Will only be available on the server side
|
||||
|
@ -1258,7 +1259,7 @@ Simply develop your app as you normally do with Next.js. Then create a custom Ne
|
|||
```js
|
||||
// next.config.js
|
||||
module.exports = {
|
||||
exportPathMap: function() {
|
||||
exportPathMap: function(defaultPathMap) {
|
||||
return {
|
||||
'/': { page: '/' },
|
||||
'/about': { page: '/about' },
|
||||
|
|
|
@ -34,7 +34,7 @@ function getRoute (loaderContext) {
|
|||
const pagesDir = resolve(loaderContext.options.context, 'pages')
|
||||
const { resourcePath } = loaderContext
|
||||
const dir = [pagesDir, nextPagesDir]
|
||||
.find((d) => resourcePath.indexOf(d) === 0)
|
||||
.find((d) => resourcePath.indexOf(d) === 0)
|
||||
const path = relative(dir, resourcePath)
|
||||
return '/' + path.replace(/((^|\/)index)?\.js$/, '')
|
||||
}
|
||||
|
|
30
server/build/plugins/pages-manifest-plugin.js
Normal file
30
server/build/plugins/pages-manifest-plugin.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// @flow
|
||||
import { RawSource } from 'webpack-sources'
|
||||
import { MATCH_ROUTE_NAME } from '../../utils'
|
||||
import {PAGES_MANIFEST} from '../../../lib/constants'
|
||||
|
||||
// This plugin creates a pages-manifest.json from page entrypoints.
|
||||
// This is used for mapping paths like `/` to `.next/dist/bundles/pages/index.js` when doing SSR
|
||||
// It's also used by next export to provide defaultPathMap
|
||||
export default class PagesManifestPlugin {
|
||||
apply (compiler: any) {
|
||||
compiler.plugin('emit', (compilation, callback) => {
|
||||
const {entries} = compilation
|
||||
const pages = {}
|
||||
|
||||
for (const entry of entries) {
|
||||
const pagePath = MATCH_ROUTE_NAME.exec(entry.name)[1]
|
||||
|
||||
if (!pagePath) {
|
||||
continue
|
||||
}
|
||||
|
||||
const {name} = entry
|
||||
pages[`/${pagePath.replace(/\\/g, '/')}`] = name
|
||||
}
|
||||
|
||||
compilation.assets[PAGES_MANIFEST] = new RawSource(JSON.stringify(pages))
|
||||
callback()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -13,12 +13,12 @@ class PageChunkTemplatePlugin {
|
|||
|
||||
let routeName = MATCH_ROUTE_NAME.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.
|
||||
// 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, '/')
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class UnlinkFilePlugin {
|
|||
apply (compiler) {
|
||||
compiler.plugin('after-emit', (compilation, callback) => {
|
||||
const removed = Object.keys(this.prevAssets)
|
||||
.filter((a) => IS_BUNDLED_PAGE.test(a) && !compilation.assets[a])
|
||||
.filter((a) => IS_BUNDLED_PAGE.test(a) && !compilation.assets[a])
|
||||
|
||||
this.prevAssets = compilation.assets
|
||||
|
||||
|
@ -23,7 +23,7 @@ export default class UnlinkFilePlugin {
|
|||
throw err
|
||||
}
|
||||
}))
|
||||
.then(() => callback(), callback)
|
||||
.then(() => callback(), callback)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import PagesPlugin from './plugins/pages-plugin'
|
|||
import NextJsSsrImportPlugin from './plugins/nextjs-ssr-import'
|
||||
import DynamicChunksPlugin from './plugins/dynamic-chunks-plugin'
|
||||
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
|
||||
import PagesManifestPlugin from './plugins/pages-manifest-plugin'
|
||||
import findBabelConfig from './babel/find-config'
|
||||
|
||||
const nextDir = path.join(__dirname, '..', '..', '..')
|
||||
|
@ -254,6 +255,7 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production')
|
||||
}),
|
||||
!dev && new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
isServer && new PagesManifestPlugin(),
|
||||
!isServer && new PagesPlugin(),
|
||||
!isServer && new DynamicChunksPlugin(),
|
||||
isServer && new NextJsSsrImportPlugin(),
|
||||
|
|
|
@ -9,7 +9,7 @@ export async function getPages (dir, {dev, isServer, pageExtensions}) {
|
|||
return getPageEntries(pageFiles, {isServer, pageExtensions})
|
||||
}
|
||||
|
||||
async function getPagePaths (dir, {dev, isServer, pageExtensions}) {
|
||||
export async function getPagePaths (dir, {dev, isServer, pageExtensions}) {
|
||||
let pages
|
||||
|
||||
if (dev) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// @flow
|
||||
import findUp from 'find-up'
|
||||
|
||||
const cache = new Map()
|
||||
|
@ -11,28 +12,29 @@ const defaultConfig = {
|
|||
configOrigin: 'default',
|
||||
useFileSystemPublicRoutes: true,
|
||||
generateEtags: true,
|
||||
pageExtensions: ['jsx', 'js'] // jsx before js because otherwise regex matching will match js first
|
||||
pageExtensions: ['jsx', 'js']
|
||||
}
|
||||
|
||||
export default function getConfig (phase, dir, customConfig) {
|
||||
export default function getConfig (phase: string, dir: string, customConfig?: ?Object) {
|
||||
if (!cache.has(dir)) {
|
||||
cache.set(dir, loadConfig(phase, dir, customConfig))
|
||||
}
|
||||
return cache.get(dir)
|
||||
}
|
||||
|
||||
export function loadConfig (phase, dir, customConfig) {
|
||||
export function loadConfig (phase: string, dir: string, customConfig?: ?Object) {
|
||||
if (customConfig && typeof customConfig === 'object') {
|
||||
customConfig.configOrigin = 'server'
|
||||
return withDefaults(customConfig)
|
||||
}
|
||||
const path = findUp.sync('next.config.js', {
|
||||
const path: string = findUp.sync('next.config.js', {
|
||||
cwd: dir
|
||||
})
|
||||
|
||||
let userConfig = {}
|
||||
|
||||
if (path && path.length) {
|
||||
// $FlowFixMe
|
||||
const userConfigModule = require(path)
|
||||
userConfig = userConfigModule.default || userConfigModule
|
||||
if (typeof userConfigModule === 'function') {
|
||||
|
@ -44,6 +46,6 @@ export function loadConfig (phase, dir, customConfig) {
|
|||
return withDefaults(userConfig)
|
||||
}
|
||||
|
||||
function withDefaults (config) {
|
||||
function withDefaults (config: Object) {
|
||||
return Object.assign({}, defaultConfig, config)
|
||||
}
|
||||
|
|
|
@ -5,10 +5,9 @@ import walk from 'walk'
|
|||
import { extname, resolve, join, dirname, sep } from 'path'
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
||||
import getConfig from './config'
|
||||
import {PHASE_EXPORT} from '../lib/constants'
|
||||
import {PHASE_EXPORT, PAGES_MANIFEST} from '../lib/constants'
|
||||
import { renderToHTML } from './render'
|
||||
import { getAvailableChunks } from './utils'
|
||||
import { printAndExit } from '../lib/utils'
|
||||
import { setAssetPrefix } from '../lib/asset'
|
||||
import * as envConfig from '../lib/runtime-config'
|
||||
|
||||
|
@ -17,7 +16,7 @@ export default async function (dir, options, configuration) {
|
|||
const nextConfig = configuration || getConfig(PHASE_EXPORT, dir)
|
||||
const nextDir = join(dir, nextConfig.distDir)
|
||||
|
||||
log(` using build directory: ${nextDir}`)
|
||||
log(`> using build directory: ${nextDir}`)
|
||||
|
||||
if (!existsSync(nextDir)) {
|
||||
console.error(
|
||||
|
@ -27,6 +26,17 @@ export default async function (dir, options, configuration) {
|
|||
}
|
||||
|
||||
const buildId = readFileSync(join(nextDir, 'BUILD_ID'), 'utf8')
|
||||
const pagesManifest = require(join(nextDir, 'dist', PAGES_MANIFEST))
|
||||
|
||||
const pages = Object.keys(pagesManifest)
|
||||
const defaultPathMap = {}
|
||||
|
||||
for (const page of pages) {
|
||||
if (page === '/_document') {
|
||||
continue
|
||||
}
|
||||
defaultPathMap[page] = { page }
|
||||
}
|
||||
|
||||
// Initialize the output directory
|
||||
const outDir = options.outdir
|
||||
|
@ -73,13 +83,13 @@ export default async function (dir, options, configuration) {
|
|||
|
||||
// Get the exportPathMap from the `next.config.js`
|
||||
if (typeof nextConfig.exportPathMap !== 'function') {
|
||||
printAndExit(
|
||||
'> Could not find "exportPathMap" function inside "next.config.js"\n' +
|
||||
'> "next export" uses that function to build html pages.'
|
||||
)
|
||||
console.log('> No "exportPathMap" found in "next.config.js". Generating map from "./pages"')
|
||||
nextConfig.exportPathMap = async (defaultMap) => {
|
||||
return defaultMap
|
||||
}
|
||||
}
|
||||
|
||||
const exportPathMap = await nextConfig.exportPathMap()
|
||||
const exportPathMap = await nextConfig.exportPathMap(defaultPathMap)
|
||||
const exportPaths = Object.keys(exportPathMap)
|
||||
|
||||
// Start the rendering process
|
||||
|
@ -115,7 +125,7 @@ export default async function (dir, options, configuration) {
|
|||
}
|
||||
|
||||
for (const path of exportPaths) {
|
||||
log(` exporting path: ${path}`)
|
||||
log(`> exporting path: ${path}`)
|
||||
if (!path.startsWith('/')) {
|
||||
throw new Error(`path "${path}" doesn't start with a backslash`)
|
||||
}
|
||||
|
|
|
@ -149,11 +149,11 @@ export default class HotReloader {
|
|||
)
|
||||
|
||||
const failedChunkNames = new Set(compilation.errors
|
||||
.map((e) => e.module.reasons)
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.map((r) => r.module.chunks)
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.map((c) => c.name))
|
||||
.map((e) => e.module.reasons)
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.map((r) => r.module.chunks)
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
.map((c) => c.name))
|
||||
|
||||
const chunkHashes = new Map(
|
||||
compilation.chunks
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable import/first, no-return-await */
|
||||
require('@zeit/source-map-support').install()
|
||||
import { resolve, join, sep } from 'path'
|
||||
import { parse as parseUrl } from 'url'
|
||||
|
|
|
@ -198,15 +198,15 @@ function serializeError (dev, err) {
|
|||
export function serveStatic (req, res, path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
send(req, path)
|
||||
.on('directory', () => {
|
||||
.on('directory', () => {
|
||||
// We don't allow directories to be read.
|
||||
const err = new Error('No directory access')
|
||||
err.code = 'ENOENT'
|
||||
reject(err)
|
||||
})
|
||||
.on('error', reject)
|
||||
.pipe(res)
|
||||
.on('finish', resolve)
|
||||
const err = new Error('No directory access')
|
||||
err.code = 'ENOENT'
|
||||
reject(err)
|
||||
})
|
||||
.on('error', reject)
|
||||
.pipe(res)
|
||||
.on('finish', resolve)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {join, parse, normalize, sep} from 'path'
|
||||
import fs from 'mz/fs'
|
||||
import {join, posix} from 'path'
|
||||
import {PAGES_MANIFEST} from '../lib/constants'
|
||||
|
||||
export function pageNotFoundError (page) {
|
||||
const err = new Error(`Cannot find module for page: ${page}`)
|
||||
|
@ -18,13 +18,8 @@ export function normalizePagePath (page) {
|
|||
page = `/${page}`
|
||||
}
|
||||
|
||||
// Windows compatibility
|
||||
if (sep !== '/') {
|
||||
page = page.replace(/\//g, sep)
|
||||
}
|
||||
|
||||
// Throw when using ../ etc in the pathname
|
||||
const resolvedPage = normalize(page)
|
||||
const resolvedPage = posix.normalize(page)
|
||||
if (page !== resolvedPage) {
|
||||
throw new Error('Requested and resolved page mismatch')
|
||||
}
|
||||
|
@ -33,7 +28,8 @@ export function normalizePagePath (page) {
|
|||
}
|
||||
|
||||
export function getPagePath (page, {dir, dist}) {
|
||||
const pageBundlesPath = join(dir, dist, 'dist', 'bundles', 'pages')
|
||||
const serverBuildPath = join(dir, dist, 'dist')
|
||||
const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST))
|
||||
|
||||
try {
|
||||
page = normalizePagePath(page)
|
||||
|
@ -42,24 +38,14 @@ export function getPagePath (page, {dir, dist}) {
|
|||
throw pageNotFoundError(page)
|
||||
}
|
||||
|
||||
const pagePath = join(pageBundlesPath, page) // Path to the page that is to be loaded
|
||||
|
||||
// Don't allow wandering outside of the bundles directory
|
||||
const pathDir = parse(pagePath).dir
|
||||
if (pathDir.indexOf(pageBundlesPath) !== 0) {
|
||||
console.error('Resolved page path goes outside of bundles path')
|
||||
if (!pagesManifest[page]) {
|
||||
throw pageNotFoundError(page)
|
||||
}
|
||||
|
||||
return pagePath
|
||||
return join(serverBuildPath, pagesManifest[page])
|
||||
}
|
||||
|
||||
export default async function requirePage (page, {dir, dist}) {
|
||||
const pagePath = getPagePath(page, {dir, dist}) + '.js'
|
||||
const fileExists = await fs.exists(pagePath)
|
||||
if (!fileExists) {
|
||||
throw pageNotFoundError(page)
|
||||
}
|
||||
|
||||
const pagePath = getPagePath(page, {dir, dist})
|
||||
return require(pagePath)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
|
||||
export default class AsyncProps extends React.Component {
|
||||
static async getInitialProps () {
|
||||
return await fetchData()
|
||||
return fetchData()
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
|
@ -29,7 +29,7 @@ export default (context, render) => {
|
|||
browser.close()
|
||||
})
|
||||
|
||||
it('should not show the default HMR error overlay', async() => {
|
||||
it('should not show the default HMR error overlay', async () => {
|
||||
const browser = await webdriver(context.appPort, '/hmr/about')
|
||||
const text = await browser
|
||||
.elementByCss('p').text()
|
||||
|
|
|
@ -70,7 +70,7 @@ describe('Custom Server', () => {
|
|||
expect($dynamic('img').attr('src')).toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
|
||||
})
|
||||
|
||||
it('should support next/asset in client side', async() => {
|
||||
it('should support next/asset in client side', async () => {
|
||||
const browser = await webdriver(context.appPort, '/')
|
||||
await browser
|
||||
.elementByCss('#go-asset').click()
|
||||
|
|
|
@ -65,9 +65,9 @@ describe('Production Usage', () => {
|
|||
it('should navigate via client side', async () => {
|
||||
const browser = await webdriver(appPort, '/')
|
||||
const text = await browser
|
||||
.elementByCss('a').click()
|
||||
.waitForElementByCss('.about-page')
|
||||
.elementByCss('div').text()
|
||||
.elementByCss('a').click()
|
||||
.waitForElementByCss('.about-page')
|
||||
.elementByCss('div').text()
|
||||
|
||||
expect(text).toBe('About Page')
|
||||
browser.close()
|
||||
|
@ -98,8 +98,8 @@ describe('Production Usage', () => {
|
|||
it('should reload the page on page script error', async () => {
|
||||
const browser = await webdriver(appPort, '/counter')
|
||||
const counter = await browser
|
||||
.elementByCss('#increase').click().click()
|
||||
.elementByCss('#counter').text()
|
||||
.elementByCss('#increase').click().click()
|
||||
.elementByCss('#counter').text()
|
||||
expect(counter).toBe('Counter: 2')
|
||||
|
||||
// When we go to the 404 page, it'll do a hard reload.
|
||||
|
@ -120,8 +120,8 @@ describe('Production Usage', () => {
|
|||
it('should reload the page on page script error with prefetch', async () => {
|
||||
const browser = await webdriver(appPort, '/counter')
|
||||
const counter = await browser
|
||||
.elementByCss('#increase').click().click()
|
||||
.elementByCss('#counter').text()
|
||||
.elementByCss('#increase').click().click()
|
||||
.elementByCss('#counter').text()
|
||||
expect(counter).toBe('Counter: 2')
|
||||
|
||||
// Let the browser to prefetch the page and error it on the console.
|
||||
|
|
|
@ -7,7 +7,7 @@ export default function (context) {
|
|||
it('should render the home page', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#home-page p').text()
|
||||
.elementByCss('#home-page p').text()
|
||||
|
||||
expect(text).toBe('This is the home page')
|
||||
browser.close()
|
||||
|
@ -16,9 +16,9 @@ export default function (context) {
|
|||
it('should do navigations via Link', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#about-via-link').click()
|
||||
.waitForElementByCss('#about-page')
|
||||
.elementByCss('#about-page p').text()
|
||||
.elementByCss('#about-via-link').click()
|
||||
.waitForElementByCss('#about-page')
|
||||
.elementByCss('#about-page p').text()
|
||||
|
||||
expect(text).toBe('This is the About page')
|
||||
browser.close()
|
||||
|
@ -27,9 +27,9 @@ export default function (context) {
|
|||
it('should do navigations via Router', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#about-via-router').click()
|
||||
.waitForElementByCss('#about-page')
|
||||
.elementByCss('#about-page p').text()
|
||||
.elementByCss('#about-via-router').click()
|
||||
.waitForElementByCss('#about-page')
|
||||
.elementByCss('#about-page p').text()
|
||||
|
||||
expect(text).toBe('This is the About page')
|
||||
browser.close()
|
||||
|
@ -38,11 +38,11 @@ export default function (context) {
|
|||
it('should do run client side javascript', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#counter').click()
|
||||
.waitForElementByCss('#counter-page')
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-page p').text()
|
||||
.elementByCss('#counter').click()
|
||||
.waitForElementByCss('#counter-page')
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-page p').text()
|
||||
|
||||
expect(text).toBe('Counter: 2')
|
||||
browser.close()
|
||||
|
@ -51,9 +51,9 @@ export default function (context) {
|
|||
it('should render pages using getInitialProps', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#get-initial-props').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
.elementByCss('#get-initial-props').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
|
||||
expect(text).toBe('cool dynamic text')
|
||||
browser.close()
|
||||
|
@ -62,9 +62,9 @@ export default function (context) {
|
|||
it('should render dynamic pages with custom urls', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#dynamic-1').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
.elementByCss('#dynamic-1').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
|
||||
expect(text).toBe('next export is nice')
|
||||
browser.close()
|
||||
|
@ -73,11 +73,11 @@ export default function (context) {
|
|||
it('should support client side naviagtion', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#counter').click()
|
||||
.waitForElementByCss('#counter-page')
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-page p').text()
|
||||
.elementByCss('#counter').click()
|
||||
.waitForElementByCss('#counter-page')
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-increase').click()
|
||||
.elementByCss('#counter-page p').text()
|
||||
|
||||
expect(text).toBe('Counter: 2')
|
||||
|
||||
|
@ -97,15 +97,15 @@ export default function (context) {
|
|||
it('should render dynamic import components in the client', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
await browser
|
||||
.elementByCss('#dynamic-imports-page').click()
|
||||
.waitForElementByCss('#dynamic-imports-page')
|
||||
.elementByCss('#dynamic-imports-page').click()
|
||||
.waitForElementByCss('#dynamic-imports-page')
|
||||
|
||||
// Wait until browser loads the dynamic import chunk
|
||||
// TODO: We may need to find a better way to do this
|
||||
await waitFor(5000)
|
||||
|
||||
const text = await browser
|
||||
.elementByCss('#dynamic-imports-page p').text()
|
||||
.elementByCss('#dynamic-imports-page p').text()
|
||||
|
||||
expect(text).toBe('Welcome to dynamic imports.')
|
||||
browser.close()
|
||||
|
@ -116,9 +116,9 @@ export default function (context) {
|
|||
|
||||
// Check for the query string content
|
||||
const text = await browser
|
||||
.elementByCss('#with-hash').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
.elementByCss('#with-hash').click()
|
||||
.waitForElementByCss('#dynamic-page')
|
||||
.elementByCss('#dynamic-page p').text()
|
||||
|
||||
expect(text).toBe('zeit is awesome')
|
||||
|
||||
|
@ -139,9 +139,9 @@ export default function (context) {
|
|||
const browser = await webdriver(context.port, '/button-link')
|
||||
|
||||
const text = await browser
|
||||
.elementByCss('button').click()
|
||||
.waitForElementByCss('#home-page')
|
||||
.elementByCss('#home-page p').text()
|
||||
.elementByCss('button').click()
|
||||
.waitForElementByCss('#home-page')
|
||||
.elementByCss('#home-page p').text()
|
||||
|
||||
expect(text).toBe('This is the home page')
|
||||
browser.close()
|
||||
|
@ -151,9 +151,9 @@ export default function (context) {
|
|||
it('should render the home page', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#level1-home-page').click()
|
||||
.waitForElementByCss('#level1-home-page')
|
||||
.elementByCss('#level1-home-page p').text()
|
||||
.elementByCss('#level1-home-page').click()
|
||||
.waitForElementByCss('#level1-home-page')
|
||||
.elementByCss('#level1-home-page p').text()
|
||||
|
||||
expect(text).toBe('This is the Level1 home page')
|
||||
browser.close()
|
||||
|
@ -162,9 +162,9 @@ export default function (context) {
|
|||
it('should render the about page', async () => {
|
||||
const browser = await webdriver(context.port, '/')
|
||||
const text = await browser
|
||||
.elementByCss('#level1-about-page').click()
|
||||
.waitForElementByCss('#level1-about-page')
|
||||
.elementByCss('#level1-about-page p').text()
|
||||
.elementByCss('#level1-about-page').click()
|
||||
.waitForElementByCss('#level1-about-page')
|
||||
.elementByCss('#level1-about-page p').text()
|
||||
|
||||
expect(text).toBe('This is the Level1 about page')
|
||||
browser.close()
|
||||
|
|
|
@ -18,27 +18,27 @@ export default function (context) {
|
|||
expect(filePathLink).toEqual('/file-name.md')
|
||||
})
|
||||
|
||||
it('should render a page with getInitialProps', async() => {
|
||||
it('should render a page with getInitialProps', async () => {
|
||||
const html = await renderViaHTTP(context.port, '/dynamic')
|
||||
expect(html).toMatch(/cool dynamic text/)
|
||||
})
|
||||
|
||||
it('should render a dynamically rendered custom url page', async() => {
|
||||
it('should render a dynamically rendered custom url page', async () => {
|
||||
const html = await renderViaHTTP(context.port, '/dynamic/one')
|
||||
expect(html).toMatch(/next export is nice/)
|
||||
})
|
||||
|
||||
it('should render pages with dynamic imports', async() => {
|
||||
it('should render pages with dynamic imports', async () => {
|
||||
const html = await renderViaHTTP(context.port, '/dynamic-imports')
|
||||
expect(html).toMatch(/Welcome to dynamic imports/)
|
||||
})
|
||||
|
||||
it('should render paths with extensions', async() => {
|
||||
it('should render paths with extensions', async () => {
|
||||
const html = await renderViaHTTP(context.port, '/file-name.md')
|
||||
expect(html).toMatch(/this file has an extension/)
|
||||
})
|
||||
|
||||
it('should give empty object for query if there is no query', async() => {
|
||||
it('should give empty object for query if there is no query', async () => {
|
||||
const html = await renderViaHTTP(context.port, '/get-initial-props-with-no-query')
|
||||
expect(html).toMatch(/Query is: {}/)
|
||||
})
|
||||
|
|
3
test/isolated/_resolvedata/dist/bundles/pages/_error.js
vendored
Normal file
3
test/isolated/_resolvedata/dist/bundles/pages/_error.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
test: 'error'
|
||||
}
|
6
test/isolated/_resolvedata/dist/pages-manifest.json
vendored
Normal file
6
test/isolated/_resolvedata/dist/pages-manifest.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"/index": "bundles/pages/index.js",
|
||||
"/world": "bundles/pages/world.js",
|
||||
"/_error": "bundles/pages/_error.js",
|
||||
"/non-existent-child": "bundles/pages/non-existent-child.js"
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
/* global describe, it, expect */
|
||||
|
||||
import { join, sep } from 'path'
|
||||
import { join } from 'path'
|
||||
import requirePage, {getPagePath, normalizePagePath, pageNotFoundError} from '../../dist/server/require'
|
||||
|
||||
const dir = '/path/to/some/project'
|
||||
const dist = '.next'
|
||||
|
||||
const pathToBundles = join(dir, dist, 'dist', 'bundles', 'pages')
|
||||
const sep = '/'
|
||||
const pathToBundles = join(__dirname, '_resolvedata', 'dist', 'bundles', 'pages')
|
||||
|
||||
describe('pageNotFoundError', () => {
|
||||
it('Should throw error with ENOENT code', () => {
|
||||
|
@ -42,17 +40,17 @@ describe('normalizePagePath', () => {
|
|||
|
||||
describe('getPagePath', () => {
|
||||
it('Should append /index to the / page', () => {
|
||||
const pagePath = getPagePath('/', {dir, dist})
|
||||
expect(pagePath).toBe(join(pathToBundles, `${sep}index`))
|
||||
const pagePath = getPagePath('/', {dir: __dirname, dist: '_resolvedata'})
|
||||
expect(pagePath).toBe(join(pathToBundles, `${sep}index.js`))
|
||||
})
|
||||
|
||||
it('Should prepend / when a page does not have it', () => {
|
||||
const pagePath = getPagePath('_error', {dir, dist})
|
||||
expect(pagePath).toBe(join(pathToBundles, `${sep}_error`))
|
||||
const pagePath = getPagePath('_error', {dir: __dirname, dist: '_resolvedata'})
|
||||
expect(pagePath).toBe(join(pathToBundles, `${sep}_error.js`))
|
||||
})
|
||||
|
||||
it('Should throw with paths containing ../', () => {
|
||||
expect(() => getPagePath('/../../package.json', {dir, dist})).toThrow()
|
||||
expect(() => getPagePath('/../../package.json', {dir: __dirname, dist: '_resolvedata'})).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue