66use Illuminate \Support \Composer ;
77use Illuminate \Support \ProcessUtils ;
88use Illuminate \Support \Str ;
9+ use Laravel \Installer \Console \Enums \NodePackageManager ;
910use RecursiveDirectoryIterator ;
1011use RecursiveIteratorIterator ;
1112use RuntimeException ;
@@ -64,6 +65,9 @@ protected function configure()
6465 ->addOption ('pest ' , null , InputOption::VALUE_NONE , 'Install the Pest testing framework ' )
6566 ->addOption ('phpunit ' , null , InputOption::VALUE_NONE , 'Install the PHPUnit testing framework ' )
6667 ->addOption ('npm ' , null , InputOption::VALUE_NONE , 'Install and build NPM dependencies ' )
68+ ->addOption ('pnpm ' , null , InputOption::VALUE_NONE , 'Install and build NPM dependencies via PNPM ' )
69+ ->addOption ('bun ' , null , InputOption::VALUE_NONE , 'Install and build NPM dependencies via Bun ' )
70+ ->addOption ('yarn ' , null , InputOption::VALUE_NONE , 'Install and build NPM dependencies via Yarn ' )
6771 ->addOption ('using ' , null , InputOption::VALUE_OPTIONAL , 'Install a custom starter kit from a community maintained package ' )
6872 ->addOption ('force ' , 'f ' , InputOption::VALUE_NONE , 'Forces install even if the directory already exists ' );
6973 }
@@ -499,43 +503,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int
499503 $ output ->writeln ('' );
500504 }
501505
502- $ this ->configureComposerDevScript ($ directory );
506+ [$ packageManager , $ runPackageManager ] = $ this ->determinePackageManager ($ directory , $ input );
507+
508+ $ this ->configureComposerScripts ($ packageManager );
503509
504510 if ($ input ->getOption ('pest ' )) {
505511 $ output ->writeln ('' );
506512 }
507513
508- $ packageInstall = 'npm install ' ;
509- $ packageBuild = 'npm run build ' ;
510-
511- if (file_exists ($ directory .'/pnpm-lock.yaml ' )) {
512- $ packageInstall = 'pnpm install ' ;
513- $ packageBuild = 'pnpm run build ' ;
514- } elseif (file_exists ($ directory .'/yarn.lock ' )) {
515- $ packageInstall = 'yarn install ' ;
516- $ packageBuild = 'yarn run build ' ;
517- } elseif (file_exists ($ directory .'/bun.lock ' )) {
518- $ packageInstall = 'bun install ' ;
519- $ packageBuild = 'bun run build ' ;
514+ if (! $ runPackageManager && $ input ->isInteractive ()) {
515+ $ runPackageManager = confirm (
516+ label: 'Would you like to run <options=bold> ' .$ packageManager ->installCommand ().'</> and <options=bold> ' .$ packageManager ->buildCommand ().'</>? '
517+ );
520518 }
521519
522- $ runNpm = $ input ->getOption ('npm ' );
523-
524- if (! $ input ->getOption ('npm ' ) && $ input ->isInteractive ()) {
525- $ runNpm = confirm (
526- label: 'Would you like to run <options=bold> ' .$ packageInstall .'</> and <options=bold> ' .$ packageBuild .'</>? '
527- );
520+ foreach (NodePackageManager::allLockFiles () as $ lockFile ) {
521+ if (! in_array ($ lockFile , $ packageManager ->lockFiles ()) && file_exists ($ directory .'/ ' .$ lockFile )) {
522+ (new Filesystem ())->delete ($ directory .'/ ' .$ lockFile );
523+ }
528524 }
529525
530- if ($ runNpm ) {
531- $ this ->runCommands ([$ packageInstall , $ packageBuild ], $ input , $ output , workingPath: $ directory );
526+ if ($ runPackageManager ) {
527+ $ this ->runCommands ([$ packageManager -> installCommand () , $ packageManager -> buildCommand () ], $ input , $ output , workingPath: $ directory );
532528 }
533529
534530 $ output ->writeln (" <bg=blue;fg=white> INFO </> Application ready in <options=bold>[ {$ name }]</>. You can start your local development using: " .PHP_EOL );
535531 $ output ->writeln ('<fg=gray>➜</> <options=bold>cd ' .$ name .'</> ' );
536532
537- if (! $ runNpm ) {
538- $ output ->writeln ('<fg=gray>➜</> <options=bold> ' .$ packageInstall .' && npm run build </> ' );
533+ if (! $ runPackageManager ) {
534+ $ output ->writeln ('<fg=gray>➜</> <options=bold> ' .$ packageManager -> installCommand () .' && ' . $ packageManager -> buildCommand (). ' </> ' );
539535 }
540536
541537 if ($ this ->isParkedOnHerdOrValet ($ directory )) {
@@ -553,6 +549,48 @@ protected function execute(InputInterface $input, OutputInterface $output): int
553549 return $ process ->getExitCode ();
554550 }
555551
552+ /**
553+ * Determine the Node package manager to use.
554+ *
555+ * @param string $directory
556+ * @param \Symfony\Component\Console\Input\InputInterface $input
557+ * @return array{NodePackageManager, bool}
558+ */
559+ protected function determinePackageManager (string $ directory , InputInterface $ input ): array
560+ {
561+ // If they passed a specific flag, respect the user's choice...
562+ if ($ input ->getOption ('pnpm ' )) {
563+ return [NodePackageManager::PNPM , true ];
564+ }
565+
566+ if ($ input ->getOption ('bun ' )) {
567+ return [NodePackageManager::BUN , true ];
568+ }
569+
570+ if ($ input ->getOption ('yarn ' )) {
571+ return [NodePackageManager::YARN , true ];
572+ }
573+
574+ if ($ input ->getOption ('npm ' )) {
575+ return [NodePackageManager::NPM , true ];
576+ }
577+
578+ // Check for an existing lock file to determine the package manager...
579+ foreach (NodePackageManager::cases () as $ packageManager ) {
580+ if ($ packageManager === NodePackageManager::NPM ) {
581+ continue ;
582+ }
583+
584+ foreach ($ packageManager ->lockFiles () as $ lockFile ) {
585+ if (file_exists ($ directory .'/ ' .$ lockFile )) {
586+ return [$ packageManager , false ];
587+ }
588+ }
589+ }
590+
591+ return [NodePackageManager::NPM , false ];
592+ }
593+
556594 /**
557595 * Return the local machine's default Git branch if set or default to `main`.
558596 *
@@ -920,21 +958,31 @@ protected function pushToGitHub(string $name, string $directory, InputInterface
920958 }
921959
922960 /**
923- * Configure the Composer "dev" script .
961+ * Configure the Composer scripts for the selected package manager .
924962 *
925- * @param string $directory
963+ * @param NodePackageManager $packageManager
926964 * @return void
927965 */
928- protected function configureComposerDevScript ( string $ directory ): void
966+ protected function configureComposerScripts ( NodePackageManager $ packageManager ): void
929967 {
930- $ this ->composer ->modify (function (array $ content ) {
968+ $ this ->composer ->modify (function (array $ content ) use ( $ packageManager ) {
931969 if (windows_os ()) {
932970 $ content ['scripts ' ]['dev ' ] = [
933971 'Composer \\Config::disableProcessTimeout ' ,
934972 "npx concurrently -c \"#93c5fd,#c4b5fd,#fdba74 \" \"php artisan serve \" \"php artisan queue:listen --tries=1 \" \"npm run dev \" --names='server,queue,vite' " ,
935973 ];
936974 }
937975
976+ foreach (['dev ' , 'dev:ssr ' , 'setup ' ] as $ scriptKey ) {
977+ if (array_key_exists ($ scriptKey , $ content ['scripts ' ])) {
978+ $ content ['scripts ' ][$ scriptKey ] = str_replace (
979+ ['npm ' , 'npx ' , 'ppnpm ' ],
980+ [$ packageManager ->value , $ packageManager ->runLocalOrRemoteCommand (), 'pnpm ' ],
981+ $ content ['scripts ' ][$ scriptKey ],
982+ );
983+ }
984+ }
985+
938986 return $ content ;
939987 });
940988 }
0 commit comments