Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages/cli/tests/snapshots/*
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default [
'**/.test-output/*',
'**/dist/*',
'packages/**/tests/**/{output,input}.ts',
'packages/cli/tests/snapshots/*',
'rolldown.config.js',
'community-addon-template/tests/*'
]
Expand Down
15 changes: 15 additions & 0 deletions packages/addons/_tests/_setup/global.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { fileURLToPath } from 'node:url';
import { setup, type ProjectVariant } from 'sv/testing';
import type { TestProject } from 'vitest/node';
import process from 'node:process';
import { exec } from 'tinyexec';

import { STORYBOOK_VERSION } from '../../storybook/index.ts';

const TEST_DIR = fileURLToPath(new URL('../../../../.test-output/addons/', import.meta.url));
const variants: ProjectVariant[] = ['kit-js', 'kit-ts', 'vite-js', 'vite-ts'];
const CI = Boolean(process.env.CI);

export default async function ({ provide }: TestProject) {
if (CI) {
// prefetch the storybook cli during ci to reduce fetching errors in tests
const { stdout } = await exec('pnpm', [
'dlx',
`create-storybook@${STORYBOOK_VERSION}`,
'--version'
]);
console.info('storybook version:', stdout);
}

// downloads different project configurations (sveltekit, js/ts, vite-only, etc)
const { templatesDir } = await setup({ cwd: TEST_DIR, variants });

Expand Down
41 changes: 13 additions & 28 deletions packages/addons/_tests/storybook/test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import process from 'node:process';
import { execSync } from 'node:child_process';
import { expect } from '@playwright/test';
import { beforeAll } from 'vitest';
import { setupTest } from '../_setup/suite.ts';
import storybook from '../../storybook/index.ts';
import eslint from '../../eslint/index.ts';
Expand All @@ -13,31 +10,19 @@ const { test, testCases, prepareServer } = setupTest(
);

let port = 6006;
const CI = Boolean(process.env.CI);

beforeAll(() => {
if (CI) {
// prefetch the storybook cli during ci to reduce fetching errors in tests
execSync('pnpm dlx create-storybook@latest --version');
}
});

test.for(testCases)(
'storybook $variant',
{ concurrent: !CI },
async (testCase, { page, ...ctx }) => {
const cwd = ctx.cwd(testCase);
test.concurrent.for(testCases)('storybook $variant', async (testCase, { page, ...ctx }) => {
const cwd = ctx.cwd(testCase);

const { close } = await prepareServer({
cwd,
page,
previewCommand: `pnpm storybook -p ${++port} --ci`,
buildCommand: ''
});
// kill server process when we're done
ctx.onTestFinished(async () => await close());
const { close } = await prepareServer({
cwd,
page,
previewCommand: `pnpm storybook -p ${++port} --ci`,
buildCommand: ''
});
// kill server process when we're done
ctx.onTestFinished(async () => await close());

expect(page.locator('main .sb-bar')).toBeTruthy();
expect(page.locator('#storybook-preview-wrapper')).toBeTruthy();
}
);
expect(page.locator('main .sb-bar')).toBeTruthy();
expect(page.locator('#storybook-preview-wrapper')).toBeTruthy();
});
3 changes: 2 additions & 1 deletion packages/addons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@sveltejs/cli-core": "workspace:*"
},
"devDependencies": {
"package-manager-detector": "^0.2.11"
"package-manager-detector": "^0.2.11",
"tinyexec": "^0.3.2"
}
}
2 changes: 1 addition & 1 deletion packages/addons/prettier/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 ??= [];
Expand Down
9 changes: 8 additions & 1 deletion packages/addons/storybook/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import process from 'node:process';
import { defineAddon } from '@sveltejs/cli-core';
import { getNodeTypesVersion } from '../common.ts';

export const STORYBOOK_VERSION = '10.1.0';

export default defineAddon({
id: 'storybook',
shortDescription: 'frontend workshop',
Expand All @@ -12,7 +14,12 @@ export default defineAddon({
runsAfter('eslint');
},
run: async ({ sv }) => {
const args = ['create-storybook@latest', '--skip-install', '--no-dev'];
const args = [
`create-storybook@${STORYBOOK_VERSION}`,
'--skip-install',
'--no-dev',
'--no-features'
];

// skips the onboarding prompt during tests
if (process.env.NODE_ENV?.toLowerCase() === 'test') args.push('--yes');
Expand Down
2 changes: 1 addition & 1 deletion packages/addons/tailwindcss/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down
6 changes: 6 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# sv

## 0.10.6
### Patch Changes


- fix(cli): files will be formatted after create ([#827](https://github.com/sveltejs/cli/pull/827))

## 0.10.5
### Patch Changes

Expand Down
21 changes: 5 additions & 16 deletions packages/cli/commands/add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ export async function runAddonsApply({
addonSetupResults?: Record<string, AddonSetupResult>;
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)
Expand All @@ -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));
Expand Down Expand Up @@ -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();
Expand All @@ -693,7 +682,7 @@ export async function runAddonsApply({
})
.filter((msg) => msg !== undefined);

return { nextSteps, argsFormattedAddons };
return { nextSteps, argsFormattedAddons, filesToFormat };
}

/**
Expand Down
31 changes: 25 additions & 6 deletions packages/cli/commands/add/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -35,14 +36,32 @@ export function getPackageJson(cwd: string): {
export async function formatFiles(options: {
packageManager: AgentName;
cwd: string;
paths: string[];
filesToFormat: string[];
}): Promise<void> {
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 {
Expand Down
17 changes: 13 additions & 4 deletions packages/cli/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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: [],
Expand All @@ -283,7 +289,7 @@ async function createProject(cwd: ProjectPath, options: Options) {
fromCommand: 'create'
});
argsFormattedAddons = argsFormatted;

addOnFilesToFormat = filesToFormat;
addOnNextSteps = nextSteps;
}

Expand All @@ -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 };
}
Expand Down
6 changes: 5 additions & 1 deletion packages/cli/lib/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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] || {};

Expand All @@ -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,
Expand All @@ -89,7 +93,7 @@ export async function applyAddons({
}

return {
filesToFormat: Array.from(filesToFormat),
filesToFormat: hasFormatter ? Array.from(filesToFormat) : [],
pnpmBuildDependencies: allPnpmBuildDependencies,
status
};
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sv",
"version": "0.10.5",
"version": "0.10.6",
"type": "module",
"description": "A CLI for creating and updating SvelteKit projects",
"license": "MIT",
Expand Down
Loading
Loading