From 7f5a2fe13f497baf134d4ee4373d802d2e853992 Mon Sep 17 00:00:00 2001 From: Manuel Serret Date: Sat, 29 Nov 2025 21:07:49 +0100 Subject: [PATCH 1/4] fix(cli): files will be formatted after create --- .changeset/many-melons-shave.md | 5 +++++ packages/cli/commands/add/index.ts | 6 ++++++ packages/cli/commands/create.ts | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/many-melons-shave.md 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/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts index e2bbb96ee..d36098311 100644 --- a/packages/cli/commands/add/index.ts +++ b/packages/cli/commands/add/index.ts @@ -582,6 +582,12 @@ export async function runAddonsApply({ options: answersOfficial }); + // reload workspace to capture any changes made by the addons + workspace = await createWorkspace({ + cwd: workspace.cwd, + packageManager: workspace.packageManager + }); + const addonSuccess: string[] = []; for (const [addonId, info] of Object.entries(status)) { if (info === 'success') addonSuccess.push(addonId); diff --git a/packages/cli/commands/create.ts b/packages/cli/commands/create.ts index b75e39a9c..112e90ee0 100644 --- a/packages/cli/commands/create.ts +++ b/packages/cli/commands/create.ts @@ -272,7 +272,7 @@ async function createProject(cwd: ProjectPath, options: Options) { answersCommunity, options: { cwd: projectPath, - install: false, + install: options.install, gitCheck: false, community: [], addons: sanitizedAddonsMap From 0941bbbb06048ae61b46b1b93d5e472e306e9c68 Mon Sep 17 00:00:00 2001 From: jycouet Date: Sun, 30 Nov 2025 17:53:59 +0100 Subject: [PATCH 2/4] simplify formatFiles udage --- packages/cli/commands/add/index.ts | 10 +--------- packages/cli/commands/add/utils.ts | 31 ++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts index d36098311..49082fca6 100644 --- a/packages/cli/commands/add/index.ts +++ b/packages/cli/commands/add/index.ts @@ -672,15 +672,7 @@ export async function runAddonsApply({ // 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(); 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 { From 764948cb895fc43c2cbd034172d72c4a4210c2d2 Mon Sep 17 00:00:00 2001 From: jycouet Date: Sun, 30 Nov 2025 18:19:25 +0100 Subject: [PATCH 3/4] rmv the tailwindcss & prettier conflic --- packages/addons/prettier/index.ts | 2 +- packages/addons/tailwindcss/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 }); From 5836fca2de96eecefaf2f678716100cec30e9457 Mon Sep 17 00:00:00 2001 From: jycouet Date: Sun, 30 Nov 2025 18:20:55 +0100 Subject: [PATCH 4/4] add formatFiles util --- packages/cli/commands/add/index.ts | 17 ++++------------- packages/cli/commands/create.ts | 19 ++++++++++++++----- packages/cli/lib/install.ts | 6 +++++- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts index 49082fca6..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)); @@ -582,12 +583,6 @@ export async function runAddonsApply({ options: answersOfficial }); - // reload workspace to capture any changes made by the addons - workspace = await createWorkspace({ - cwd: workspace.cwd, - packageManager: workspace.packageManager - }); - const addonSuccess: string[] = []; for (const [addonId, info] of Object.entries(status)) { if (info === 'success') addonSuccess.push(addonId); @@ -668,10 +663,6 @@ 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')) { await formatFiles({ packageManager, cwd: options.cwd, filesToFormat }); } @@ -691,7 +682,7 @@ export async function runAddonsApply({ }) .filter((msg) => msg !== undefined); - return { nextSteps, argsFormattedAddons }; + return { nextSteps, argsFormattedAddons, filesToFormat }; } /** diff --git a/packages/cli/commands/create.ts b/packages/cli/commands/create.ts index 112e90ee0..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,13 +266,19 @@ 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, - install: options.install, + // 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: [], addons: sanitizedAddonsMap @@ -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 };