diff --git a/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php b/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php index faa7fc03..17f4e2a5 100644 --- a/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php +++ b/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php @@ -5,10 +5,15 @@ use Illuminate\Support\Str; use Spatie\Ignition\Contracts\BaseSolution; use Spatie\Ignition\Contracts\HasSolutionsForThrowable; +use Spatie\Ignition\Contracts\Solution; use Throwable; class MissingViteManifestSolutionProvider implements HasSolutionsForThrowable { + protected array $links = [ + 'Asset bundling with Vite' => 'https://laravel.com/docs/9.x/vite#running-vite', + ]; + public function canSolve(Throwable $throwable): bool { return Str::startsWith($throwable->getMessage(), 'Vite manifest not found'); @@ -17,8 +22,34 @@ public function canSolve(Throwable $throwable): bool public function getSolutions(Throwable $throwable): array { return [ - BaseSolution::create('Missing Vite Manifest File') - ->setSolutionDescription('Did you forget to run `npm install && npm run dev`?'), + $this->getSolution(), ]; } + + public function getSolution(): Solution + { + /** @var string */ + $baseCommand = collect([ + 'pnpm-lock.yaml' => 'pnpm', + 'yarn.lock' => 'yarn', + ])->first(fn ($_, $lockfile) => file_exists(base_path($lockfile)), 'npm run'); + + return app()->environment('local') + ? $this->getLocalSolution($baseCommand) + : $this->getProductionSolution($baseCommand); + } + + protected function getLocalSolution(string $baseCommand): Solution + { + return BaseSolution::create('Start the development server') + ->setSolutionDescription("Run `{$baseCommand} dev` in your terminal and refresh the page.") + ->setDocumentationLinks($this->links); + } + + protected function getProductionSolution(string $baseCommand): Solution + { + return BaseSolution::create('Build the production assets') + ->setSolutionDescription("Run `{$baseCommand} build` in your deployment script.") + ->setDocumentationLinks($this->links); + } } diff --git a/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php b/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php index 18bafbf2..2a5bb8bf 100644 --- a/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php +++ b/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php @@ -10,10 +10,42 @@ expect($canSolve)->toBeTrue(); }); -it('can recommend running npm install and npm run dev', function () { +it('recommends running `npm run dev` in a local environment', function () { + app()->detectEnvironment(fn () => 'local'); + + /** @var \Spatie\Ignition\Contracts\Solution $solution */ + $solution = app(MissingViteManifestSolutionProvider::class) + ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; + + + expect(Str::contains($solution->getSolutionDescription(), 'Run `npm run dev` in your terminal and refresh the page.'))->toBeTrue(); +}); + +it('recommends running `npm run build` in a production environment', function () { + app()->detectEnvironment(fn () => 'production'); + /** @var \Spatie\Ignition\Contracts\Solution $solution */ $solution = app(MissingViteManifestSolutionProvider::class) ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; - expect(Str::contains($solution->getSolutionDescription(), 'Did you forget to run `npm install && npm run dev`?'))->toBeTrue(); + + expect(Str::contains($solution->getSolutionDescription(), 'Run `npm run build` in your deployment script.'))->toBeTrue(); }); + +it('detects the package manager and adapts the recommended command', function (string $lockfile, string $command) { + app()->detectEnvironment(fn () => 'local'); + + file_put_contents(base_path($lockfile), ''); + + /** @var \Spatie\Ignition\Contracts\Solution $solution */ + $solution = app(MissingViteManifestSolutionProvider::class) + ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; + + expect(Str::contains($solution->getSolutionDescription(), "Run `{$command}` in your terminal and refresh the page."))->toBeTrue(); + + unlink(base_path($lockfile)); +})->with([ + ['pnpm-lock.yaml', 'pnpm dev'], + ['yarn.lock', 'yarn dev'], + ['package-lock.json', 'npm run dev'] +]);