diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/mock-manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/mock-manifest.json new file mode 100644 index 0000000000..d0f621feb5 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/mock-manifest.json @@ -0,0 +1,21 @@ +{ + "create-vp-test-vite-plus": { + "name": "create-vp-test-vite-plus", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "create-vp-test-vite-plus", + "version": "1.0.0", + "bin": { + "create-vp-test-vite-plus": "index.cjs" + }, + "dist": { + "tarball": "{REGISTRY}/create-vp-test-vite-plus/-/create-vp-test-vite-plus-1.0.0.tgz", + "integrity": "sha512-xvpZCYhS9b6ee0uUQC7FlICwKIR/W6nkIQfWZ1UAfd8b+gzgUjT5kR8JILcITLstgv0prAnOeAVmsgyQExbD7A==" + } + } + } + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots.toml new file mode 100644 index 0000000000..1ce15ee705 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots.toml @@ -0,0 +1,10 @@ +# The fake `create-vp-test-vite-plus` CLI writes a project that already uses +# Vite+, so `vp create` must leave its setup unchanged. +[[case]] +name = "create_remote_vite_plus_template" +vp = "local" +steps = [ + { argv = ["vp", "create", "vp-test-vite-plus", "--no-interactive", "--no-agent", "--no-editor", "--no-git", "--no-hooks", "--", "my-app"], comment = "create from a template that already generates a Vite+ project", snapshot = false, continue-on-failure = true }, + { argv = ["vpt", "print-file", "my-app/package.json"], comment = "dependencies and scripts are not rewritten", continue-on-failure = true }, + { argv = ["vpt", "stat-file", "my-app/pnpm-workspace.yaml", "--assert-not", "file"], comment = "no Vite+ overrides are added", continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots/create_remote_vite_plus_template.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots/create_remote_vite_plus_template.md new file mode 100644 index 0000000000..29f82ffa4a --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/snapshots/create_remote_vite_plus_template.md @@ -0,0 +1,41 @@ +# create_remote_vite_plus_template + +## `vp create vp-test-vite-plus --no-interactive --no-agent --no-editor --no-git --no-hooks -- my-app` + +create from a template that already generates a Vite+ project + + +## `vpt print-file my-app/package.json` + +dependencies and scripts are not rewritten + +``` +{ + "name": "my-app", + "private": true, + "type": "module", + "scripts": { + "dev": "vp dev", + "lint": "eslint ." + }, + "devDependencies": { + "eslint": "^9.0.0", + "vite-plus": "latest" + }, + "devEngines": { + "packageManager": { + "name": "pnpm", + "version": "", + "onFail": "download" + } + } +} +``` + +## `vpt stat-file my-app/pnpm-workspace.yaml --assert-not file` + +no Vite+ overrides are added + +``` +my-app/pnpm-workspace.yaml: missing +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/tarballs/create-vp-test-vite-plus-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/tarballs/create-vp-test-vite-plus-1.0.0.tgz new file mode 100644 index 0000000000..d037e32f0d Binary files /dev/null and b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_remote_vite_plus_template/tarballs/create-vp-test-vite-plus-1.0.0.tgz differ diff --git a/docs/guide/create.md b/docs/guide/create.md index 1e3c258f74..1c36b98261 100644 --- a/docs/guide/create.md +++ b/docs/guide/create.md @@ -74,6 +74,8 @@ Vite+ ships with these built-in templates: Run `vp create --list` to see the built-in templates and the common shorthand templates Vite+ recognizes. +After a third-party template runs, `vp create` migrates the generated project to Vite+. When a standalone project already depends on `vite-plus`, `vp create` skips this migration and keeps the template's tooling choices. + ## Options - `--directory ` writes the generated project into a specific target directory. Only built-in templates and bundled `@org` templates support this option. diff --git a/packages/cli/src/create/bin.ts b/packages/cli/src/create/bin.ts index 30bd7261f5..87c1c3ada9 100644 --- a/packages/cli/src/create/bin.ts +++ b/packages/cli/src/create/bin.ts @@ -38,11 +38,13 @@ import { resolveApproveBuildTargets, } from '../utils/approve-builds.ts'; import { unwrapCliParseOutcome } from '../utils/cli-parse.ts'; +import { isForceOverrideMode } from '../utils/constants.ts'; import { documentationUrl } from '../utils/documentation.ts'; import { detectExistingEditors, selectEditors, writeEditorConfigs } from '../utils/editor.ts'; import { findGitRoot, initGitRepository } from '../utils/git.ts'; import { renderCliDoc } from '../utils/help.ts'; import { readJsonFile } from '../utils/json.ts'; +import { hasVitePlusDependency } from '../utils/package.ts'; import { displayRelative } from '../utils/path.ts'; import { cancelAndExit, @@ -1149,6 +1151,18 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h resumeCreateProgress(); } + // A `create-xxx` CLI that already generates a Vite+ project made its own + // toolchain choices (e.g. keeping ESLint), so skip migration like `vp migrate` + // does for Vite+ projects. Monorepo packages still need the rewrite to align + // with the workspace catalog. + const packageJsonPath = path.join(fullPath, 'package.json'); + const isVitePlusTemplate = + !isMonorepo && + templateInfo.type === TemplateType.remote && + !isForceOverrideMode() && + fs.existsSync(packageJsonPath) && + hasVitePlusDependency(readJsonFile(packageJsonPath)); + // The migrate-before-rewrite reorder is only needed when the template // actually ships ESLint or Prettier (e.g. `create-vite --template // react-ts`). Builtin templates (vite:library, vite:application, @@ -1156,9 +1170,10 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h // and relies on `rewrite*Project` to add tarball overrides BEFORE the // first install, so install-first would break CI's local-tarball resolve. const shouldMigrateLintFmtTools = - detectEslintProject(fullPath).hasDependency || - detectPrettierProject(fullPath).hasDependency || - detectTsupProject(fullPath).hasDependency; + !isVitePlusTemplate && + (detectEslintProject(fullPath).hasDependency || + detectPrettierProject(fullPath).hasDependency || + detectTsupProject(fullPath).hasDependency); let installSummary: CommandRunSummary | undefined; @@ -1338,12 +1353,14 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h await installAndMigrate(fullPath); } updateCreateProgress('Applying Vite+ project setup'); - const skipStagedMigration = shouldSkipStagedMigrationForHooks( - fullPath, - shouldSetupHooks, - workspaceInfo.packageManager, - ); - rewriteStandaloneProject(fullPath, workspaceInfo, skipStagedMigration, compactOutput); + if (!isVitePlusTemplate) { + const skipStagedMigration = shouldSkipStagedMigrationForHooks( + fullPath, + shouldSetupHooks, + workspaceInfo.packageManager, + ); + rewriteStandaloneProject(fullPath, workspaceInfo, skipStagedMigration, compactOutput); + } setPackageManager(fullPath, workspaceInfo.downloadPackageManager); for (const framework of detectFramework(fullPath)) { if (!hasFrameworkShim(fullPath, framework)) {