@@ -899,23 +899,6 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
899899 } ) ;
900900 resumeCreateProgress ( ) ;
901901
902- // Auto-migrate ESLint → Oxlint and Prettier → Oxfmt after install #1 so
903- // `@oxlint/migrate` can resolve imports from eslint.config.js, but before
904- // the vite-plus rewrite so the generated .oxlintrc/.oxfmtrc get merged
905- // into vite.config.ts — matching `vp migrate`. Always non-interactive;
906- // Vite+ is opinionated about oxlint/oxfmt. Gated on install success so
907- // VP_SKIP_INSTALL snap tests don't hit ERR_MODULE_NOT_FOUND.
908- const migrateLintFmtTools = async ( installed : boolean ) => {
909- if ( ! installed ) {
910- return ;
911- }
912- updateCreateProgress ( 'Migrating lint and format tools' ) ;
913- pauseCreateProgress ( ) ;
914- await promptEslintMigration ( fullPath , /* interactive */ false ) ;
915- await promptPrettierMigration ( fullPath , /* interactive */ false ) ;
916- resumeCreateProgress ( ) ;
917- } ;
918-
919902 // The migrate-before-rewrite reorder is only needed when the template
920903 // actually ships ESLint or Prettier (e.g. `create-vite --template
921904 // react-ts`). Builtin templates (vite:library, vite:application,
@@ -926,6 +909,36 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
926909 detectEslintProject ( fullPath ) . hasDependency || detectPrettierProject ( fullPath ) . hasDependency ;
927910
928911 let installSummary : CommandRunSummary | undefined ;
912+
913+ // For templates that ship ESLint/Prettier, install template deps first so
914+ // `@oxlint/migrate` can resolve eslint.config.js's plugin imports, then
915+ // migrate before the vite-plus rewrite so the generated .oxlintrc/.oxfmtrc
916+ // get merged into vite.config.ts — matching `vp migrate`. Pin the
917+ // packageManager field (vite_install hardcodes pnpm in CI/non-TTY when no
918+ // signal is present) and force yarn's classic node_modules layout (PnP
919+ // zip entries break @oxlint /migrate's fileURLToPath resolution).
920+ const installAndMigrate = async ( installCwd : string ) => {
921+ setPackageManager ( fullPath , workspaceInfo . downloadPackageManager ) ;
922+ if ( workspaceInfo . packageManager === PackageManager . yarn ) {
923+ const yarnrcPath = path . join ( fullPath , '.yarnrc.yml' ) ;
924+ if ( ! fs . existsSync ( yarnrcPath ) ) {
925+ fs . writeFileSync ( yarnrcPath , 'nodeLinker: node-modules\n' ) ;
926+ }
927+ }
928+ updateCreateProgress ( 'Installing dependencies' ) ;
929+ installSummary = await runViteInstall ( installCwd , options . interactive , installArgs , {
930+ silent : compactOutput ,
931+ } ) ;
932+ if ( installSummary . status !== 'installed' ) {
933+ return ;
934+ }
935+ updateCreateProgress ( 'Migrating lint and format tools' ) ;
936+ pauseCreateProgress ( ) ;
937+ await promptEslintMigration ( fullPath , /* interactive */ false ) ;
938+ await promptPrettierMigration ( fullPath , /* interactive */ false ) ;
939+ resumeCreateProgress ( ) ;
940+ } ;
941+
929942 if ( isMonorepo ) {
930943 if ( ! compactOutput ) {
931944 prompts . log . step ( 'Monorepo integration...' ) ;
@@ -991,28 +1004,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
9911004
9921005 updateWorkspaceConfig ( projectDir , workspaceInfo ) ;
9931006 if ( shouldMigrateLintFmtTools ) {
994- // Pin the packageManager field before install so `vp install` honors
995- // the user's `--package-manager` choice instead of falling back to
996- // pnpm (the hardcoded non-interactive/CI default in vite_install).
997- setPackageManager ( fullPath , workspaceInfo . downloadPackageManager ) ;
998- // Yarn Berry's default Plug'n'Play stores deps inside .yarn/cache/*.zip,
999- // which @oxlint /migrate can't resolve (ESM's fileURLToPath over a zip
1000- // entry throws MODULE_NOT_FOUND). Force classic node_modules layout so
1001- // the migration step can import the template's ESLint plugins.
1002- if ( workspaceInfo . packageManager === PackageManager . yarn ) {
1003- const yarnrcPath = path . join ( fullPath , '.yarnrc.yml' ) ;
1004- if ( ! fs . existsSync ( yarnrcPath ) ) {
1005- fs . writeFileSync ( yarnrcPath , 'nodeLinker: node-modules\n' ) ;
1006- }
1007- }
1008- updateCreateProgress ( 'Installing dependencies' ) ;
1009- installSummary = await runViteInstall (
1010- workspaceInfo . rootDir ,
1011- options . interactive ,
1012- installArgs ,
1013- { silent : compactOutput } ,
1014- ) ;
1015- await migrateLintFmtTools ( installSummary . status === 'installed' ) ;
1007+ await installAndMigrate ( workspaceInfo . rootDir ) ;
10161008 }
10171009 updateCreateProgress ( 'Integrating into monorepo' ) ;
10181010 rewriteMonorepoProject ( fullPath , workspaceInfo . packageManager , undefined , compactOutput ) ;
@@ -1031,25 +1023,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
10311023 } ) ;
10321024 } else {
10331025 if ( shouldMigrateLintFmtTools ) {
1034- // Pin the packageManager field before install so `vp install` honors
1035- // the user's `--package-manager` choice instead of falling back to
1036- // pnpm (the hardcoded non-interactive/CI default in vite_install).
1037- setPackageManager ( fullPath , workspaceInfo . downloadPackageManager ) ;
1038- // Yarn Berry's default Plug'n'Play stores deps inside .yarn/cache/*.zip,
1039- // which @oxlint /migrate can't resolve (ESM's fileURLToPath over a zip
1040- // entry throws MODULE_NOT_FOUND). Force classic node_modules layout so
1041- // the migration step can import the template's ESLint plugins.
1042- if ( workspaceInfo . packageManager === PackageManager . yarn ) {
1043- const yarnrcPath = path . join ( fullPath , '.yarnrc.yml' ) ;
1044- if ( ! fs . existsSync ( yarnrcPath ) ) {
1045- fs . writeFileSync ( yarnrcPath , 'nodeLinker: node-modules\n' ) ;
1046- }
1047- }
1048- updateCreateProgress ( 'Installing dependencies' ) ;
1049- installSummary = await runViteInstall ( fullPath , options . interactive , installArgs , {
1050- silent : compactOutput ,
1051- } ) ;
1052- await migrateLintFmtTools ( installSummary . status === 'installed' ) ;
1026+ await installAndMigrate ( fullPath ) ;
10531027 }
10541028 updateCreateProgress ( 'Applying Vite+ project setup' ) ;
10551029 rewriteStandaloneProject ( fullPath , workspaceInfo , undefined , compactOutput ) ;
0 commit comments