fix(cli): handle Tailwind CSS + src/ correctly (#47238)

### What?

- [x] fixes a bug in the CLI with the combination of `--tailwind` and
`--src-dir` flags.
- [x] fixes Tailwind CSS config when `--src-dir` is set
- [x] respect `NEXT_TEST_SKIP_CLEANUP` in test utils

### Why?

`pnpm create next-app@canary --tailwind --src-dir` should not fail.

### How?

We introduced the `app-tw` and `default-tw` templates, so we need to
respect them when working with files (in this case, the CLI was
erroneously assuming that if `template !== "app"` it must be a pages
template.)

I also noticed that the `tailwind.config.js` file need to also respect
`--src-dir` by prefixing the paths in `content`

Fixes #47236
fix NEXT-838 ([link](https://linear.app/vercel/issue/NEXT-838))

Related: #46927, #47276

---------

Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
Balázs Orbán 2023-03-20 22:21:29 +01:00 committed by GitHub
parent 5d9b166eba
commit 5448c234d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 7 deletions

View file

@ -123,21 +123,38 @@ export const installTemplate = async ({
})
})
)
const isAppTemplate = template.startsWith('app')
// Change the `Get started by editing pages/index` / `app/page` to include `src`
const indexPageFile = path.join(
'src',
template === 'app' ? 'app' : 'pages',
`${template === 'app' ? 'page' : 'index'}.${mode === 'ts' ? 'tsx' : 'js'}`
isAppTemplate ? 'app' : 'pages',
`${isAppTemplate ? 'page' : 'index'}.${mode === 'ts' ? 'tsx' : 'js'}`
)
await fs.promises.writeFile(
indexPageFile,
(
await fs.promises.readFile(indexPageFile, 'utf8')
).replace(
template === 'app' ? 'app/page' : 'pages/index',
template === 'app' ? 'src/app/page' : 'src/pages/index'
isAppTemplate ? 'app/page' : 'pages/index',
isAppTemplate ? 'src/app/page' : 'src/pages/index'
)
)
if (tailwind) {
const tailwindConfigFile = path.join(root, 'tailwind.config.js')
await fs.promises.writeFile(
tailwindConfigFile,
(
await fs.promises.readFile(tailwindConfigFile, 'utf8')
).replace(
/\.\/(\w+)\/\*\*\/\*\.\{js,ts,jsx,tsx\}/g,
'./src/$1/**/*.{js,ts,jsx,tsx}'
)
)
}
}
/**

View file

@ -309,6 +309,56 @@ describe('create-next-app templates', () => {
})
})
it('should work with --tailwind and --src together', async () => {
await useTempDir(async (cwd) => {
const projectName = 'tailwind-js-src'
/**
* Start the create-next-app call.
*/
const childProcess = createNextApp(
[
projectName,
'--js',
'--no-eslint',
'--tailwind',
'--src-dir',
'--no-experimental-app',
`--import-alias=@/*`,
],
{
cwd,
},
testVersion
)
/**
* Wait for the prompt to display.
*/
// await new Promise((resolve) => setTimeout(resolve, 1000));
/**
* Bind the exit listener.
*/
await new Promise<void>((resolve, reject) => {
childProcess.on('exit', async (exitCode) => {
expect(exitCode).toBe(0)
/**
* Verify it correctly emitted a Tailwind project by looking for tailwind.config.js.
*/
projectFilesShouldExist({
cwd,
projectName,
files: ['tailwind.config.js'],
})
resolve()
})
/**
* Simulate "N" for Tailwind.
*/
childProcess.stdin.write('N\n')
})
})
})
it('should prompt user to choose if --tailwind or --no-tailwind is not provided', async () => {
await useTempDir(async (cwd) => {
const projectName = 'choose-tailwind'
@ -483,7 +533,7 @@ describe('create-next-app --experimental-app', () => {
'--tailwind',
'--experimental-app',
'--eslint',
'--no-src-dir',
'--src-dir',
`--import-alias=@/*`,
],
{
@ -499,6 +549,7 @@ describe('create-next-app --experimental-app', () => {
projectName,
template: 'app-tw',
mode: 'ts',
srcDir: true,
})
await startsWithoutError(
path.join(cwd, projectName),

View file

@ -4,7 +4,7 @@ import path from 'path'
/**
* Create a randomly-named directory in `os.tmpdir()`, await a function call,
* and delete the directory when finished.
* and delete the directory when finished, unless `NEXT_TEST_SKIP_CLEANUP` is set.
*/
export async function useTempDir(
fn: (folder: string) => void | Promise<void>,
@ -23,6 +23,8 @@ export async function useTempDir(
try {
await fn(folder)
} finally {
await fs.remove(folder)
if (!process.env.NEXT_TEST_SKIP_CLEANUP) {
await fs.remove(folder)
}
}
}