diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index fbc4663aa4..ad5e089cba 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -27,9 +27,8 @@ jobs: tailwind: ["true", "false"] nextAuth: ["true", "false"] prisma: ["true", "false"] - prettierAndExtendedEslint: ["true", "false"] - name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.prettierAndExtendedEslint }}" + name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}" steps: - uses: actions/checkout@v3 with: @@ -66,7 +65,7 @@ jobs: # has to be scaffolded outside the CLI project so that no lint/tsconfig are leaking # through. this way it ensures that it is the app's configs that are being used # FIXME: this is a bit hacky, would rather have --packages=trpc,tailwind,... but not sure how to setup the matrix for that - - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.prettierAndExtendedEslint }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --prettier-and-extended-eslint=${{ matrix.prettierAndExtendedEslint }} - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.prettierAndExtendedEslint }} && pnpm build + - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }} && pnpm build env: NEXTAUTH_SECRET: foo diff --git a/cli/src/cli/index.ts b/cli/src/cli/index.ts index bc7e3b8e71..73c8833879 100644 --- a/cli/src/cli/index.ts +++ b/cli/src/cli/index.ts @@ -2,10 +2,8 @@ import chalk from "chalk"; import { Command } from "commander"; import inquirer from "inquirer"; import { CREATE_T3_APP, DEFAULT_APP_NAME } from "~/consts.js"; -import { - availablePackages, - type AvailablePackages, -} from "~/installers/index.js"; +import { type AvailablePackages } from "~/installers/index.js"; +import { availablePackages } from "~/installers/index.js"; import { getVersion } from "~/utils/getT3Version.js"; import { getUserPkgManager } from "~/utils/getUserPkgManager.js"; import { logger } from "~/utils/logger.js"; @@ -17,7 +15,6 @@ interface CliFlags { noInstall: boolean; default: boolean; importAlias: string; - prettierAndExtendedEslint: boolean; /** @internal Used in CI. */ CI: boolean; @@ -50,7 +47,6 @@ const defaultOptions: CliResults = { prisma: false, nextAuth: false, importAlias: "~/", - prettierAndExtendedEslint: false, }, }; @@ -118,12 +114,6 @@ export const runCli = async () => { "Explicitly tell the CLI to use a custom import alias", defaultOptions.flags.importAlias, ) - /** @experimental - Used for CI E2E tests. Used in conjunction with `--CI` to skip prompting. */ - .option( - "-p, --prettier-and-extended-eslint", - "Explicitly tell the CLI to use a custom import alias", - defaultOptions.flags.prettierAndExtendedEslint, - ) /** END CI-FLAGS */ .version(getVersion(), "-v, --version", "Display the version number") .addHelpText( @@ -163,9 +153,6 @@ export const runCli = async () => { if (cliResults.flags.tailwind) cliResults.packages.push("tailwind"); if (cliResults.flags.prisma) cliResults.packages.push("prisma"); if (cliResults.flags.nextAuth) cliResults.packages.push("nextAuth"); - if (cliResults.flags.prettierAndExtendedEslint) { - cliResults.flags.prettierAndExtendedEslint = true; - } } // Explained below why this is in a try/catch block @@ -199,9 +186,6 @@ export const runCli = async () => { } cliResults.flags.importAlias = await promptImportAlias(); - - cliResults.flags.prettierAndExtendedEslint = - await promtPrettierAndExtendedEslint(); } } catch (err) { // If the user is not calling create-t3-app from an interactive terminal, inquirer will throw an error with isTTYError = true @@ -345,16 +329,3 @@ const promptImportAlias = async (): Promise => { return importAlias; }; - -const promtPrettierAndExtendedEslint = async (): Promise => { - const { prettierAndExtendedEslint } = await inquirer.prompt< - Pick - >({ - name: "prettierAndExtendedEslint", - type: "confirm", - message: "Would you like to use prettier and extended eslint conifg?", - default: defaultOptions.flags.prettierAndExtendedEslint, - }); - - return prettierAndExtendedEslint; -}; diff --git a/cli/src/helpers/createProject.ts b/cli/src/helpers/createProject.ts index fe2ca1560c..ea1e3942f4 100644 --- a/cli/src/helpers/createProject.ts +++ b/cli/src/helpers/createProject.ts @@ -2,9 +2,7 @@ import path from "path"; import { installPackages } from "~/helpers/installPackages.js"; import { scaffoldProject } from "~/helpers/scaffoldProject.js"; import { selectAppFile, selectIndexFile } from "~/helpers/selectBoilerplate.js"; -import { installExtendedEslint } from "~/installers/eslint.js"; import { type PkgInstallerMap } from "~/installers/index.js"; -import { installPrettier } from "~/installers/prettier.js"; import { getUserPkgManager } from "~/utils/getUserPkgManager.js"; interface CreateProjectOptions { @@ -12,14 +10,12 @@ interface CreateProjectOptions { packages: PkgInstallerMap; noInstall: boolean; importAlias: string; - prettierAndExtendedEslint: boolean; } export const createProject = async ({ projectName, packages, noInstall, - prettierAndExtendedEslint, }: CreateProjectOptions) => { const pkgManager = getUserPkgManager(); const projectDir = path.resolve(process.cwd(), projectName); @@ -40,16 +36,6 @@ export const createProject = async ({ noInstall, }); - if (prettierAndExtendedEslint) { - const installArgs = { - projectDir, - pkgManager, - noInstall, - }; - installPrettier(installArgs); - installExtendedEslint(installArgs); - } - // TODO: Look into using handlebars or other templating engine to scaffold without needing to maintain multiple copies of the same file selectAppFile({ projectDir, packages }); selectIndexFile({ projectDir, packages }); diff --git a/cli/src/index.ts b/cli/src/index.ts index 3e867b6e88..66bca71a87 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -32,7 +32,7 @@ const main = async () => { const { appName, packages, - flags: { noGit, noInstall, importAlias, prettierAndExtendedEslint }, + flags: { noGit, noInstall, importAlias }, } = await runCli(); const usePackages = buildPkgInstallerMap(packages); @@ -45,7 +45,6 @@ const main = async () => { packages: usePackages, importAlias: importAlias, noInstall, - prettierAndExtendedEslint, }); // Write name to package.json @@ -68,12 +67,10 @@ const main = async () => { } // Rename _eslintrc.json to .eslintrc.json - we use _eslintrc.json to avoid conflicts with the monorepos linter - if (fs.existsSync(path.join(projectDir, "_eslintrc.cjs"))) { - fs.renameSync( - path.join(projectDir, "_eslintrc.cjs"), - path.join(projectDir, ".eslintrc.cjs"), - ); - } + fs.renameSync( + path.join(projectDir, "_eslintrc.cjs"), + path.join(projectDir, ".eslintrc.cjs"), + ); if (!noGit) { await initializeGit(projectDir); diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index 5fde931227..dffeacc809 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -15,6 +15,9 @@ export const dependencyVersionMap = { tailwindcss: "^3.3.0", autoprefixer: "^10.4.14", postcss: "^8.4.21", + prettier: "^2.8.6", + "prettier-plugin-tailwindcss": "^0.2.6", + "@types/prettier": "^2.7.2", // tRPC "@trpc/client": "^10.18.0", @@ -23,14 +26,5 @@ export const dependencyVersionMap = { "@trpc/next": "^10.18.0", "@tanstack/react-query": "^4.28.0", superjson: "1.12.2", - - // Prettier - prettier: "^2.8.6", - "prettier-plugin-tailwindcss": "^0.2.6", - "@types/prettier": "^2.7.2", - "@ianvs/prettier-plugin-sort-imports": "^3.7.2", - - // Eslint - "eslint-config-next": "^13.4.1", } as const; export type AvailableDependencies = keyof typeof dependencyVersionMap; diff --git a/cli/src/installers/eslint.ts b/cli/src/installers/eslint.ts deleted file mode 100644 index 7c5536132b..0000000000 --- a/cli/src/installers/eslint.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { type Installer } from "./index.js"; -import fs from "fs-extra"; -import path from "path"; -import { PKG_ROOT } from "~/consts.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; - -export const installExtendedEslint: Installer = ({ projectDir }) => { - addPackageDependency({ - dependencies: ["eslint-config-next"], - devMode: true, - projectDir, - }); - - const configDir = path.join(PKG_ROOT, "template/extras/config"); - - // Remove the default config - fs.rmSync(path.join(projectDir, "_eslintrc.cjs")); - - fs.copySync( - path.join(configDir, "_eslintrc.cjs"), - path.join(projectDir, ".eslintrc.cjs"), - ); -}; diff --git a/cli/src/installers/prettier.ts b/cli/src/installers/prettier.ts deleted file mode 100644 index 8b33d3b9d0..0000000000 --- a/cli/src/installers/prettier.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { type Installer } from "../installers/index.js"; -import { type AvailableDependencies } from "./dependencyVersionMap.js"; -import fs from "fs-extra"; -import path from "path"; -import { PKG_ROOT } from "~/consts.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; -import { addPackageScript } from "~/utils/addPackageScript.js"; - -export const installPrettier: Installer = ({ projectDir, packages }) => { - const packeagesToInstall: AvailableDependencies[] = [ - "prettier", - "@types/prettier", - "@ianvs/prettier-plugin-sort-imports", - ]; - - if (packages?.tailwind.inUse) { - packeagesToInstall.push("prettier-plugin-tailwindcss"); - } - - addPackageDependency({ - projectDir, - dependencies: packeagesToInstall, - devMode: true, - }); - - addPackageScript({ - projectDir, - scripts: [ - { - name: "format", - value: "pnpm format:check --write", - }, - { - name: "format:check", - value: - "pnpm prettier --check --plugin-search-dir=. **/*.{cjs,mjs,ts,tsx,md,json} --ignore-path ../.gitignore --ignore-unknown --no-error-on-unmatched-pattern", - }, - ], - }); - - if (packages?.tailwind.inUse) { - fs.copySync( - path.join( - PKG_ROOT, - "template/extras/config/prettier-with-tailwind.config.cjs", - ), - path.join(projectDir, "prettier.config.cjs"), - ); - } else { - fs.copySync( - path.join(PKG_ROOT, "template/extras/config/_prettier.config.cjs"), - path.join(projectDir, "prettier.config.cjs"), - ); - } -}; diff --git a/cli/src/installers/tailwind.ts b/cli/src/installers/tailwind.ts index 681841b989..10fd860a3c 100644 --- a/cli/src/installers/tailwind.ts +++ b/cli/src/installers/tailwind.ts @@ -7,7 +7,14 @@ import { addPackageDependency } from "~/utils/addPackageDependency.js"; export const tailwindInstaller: Installer = ({ projectDir }) => { addPackageDependency({ projectDir, - dependencies: ["tailwindcss", "postcss", "autoprefixer"], + dependencies: [ + "tailwindcss", + "postcss", + "autoprefixer", + "prettier", + "prettier-plugin-tailwindcss", + "@types/prettier", + ], devMode: true, }); @@ -19,12 +26,16 @@ export const tailwindInstaller: Installer = ({ projectDir }) => { const postcssCfgSrc = path.join(extrasDir, "config/postcss.config.cjs"); const postcssCfgDest = path.join(projectDir, "postcss.config.cjs"); + const prettierSrc = path.join(extrasDir, "config/prettier.config.cjs"); + const prettierDest = path.join(projectDir, "prettier.config.cjs"); + const cssSrc = path.join(extrasDir, "src/styles/globals.css"); const cssDest = path.join(projectDir, "src/styles/globals.css"); fs.copySync(twCfgSrc, twCfgDest); fs.copySync(postcssCfgSrc, postcssCfgDest); fs.copySync(cssSrc, cssDest); + fs.copySync(prettierSrc, prettierDest); // Remove vanilla css file const indexModuleCss = path.join(projectDir, "src/pages/index.module.css"); diff --git a/cli/src/utils/addPackageScript.ts b/cli/src/utils/addPackageScript.ts deleted file mode 100644 index 6ad54b3e44..0000000000 --- a/cli/src/utils/addPackageScript.ts +++ /dev/null @@ -1,26 +0,0 @@ -import fs from "fs-extra"; -import path from "path"; -import sortPackageJson from "sort-package-json"; -import { type PackageJson } from "type-fest"; - -export const addPackageScript = (opts: { - scripts: { name: string; value: string }[]; - projectDir: string; -}) => { - const pkgJson = fs.readJSONSync( - path.join(opts.projectDir, "package.json"), - ) as PackageJson; - - if (!pkgJson.scripts) { - pkgJson.scripts = {}; - } - - for (const script of opts.scripts) { - pkgJson.scripts[script.name] = script.value; - } - const sortedPkgJson = sortPackageJson(pkgJson); - - fs.writeJSONSync(path.join(opts.projectDir, "package.json"), sortedPkgJson, { - spaces: 2, - }); -}; diff --git a/cli/template/base/_eslintrc.cjs b/cli/template/base/_eslintrc.cjs index 3733acb0cf..8b7a0e8f9c 100644 --- a/cli/template/base/_eslintrc.cjs +++ b/cli/template/base/_eslintrc.cjs @@ -3,11 +3,33 @@ const path = require("path"); /** @type {import("eslint").Linter.Config} */ const config = { + overrides: [ + { + extends: [ + "plugin:@typescript-eslint/recommended-requiring-type-checking", + ], + files: ["*.ts", "*.tsx"], + parserOptions: { + project: path.join(__dirname, "tsconfig.json"), + }, + }, + ], parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "tsconfig.json"), }, plugins: ["@typescript-eslint"], + extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], + rules: { + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + prefer: "type-imports", + fixStyle: "inline-type-imports", + }, + ], + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + }, }; module.exports = config; diff --git a/cli/template/base/package.json b/cli/template/base/package.json index 104332ac5c..23bb2c89da 100644 --- a/cli/template/base/package.json +++ b/cli/template/base/package.json @@ -23,6 +23,7 @@ "@typescript-eslint/eslint-plugin": "^5.56.0", "@typescript-eslint/parser": "^5.56.0", "eslint": "^8.36.0", + "eslint-config-next": "^13.4.1", "typescript": "^5.0.2" } } diff --git a/cli/template/extras/config/_eslintrc.cjs b/cli/template/extras/config/_eslintrc.cjs deleted file mode 100644 index 758c95a7b3..0000000000 --- a/cli/template/extras/config/_eslintrc.cjs +++ /dev/null @@ -1,43 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const path = require("path"); - -/** @type {import("eslint").Linter.Config} */ -const config = { - overrides: [ - { - extends: [ - "plugin:@typescript-eslint/recommended-requiring-type-checking", - ], - files: ["*.ts", "*.tsx"], - parserOptions: { - project: path.join(__dirname, "tsconfig.json"), - }, - }, - ], - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "tsconfig.json"), - }, - plugins: ["@typescript-eslint"], - extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], - rules: { - "@typescript-eslint/consistent-type-imports": [ - "warn", - { - prefer: "type-imports", - fixStyle: "inline-type-imports", - }, - ], - "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], - "@typescript-eslint/no-misused-promises": [ - 2, - { - checksVoidReturn: { - attributes: false, - }, - }, - ], - }, -}; - -module.exports = config; diff --git a/cli/template/extras/config/prettier-with-tailwind.config.cjs b/cli/template/extras/config/prettier-with-tailwind.config.cjs deleted file mode 100644 index f817bf3608..0000000000 --- a/cli/template/extras/config/prettier-with-tailwind.config.cjs +++ /dev/null @@ -1,9 +0,0 @@ -/** @type {import("prettier").Config} */ -const config = { - plugins: [ - "@ianvs/prettier-plugin-sort-imports", - "prettier-plugin-tailwindcss", - ], -}; - -module.exports = config; diff --git a/cli/template/extras/config/_prettier.config.cjs b/cli/template/extras/config/prettier.config.cjs similarity index 58% rename from cli/template/extras/config/_prettier.config.cjs rename to cli/template/extras/config/prettier.config.cjs index 6058b6de93..ca28ed9e46 100644 --- a/cli/template/extras/config/_prettier.config.cjs +++ b/cli/template/extras/config/prettier.config.cjs @@ -1,6 +1,6 @@ /** @type {import("prettier").Config} */ const config = { - plugins: ["@ianvs/prettier-plugin-sort-imports"], + plugins: [require.resolve("prettier-plugin-tailwindcss")], }; module.exports = config; diff --git a/www/.prettierrc.cjs b/www/.prettierrc.cjs index 39a5ef01c8..3dd61cf5bd 100644 --- a/www/.prettierrc.cjs +++ b/www/.prettierrc.cjs @@ -5,7 +5,6 @@ const config = { plugins: [ ...baseConfig.plugins, require.resolve("prettier-plugin-astro"), - require.resolve("@ianvs/prettier-plugin-sort-imports"), require.resolve("prettier-plugin-tailwindcss"), // MUST come last ], pluginSearchDirs: false, diff --git a/www/src/pages/en/usage/tailwind.md b/www/src/pages/en/usage/tailwind.md index 12e11a3521..bdb355a4b0 100644 --- a/www/src/pages/en/usage/tailwind.md +++ b/www/src/pages/en/usage/tailwind.md @@ -74,7 +74,7 @@ Make sure you have editor plugins for Tailwind installed to improve your experie ### Formatting -Tailwind CSS classes can easily get a bit messy, so a formatter for the classes is a must have. [Tailwind CSS Prettier Plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) sorts the classes in the [recommended order](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier#how-classes-are-sorted) so that the classes match the outputted css bundle. When selecting Tailwind in the CLI, we will install and configure this for you when the prettier option is selected. +Tailwind CSS classes can easily get a bit messy, so a formatter for the classes is a must have. [Tailwind CSS Prettier Plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) sorts the classes in the [recommended order](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier#how-classes-are-sorted) so that the classes match the outputted css bundle. When selecting Tailwind in the CLI, we will install and configure this for you. ### Conditionally Applying Classes