2019-07-19 21:55:30 +02:00
|
|
|
#!/usr/bin/env node
|
2020-05-28 10:23:10 +02:00
|
|
|
/* eslint-disable import/no-extraneous-dependencies */
|
2019-07-19 21:55:30 +02:00
|
|
|
import chalk from 'chalk'
|
|
|
|
import Commander from 'commander'
|
2023-01-14 01:51:25 +01:00
|
|
|
import Conf from 'conf'
|
2019-07-19 21:55:30 +02:00
|
|
|
import path from 'path'
|
|
|
|
import prompts from 'prompts'
|
|
|
|
import checkForUpdate from 'update-check'
|
2020-05-26 18:39:18 +02:00
|
|
|
import { createApp, DownloadError } from './create-app'
|
2022-03-04 00:49:24 +01:00
|
|
|
import { getPkgManager } from './helpers/get-pkg-manager'
|
2019-07-19 21:55:30 +02:00
|
|
|
import { validateNpmName } from './helpers/validate-pkg'
|
|
|
|
import packageJson from './package.json'
|
2022-10-31 06:43:39 +01:00
|
|
|
import ciInfo from 'ci-info'
|
2023-01-23 21:10:45 +01:00
|
|
|
import { isFolderEmpty } from './helpers/is-folder-empty'
|
|
|
|
import fs from 'fs'
|
2019-07-19 21:55:30 +02:00
|
|
|
|
|
|
|
let projectPath: string = ''
|
|
|
|
|
2023-01-24 04:30:38 +01:00
|
|
|
const handleSigTerm = () => process.exit(0)
|
|
|
|
|
|
|
|
process.on('SIGINT', handleSigTerm)
|
|
|
|
process.on('SIGTERM', handleSigTerm)
|
|
|
|
|
|
|
|
const onPromptState = (state: any) => {
|
|
|
|
if (state.aborted) {
|
|
|
|
// If we don't re-enable the terminal cursor before exiting
|
|
|
|
// the program, the cursor will remain hidden
|
|
|
|
process.stdout.write('\x1B[?25h')
|
|
|
|
process.stdout.write('\n')
|
|
|
|
process.exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-19 21:55:30 +02:00
|
|
|
const program = new Commander.Command(packageJson.name)
|
|
|
|
.version(packageJson.version)
|
|
|
|
.arguments('<project-directory>')
|
|
|
|
.usage(`${chalk.green('<project-directory>')} [options]`)
|
2020-05-18 21:24:37 +02:00
|
|
|
.action((name) => {
|
2019-07-19 21:55:30 +02:00
|
|
|
projectPath = name
|
|
|
|
})
|
2021-05-07 10:08:16 +02:00
|
|
|
.option(
|
|
|
|
'--ts, --typescript',
|
|
|
|
`
|
|
|
|
|
2022-10-31 06:43:39 +01:00
|
|
|
Initialize as a TypeScript project. (default)
|
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--js, --javascript',
|
|
|
|
`
|
|
|
|
|
|
|
|
Initialize as a JavaScript project.
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--tailwind',
|
|
|
|
`
|
|
|
|
|
|
|
|
Initialize with Tailwind CSS config. (default)
|
2022-10-31 16:51:50 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--eslint',
|
|
|
|
`
|
|
|
|
|
|
|
|
Initialize with eslint config.
|
2022-10-22 23:18:39 +02:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
2023-05-03 02:28:31 +02:00
|
|
|
'--app',
|
2022-10-22 23:18:39 +02:00
|
|
|
`
|
|
|
|
|
2023-05-03 02:28:31 +02:00
|
|
|
Initialize as an App Router project.
|
2023-01-10 00:41:12 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--src-dir',
|
|
|
|
`
|
|
|
|
|
|
|
|
Initialize inside a \`src/\` directory.
|
2023-01-14 01:51:25 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--import-alias <alias-to-configure>',
|
|
|
|
`
|
|
|
|
|
|
|
|
Specify import alias to use (default "@/*").
|
2021-05-07 10:08:16 +02:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--use-npm',
|
|
|
|
`
|
|
|
|
|
2023-05-03 02:28:31 +02:00
|
|
|
Explicitly tell the CLI to bootstrap the application using npm
|
2022-03-04 00:49:24 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--use-pnpm',
|
|
|
|
`
|
|
|
|
|
2023-05-03 02:28:31 +02:00
|
|
|
Explicitly tell the CLI to bootstrap the application using pnpm
|
2023-05-10 14:51:12 +02:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--use-yarn',
|
|
|
|
`
|
|
|
|
|
|
|
|
Explicitly tell the CLI to bootstrap the application using Yarn
|
2021-05-07 10:08:16 +02:00
|
|
|
`
|
|
|
|
)
|
2019-07-19 21:55:30 +02:00
|
|
|
.option(
|
2020-04-07 19:11:29 +02:00
|
|
|
'-e, --example [name]|[github-url]',
|
2020-02-27 16:32:33 +01:00
|
|
|
`
|
|
|
|
|
|
|
|
An example to bootstrap the app with. You can use an example name
|
|
|
|
from the official Next.js repo or a GitHub URL. The URL can use
|
|
|
|
any branch and/or subdirectory
|
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--example-path <path-to-example>',
|
|
|
|
`
|
|
|
|
|
|
|
|
In a rare case, your GitHub URL might contain a branch name with
|
|
|
|
a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar).
|
|
|
|
In this case, you must specify the path to the example separately:
|
|
|
|
--example-path foo/bar
|
2023-01-14 01:51:25 +01:00
|
|
|
`
|
|
|
|
)
|
|
|
|
.option(
|
|
|
|
'--reset-preferences',
|
|
|
|
`
|
|
|
|
|
|
|
|
Explicitly tell the CLI to reset any stored preferences
|
2020-02-27 16:32:33 +01:00
|
|
|
`
|
2019-07-19 21:55:30 +02:00
|
|
|
)
|
|
|
|
.allowUnknownOption()
|
|
|
|
.parse(process.argv)
|
|
|
|
|
2022-10-13 23:34:55 +02:00
|
|
|
const packageManager = !!program.useNpm
|
|
|
|
? 'npm'
|
|
|
|
: !!program.usePnpm
|
|
|
|
? 'pnpm'
|
2023-05-10 14:51:12 +02:00
|
|
|
: !!program.useYarn
|
|
|
|
? 'yarn'
|
2022-10-13 23:34:55 +02:00
|
|
|
: getPkgManager()
|
|
|
|
|
2020-05-10 23:51:47 +02:00
|
|
|
async function run(): Promise<void> {
|
2023-01-14 01:51:25 +01:00
|
|
|
const conf = new Conf({ projectName: 'create-next-app' })
|
|
|
|
|
|
|
|
if (program.resetPreferences) {
|
|
|
|
conf.clear()
|
|
|
|
console.log(`Preferences reset successfully`)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-07-19 21:55:30 +02:00
|
|
|
if (typeof projectPath === 'string') {
|
|
|
|
projectPath = projectPath.trim()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!projectPath) {
|
|
|
|
const res = await prompts({
|
2023-01-24 04:30:38 +01:00
|
|
|
onState: onPromptState,
|
2019-07-19 21:55:30 +02:00
|
|
|
type: 'text',
|
|
|
|
name: 'path',
|
|
|
|
message: 'What is your project named?',
|
|
|
|
initial: 'my-app',
|
2020-05-18 21:24:37 +02:00
|
|
|
validate: (name) => {
|
2019-07-19 21:55:30 +02:00
|
|
|
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(
|
2022-05-22 20:50:08 +02:00
|
|
|
'\nPlease specify the project directory:\n' +
|
|
|
|
` ${chalk.cyan(program.name())} ${chalk.green(
|
|
|
|
'<project-directory>'
|
|
|
|
)}\n` +
|
|
|
|
'For example:\n' +
|
|
|
|
` ${chalk.cyan(program.name())} ${chalk.green('my-next-app')}\n\n` +
|
|
|
|
`Run ${chalk.cyan(`${program.name()} --help`)} to see all options.`
|
2019-07-19 21:55:30 +02:00
|
|
|
)
|
|
|
|
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:`
|
|
|
|
)
|
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
problems!.forEach((p) => console.error(` ${chalk.red.bold('*')} ${p}`))
|
2019-07-19 21:55:30 +02:00
|
|
|
process.exit(1)
|
|
|
|
}
|
|
|
|
|
2020-06-10 05:14:24 +02:00
|
|
|
if (program.example === true) {
|
|
|
|
console.error(
|
|
|
|
'Please provide an example name or url, otherwise remove the example option.'
|
|
|
|
)
|
|
|
|
process.exit(1)
|
2020-04-07 19:11:29 +02:00
|
|
|
}
|
|
|
|
|
2023-01-23 21:10:45 +01:00
|
|
|
/**
|
|
|
|
* Verify the project dir is empty or doesn't exist
|
|
|
|
*/
|
|
|
|
const root = path.resolve(resolvedProjectPath)
|
|
|
|
const appName = path.basename(root)
|
|
|
|
const folderExists = fs.existsSync(root)
|
|
|
|
|
|
|
|
if (folderExists && !isFolderEmpty(root, appName)) {
|
|
|
|
process.exit(1)
|
|
|
|
}
|
|
|
|
|
2020-05-24 00:50:31 +02:00
|
|
|
const example = typeof program.example === 'string' && program.example.trim()
|
2023-01-14 01:51:25 +01:00
|
|
|
const preferences = (conf.get('preferences') || {}) as Record<
|
|
|
|
string,
|
|
|
|
boolean | string
|
|
|
|
>
|
2022-10-31 06:43:39 +01:00
|
|
|
/**
|
|
|
|
* If the user does not provide the necessary flags, prompt them for whether
|
|
|
|
* to use TS or JS.
|
|
|
|
*/
|
2022-11-03 04:17:37 +01:00
|
|
|
if (!example) {
|
2023-01-14 01:51:25 +01:00
|
|
|
const defaults: typeof preferences = {
|
|
|
|
typescript: true,
|
|
|
|
eslint: true,
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
tailwind: true,
|
2023-01-14 01:51:25 +01:00
|
|
|
srcDir: false,
|
|
|
|
importAlias: '@/*',
|
2023-05-02 19:01:36 +02:00
|
|
|
customizeImportAlias: false,
|
2023-01-14 01:51:25 +01:00
|
|
|
}
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
const getPrefOrDefault = (field: string) =>
|
|
|
|
preferences[field] ?? defaults[field]
|
2023-01-14 01:51:25 +01:00
|
|
|
|
2022-11-07 23:02:34 +01:00
|
|
|
if (!program.typescript && !program.javascript) {
|
|
|
|
if (ciInfo.isCI) {
|
|
|
|
// default to JavaScript in CI as we can't prompt to
|
|
|
|
// prevent breaking setup flows
|
|
|
|
program.typescript = false
|
|
|
|
program.javascript = true
|
|
|
|
} else {
|
2023-03-20 23:33:44 +01:00
|
|
|
const styledTypeScript = chalk.hex('#007acc')('TypeScript')
|
2022-11-03 04:17:37 +01:00
|
|
|
const { typescript } = await prompts(
|
|
|
|
{
|
|
|
|
type: 'toggle',
|
|
|
|
name: 'typescript',
|
|
|
|
message: `Would you like to use ${styledTypeScript} with this project?`,
|
2023-01-14 01:51:25 +01:00
|
|
|
initial: getPrefOrDefault('typescript'),
|
2022-11-03 04:17:37 +01:00
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
2022-10-31 06:43:39 +01:00
|
|
|
},
|
2022-11-03 04:17:37 +01:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* User inputs Ctrl+C or Ctrl+D to exit the prompt. We should close the
|
|
|
|
* process and not write to the file system.
|
|
|
|
*/
|
|
|
|
onCancel: () => {
|
|
|
|
console.error('Exiting.')
|
|
|
|
process.exit(1)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
/**
|
|
|
|
* Depending on the prompt response, set the appropriate program flags.
|
|
|
|
*/
|
|
|
|
program.typescript = Boolean(typescript)
|
|
|
|
program.javascript = !Boolean(typescript)
|
2023-01-14 01:51:25 +01:00
|
|
|
preferences.typescript = Boolean(typescript)
|
2022-11-03 04:17:37 +01:00
|
|
|
}
|
2022-11-07 23:02:34 +01:00
|
|
|
}
|
2022-10-31 16:51:50 +01:00
|
|
|
|
2022-11-07 23:02:34 +01:00
|
|
|
if (
|
|
|
|
!process.argv.includes('--eslint') &&
|
|
|
|
!process.argv.includes('--no-eslint')
|
|
|
|
) {
|
|
|
|
if (ciInfo.isCI) {
|
|
|
|
program.eslint = true
|
|
|
|
} else {
|
2023-03-20 23:33:44 +01:00
|
|
|
const styledEslint = chalk.hex('#007acc')('ESLint')
|
2022-10-31 16:51:50 +01:00
|
|
|
const { eslint } = await prompts({
|
2023-01-24 04:30:38 +01:00
|
|
|
onState: onPromptState,
|
2022-10-31 16:51:50 +01:00
|
|
|
type: 'toggle',
|
|
|
|
name: 'eslint',
|
|
|
|
message: `Would you like to use ${styledEslint} with this project?`,
|
2023-01-14 01:51:25 +01:00
|
|
|
initial: getPrefOrDefault('eslint'),
|
2022-10-31 16:51:50 +01:00
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
|
|
|
})
|
|
|
|
program.eslint = Boolean(eslint)
|
2023-01-14 01:51:25 +01:00
|
|
|
preferences.eslint = Boolean(eslint)
|
2022-10-31 16:51:50 +01:00
|
|
|
}
|
2022-10-31 06:43:39 +01:00
|
|
|
}
|
2023-01-10 00:41:12 +01:00
|
|
|
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
if (
|
|
|
|
!process.argv.includes('--tailwind') &&
|
|
|
|
!process.argv.includes('--no-tailwind')
|
|
|
|
) {
|
|
|
|
if (ciInfo.isCI) {
|
|
|
|
program.tailwind = false
|
|
|
|
} else {
|
2023-03-20 23:33:44 +01:00
|
|
|
const tw = chalk.hex('#007acc')('Tailwind CSS')
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
const { tailwind } = await prompts({
|
|
|
|
onState: onPromptState,
|
|
|
|
type: 'toggle',
|
|
|
|
name: 'tailwind',
|
|
|
|
message: `Would you like to use ${tw} with this project?`,
|
|
|
|
initial: getPrefOrDefault('tailwind'),
|
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
|
|
|
})
|
|
|
|
program.tailwind = Boolean(tailwind)
|
|
|
|
preferences.tailwind = Boolean(tailwind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-10 00:41:12 +01:00
|
|
|
if (
|
|
|
|
!process.argv.includes('--src-dir') &&
|
|
|
|
!process.argv.includes('--no-src-dir')
|
|
|
|
) {
|
|
|
|
if (ciInfo.isCI) {
|
|
|
|
program.srcDir = false
|
|
|
|
} else {
|
|
|
|
const styledSrcDir = chalk.hex('#007acc')('`src/` directory')
|
|
|
|
const { srcDir } = await prompts({
|
2023-01-24 04:30:38 +01:00
|
|
|
onState: onPromptState,
|
2023-01-10 00:41:12 +01:00
|
|
|
type: 'toggle',
|
|
|
|
name: 'srcDir',
|
|
|
|
message: `Would you like to use ${styledSrcDir} with this project?`,
|
2023-01-14 01:51:25 +01:00
|
|
|
initial: getPrefOrDefault('srcDir'),
|
2023-01-10 00:41:12 +01:00
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
|
|
|
})
|
|
|
|
program.srcDir = Boolean(srcDir)
|
2023-01-14 01:51:25 +01:00
|
|
|
preferences.srcDir = Boolean(srcDir)
|
2023-01-10 00:41:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-03 02:28:31 +02:00
|
|
|
if (!process.argv.includes('--app') && !process.argv.includes('--no-app')) {
|
2023-01-10 00:41:12 +01:00
|
|
|
if (ciInfo.isCI) {
|
2023-05-03 02:28:31 +02:00
|
|
|
program.app = true
|
2023-01-10 00:41:12 +01:00
|
|
|
} else {
|
2023-05-03 02:28:31 +02:00
|
|
|
const styledAppDir = chalk.hex('#007acc')('App Router')
|
|
|
|
const { appRouter } = await prompts({
|
2023-01-24 04:30:38 +01:00
|
|
|
onState: onPromptState,
|
2023-01-10 00:41:12 +01:00
|
|
|
type: 'toggle',
|
2023-05-03 02:28:31 +02:00
|
|
|
name: 'appRouter',
|
|
|
|
message: `Use ${styledAppDir} (recommended)?`,
|
|
|
|
initial: true,
|
2023-01-10 00:41:12 +01:00
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
|
|
|
})
|
2023-05-03 02:28:31 +02:00
|
|
|
program.app = Boolean(appRouter)
|
2023-01-10 00:41:12 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-14 01:51:25 +01:00
|
|
|
|
|
|
|
if (
|
|
|
|
typeof program.importAlias !== 'string' ||
|
|
|
|
!program.importAlias.length
|
|
|
|
) {
|
|
|
|
if (ciInfo.isCI) {
|
|
|
|
program.importAlias = '@/*'
|
|
|
|
} else {
|
2023-01-25 01:36:16 +01:00
|
|
|
const styledImportAlias = chalk.hex('#007acc')('import alias')
|
2023-05-02 19:01:36 +02:00
|
|
|
|
|
|
|
const { customizeImportAlias } = await prompts({
|
2023-01-25 01:36:16 +01:00
|
|
|
onState: onPromptState,
|
2023-05-02 19:01:36 +02:00
|
|
|
type: 'toggle',
|
|
|
|
name: 'customizeImportAlias',
|
|
|
|
message: `Would you like to customize the default ${styledImportAlias}?`,
|
|
|
|
initial: getPrefOrDefault('customizeImportAlias'),
|
|
|
|
active: 'Yes',
|
|
|
|
inactive: 'No',
|
2023-01-25 01:36:16 +01:00
|
|
|
})
|
2023-05-02 19:01:36 +02:00
|
|
|
|
|
|
|
if (!customizeImportAlias) {
|
|
|
|
program.importAlias = '@/*'
|
|
|
|
} else {
|
|
|
|
const { importAlias } = await prompts({
|
|
|
|
onState: onPromptState,
|
|
|
|
type: 'text',
|
|
|
|
name: 'importAlias',
|
|
|
|
message: `What ${styledImportAlias} would you like configured?`,
|
|
|
|
initial: getPrefOrDefault('importAlias'),
|
|
|
|
validate: (value) =>
|
|
|
|
/.+\/\*/.test(value)
|
|
|
|
? true
|
|
|
|
: 'Import alias must follow the pattern <prefix>/*',
|
|
|
|
})
|
|
|
|
program.importAlias = importAlias
|
|
|
|
preferences.importAlias = importAlias
|
|
|
|
}
|
2023-01-14 01:51:25 +01:00
|
|
|
}
|
|
|
|
}
|
2022-10-31 06:43:39 +01:00
|
|
|
}
|
|
|
|
|
2020-05-26 18:39:18 +02:00
|
|
|
try {
|
|
|
|
await createApp({
|
|
|
|
appPath: resolvedProjectPath,
|
2022-03-04 00:49:24 +01:00
|
|
|
packageManager,
|
2020-05-26 18:39:18 +02:00
|
|
|
example: example && example !== 'default' ? example : undefined,
|
|
|
|
examplePath: program.examplePath,
|
2021-05-07 10:08:16 +02:00
|
|
|
typescript: program.typescript,
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
tailwind: program.tailwind,
|
2022-10-31 16:51:50 +01:00
|
|
|
eslint: program.eslint,
|
2023-05-03 02:28:31 +02:00
|
|
|
appRouter: program.app,
|
2023-01-10 00:41:12 +01:00
|
|
|
srcDir: program.srcDir,
|
2023-01-14 01:51:25 +01:00
|
|
|
importAlias: program.importAlias,
|
2020-05-26 18:39:18 +02:00
|
|
|
})
|
|
|
|
} catch (reason) {
|
|
|
|
if (!(reason instanceof DownloadError)) {
|
|
|
|
throw reason
|
|
|
|
}
|
|
|
|
|
|
|
|
const res = await prompts({
|
2023-01-24 04:30:38 +01:00
|
|
|
onState: onPromptState,
|
2020-05-26 18:39:18 +02:00
|
|
|
type: 'confirm',
|
|
|
|
name: 'builtin',
|
|
|
|
message:
|
|
|
|
`Could not download "${example}" because of a connectivity issue between your machine and GitHub.\n` +
|
|
|
|
`Do you want to use the default template instead?`,
|
|
|
|
initial: true,
|
|
|
|
})
|
|
|
|
if (!res.builtin) {
|
|
|
|
throw reason
|
|
|
|
}
|
|
|
|
|
2021-05-07 10:08:16 +02:00
|
|
|
await createApp({
|
|
|
|
appPath: resolvedProjectPath,
|
2022-03-04 00:49:24 +01:00
|
|
|
packageManager,
|
2021-05-07 10:08:16 +02:00
|
|
|
typescript: program.typescript,
|
2022-10-31 16:51:50 +01:00
|
|
|
eslint: program.eslint,
|
feat(cli): introduce `--tailwind` flag (#46927)
### What?
This PR introduces a new `--tailwind` flag to the `create-next-app` CLI,
to make it easier to bootstrap a Next.js app with Tailwind CSS
pre-configured. This is going to be the **default**. To opt-out of
Tailwind CSS, you can use the `--no-tailwind` flag.
### Why?
Tailwind CSS is one of the most popular styling solutions right now, and
we would like to make it easier to get started.
Currently, the closest you can come to this is by running `pnpm create
next-app -e with-tailwindcss` which will clone the
https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss
example. But that example is not configured for the App Router. This PR
will let you add Tailwind CSS to both `app/`, `pages/`, and start out
with TypeScript or JavaScript via the CLI prompts.
(Some community feedback
https://twitter.com/dev_jonaskaas/status/1632367991827443713,
https://twitter.com/samselikoff/status/1634662473331617794)
### How?
We are adding 4 new templates to the CLI bundle.
> Note: The styling is not pixel-perfect compared to the current
templates (using CSS modules) to require fewer overrides, but I tried to
match it as close as possible. Here are a few screenshots:
<details>
<summary><b>Current, light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733372-9dba86fe-9191-471d-ad9f-ab904c47f544.png"/>
</details>
<details>
<summary><b>Tailwind (new), light</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733610-038d9d0f-634d-4b69-b5c2-a5056b56760c.png"/>
</details>
<details>
<summary><b>Current, dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224733790-9b4d730c-0336-4dbe-bc10-1cae1d7fd145.png"/>
</details>
<details>
<summary><b>Tailwind (new), dark, responsive</b></summary>
<img
src="https://user-images.githubusercontent.com/18369201/224734375-28384bbc-2c3a-4125-8f29-c102f3b7aa1d.png"/>
</details>
#### For reviewers
This introduces 4 new templates, with a very similar code base to the
original ones. To keep the PR focused, I decided to copy over duplicate
code, but we could potentially create a shared folder for files that are
the same across templates to somewhat reduce the CLI size. Not sure if
it's worth it, let me know. Probably fine for now, but something to
consider if we are adding more permutations in the future.
---
~Work remaining:~
- [x] app+ts
- [x] layout
- [x] dark mode
- [x] media queries
- [x] animations
- [x] app+js
- [x] pages+ts
- [x] pages+js
- [x] prompt/config
- [x] deprecate Tailwind CSS example in favor of CLI
- [x] update docs
- [x] add test
- [x] add [Prettier
plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
Closes NEXT-772
Related #45814, #44286
2023-03-16 16:06:27 +01:00
|
|
|
tailwind: program.tailwind,
|
2023-05-03 02:28:31 +02:00
|
|
|
appRouter: program.app,
|
2023-01-10 00:41:12 +01:00
|
|
|
srcDir: program.srcDir,
|
2023-01-14 01:51:25 +01:00
|
|
|
importAlias: program.importAlias,
|
2021-05-07 10:08:16 +02:00
|
|
|
})
|
2020-05-26 18:39:18 +02:00
|
|
|
}
|
2023-01-14 01:51:25 +01:00
|
|
|
conf.set('preferences', preferences)
|
2019-07-19 21:55:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const update = checkForUpdate(packageJson).catch(() => null)
|
|
|
|
|
2020-05-10 23:51:47 +02:00
|
|
|
async function notifyUpdate(): Promise<void> {
|
2019-07-19 21:55:30 +02:00
|
|
|
try {
|
|
|
|
const res = await update
|
2020-01-08 17:30:53 +01:00
|
|
|
if (res?.latest) {
|
2022-10-13 23:34:55 +02:00
|
|
|
const updateMessage =
|
|
|
|
packageManager === 'yarn'
|
|
|
|
? 'yarn global add create-next-app'
|
|
|
|
: packageManager === 'pnpm'
|
|
|
|
? 'pnpm add -g create-next-app'
|
|
|
|
: 'npm i -g create-next-app'
|
|
|
|
|
2019-07-19 21:55:30 +02:00
|
|
|
console.log(
|
2022-05-22 20:50:08 +02:00
|
|
|
chalk.yellow.bold('A new version of `create-next-app` is available!') +
|
|
|
|
'\n' +
|
|
|
|
'You can update by running: ' +
|
2022-10-13 23:34:55 +02:00
|
|
|
chalk.cyan(updateMessage) +
|
2022-05-22 20:50:08 +02:00
|
|
|
'\n'
|
2019-07-19 21:55:30 +02:00
|
|
|
)
|
|
|
|
}
|
2020-04-07 19:11:29 +02:00
|
|
|
process.exit()
|
2019-07-19 21:55:30 +02:00
|
|
|
} catch {
|
|
|
|
// ignore error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
run()
|
|
|
|
.then(notifyUpdate)
|
2020-05-18 21:24:37 +02:00
|
|
|
.catch(async (reason) => {
|
2019-07-19 21:55:30 +02:00
|
|
|
console.log()
|
|
|
|
console.log('Aborting installation.')
|
|
|
|
if (reason.command) {
|
|
|
|
console.log(` ${chalk.cyan(reason.command)} has failed.`)
|
|
|
|
} else {
|
2022-05-22 20:50:08 +02:00
|
|
|
console.log(
|
|
|
|
chalk.red('Unexpected error. Please report it as a bug:') + '\n',
|
|
|
|
reason
|
|
|
|
)
|
2019-07-19 21:55:30 +02:00
|
|
|
}
|
|
|
|
console.log()
|
|
|
|
|
|
|
|
await notifyUpdate()
|
|
|
|
|
|
|
|
process.exit(1)
|
|
|
|
})
|