diff --git a/.changeset/many-melons-shave.md b/.changeset/many-melons-shave.md new file mode 100644 index 000000000..a0adb3170 --- /dev/null +++ b/.changeset/many-melons-shave.md @@ -0,0 +1,5 @@ +--- +'sv': patch +--- + +fix(cli): files will be formatted after create diff --git a/packages/addons/prettier/index.ts b/packages/addons/prettier/index.ts index 39de21190..7bf185f10 100644 --- a/packages/addons/prettier/index.ts +++ b/packages/addons/prettier/index.ts @@ -56,7 +56,7 @@ export default defineAddon({ data.tailwindStylesheet ??= files.getRelative({ to: files.stylesheet }); } if (!plugins.includes('prettier-plugin-svelte')) { - data.plugins.unshift('prettier-plugin-svelte'); + data.plugins.push('prettier-plugin-svelte'); } data.overrides ??= []; diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index 55b39aab5..8c56eb72e 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -141,7 +141,7 @@ export default defineAddon({ data.plugins ??= []; const plugins: string[] = data.plugins; - if (!plugins.includes(PLUGIN_NAME)) plugins.push(PLUGIN_NAME); + if (!plugins.includes(PLUGIN_NAME)) plugins.unshift(PLUGIN_NAME); data.tailwindStylesheet ??= files.getRelative({ to: files.stylesheet }); diff --git a/packages/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts index e2bbb96ee..bee6e5e68 100644 --- a/packages/cli/commands/add/index.ts +++ b/packages/cli/commands/add/index.ts @@ -556,7 +556,7 @@ export async function runAddonsApply({ addonSetupResults?: Record; workspace: Workspace; fromCommand: 'create' | 'add'; -}): Promise<{ nextSteps: string[]; argsFormattedAddons: string[] }> { +}): Promise<{ nextSteps: string[]; argsFormattedAddons: string[]; filesToFormat: string[] }> { if (!addonSetupResults) { const setups = selectedAddons.length ? selectedAddons.map(({ addon }) => addon) @@ -565,7 +565,8 @@ export async function runAddonsApply({ } // we'll return early when no addons are selected, // indicating that installing deps was skipped and no PM was selected - if (selectedAddons.length === 0) return { nextSteps: [], argsFormattedAddons: [] }; + if (selectedAddons.length === 0) + return { nextSteps: [], argsFormattedAddons: [], filesToFormat: [] }; // apply addons const officialDetails = Object.keys(answersOfficial).map((id) => getAddonDetails(id)); @@ -662,19 +663,7 @@ export async function runAddonsApply({ if (packageManager) { workspace.packageManager = packageManager; await installDependencies(packageManager, options.cwd); - } - - // format modified/created files with prettier (if available) - if (filesToFormat.length > 0 && packageManager && !!workspace.dependencyVersion('prettier')) { - const { start, stop } = p.spinner(); - start('Formatting modified files'); - try { - await formatFiles({ packageManager, cwd: options.cwd, paths: filesToFormat }); - stop('Successfully formatted modified files'); - } catch (e) { - stop('Failed to format files'); - if (e instanceof Error) p.log.error(e.message); - } + await formatFiles({ packageManager, cwd: options.cwd, filesToFormat }); } const highlighter = getHighlighter(); @@ -693,7 +682,7 @@ export async function runAddonsApply({ }) .filter((msg) => msg !== undefined); - return { nextSteps, argsFormattedAddons }; + return { nextSteps, argsFormattedAddons, filesToFormat }; } /** diff --git a/packages/cli/commands/add/utils.ts b/packages/cli/commands/add/utils.ts index 8e07c89a1..5eab948e6 100644 --- a/packages/cli/commands/add/utils.ts +++ b/packages/cli/commands/add/utils.ts @@ -5,6 +5,7 @@ import { exec } from 'tinyexec'; import { parseJson } from '@sveltejs/cli-core/parsers'; import { resolveCommand, type AgentName } from 'package-manager-detector'; import type { Highlighter, Workspace } from '@sveltejs/cli-core'; +import * as p from '@clack/prompts'; export type Package = { name: string; @@ -35,14 +36,32 @@ export function getPackageJson(cwd: string): { export async function formatFiles(options: { packageManager: AgentName; cwd: string; - paths: string[]; + filesToFormat: string[]; }): Promise { - const args = ['prettier', '--write', '--ignore-unknown', ...options.paths]; + if (options.filesToFormat.length === 0) return; + const { start, stop } = p.spinner(); + start('Formatting modified files'); + + const args = ['prettier', '--write', '--ignore-unknown', ...options.filesToFormat]; const cmd = resolveCommand(options.packageManager, 'execute-local', args)!; - await exec(cmd.command, cmd.args, { - nodeOptions: { cwd: options.cwd, stdio: 'pipe' }, - throwOnError: true - }); + + try { + const result = await exec(cmd.command, cmd.args, { + nodeOptions: { cwd: options.cwd, stdio: 'pipe' }, + throwOnError: true + }); + if (result.exitCode !== 0) { + stop('Failed to format files'); + p.log.error(result.stderr); + return; + } + } catch (e) { + stop('Failed to format files'); + // @ts-expect-error + p.log.error(e?.output?.stderr || 'unknown error'); + return; + } + stop('Successfully formatted modified files'); } export function readFile(cwd: string, filePath: string): string { diff --git a/packages/cli/commands/create.ts b/packages/cli/commands/create.ts index b75e39a9c..35addd565 100644 --- a/packages/cli/commands/create.ts +++ b/packages/cli/commands/create.ts @@ -37,7 +37,7 @@ import { sanitizeAddons, type SelectedAddon } from './add/index.ts'; -import { commonFilePaths, getPackageJson } from './add/utils.ts'; +import { commonFilePaths, formatFiles, getPackageJson } from './add/utils.ts'; import { createWorkspace } from './add/workspace.ts'; import { dist } from '../../create/utils.ts'; @@ -266,12 +266,18 @@ async function createProject(cwd: ProjectPath, options: Options) { let addOnNextSteps: string[] = []; let argsFormattedAddons: string[] = []; + let addOnFilesToFormat: string[] = []; if (options.addOns || options.add.length > 0) { - const { nextSteps, argsFormattedAddons: argsFormatted } = await runAddonsApply({ + const { + nextSteps, + argsFormattedAddons: argsFormatted, + filesToFormat + } = await runAddonsApply({ answersOfficial, answersCommunity, options: { cwd: projectPath, + // in the create command, we don't want to install dependencies, we want to do it after the project is created install: false, gitCheck: false, community: [], @@ -283,7 +289,7 @@ async function createProject(cwd: ProjectPath, options: Options) { fromCommand: 'create' }); argsFormattedAddons = argsFormatted; - + addOnFilesToFormat = filesToFormat; addOnNextSteps = nextSteps; } @@ -308,7 +314,10 @@ async function createProject(cwd: ProjectPath, options: Options) { common.logArgs(packageManager, 'create', argsFormatted, [directory]); await addPnpmBuildDependencies(projectPath, packageManager, ['esbuild']); - if (packageManager) await installDependencies(packageManager, projectPath); + if (packageManager) { + await installDependencies(packageManager, projectPath); + await formatFiles({ packageManager, cwd: projectPath, filesToFormat: addOnFilesToFormat }); + } return { directory: projectPath, addOnNextSteps, packageManager }; } diff --git a/packages/cli/lib/install.ts b/packages/cli/lib/install.ts index 80fed8ea6..fb9b0b692 100644 --- a/packages/cli/lib/install.ts +++ b/packages/cli/lib/install.ts @@ -63,6 +63,8 @@ export async function applyAddons({ const mapped = Object.entries(addons).map(([, addon]) => addon); const ordered = orderAddons(mapped, addonSetupResults); + let hasFormatter = false; + for (const addon of ordered) { const workspaceOptions = options[addon.id] || {}; @@ -71,6 +73,8 @@ export async function applyAddons({ cwd: workspace.cwd, packageManager: workspace.packageManager }); + // If we don't have a formatter yet, check if the addon adds one + if (!hasFormatter) hasFormatter = !!addonWorkspace.dependencyVersion('prettier'); const { files, pnpmBuildDependencies, cancels } = await runAddon({ workspace: addonWorkspace, @@ -89,7 +93,7 @@ export async function applyAddons({ } return { - filesToFormat: Array.from(filesToFormat), + filesToFormat: hasFormatter ? Array.from(filesToFormat) : [], pnpmBuildDependencies: allPnpmBuildDependencies, status };