Skip to content

Commit 4d01473

Browse files
committed
Merge v3-beta in dynamic-imports
2 parents d4e0478 + d4c62b1 commit 4d01473

File tree

103 files changed

+2233
-705
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+2233
-705
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ dist
66
node_modules
77

88
# logs
9-
npm-debug.log
9+
*.log
1010

1111
# coverage
1212
.nyc_output
1313
coverage
1414

15+
# test output
16+
test/**/out
1517
.DS_Store

bin/next

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const commands = new Set([
2222
'init',
2323
'build',
2424
'start',
25+
'export',
2526
defaultCommand
2627
])
2728

bin/next-export

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env node
2+
import { resolve, join } from 'path'
3+
import { existsSync } from 'fs'
4+
import parseArgs from 'minimist'
5+
import exportApp from '../server/export'
6+
import { printAndExit } from '../lib/utils'
7+
8+
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
9+
10+
const argv = parseArgs(process.argv.slice(2), {
11+
alias: {
12+
h: 'help',
13+
s: 'silent',
14+
o: 'outdir'
15+
},
16+
boolean: ['h'],
17+
default: {
18+
s: false,
19+
o: null
20+
}
21+
})
22+
23+
if (argv.help) {
24+
console.log(`
25+
Description
26+
Exports the application for production deployment
27+
28+
Usage
29+
$ next export [options] <dir>
30+
31+
<dir> represents where the compiled dist folder should go.
32+
If no directory is provided, the dist folder will be created in the current directory.
33+
You can set a custom folder in config https://github.com/zeit/next.js#custom-configuration, otherwise it will be created inside '.next'
34+
35+
Options
36+
-h - list this help
37+
-o - set the output dir (defaults to 'out')
38+
-s - do not print any messages to console
39+
`)
40+
process.exit(0)
41+
}
42+
43+
const dir = resolve(argv._[0] || '.')
44+
45+
// Check if pages dir exists and warn if not
46+
if (!existsSync(dir)) {
47+
printAndExit(`> No such directory exists as the project root: ${dir}`)
48+
}
49+
50+
if (!existsSync(join(dir, 'pages'))) {
51+
if (existsSync(join(dir, '..', 'pages'))) {
52+
printAndExit('> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?')
53+
}
54+
55+
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
56+
}
57+
58+
const options = {
59+
silent: argv.silent,
60+
outdir: argv.outdir ? resolve(argv.outdir) : resolve(dir, 'out')
61+
}
62+
63+
exportApp(dir, options)
64+
.catch((err) => {
65+
console.error(err)
66+
process.exit(1)
67+
})

client/index.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const {
3030
location
3131
} = window
3232

33+
const asPath = getURL()
34+
3335
const pageLoader = new PageLoader(buildId, assetPrefix)
3436
window.__NEXT_LOADED_PAGES__.forEach(({ route, fn }) => {
3537
pageLoader.registerPage(route, fn)
@@ -68,7 +70,7 @@ export default async () => {
6870
Component = ErrorComponent
6971
}
7072

71-
router = createRouter(pathname, query, getURL(), {
73+
router = createRouter(pathname, query, asPath, {
7274
pageLoader,
7375
Component,
7476
ErrorComponent,
@@ -119,7 +121,7 @@ export async function renderError (error) {
119121
console.error(errorMessage)
120122

121123
if (prod) {
122-
const initProps = { err: error, pathname, query }
124+
const initProps = { err: error, pathname, query, asPath }
123125
const props = await loadGetInitialProps(ErrorComponent, initProps)
124126
ReactDOM.render(createElement(ErrorComponent, props), errorContainer)
125127
} else {
@@ -132,8 +134,8 @@ async function doRender ({ Component, props, hash, err, emitter }) {
132134
Component !== ErrorComponent &&
133135
lastAppProps.Component === ErrorComponent) {
134136
// fetch props if ErrorComponent was replaced with a page component by HMR
135-
const { pathname, query } = router
136-
props = await loadGetInitialProps(Component, { err, pathname, query })
137+
const { pathname, query, asPath } = router
138+
props = await loadGetInitialProps(Component, { err, pathname, query, asPath })
137139
}
138140

139141
if (emitter) {

examples/root-static-files/README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/custom-server)
2+
3+
# Root static files example
4+
5+
## How to use
6+
7+
Download the example [or clone the repo](https://github.com/zeit/next.js):
8+
9+
```bash
10+
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/custom-server
11+
cd custom-server
12+
```
13+
14+
Install it and run:
15+
16+
```bash
17+
npm install
18+
npm run dev
19+
```
20+
21+
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
22+
23+
```bash
24+
now
25+
```
26+
27+
## The idea behind the example
28+
29+
This example demonstrates how to serve files such as /robots.txt and /sitemap.xml from the root.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"scripts": {
3+
"dev": "node server.js",
4+
"build": "next build",
5+
"start": "NODE_ENV=production node server.js"
6+
},
7+
"dependencies": {
8+
"next": "latest",
9+
"react": "^15.5.4",
10+
"react-dom": "^15.5.4"
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default () => (
2+
<ul>
3+
<li><a href='/robots.txt'>/robots.txt</a></li>
4+
<li><a href='/sitemap.xml'>/sitemap.xml</a></li>
5+
<li><a href='/favicon.ico'>/favicon.ico</a></li>
6+
</ul>
7+
)

examples/root-static-files/server.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const { createServer } = require('http')
2+
const { parse } = require('url')
3+
const next = require('next')
4+
const { join } = require('path')
5+
6+
const dev = process.env.NODE_ENV !== 'production'
7+
const app = next({ dev })
8+
const handle = app.getRequestHandler()
9+
10+
app.prepare()
11+
.then(() => {
12+
createServer((req, res) => {
13+
const parsedUrl = parse(req.url, true)
14+
const rootStaticFiles = [
15+
'/robots.txt',
16+
'/sitemap.xml',
17+
'/favicon.ico'
18+
]
19+
if (rootStaticFiles.indexOf(parsedUrl.pathname) > -1) {
20+
const path = join(__dirname, 'static', parsedUrl.pathname)
21+
app.serveStatic(req, res, path)
22+
} else {
23+
handle(req, res, parsedUrl)
24+
}
25+
})
26+
.listen(3000, (err) => {
27+
if (err) throw err
28+
console.log('> Ready on http://localhost:3000')
29+
})
30+
})
1.06 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
User-agent: *
2+
Disallow: /
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3+
<url>
4+
<loc>http://www.example.com/foo.html</loc>
5+
</url>
6+
</urlset>

examples/svg-components/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"start": "next start"
88
},
99
"dependencies": {
10-
"next": "beta"
10+
"next": "latest"
1111
},
1212
"devDependencies": {
1313
"babel-plugin-inline-react-svg": "^0.2.0"

examples/with-aphrodite/pages/_document.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,31 @@ import { StyleSheetServer } from 'aphrodite'
44
export default class MyDocument extends Document {
55
static async getInitialProps ({ renderPage }) {
66
const { html, css } = StyleSheetServer.renderStatic(() => renderPage())
7-
return { ...html, css }
7+
const ids = css.renderedClassNames
8+
return { ...html, css, ids }
9+
}
10+
11+
constructor (props) {
12+
super(props)
13+
/* Take the renderedClassNames from aphrodite (as generated
14+
in getInitialProps) and assign them to __NEXT_DATA__ so that they
15+
are accessible to the client for rehydration. */
16+
const { __NEXT_DATA__, ids } = props
17+
if (ids) {
18+
__NEXT_DATA__.ids = this.props.ids
19+
}
820
}
921

1022
render () {
23+
/* Make sure to use data-aphrodite attribute in the style tag here
24+
so that aphrodite knows which style tag it's in control of when
25+
the client goes to render styles. If you don't you'll get a second
26+
<style> tag */
1127
return (
1228
<html>
1329
<Head>
1430
<title>My page</title>
15-
<style dangerouslySetInnerHTML={{ __html: this.props.css.content }} />
31+
<style data-aphrodite dangerouslySetInnerHTML={{ __html: this.props.css.content }} />
1632
</Head>
1733
<body>
1834
<Main />

examples/with-aphrodite/pages/index.js

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import React from 'react'
22
import { StyleSheet, css } from 'aphrodite'
33

4+
if (typeof window !== 'undefined') {
5+
/* StyleSheet.rehydrate takes an array of rendered classnames,
6+
and ensures that the client side render doesn't generate
7+
duplicate style definitions in the <style data-aphrodite> tag */
8+
StyleSheet.rehydrate(window.__NEXT_DATA__.ids)
9+
}
10+
411
export default () => (
512
<div className={css(styles.root)}>
613
<h1 className={css(styles.title)}>My page</h1>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ApolloClient, createNetworkInterface } from 'react-apollo'
2+
import fetch from 'isomorphic-fetch'
3+
4+
let apolloClient = null
5+
6+
// Polyfill fetch() on the server (used by apollo-client)
7+
if (!process.browser) {
8+
global.fetch = fetch
9+
}
10+
11+
function create () {
12+
return new ApolloClient({
13+
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
14+
networkInterface: createNetworkInterface({
15+
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
16+
opts: { // Additional fetch() options like `credentials` or `headers`
17+
credentials: 'same-origin'
18+
}
19+
})
20+
})
21+
}
22+
23+
export default function initApollo () {
24+
// Make sure to create a new client for every server-side request so that data
25+
// isn't shared between connections (which would be bad)
26+
if (!process.browser) {
27+
return create()
28+
}
29+
30+
// Reuse client on the client-side
31+
if (!apolloClient) {
32+
apolloClient = create()
33+
}
34+
35+
return apolloClient
36+
}

examples/with-apollo-and-redux/lib/initClient.js

-28
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { createStore, combineReducers, applyMiddleware, compose } from 'redux'
2+
import reducers from './reducers'
3+
4+
let reduxStore = null
5+
6+
// Get the Redux DevTools extension and fallback to a no-op function
7+
let devtools = f => f
8+
if (process.browser && window.__REDUX_DEVTOOLS_EXTENSION__) {
9+
devtools = window.__REDUX_DEVTOOLS_EXTENSION__()
10+
}
11+
12+
function create (apollo, initialState = {}) {
13+
return createStore(
14+
combineReducers({ // Setup reducers
15+
...reducers,
16+
apollo: apollo.reducer()
17+
}),
18+
initialState, // Hydrate the store with server-side data
19+
compose(
20+
applyMiddleware(apollo.middleware()), // Add additional middleware here
21+
devtools
22+
)
23+
)
24+
}
25+
26+
export default function initRedux (apollo, initialState) {
27+
// Make sure to create a new store for every server-side request so that data
28+
// isn't shared between connections (which would be bad)
29+
if (!process.browser) {
30+
return create(apollo, initialState)
31+
}
32+
33+
// Reuse store on the client-side
34+
if (!reduxStore) {
35+
reduxStore = create(apollo, initialState)
36+
}
37+
38+
return reduxStore
39+
}

0 commit comments

Comments
 (0)