diff --git a/packages/create-next-app/@types/promisepipe.d.ts b/packages/create-next-app/@types/promisepipe.d.ts
new file mode 100644
index 00000000000000..6c82191c976588
--- /dev/null
+++ b/packages/create-next-app/@types/promisepipe.d.ts
@@ -0,0 +1 @@
+declare module 'promisepipe'
diff --git a/packages/create-next-app/@types/update-check.d.ts b/packages/create-next-app/@types/update-check.d.ts
new file mode 100644
index 00000000000000..c951132725752d
--- /dev/null
+++ b/packages/create-next-app/@types/update-check.d.ts
@@ -0,0 +1 @@
+declare module 'update-check'
diff --git a/packages/create-next-app/@types/validate-npm-package-name.d.ts b/packages/create-next-app/@types/validate-npm-package-name.d.ts
new file mode 100644
index 00000000000000..d60e51e6a9eda9
--- /dev/null
+++ b/packages/create-next-app/@types/validate-npm-package-name.d.ts
@@ -0,0 +1,12 @@
+declare module 'validate-npm-package-name' {
+ function validate(
+ projectName: string
+ ): {
+ validForNewPackages: boolean
+ validForOldPackages: boolean
+ errors?: string[] | null
+ warnings?: string[] | null
+ }
+
+ export default validate
+}
diff --git a/packages/create-next-app/LICENSE b/packages/create-next-app/LICENSE
deleted file mode 100644
index 25421e96a258cf..00000000000000
--- a/packages/create-next-app/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-MIT License
-
-Copyright (c) 2017-present Segment.io, Inc. friends@segment.com
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/packages/create-next-app/README.md b/packages/create-next-app/README.md
deleted file mode 100644
index 105a2aa7edfbd3..00000000000000
--- a/packages/create-next-app/README.md
+++ /dev/null
@@ -1,181 +0,0 @@
-
Create Next App
-
-
-
-The easiest way to create a React app with server-side rendering thanks to Next.js
-
-
-
-
-
-
-
-
-
-
- Getting Started
- · Starting from scratch with Create Next App
- · Starting from Next.js Examples
-
-
-
-
-If you run into any issues or have feedback, please file an issue
-
-
-## Overview
-
-| | [npx](https://github.com/zkat/npx) & npm (Node 8.x.x+) | [yarn create](https://yarnpkg.com/en/docs/cli/create) (Yarn 1.0.0+) | manual install (Node 6.x.x+) |
-| --- | ------------------------------------------------------ | ------------------------------------------------------------------- | -------------------------------- |
-| 1. | `npx create-next-app my-app` | `yarn create next-app my-app` | `npm install -g create-next-app` |
-| 2. | `cd my-app/` | `cd my-app/` | `create-next-app my-app` |
-| 3. | `npm run dev` | `yarn dev` | `cd my-app/` |
-| 4. | | | `npm run dev` |
-
-Open [http://localhost:3000](http://localhost:3000) to view your running app.
-When you're ready for production, run the `build` then `start` scripts.
-
-### Start Coding Now
-
-You **don't** need to install or setup Webpack or Babel.
-They come packaged with `next`, so you can just start coding.
-
-After running `create-next-app`, you're good to go!
-
-## Getting Started
-
-### Creating an App
-
-Follow the steps in the [above table](#overview):
-
-Minimum Requirements:
-
-- Node >= `6.x.x` - Use [nvm](https://github.com/creationix/nvm#usage) or [asdf](https://github.com/asdf-vm/asdf#readme) to easily switch Node versions between projects.
-
-**You don't need to use Node as your primary backend**. The Node installation is only required for Create Next App and running the Next.js server in development/production.
-
-### What's in an App
-
-`create-next-app` will have created a directory called `my-app` inside the current folder. Inside that directory, it will generate the initial project structure and install necessary dependencies:
-
-```
-.
-├── README.md
-├── components
-│ ├── head.js
-│ └── nav.js
-├── next.config.js
-├── node_modules
-│ ├── [...]
-├── package.json
-├── pages
-│ └── index.js
-├── static
-│ └── favicon.ico
-└── yarn.lock
-```
-
-Routing in Next.js is based on the file system, so `./pages/index.js` maps to the `/` route and
-`./pages/about.js` would map to `/about`.
-
-The `./static` directory maps to `/static` in the `next` server, so you can put all your
-other static resources like images or compiled CSS in there.
-
-Out of the box, we get:
-
-- Automatic transpilation and bundling (with webpack and babel)
-- Hot code reloading
-- Server rendering and indexing of `./pages`
-- Static file serving. `./static/` is mapped to `/static/`
-
-Once the installation is finished, you can run some commands in your project:
-
-### `npm run dev` or `yarn dev`
-
-Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
-
-The page will reload if you make edits.
-You will also see any errors in the console.
-
-### `npm run build` or `yarn build`
-
-Builds the app for production to the `.next` folder.
-It correctly bundles React in production mode and optimizes the build for the best performance.
-
-### `npm run start` or `yarn start`
-
-Starts the application in production mode.
-The application should be compiled with \`npm run build\` first.
-
-Now you're ready to code & deploy your app!
-
-## Starting from Next.js Examples
-
-There are a ton of examples in the [Next.js repo](https://github.com/zeit/next.js/tree/master/examples/) (and growing!) that you can use to bootstrap your app.
-
-To use an example:
-
-1. Go to https://github.com/zeit/next.js/tree/master/examples
-2. Search for an example you want and get it's name (looks like `basic-css`)
-3. Run: `create-next-app --example basic-css example-app`
-4. Done 💥
-
-**It is worth noting that the _basic-css_ example above uses [styled-jsx](https://github.com/zeit/styled-jsx).**
-
-## Acknowledgements
-
-We are grateful to the authors of existing related projects for their ideas as inspiration:
-
-- [Create React App](https://github.com/facebookincubator/create-react-app)
-- [Next.js](https://github.com/zeit/next.js)
-- [@eanplatter](https://github.com/eanplatter)
-- [@insin](https://github.com/insin)
-- [@mxstbr](https://github.com/mxstbr)
-
-Looking for alternatives? Here are some other project starter kits:
-
-- [Create React App](https://github.com/facebookincubator/create-react-app)
-- [insin/nwb](https://github.com/insin/nwb)
-- [mozilla-neutrino/neutrino-dev](https://github.com/mozilla-neutrino/neutrino-dev)
-- [NYTimes/kyt](https://github.com/NYTimes/kyt)
-- [gatsbyjs/gatsby](https://github.com/gatsbyjs/gatsby)
-- [enclave](https://github.com/eanplatter/enclave)
-- [motion](https://github.com/motion/motion)
-- [quik](https://github.com/satya164/quik)
-- [sagui](https://github.com/saguijs/sagui)
-- [roc](https://github.com/rocjs/roc)
-- [aik](https://github.com/d4rkr00t/aik)
-- [react-app](https://github.com/kriasoft/react-app)
-- [dev-toolkit](https://github.com/stoikerty/dev-toolkit)
-- [tarec](https://github.com/geowarin/tarec)
-- [sku](https://github.com/seek-oss/sku)
-
-Questions? Feedback? [Please let us know](https://github.com/zeit/next.js/issues/new)
-
-## Maintainers
-
-This repo, `create-next-app`, was previously maintained by Segment, Inc. It is now maintained by ZEIT, Inc.
-
-## License (MIT)
-
-```
-WWWWWW||WWWWWW
- W W W||W W W
- ||
- ( OO )__________
- / | \
- /o o| MIT \
- \___/||_||__||_|| *
- || || || ||
- _||_|| _||_||
- (__|__|(__|__|
-```
-
-Copyright (c) 2017-present Segment.io, Inc. friends@segment.com
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/packages/create-next-app/cli.js b/packages/create-next-app/cli.js
deleted file mode 100755
index 2f2f1da50d3b49..00000000000000
--- a/packages/create-next-app/cli.js
+++ /dev/null
@@ -1,30 +0,0 @@
-#! /usr/bin/env node
-
-const chalk = require('chalk')
-const program = require('commander')
-const lib = require('.')
-const pkg = require('./package.json')
-
-const messages = lib.messages
-const createNextApp = lib.createNextApp
-
-let projectName
-
-program
- .version(pkg.version)
- .arguments('')
- .usage(`${chalk.green('')} [options]`)
- .action(function (name) {
- projectName = name
- })
- .option('-e, --example ', messages.exampleHelp())
- .allowUnknownOption()
- .on('--help', messages.help)
- .parse(process.argv)
-
-const example = program.example
-
-createNextApp({
- projectName,
- example
-})
diff --git a/packages/create-next-app/create-app.ts b/packages/create-next-app/create-app.ts
new file mode 100644
index 00000000000000..e00fcd80e90980
--- /dev/null
+++ b/packages/create-next-app/create-app.ts
@@ -0,0 +1,132 @@
+import chalk from 'chalk'
+import cpy from 'cpy'
+import fs from 'fs'
+import makeDir from 'make-dir'
+import os from 'os'
+import path from 'path'
+
+import { downloadAndExtractExample, hasExample } from './helpers/examples'
+import { install } from './helpers/install'
+import { isFolderEmpty } from './helpers/is-folder-empty'
+import { getOnline } from './helpers/is-online'
+import { shouldUseYarn } from './helpers/should-use-yarn'
+
+export async function createApp({
+ appPath,
+ useNpm,
+ example,
+}: {
+ appPath: string
+ useNpm: boolean
+ example?: string
+}) {
+ if (example) {
+ const found = await hasExample(example)
+ if (!found) {
+ console.error(
+ `Could not locate an example named ${chalk.red(
+ `"${example}"`
+ )}. Please check your spelling and try again.`
+ )
+ process.exit(1)
+ }
+ }
+
+ const root = path.resolve(appPath)
+ const appName = path.basename(root)
+
+ await makeDir(root)
+ if (!isFolderEmpty(root, appName)) {
+ process.exit(1)
+ }
+
+ const useYarn = useNpm ? false : shouldUseYarn()
+ const isOnline = !useYarn || (await getOnline())
+ const originalDirectory = process.cwd()
+
+ const displayedCommand = useYarn ? 'yarn' : 'npm'
+ console.log(`Creating a new Next.js app in ${chalk.green(root)}.`)
+ console.log()
+
+ await makeDir(root)
+ process.chdir(root)
+
+ if (example) {
+ console.log(
+ `Downloading files for example ${chalk.cyan(
+ example
+ )}. This might take a moment.`
+ )
+ console.log()
+ await downloadAndExtractExample(root, example)
+
+ console.log('Installing packages. This might take a couple of minutes.')
+ console.log()
+
+ await install(root, null, { useYarn, isOnline })
+ console.log()
+ } else {
+ const packageJson = {
+ name: appName,
+ version: '0.1.0',
+ private: true,
+ scripts: { dev: 'next dev', build: 'next build', start: 'next start' },
+ }
+ fs.writeFileSync(
+ path.join(root, 'package.json'),
+ JSON.stringify(packageJson, null, 2) + os.EOL
+ )
+
+ console.log(
+ `Installing ${chalk.cyan('react')}, ${chalk.cyan(
+ 'react-dom'
+ )}, and ${chalk.cyan('next')} using ${displayedCommand}...`
+ )
+ console.log()
+
+ await install(root, ['react', 'react-dom', 'next'], { useYarn, isOnline })
+ console.log()
+
+ await cpy('**', root, {
+ parents: true,
+ cwd: path.join(__dirname, 'templates', 'default'),
+ rename: name => {
+ switch (name) {
+ case 'gitignore': {
+ return '.'.concat(name)
+ }
+ default: {
+ return name
+ }
+ }
+ },
+ })
+ }
+
+ let cdpath: string
+ if (path.join(originalDirectory, appName) === appPath) {
+ cdpath = appName
+ } else {
+ cdpath = appPath
+ }
+
+ console.log(`${chalk.green('Success!')} Created ${appName} at ${appPath}`)
+ console.log('Inside that directory, you can run several commands:')
+ console.log()
+ console.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}dev`))
+ console.log(' Starts the development server.')
+ console.log()
+ console.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`))
+ console.log(' Builds the app for production.')
+ console.log()
+ console.log(chalk.cyan(` ${displayedCommand} start`))
+ console.log(' Runs the built app in production mode.')
+ console.log()
+ console.log('We suggest that you begin by typing:')
+ console.log()
+ console.log(chalk.cyan(' cd'), cdpath)
+ console.log(
+ ` ${chalk.cyan(`${displayedCommand} ${useYarn ? '' : 'run '}dev`)}`
+ )
+ console.log()
+}
diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts
new file mode 100644
index 00000000000000..746f5cd3a860ad
--- /dev/null
+++ b/packages/create-next-app/helpers/examples.ts
@@ -0,0 +1,22 @@
+import got from 'got'
+import promisePipe from 'promisepipe'
+import tar from 'tar'
+
+export async function hasExample(name: string): Promise {
+ const res = await got(
+ `https://api.github.com/repos/zeit/next.js/contents/examples/${encodeURIComponent(
+ name
+ )}/package.json`
+ ).catch(e => e)
+ return res.statusCode === 200
+}
+
+export async function downloadAndExtractExample(
+ root: string,
+ name: string
+): Promise {
+ return await promisePipe(
+ got.stream('https://codeload.github.com/zeit/next.js/tar.gz/canary'),
+ tar.extract({ cwd: root, strip: 3 }, [`next.js-canary/examples/${name}`])
+ )
+}
diff --git a/packages/create-next-app/helpers/install.ts b/packages/create-next-app/helpers/install.ts
new file mode 100644
index 00000000000000..c0b73e9d0193ef
--- /dev/null
+++ b/packages/create-next-app/helpers/install.ts
@@ -0,0 +1,48 @@
+import chalk from 'chalk'
+import spawn from 'cross-spawn'
+
+export function install(
+ root: string,
+ dependencies: string[] | null,
+ { useYarn, isOnline }: { useYarn: boolean; isOnline: boolean }
+) {
+ return new Promise((resolve, reject) => {
+ let command: string
+ let args: string[]
+ if (useYarn) {
+ command = 'yarnpkg'
+ args = dependencies ? ['add', '--exact'] : ['install']
+ if (!isOnline) {
+ args.push('--offline')
+ }
+ if (dependencies) {
+ args.push(...dependencies)
+ }
+ args.push('--cwd', root)
+
+ if (!isOnline) {
+ console.log(chalk.yellow('You appear to be offline.'))
+ console.log(chalk.yellow('Falling back to the local Yarn cache.'))
+ console.log()
+ }
+ } else {
+ command = 'npm'
+ args = ([
+ 'install',
+ dependencies && '--save',
+ dependencies && '--save-exact',
+ '--loglevel',
+ 'error',
+ ].filter(Boolean) as string[]).concat(dependencies || [])
+ }
+
+ const child = spawn(command, args, { stdio: 'inherit' })
+ child.on('close', code => {
+ if (code !== 0) {
+ reject({ command: `${command} ${args.join(' ')}` })
+ return
+ }
+ resolve()
+ })
+ })
+}
diff --git a/packages/create-next-app/helpers/is-folder-empty.ts b/packages/create-next-app/helpers/is-folder-empty.ts
new file mode 100644
index 00000000000000..292bf4d1010e1e
--- /dev/null
+++ b/packages/create-next-app/helpers/is-folder-empty.ts
@@ -0,0 +1,59 @@
+import chalk from 'chalk'
+import fs from 'fs'
+import path from 'path'
+
+export function isFolderEmpty(root: string, name: string) {
+ const validFiles = [
+ '.DS_Store',
+ '.git',
+ '.gitattributes',
+ '.gitignore',
+ '.gitlab-ci.yml',
+ '.hg',
+ '.hgcheck',
+ '.hgignore',
+ '.idea',
+ '.npmignore',
+ '.travis.yml',
+ 'LICENSE',
+ 'Thumbs.db',
+ 'docs',
+ 'mkdocs.yml',
+ 'npm-debug.log',
+ 'yarn-debug.log',
+ 'yarn-error.log',
+ ]
+
+ const conflicts = fs
+ .readdirSync(root)
+ .filter(file => !validFiles.includes(file))
+ // Support IntelliJ IDEA-based editors
+ .filter(file => !/\.iml$/.test(file))
+
+ if (conflicts.length > 0) {
+ console.log(
+ `The directory ${chalk.green(name)} contains files that could conflict:`
+ )
+ console.log()
+ for (const file of conflicts) {
+ try {
+ const stats = fs.lstatSync(path.join(root, file))
+ if (stats.isDirectory()) {
+ console.log(` ${chalk.blue(file)}/`)
+ } else {
+ console.log(` ${file}`)
+ }
+ } catch {
+ console.log(` ${file}`)
+ }
+ }
+ console.log()
+ console.log(
+ 'Either try using a new directory name, or remove the files listed above.'
+ )
+ console.log()
+ return false
+ }
+
+ return true
+}
diff --git a/packages/create-next-app/helpers/is-online.ts b/packages/create-next-app/helpers/is-online.ts
new file mode 100644
index 00000000000000..aed37e385099ed
--- /dev/null
+++ b/packages/create-next-app/helpers/is-online.ts
@@ -0,0 +1,42 @@
+import { execSync } from 'child_process'
+import dns from 'dns'
+import url from 'url'
+
+function getProxy(): string | undefined {
+ if (process.env.https_proxy) {
+ return process.env.https_proxy
+ }
+
+ try {
+ const httpsProxy = execSync('npm config get https-proxy')
+ .toString()
+ .trim()
+ return httpsProxy !== 'null' ? httpsProxy : undefined
+ } catch (e) {
+ return
+ }
+}
+
+export function getOnline(): Promise {
+ return new Promise(resolve => {
+ dns.lookup('registry.yarnpkg.com', registryErr => {
+ if (!registryErr) {
+ return resolve(true)
+ }
+
+ const proxy = getProxy()
+ if (!proxy) {
+ return resolve(false)
+ }
+
+ const { hostname } = url.parse(proxy)
+ if (!hostname) {
+ return resolve(false)
+ }
+
+ dns.lookup(hostname, proxyErr => {
+ resolve(proxyErr == null)
+ })
+ })
+ })
+}
diff --git a/packages/create-next-app/helpers/should-use-yarn.ts b/packages/create-next-app/helpers/should-use-yarn.ts
new file mode 100644
index 00000000000000..b3ca1bbe342345
--- /dev/null
+++ b/packages/create-next-app/helpers/should-use-yarn.ts
@@ -0,0 +1,10 @@
+import { execSync } from 'child_process'
+
+export function shouldUseYarn() {
+ try {
+ execSync('yarnpkg --version', { stdio: 'ignore' })
+ return true
+ } catch (e) {
+ return false
+ }
+}
diff --git a/packages/create-next-app/helpers/validate-pkg.ts b/packages/create-next-app/helpers/validate-pkg.ts
new file mode 100644
index 00000000000000..a0dccc6e3c0448
--- /dev/null
+++ b/packages/create-next-app/helpers/validate-pkg.ts
@@ -0,0 +1,18 @@
+import validateProjectName from 'validate-npm-package-name'
+
+export function validateNpmName(
+ name: string
+): { valid: boolean; problems?: string[] } {
+ const nameValidation = validateProjectName(name)
+ if (nameValidation.validForNewPackages) {
+ return { valid: true }
+ }
+
+ return {
+ valid: false,
+ problems: [
+ ...(nameValidation.errors || []),
+ ...(nameValidation.warnings || []),
+ ],
+ }
+}
diff --git a/packages/create-next-app/index.js b/packages/create-next-app/index.js
deleted file mode 100644
index ea0abc0ee7aaef..00000000000000
--- a/packages/create-next-app/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const createNextApp = require('./lib')
-const messages = require('./lib/messages')
-
-module.exports = {
- messages: messages,
- createNextApp: createNextApp
-}
diff --git a/packages/create-next-app/index.ts b/packages/create-next-app/index.ts
new file mode 100644
index 00000000000000..81bc93bb755965
--- /dev/null
+++ b/packages/create-next-app/index.ts
@@ -0,0 +1,139 @@
+#!/usr/bin/env node
+import chalk from 'chalk'
+import Commander from 'commander'
+import path from 'path'
+import prompts from 'prompts'
+import checkForUpdate from 'update-check'
+
+import { createApp } from './create-app'
+import { validateNpmName } from './helpers/validate-pkg'
+import packageJson from './package.json'
+import { shouldUseYarn } from './helpers/should-use-yarn'
+
+let projectPath: string = ''
+
+const program = new Commander.Command(packageJson.name)
+ .version(packageJson.version)
+ .arguments('')
+ .usage(`${chalk.green('')} [options]`)
+ .action(name => {
+ projectPath = name
+ })
+ .option('--use-npm')
+ .option(
+ '-e, --example ',
+ 'an example to bootstrap the app with'
+ )
+ .allowUnknownOption()
+ .parse(process.argv)
+
+async function run() {
+ if (typeof projectPath === 'string') {
+ projectPath = projectPath.trim()
+ }
+
+ if (!projectPath) {
+ const res = await prompts({
+ type: 'text',
+ name: 'path',
+ message: 'What is your project named?',
+ initial: 'my-app',
+ validate: name => {
+ const validation = validateNpmName(path.basename(path.resolve(name)))
+ if (validation.valid) {
+ return true
+ }
+ return 'Invalid project name: ' + validation.problems![0]
+ },
+ })
+
+ if (typeof res.path === 'string') {
+ projectPath = res.path.trim()
+ }
+ }
+
+ if (!projectPath) {
+ console.log()
+ console.log('Please specify the project directory:')
+ console.log(
+ ` ${chalk.cyan(program.name())} ${chalk.green('')}`
+ )
+ console.log()
+ console.log('For example:')
+ console.log(` ${chalk.cyan(program.name())} ${chalk.green('my-next-app')}`)
+ console.log()
+ console.log(
+ `Run ${chalk.cyan(`${program.name()} --help`)} to see all options.`
+ )
+ process.exit(1)
+ }
+
+ const resolvedProjectPath = path.resolve(projectPath)
+ const projectName = path.basename(resolvedProjectPath)
+
+ const { valid, problems } = validateNpmName(projectName)
+ if (!valid) {
+ console.error(
+ `Could not create a project called ${chalk.red(
+ `"${projectName}"`
+ )} because of npm naming restrictions:`
+ )
+
+ problems!.forEach(p => console.error(` ${chalk.red.bold('*')} ${p}`))
+ process.exit(1)
+ }
+
+ await createApp({
+ appPath: resolvedProjectPath,
+ useNpm: !!program.useNpm,
+ example:
+ typeof program.example === 'string' && program.example.trim()
+ ? program.example.trim()
+ : undefined,
+ })
+}
+
+const update = checkForUpdate(packageJson).catch(() => null)
+
+async function notifyUpdate() {
+ try {
+ const res = await update
+ if (res && res.latest) {
+ const isYarn = shouldUseYarn()
+
+ console.log()
+ console.log(
+ chalk.yellow.bold('A new version of `create-next-app` is available!')
+ )
+ console.log(
+ 'You can update by running: ' +
+ chalk.cyan(
+ isYarn
+ ? 'yarn global add create-next-app'
+ : 'npm i -g create-next-app'
+ )
+ )
+ console.log()
+ }
+ } catch {
+ // ignore error
+ }
+}
+
+run()
+ .then(notifyUpdate)
+ .catch(async reason => {
+ console.log()
+ console.log('Aborting installation.')
+ if (reason.command) {
+ console.log(` ${chalk.cyan(reason.command)} has failed.`)
+ } else {
+ console.log(chalk.red('Unexpected error. Please report it as a bug:'))
+ console.log(reason)
+ }
+ console.log()
+
+ await notifyUpdate()
+
+ process.exit(1)
+ })
diff --git a/packages/create-next-app/lib/index.js b/packages/create-next-app/lib/index.js
deleted file mode 100644
index 9ed4bbee482755..00000000000000
--- a/packages/create-next-app/lib/index.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const path = require('path')
-const fs = require('fs')
-const copyDir = require('./utils/copy-dir')
-const install = require('./utils/install')
-const loadExample = require('./utils/load-example')
-const messages = require('./messages')
-
-module.exports = function createNextApp (opts) {
- const projectName = opts.projectName
-
- if (!projectName) {
- console.log(messages.missingProjectName())
- process.exit(1)
- }
-
- if (fs.existsSync(projectName) && projectName !== '.') {
- console.log(messages.alreadyExists(projectName))
- process.exit(1)
- }
-
- const projectPath = (opts.projectPath = process.cwd() + '/' + projectName)
-
- if (opts.example) {
- loadExample({
- projectName: projectName,
- example: opts.example
- }).then(installWithMessageFactory(opts))
- } else {
- const templatePath = path.resolve(__dirname, './templates/default')
-
- copyDir({
- templatePath: templatePath,
- projectPath: projectPath,
- projectName: projectName
- })
- .then(installWithMessageFactory(opts))
- .catch(function (err) {
- throw err
- })
- }
-}
-
-function installWithMessageFactory (opts) {
- const projectName = opts.projectName
- const projectPath = opts.projectPath
-
- return function installWithMessage () {
- return install({
- projectName: projectName,
- projectPath: projectPath,
- packages: ['react', 'react-dom', 'next']
- })
- .then(function () {
- console.log(messages.start(projectName))
- })
- .catch(function (err) {
- throw err
- })
- }
-}
diff --git a/packages/create-next-app/lib/messages.js b/packages/create-next-app/lib/messages.js
deleted file mode 100644
index be68c9a8d0200b..00000000000000
--- a/packages/create-next-app/lib/messages.js
+++ /dev/null
@@ -1,112 +0,0 @@
-const chalk = require('chalk')
-const getInstallCmd = require('./utils/get-install-cmd')
-const output = require('./utils/output')
-
-const program = {
- name: 'create-next-app'
-}
-
-exports.help = function () {
- return `
- Only ${chalk.green('')} is required.
-
- If you have any problems, do not hesitate to file an issue:
- ${chalk.cyan('https://github.com/zeit/next.js/issues/new')}
- `
-}
-
-exports.exampleHelp = function () {
- return `Example from https://github.com/zeit/next.js/tree/master/examples/ ${output.param(
- 'example-path'
- )}`
-}
-
-exports.missingProjectName = function () {
- return `
-Please specify the project directory:
-
- ${chalk.cyan(program.name)} ${chalk.green('')}
-
-For example:
-
- ${chalk.cyan(program.name)} ${chalk.green('my-next-app')}
- ${chalk.cyan(program.name)} ${chalk.cyan(
- '--example custom-server'
-)} ${chalk.green('custom-server-app')}
-
-Run ${chalk.cyan(`${program.name} --help`)} to see all options.
-`
-}
-
-exports.alreadyExists = function (projectName) {
- return `
-Uh oh! Looks like there's already a directory called ${chalk.red(
- projectName
- )}. Please try a different name or delete that folder.`
-}
-
-exports.installing = function (packages) {
- const pkgText = packages
- .map(function (pkg) {
- return ` ${chalk.cyan(chalk.bold(pkg))}`
- })
- .join('\n')
-
- return `
- Installing npm modules:
-${pkgText}
-`
-}
-
-exports.installError = function (packages) {
- const pkgText = packages
- .map(function (pkg) {
- return `${chalk.cyan(chalk.bold(pkg))}`
- })
- .join(', ')
-
- output.error(`Failed to install ${pkgText}, try again.`)
-}
-
-exports.copying = function (projectName) {
- return `
-Creating ${chalk.bold(chalk.green(projectName))}...
-`
-}
-
-exports.start = function (projectName) {
- const cmd = getInstallCmd()
-
- const commands = {
- install: cmd === 'npm' ? 'npm install' : 'yarn',
- build: cmd === 'npm' ? 'npm run build' : 'yarn build',
- start: cmd === 'npm' ? 'npm run start' : 'yarn start',
- dev: cmd === 'npm' ? 'npm run dev' : 'yarn dev'
- }
-
- return `
- ${chalk.green('Awesome!')} You're now ready to start coding.
-
- We already ran ${output.cmd(
- commands.install
- )} for you, so your next steps are:
-
- $ ${output.cmd(`cd ${projectName}`)}
-
- To build a version for production:
-
- $ ${output.cmd(commands.build)}
-
- To run the server in production:
-
- $ ${output.cmd(commands.start)}
-
- To start a local server for development:
-
- $ ${output.cmd(commands.dev)}
-
- Questions? Feedback? Please let us know!
-
- ${chalk.green('https://github.com/zeit/next.js/issues')}
-`
-}
diff --git a/packages/create-next-app/lib/templates/default/components/head.js b/packages/create-next-app/lib/templates/default/components/head.js
deleted file mode 100644
index bd74f5d4b7637e..00000000000000
--- a/packages/create-next-app/lib/templates/default/components/head.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react'
-import NextHead from 'next/head'
-import { string } from 'prop-types'
-
-const defaultDescription = ''
-const defaultOGURL = ''
-const defaultOGImage = ''
-
-const Head = props => (
-
-
- {props.title || ''}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-)
-
-Head.propTypes = {
- title: string,
- description: string,
- url: string,
- ogImage: string
-}
-
-export default Head
diff --git a/packages/create-next-app/lib/templates/default/gitignore b/packages/create-next-app/lib/templates/default/gitignore
deleted file mode 100644
index 7002712dfa86f6..00000000000000
--- a/packages/create-next-app/lib/templates/default/gitignore
+++ /dev/null
@@ -1,19 +0,0 @@
-# See https://help.github.com/ignore-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-
-# testing
-/coverage
-
-# production
-/build
-/dist
-/.next
-
-# misc
-.DS_Store
-.env
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
diff --git a/packages/create-next-app/lib/templates/default/package.json b/packages/create-next-app/lib/templates/default/package.json
deleted file mode 100644
index 6622905b4eaf42..00000000000000
--- a/packages/create-next-app/lib/templates/default/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "create-next-example-app",
- "scripts": {
- "dev": "next",
- "build": "next build",
- "start": "next start"
- },
- "dependencies": {}
-}
diff --git a/packages/create-next-app/lib/utils/copy-dir.js b/packages/create-next-app/lib/utils/copy-dir.js
deleted file mode 100644
index fd4d5ece36199a..00000000000000
--- a/packages/create-next-app/lib/utils/copy-dir.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const path = require('path')
-const Promise = require('promise')
-const messages = require('../messages')
-const output = require('./output')
-const fs = require('fs-extra')
-
-module.exports = function copyDir (opts) {
- const templatePath = opts.templatePath
- const projectPath = opts.projectPath
- const projectName = opts.projectName
-
- console.log(messages.copying(projectName))
-
- return new Promise(function (resolve, reject) {
- const stopCopySpinner = output.wait('Copying files')
-
- fs.copy(templatePath, projectPath)
- .then(function () {
- return fs.move(
- path.resolve(projectPath, './gitignore'),
- path.resolve(projectPath, './.gitignore')
- )
- })
- .then(function () {
- stopCopySpinner()
- output.success(
- `Created files for "${output.cmd(projectName)}" next app`
- )
- return this
- })
- .then(resolve)
- .catch(function (err) {
- console.error(err)
- stopCopySpinner()
- output.error('Copy command failed, try again.')
- reject(err)
- process.exit(1)
- })
- })
-}
diff --git a/packages/create-next-app/lib/utils/get-install-cmd.js b/packages/create-next-app/lib/utils/get-install-cmd.js
deleted file mode 100644
index 8889a199483dd9..00000000000000
--- a/packages/create-next-app/lib/utils/get-install-cmd.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const execa = require('execa')
-
-let cmd
-
-module.exports = function getInstallCmd () {
- if (cmd) {
- return cmd
- }
-
- try {
- execa.shellSync('yarnpkg --version')
- cmd = 'yarn'
- } catch (e) {
- cmd = 'npm'
- }
-
- return cmd
-}
diff --git a/packages/create-next-app/lib/utils/install.js b/packages/create-next-app/lib/utils/install.js
deleted file mode 100644
index 05292f3f8ac5d6..00000000000000
--- a/packages/create-next-app/lib/utils/install.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const execa = require('execa')
-const Promise = require('promise')
-const messages = require('../messages')
-const getInstallCmd = require('./get-install-cmd')
-const output = require('./output')
-
-module.exports = function install (opts) {
- const projectName = opts.projectName
- const projectPath = opts.projectPath
- const packages = opts.packages || []
-
- if (packages.length === 0) {
- console.log('Missing packages in `install`, try running again.')
- process.exit(1)
- }
-
- const installCmd = getInstallCmd()
- const installArgs = getInstallArgs(installCmd, packages)
-
- console.log(messages.installing(packages))
- process.chdir(projectPath)
-
- return new Promise(function (resolve, reject) {
- const stopInstallSpinner = output.wait('Installing modules')
-
- execa(installCmd, installArgs)
- .then(function () {
- // Confirm that all dependencies were installed
- return execa(installCmd, ['install'])
- })
- .then(function () {
- stopInstallSpinner()
- output.success(`Installed dependencies for ${projectName}`)
- resolve()
- })
- .catch(function () {
- stopInstallSpinner()
- console.log(messages.installError(packages))
- return reject(new Error(`${installCmd} installation failed`))
- })
- })
-}
-
-function getInstallArgs (cmd, packages) {
- if (cmd === 'npm') {
- const args = ['install', '--save', '--save-exact']
- return args.concat(packages, ['--verbose'])
- } else if (cmd === 'yarn') {
- const args = ['add']
- return args.concat(packages)
- }
-}
diff --git a/packages/create-next-app/lib/utils/load-example.js b/packages/create-next-app/lib/utils/load-example.js
deleted file mode 100644
index e120ce0bcce558..00000000000000
--- a/packages/create-next-app/lib/utils/load-example.js
+++ /dev/null
@@ -1,64 +0,0 @@
-const Promise = require('promise')
-const got = require('got')
-const mkdir = require('make-dir')
-const tar = require('tar')
-const Octokit = require('@octokit/rest')
-const output = require('./output')
-
-// Ensure the given `example` name has a package.json file
-// A "not found" error will be returned if not
-const validateExampleName = example =>
- new Octokit().repos.getContent({
- owner: 'zeit',
- repo: 'next.js',
- path: `examples/${example}/package.json`
- })
-
-// Stream and untar the archive, keeping only the requested example
-const fetchAndExtract = ({ projectName, example }) =>
- new Promise((resolve, reject) => {
- got
- .stream('https://codeload.github.com/zeit/next.js/tar.gz/canary')
- .on('error', reject)
- .pipe(
- tar.extract(
- {
- // Extract to the project name
- cwd: projectName,
- // Strip the first 3 dirs
- strip: 3
- },
- [
- // We only care about this dir
- `next.js-canary/examples/${example}`
- ]
- )
- )
- .on('error', reject)
- .on('end', () => resolve())
- })
-
-module.exports = function loadExample (opts) {
- const { projectName, example } = opts
- const stopExampleSpinner = output.wait(
- `Downloading files for ${output.cmd(example)} example`
- )
- return validateExampleName(example)
- .then(() => mkdir(projectName))
- .then(() => fetchAndExtract({ projectName, example }))
- .then(() => {
- stopExampleSpinner()
- output.success(
- `Downloaded ${output.cmd(example)} files for ${output.cmd(projectName)}`
- )
- })
- .catch(err => {
- stopExampleSpinner()
- output.error(
- `Error downloading ${output.cmd(example)} files for ${output.cmd(
- projectName
- )}`
- )
- throw err
- })
-}
diff --git a/packages/create-next-app/lib/utils/output.js b/packages/create-next-app/lib/utils/output.js
deleted file mode 100644
index 3b1d999eabf808..00000000000000
--- a/packages/create-next-app/lib/utils/output.js
+++ /dev/null
@@ -1,83 +0,0 @@
-const { eraseLine } = require('ansi-escapes')
-const chalk = require('chalk')
-const ora = require('ora')
-const ms = require('ms')
-const Promise = require('promise')
-
-exports.info = function (msg) {
- console.log(`${chalk.gray('>')} ${msg}`)
-}
-
-exports.error = function (msg) {
- if (msg instanceof Error) {
- msg = msg.message
- }
-
- console.error(`${chalk.red('> Error!')} ${msg}`)
-}
-
-exports.success = function (msg) {
- console.log(`${chalk.green('> Success!')} ${msg}`)
-}
-
-exports.time = function () {
- const start = new Date()
- return chalk.gray(`[${ms(new Date() - start)}]`)
-}
-
-exports.wait = function (msg) {
- const spinner = ora(chalk.green(msg))
- spinner.color = 'blue'
- spinner.start()
-
- return function () {
- spinner.stop()
- process.stdout.write(eraseLine)
- }
-}
-
-exports.prompt = function (opts) {
- return new Promise(function (resolve, reject) {
- opts.forEach(function (val, i) {
- const text = val[1]
- console.log(`${chalk.gray('>')} [${chalk.bold(i + 1)}] ${text}`)
- })
-
- const ondata = v => {
- const s = v.toString()
-
- function cleanup () {
- process.stdin.setRawMode(false)
- process.stdin.removeListener('data', ondata)
- }
-
- if (s === '\u0003') {
- cleanup()
- reject(new Error('Aborted'))
- return
- }
-
- const n = Number(s)
- if (opts[n - 1]) {
- cleanup()
- resolve(opts[n - 1][0])
- }
- }
-
- process.stdin.setRawMode(true)
- process.stdin.resume()
- process.stdin.on('data', ondata)
- })
-}
-
-exports.cmd = function (cmd) {
- return chalk.bold(chalk.cyan(cmd))
-}
-
-exports.code = function (cmd) {
- return `${chalk.gray('`')}${chalk.bold(cmd)}${chalk.gray('`')}`
-}
-
-exports.param = function (param) {
- return chalk.bold(`${chalk.gray('{')}${chalk.bold(param)}${chalk.gray('}')}`)
-}
diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json
index f50e01036a7706..08f12debe43f58 100644
--- a/packages/create-next-app/package.json
+++ b/packages/create-next-app/package.json
@@ -1,39 +1,49 @@
{
"name": "create-next-app",
- "description": "Create Next.js apps in one command",
- "version": "9.0.3-canary.1",
- "main": "index.js",
+ "version": "0.0.0",
+ "keywords": [
+ "react",
+ "next",
+ "next.js"
+ ],
+ "description": "Create Next.js-powered React apps with one command",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/zeit/next.js",
+ "directory": "packages/create-next-app"
+ },
+ "author": "Next.js Team ",
"license": "MIT",
"bin": {
- "create-next-app": "./cli.js"
+ "create-next-app": "./dist/index.js"
},
- "engines": {
- "node": ">=4"
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "build": "ncc build ./index.ts -w -o dist/",
+ "prerelease": "rimraf ./dist/",
+ "release": "ncc build ./index.ts -o ./dist/ --minify --no-cache --no-source-map-register",
+ "prepublish": "yarn release"
},
- "repository": "zeit/next.js",
- "bugs": "https://github.com/zeit/next.js/issues",
- "homepage": "https://nextjs.org",
- "dependencies": {
- "@octokit/rest": "^15.9.4",
- "ansi-escapes": "^2.0.0",
- "chalk": "^1.1.3",
- "commander": "^2.9.0",
- "execa": "^0.6.3",
- "fs-extra": "^3.0.0",
- "got": "^8.3.1",
- "make-dir": "^1.3.0",
- "ms": "^1.0.0",
- "mz": "^2.6.0",
- "ora": "^1.2.0",
- "promise": "^7.1.1",
- "tar": "^4.4.4"
- },
- "keywords": [
- "next",
- "react",
- "next.js",
- "create-next-app",
- "create-react-app",
- "boilerplate"
- ]
+ "devDependencies": {
+ "@types/got": "9.6.2",
+ "@types/node": "^12.6.8",
+ "@types/prompts": "2.0.1",
+ "@types/tar": "4.0.3",
+ "@zeit/ncc": "^0.20.4",
+ "chalk": "2.4.2",
+ "commander": "2.20.0",
+ "cpy": "7.3.0",
+ "cross-spawn": "6.0.5",
+ "got": "9.6.0",
+ "make-dir": "3.0.0",
+ "promisepipe": "3.0.0",
+ "prompts": "2.1.0",
+ "rimraf": "2.6.3",
+ "tar": "4.4.10",
+ "typescript": "^3.5.3",
+ "update-check": "1.5.3",
+ "validate-npm-package-name": "3.0.0"
+ }
}
diff --git a/packages/create-next-app/lib/templates/default/README.md b/packages/create-next-app/templates/default/README.md
similarity index 64%
rename from packages/create-next-app/lib/templates/default/README.md
rename to packages/create-next-app/templates/default/README.md
index 4571f4863d1264..5074a5c555086e 100644
--- a/packages/create-next-app/lib/templates/default/README.md
+++ b/packages/create-next-app/templates/default/README.md
@@ -13,7 +13,6 @@ Find the most recent version of this guide at [here](https://github.com/zeit/nex
- [Using CSS](#using-css)
- [Adding Components](#adding-components)
- [Fetching Data](#fetching-data)
-- [Custom Server](#custom-server)
- [Syntax Highlighting](#syntax-highlighting)
- [Using the `static` Folder](#using-the-static-folder)
- [Deploy to Now](#deploy-to-now)
@@ -52,9 +51,9 @@ other static resources like images or compiled CSS in there.
Out of the box, we get:
-- Automatic transpilation and bundling (with webpack and babel)
+- Automatic compilation and bundling (with Babel and webpack)
- Hot code reloading
-- Server rendering and indexing of `./pages`
+- Server rendering and indexing of `./pages/`
- Static file serving. `./static/` is mapped to `/static/`
Read more about [Next's Routing](https://github.com/zeit/next.js#routing)
@@ -85,7 +84,8 @@ See the section in Next docs about [deployment](https://github.com/zeit/next.js/
## Using CSS
-[`styled-jsx`](https://github.com/zeit/styled-jsx) is bundled with next to provide support for isolated scoped CSS. The aim is to support "shadow CSS" resembling of Web Components, which unfortunately [do not support server-rendering and are JS-only](https://github.com/w3c/webcomponents/issues/71).
+[`styled-jsx`](https://github.com/zeit/styled-jsx) is bundled with next to provide support for isolated scoped CSS.
+The aim is to support "shadow CSS" resembling of Web Components.
```jsx
export default () => (
@@ -113,38 +113,22 @@ Read more about [Next's CSS features](https://github.com/zeit/next.js#css).
## Adding Components
-We recommend keeping React components in `./components` and they should look like:
+We recommend keeping React components in `./components/` and they should look like:
-### `./components/simple.js`
+### `./components/hello.js`
```jsx
-const Simple = () => Simple Component
+import { useState } from 'react'
-export default Simple // don't forget to export default!
-```
-
-### `./components/complex.js`
-
-```jsx
-import { Component } from 'react'
-
-class Complex extends Component {
- state = {
- text: 'World'
- }
-
- render() {
- const { text } = this.state
- return Hello {text}
- }
+export function Hello() {
+ const [text, setText] = useState('World')
+ return Hello {text}
}
-
-export default Complex // don't forget to export default!
```
## Fetching Data
-You can fetch data in `pages` components using `getInitialProps` like this:
+You can fetch data in `./pages/` components using `getInitialProps` like this:
### `./pages/stars.js`
@@ -161,54 +145,12 @@ Page.getInitialProps = async ({ req }) => {
export default Page
```
-For the initial page load, `getInitialProps` will execute on the server only. `getInitialProps` will only be executed on the client when navigating to a different route via the `Link` component or using the routing APIs.
+For the initial page load, `getInitialProps` will execute on the server only. `getInitialProps` will only be executed on the client when navigating to a different route via the ` ` component or using the routing APIs.
-_Note: `getInitialProps` can **not** be used in children components. Only in `pages`._
+_Note: `getInitialProps` can **not** be used in children components. Only in `./pages/`._
Read more about [fetching data and the component lifecycle](https://github.com/zeit/next.js#fetching-data-and-component-lifecycle)
-## Custom Server
-
-Want to start a new app with a custom server? Run `create-next-app --example custom-server custom-app`
-
-Typically you start your next server with `next start`. It's possible, however, to start a server 100% programmatically in order to customize routes, use route patterns, etc
-
-This example makes `/a` resolve to `./pages/b`, and `/b` resolve to `./pages/a`:
-
-```jsx
-const { createServer } = require('http')
-const { parse } = require('url')
-const next = require('next')
-
-const dev = process.env.NODE_ENV !== 'production'
-const app = next({ dev })
-const handle = app.getRequestHandler()
-
-app.prepare().then(() => {
- createServer((req, res) => {
- // Be sure to pass `true` as the second argument to `url.parse`.
- // This tells it to parse the query portion of the URL.
- const parsedUrl = parse(req.url, true)
- const { pathname, query } = parsedUrl
-
- if (pathname === '/a') {
- app.render(req, res, '/b', query)
- } else if (pathname === '/b') {
- app.render(req, res, '/a', query)
- } else {
- handle(req, res, parsedUrl)
- }
- }).listen(3000, err => {
- if (err) throw err
- console.log('> Ready on http://localhost:3000')
- })
-})
-```
-
-Then, change your `start` script to `NODE_ENV=production node server.js`.
-
-Read more about [custom server and routing](https://github.com/zeit/next.js#custom-server-and-routing)
-
## Syntax Highlighting
To configure the syntax highlighting in your favorite text editor, head to the [relevant Babel documentation page](https://babeljs.io/docs/editors) and follow the instructions. Some of the most popular editors are covered.
@@ -217,7 +159,7 @@ To configure the syntax highlighting in your favorite text editor, head to the [
[now](https://zeit.co/now) offers a zero-configuration single-command deployment.
-1. Install the `now` command-line tool either via the recommended [desktop tool](https://zeit.co/download) or via node with `npm install -g now`.
+1. Install the `now` command-line tool either via npm `npm install -g now` or Yarn `yarn global add now`.
2. Run `now` from your project directory. You will see a **now.sh** URL in your output like this:
diff --git a/packages/create-next-app/lib/templates/default/components/nav.js b/packages/create-next-app/templates/default/components/nav.js
similarity index 79%
rename from packages/create-next-app/lib/templates/default/components/nav.js
rename to packages/create-next-app/templates/default/components/nav.js
index f74b2fb76b6055..60569fe6ce768c 100644
--- a/packages/create-next-app/lib/templates/default/components/nav.js
+++ b/packages/create-next-app/templates/default/components/nav.js
@@ -2,6 +2,7 @@ import React from 'react'
import Link from 'next/link'
const links = [
+ { href: 'https://zeit.co/now', label: 'ZEIT' },
{ href: 'https://github.com/zeit/next.js', label: 'GitHub' }
].map(link => {
link.key = `nav-link-${link.href}-${link.label}`
@@ -12,19 +13,15 @@ const Nav = () => (
-
+
Home
-
- {links.map(({ key, href, label }) => (
-
-
- {label}
-
-
- ))}
-
+ {links.map(({ key, href, label }) => (
+
+ {label}
+
+ ))}