diff --git a/.changeset/standalone-prettier-toolchain.md b/.changeset/standalone-prettier-toolchain.md new file mode 100644 index 00000000..320e8d15 --- /dev/null +++ b/.changeset/standalone-prettier-toolchain.md @@ -0,0 +1,5 @@ +--- +'@tanstack/create': minor +--- + +Add a standalone Prettier toolchain for React and Solid apps, available with `--toolchain prettier` or `tanstack add prettier`. diff --git a/packages/cli/tests-e2e/prettier-smoke.spec.ts b/packages/cli/tests-e2e/prettier-smoke.spec.ts new file mode 100644 index 00000000..106fc5ec --- /dev/null +++ b/packages/cli/tests-e2e/prettier-smoke.spec.ts @@ -0,0 +1,51 @@ +import { execFile } from 'node:child_process' +import { appendFile, readFile } from 'node:fs/promises' +import { join } from 'node:path' +import { promisify } from 'node:util' +import { expect, test } from '@playwright/test' +import { createReactAppFixture } from './helpers' + +const execFileAsync = promisify(execFile) + +for (const framework of ['react', 'solid'] as const) { + for (const mode of ['standard', 'blank', 'existing'] as const) { + test(`@blocking formats a ${mode} ${framework} app with standalone Prettier`, async () => { + const packageManager = mode === 'blank' ? 'npm' : 'pnpm' + const fixture = await createReactAppFixture({ + appName: `${framework}-prettier-${mode}`, + framework, + bundler: mode === 'blank' ? 'rsbuild' : 'vite', + blank: mode !== 'standard', + ...(mode === 'existing' + ? { postCreateAddOns: ['prettier'] } + : { toolchain: 'prettier' }), + packageManager, + skipDevServer: true, + runQualityGatesChecks: true, + }) + const run = (script: string) => + execFileAsync(packageManager, ['run', script], { + cwd: fixture.appDir, + timeout: 60_000, + }) + try { + const manifest = JSON.parse( + await readFile(join(fixture.appDir, 'package.json'), 'utf8'), + ) + expect(manifest.devDependencies.prettier).toBe('^3.8.1') + expect(manifest.devDependencies.eslint).toBeUndefined() + expect(manifest.devDependencies['@biomejs/biome']).toBeUndefined() + expect(manifest.scripts.lint).toBeUndefined() + await run('format') + await run('check') + await appendFile(join(fixture.appDir, 'src/routes/index.tsx'), '\n\n\n') + await expect(run('check')).rejects.toMatchObject({ code: 1 }) + await run('format') + await run('check') + } finally { + await fixture.stop() + await fixture.cleanup() + } + }) + } +} diff --git a/packages/create/src/frameworks/react/toolchains/prettier/README.md.ejs b/packages/create/src/frameworks/react/toolchains/prettier/README.md.ejs new file mode 100644 index 00000000..929f373a --- /dev/null +++ b/packages/create/src/frameworks/react/toolchains/prettier/README.md.ejs @@ -0,0 +1,6 @@ +## Formatting + +Run `<%= getPackageManagerRunScript('format') %>` to format your files and +`<%= getPackageManagerRunScript('check') %>` to check formatting without changing them. + +Prettier is configured in `prettier.config.js`. This toolchain does not add a linter. diff --git a/packages/create/src/frameworks/react/toolchains/prettier/assets/_dot_prettierignore b/packages/create/src/frameworks/react/toolchains/prettier/assets/_dot_prettierignore new file mode 100644 index 00000000..3ac44f99 --- /dev/null +++ b/packages/create/src/frameworks/react/toolchains/prettier/assets/_dot_prettierignore @@ -0,0 +1,13 @@ +node_modules +dist +build +.output +.tanstack +coverage +src/routeTree.gen.ts +package-lock.json +pnpm-lock.yaml +yarn.lock +bun.lock +bun.lockb +deno.lock diff --git a/packages/create/src/frameworks/react/toolchains/prettier/assets/prettier.config.js b/packages/create/src/frameworks/react/toolchains/prettier/assets/prettier.config.js new file mode 100644 index 00000000..27a4d258 --- /dev/null +++ b/packages/create/src/frameworks/react/toolchains/prettier/assets/prettier.config.js @@ -0,0 +1,6 @@ +/** @type {import('prettier').Config} */ +export default { + semi: false, + singleQuote: true, + trailingComma: 'all', +} diff --git a/packages/create/src/frameworks/react/toolchains/prettier/info.json b/packages/create/src/frameworks/react/toolchains/prettier/info.json new file mode 100644 index 00000000..b063838f --- /dev/null +++ b/packages/create/src/frameworks/react/toolchains/prettier/info.json @@ -0,0 +1,16 @@ +{ + "name": "Prettier", + "description": "Format code without adding a linter.", + "phase": "setup", + "type": "toolchain", + "category": "tooling", + "exclusive": [ + "linter" + ], + "color": "#F7B93E", + "modes": [ + "code-router", + "file-router" + ], + "link": "https://prettier.io" +} diff --git a/packages/create/src/frameworks/react/toolchains/prettier/package.json b/packages/create/src/frameworks/react/toolchains/prettier/package.json new file mode 100644 index 00000000..c3030fab --- /dev/null +++ b/packages/create/src/frameworks/react/toolchains/prettier/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "format": "prettier --write .", + "check": "prettier --check ." + }, + "devDependencies": { + "prettier": "^3.8.1" + } +} diff --git a/packages/create/src/frameworks/solid/toolchains/prettier/README.md.ejs b/packages/create/src/frameworks/solid/toolchains/prettier/README.md.ejs new file mode 100644 index 00000000..929f373a --- /dev/null +++ b/packages/create/src/frameworks/solid/toolchains/prettier/README.md.ejs @@ -0,0 +1,6 @@ +## Formatting + +Run `<%= getPackageManagerRunScript('format') %>` to format your files and +`<%= getPackageManagerRunScript('check') %>` to check formatting without changing them. + +Prettier is configured in `prettier.config.js`. This toolchain does not add a linter. diff --git a/packages/create/src/frameworks/solid/toolchains/prettier/assets/_dot_prettierignore b/packages/create/src/frameworks/solid/toolchains/prettier/assets/_dot_prettierignore new file mode 100644 index 00000000..3ac44f99 --- /dev/null +++ b/packages/create/src/frameworks/solid/toolchains/prettier/assets/_dot_prettierignore @@ -0,0 +1,13 @@ +node_modules +dist +build +.output +.tanstack +coverage +src/routeTree.gen.ts +package-lock.json +pnpm-lock.yaml +yarn.lock +bun.lock +bun.lockb +deno.lock diff --git a/packages/create/src/frameworks/solid/toolchains/prettier/assets/prettier.config.js b/packages/create/src/frameworks/solid/toolchains/prettier/assets/prettier.config.js new file mode 100644 index 00000000..27a4d258 --- /dev/null +++ b/packages/create/src/frameworks/solid/toolchains/prettier/assets/prettier.config.js @@ -0,0 +1,6 @@ +/** @type {import('prettier').Config} */ +export default { + semi: false, + singleQuote: true, + trailingComma: 'all', +} diff --git a/packages/create/src/frameworks/solid/toolchains/prettier/info.json b/packages/create/src/frameworks/solid/toolchains/prettier/info.json new file mode 100644 index 00000000..b063838f --- /dev/null +++ b/packages/create/src/frameworks/solid/toolchains/prettier/info.json @@ -0,0 +1,16 @@ +{ + "name": "Prettier", + "description": "Format code without adding a linter.", + "phase": "setup", + "type": "toolchain", + "category": "tooling", + "exclusive": [ + "linter" + ], + "color": "#F7B93E", + "modes": [ + "code-router", + "file-router" + ], + "link": "https://prettier.io" +} diff --git a/packages/create/src/frameworks/solid/toolchains/prettier/package.json b/packages/create/src/frameworks/solid/toolchains/prettier/package.json new file mode 100644 index 00000000..c3030fab --- /dev/null +++ b/packages/create/src/frameworks/solid/toolchains/prettier/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "format": "prettier --write .", + "check": "prettier --check ." + }, + "devDependencies": { + "prettier": "^3.8.1" + } +}