From 45706b94597cf6f9a16844f6f0fa54e807f11a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A2=85=EA=B2=BD?= Date: Mon, 1 Jun 2026 10:23:42 +0900 Subject: [PATCH] fix(create): skip monorepo editor configs by default --- .../new-vite-monorepo/snap.txt | 17 +++++ .../new-vite-monorepo/steps.json | 13 ++++ .../cli/src/create/__tests__/utils.spec.ts | 29 +++++++++ packages/cli/src/create/bin.ts | 62 +++++++++++-------- packages/cli/src/create/utils.ts | 33 ++++++++++ 5 files changed, 128 insertions(+), 26 deletions(-) diff --git a/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt b/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt index 3837a993fa..4f32be25ba 100644 --- a/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt +++ b/packages/cli/snap-tests-global/new-vite-monorepo/snap.txt @@ -163,10 +163,27 @@ website > ls vite-plus-monorepo/apps/vite-plus-application/package.json # check vite-plus-application package.json vite-plus-monorepo/apps/vite-plus-application/package.json +> test ! -e vite-plus-monorepo/apps/vite-plus-application/.vscode && echo 'No app editor config' || (echo 'ERROR: app editor config exists' && exit 1) # monorepo package create without --editor should not write VS Code config +No app editor config + +> cd vite-plus-monorepo && vp create --no-interactive vite:application --directory apps/no-editor --no-editor # create application with explicit editor opt-out inside monorepo +> test ! -e vite-plus-monorepo/apps/no-editor/.vscode && echo 'No opt-out app editor config' || (echo 'ERROR: opt-out app editor config exists' && exit 1) # --no-editor should not write VS Code config +No opt-out app editor config + +> cd vite-plus-monorepo && vp create --no-interactive vite:application --directory apps/editor-opt-in --editor vscode # create application with explicit editor opt-in inside monorepo +> test -f vite-plus-monorepo/apps/editor-opt-in/.vscode/settings.json && echo 'Opt-in app VS Code settings exist' # explicit --editor should write VS Code settings +Opt-in app VS Code settings exist + +> test -f vite-plus-monorepo/apps/editor-opt-in/.vscode/extensions.json && echo 'Opt-in app VS Code extensions exist' # explicit --editor should write VS Code extensions +Opt-in app VS Code extensions exist + > cd vite-plus-monorepo && vp create --no-interactive vite:library # create library in non-interactive mode > ls vite-plus-monorepo/packages/vite-plus-library/package.json # check vite-plus-library package.json vite-plus-monorepo/packages/vite-plus-library/package.json +> test ! -e vite-plus-monorepo/packages/vite-plus-library/.vscode && echo 'No library editor config' || (echo 'ERROR: library editor config exists' && exit 1) # monorepo package create without --editor should not write VS Code config +No library editor config + > cd vite-plus-monorepo && vp create --no-interactive vite:generator # create generator in non-interactive mode > ls vite-plus-monorepo/tools # check tools directory created vite-plus-generator diff --git a/packages/cli/snap-tests-global/new-vite-monorepo/steps.json b/packages/cli/snap-tests-global/new-vite-monorepo/steps.json index 959500cbe9..b0bb546754 100644 --- a/packages/cli/snap-tests-global/new-vite-monorepo/steps.json +++ b/packages/cli/snap-tests-global/new-vite-monorepo/steps.json @@ -25,11 +25,24 @@ }, "ls vite-plus-monorepo/apps # check apps directory created", "ls vite-plus-monorepo/apps/vite-plus-application/package.json # check vite-plus-application package.json", + "test ! -e vite-plus-monorepo/apps/vite-plus-application/.vscode && echo 'No app editor config' || (echo 'ERROR: app editor config exists' && exit 1) # monorepo package create without --editor should not write VS Code config", + { + "command": "cd vite-plus-monorepo && vp create --no-interactive vite:application --directory apps/no-editor --no-editor # create application with explicit editor opt-out inside monorepo", + "ignoreOutput": true + }, + "test ! -e vite-plus-monorepo/apps/no-editor/.vscode && echo 'No opt-out app editor config' || (echo 'ERROR: opt-out app editor config exists' && exit 1) # --no-editor should not write VS Code config", + { + "command": "cd vite-plus-monorepo && vp create --no-interactive vite:application --directory apps/editor-opt-in --editor vscode # create application with explicit editor opt-in inside monorepo", + "ignoreOutput": true + }, + "test -f vite-plus-monorepo/apps/editor-opt-in/.vscode/settings.json && echo 'Opt-in app VS Code settings exist' # explicit --editor should write VS Code settings", + "test -f vite-plus-monorepo/apps/editor-opt-in/.vscode/extensions.json && echo 'Opt-in app VS Code extensions exist' # explicit --editor should write VS Code extensions", { "command": "cd vite-plus-monorepo && vp create --no-interactive vite:library # create library in non-interactive mode", "ignoreOutput": true }, "ls vite-plus-monorepo/packages/vite-plus-library/package.json # check vite-plus-library package.json", + "test ! -e vite-plus-monorepo/packages/vite-plus-library/.vscode && echo 'No library editor config' || (echo 'ERROR: library editor config exists' && exit 1) # monorepo package create without --editor should not write VS Code config", { "command": "cd vite-plus-monorepo && vp create --no-interactive vite:generator # create generator in non-interactive mode", "ignoreOutput": true diff --git a/packages/cli/src/create/__tests__/utils.spec.ts b/packages/cli/src/create/__tests__/utils.spec.ts index 377c91c11e..ecec51f39c 100644 --- a/packages/cli/src/create/__tests__/utils.spec.ts +++ b/packages/cli/src/create/__tests__/utils.spec.ts @@ -10,7 +10,9 @@ import { ensureGitignoreVsCodeEditorConfigs, formatTargetDir, getProjectDirFromPackageName, + normalizeEditorOption, renameFiles, + shouldConfigureEditorsForCreate, } from '../utils.js'; describe('getProjectDirFromPackageName', () => { @@ -20,6 +22,33 @@ describe('getProjectDirFromPackageName', () => { }); }); +describe('editor configuration policy', () => { + it('normalizes repeated editor options to a single editor value', () => { + expect(normalizeEditorOption('vscode')).toBe('vscode'); + expect(normalizeEditorOption(['vscode', 'zed'])).toBe('zed'); + expect(normalizeEditorOption(['vscode', false])).toBe(false); + expect(normalizeEditorOption([undefined, 'vscode'])).toBe('vscode'); + }); + + it('allows automatic editor configuration outside existing monorepos', () => { + expect(shouldConfigureEditorsForCreate({ isMonorepo: false, editor: undefined })).toBe(true); + }); + + it('skips automatic editor configuration inside existing monorepos', () => { + expect(shouldConfigureEditorsForCreate({ isMonorepo: true, editor: undefined })).toBe(false); + }); + + it('allows explicit editor opt-in inside existing monorepos', () => { + expect(shouldConfigureEditorsForCreate({ isMonorepo: true, editor: 'vscode' })).toBe(true); + expect(shouldConfigureEditorsForCreate({ isMonorepo: true, editor: ' ' })).toBe(false); + }); + + it('keeps --no-editor as an explicit opt-out in every workspace mode', () => { + expect(shouldConfigureEditorsForCreate({ isMonorepo: false, editor: false })).toBe(false); + expect(shouldConfigureEditorsForCreate({ isMonorepo: true, editor: false })).toBe(false); + }); +}); + describe('formatTargetDir', () => { it('should format "." as current directory with empty package name', () => { expect(formatTargetDir('.')).toEqual({ diff --git a/packages/cli/src/create/bin.ts b/packages/cli/src/create/bin.ts index ca581f35ce..183d78ac6a 100644 --- a/packages/cli/src/create/bin.ts +++ b/packages/cli/src/create/bin.ts @@ -78,6 +78,8 @@ import { ensureGitignoreNodeModules, ensureGitignoreVsCodeEditorConfigs, formatTargetDir, + normalizeEditorOption, + shouldConfigureEditorsForCreate, } from './utils.ts'; const helpMessage = renderCliDoc({ @@ -222,7 +224,7 @@ export interface Options { help: boolean; verbose: boolean; agent?: string | string[] | false; - editor?: string; + editor?: string | false; hooks?: boolean; packageManager?: string; } @@ -257,7 +259,7 @@ function parseArgs() { help?: boolean; verbose?: boolean; agent?: ParsedAgentOption; - editor?: string; + editor?: string | false | Array; git?: boolean; hooks?: boolean; 'package-manager'?: string; @@ -279,7 +281,7 @@ function parseArgs() { help: parsed.help || false, verbose: parsed.verbose || false, agent: normalizeAgentOption(parsed.agent), - editor: parsed.editor, + editor: normalizeEditorOption(parsed.editor), git: parsed.git, hooks: parsed.hooks, packageManager: parsed['package-manager'], @@ -787,17 +789,23 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h ); } - const existingEditors = - options.editor || !options.interactive - ? undefined - : detectExistingEditors(workspaceInfoOptional.rootDir); - selectedEditors = - existingEditors ?? - (await selectEditors({ - interactive: options.interactive, - editor: options.editor, - onCancel: () => cancelAndExit(), - })); + const shouldConfigureEditors = shouldConfigureEditorsForCreate({ + editor: options.editor, + isMonorepo, + }); + if (shouldConfigureEditors) { + const existingEditors = + options.editor || !options.interactive + ? undefined + : detectExistingEditors(workspaceInfoOptional.rootDir); + selectedEditors = + existingEditors ?? + (await selectEditors({ + interactive: options.interactive, + editor: options.editor, + onCancel: () => cancelAndExit(), + })); + } const shouldSetupGit = await promptGitInit(options); if (!isMonorepo) { @@ -1076,19 +1084,21 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h }); } resumeCreateProgress(); - updateCreateProgress('Writing editor configs'); - pauseCreateProgress(); - await writeEditorConfigs({ - projectRoot: fullPath, - editorId: selectedEditors, - interactive: options.interactive, - silent: compactOutput, - extraVsCodeSettings: { 'npm.scriptRunner': 'vp' }, - }); - if (selectedEditors?.includes('vscode')) { - ensureGitignoreVsCodeEditorConfigs(fullPath); + if (shouldConfigureEditors) { + updateCreateProgress('Writing editor configs'); + pauseCreateProgress(); + await writeEditorConfigs({ + projectRoot: fullPath, + editorId: selectedEditors, + interactive: options.interactive, + silent: compactOutput, + extraVsCodeSettings: { 'npm.scriptRunner': 'vp' }, + }); + if (selectedEditors?.includes('vscode')) { + ensureGitignoreVsCodeEditorConfigs(fullPath); + } + resumeCreateProgress(); } - resumeCreateProgress(); // The migrate-before-rewrite reorder is only needed when the template // actually ships ESLint or Prettier (e.g. `create-vite --template diff --git a/packages/cli/src/create/utils.ts b/packages/cli/src/create/utils.ts index 379eefb352..6ae984e8e5 100644 --- a/packages/cli/src/create/utils.ts +++ b/packages/cli/src/create/utils.ts @@ -6,6 +6,39 @@ import validateNpmPackageName from 'validate-npm-package-name'; import { editJsonFile } from '../utils/json.ts'; import { getRandomProjectName } from './random-name.ts'; +export type CreateEditorOption = string | false | undefined; +type ParsedCreateEditorOption = CreateEditorOption | CreateEditorOption[]; + +function hasExplicitEditorOptIn(editor: CreateEditorOption): boolean { + return typeof editor === 'string' && editor.trim() !== ''; +} + +export function normalizeEditorOption(editor: ParsedCreateEditorOption): CreateEditorOption { + if (!Array.isArray(editor)) { + return editor; + } + if (editor.includes(false)) { + return false; + } + return editor.findLast((value): value is string => typeof value === 'string'); +} + +export function shouldConfigureEditorsForCreate({ + editor, + isMonorepo, +}: { + editor: CreateEditorOption; + isMonorepo: boolean; +}): boolean { + if (editor === false) { + return false; + } + if (!isMonorepo) { + return true; + } + return hasExplicitEditorOptIn(editor); +} + // Helper functions for file operations export function copy(src: string, dest: string) { const stat = fs.statSync(src);