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:
parent
5d9b166eba
commit
5448c234d6
3 changed files with 77 additions and 7 deletions
|
@ -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}'
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue