diff --git a/src/Commands/Concerns/InstallsForImportmap.php b/src/Commands/Concerns/InstallsForImportmap.php index d4053cb..8efc5fd 100644 --- a/src/Commands/Concerns/InstallsForImportmap.php +++ b/src/Commands/Concerns/InstallsForImportmap.php @@ -46,7 +46,9 @@ protected function registerImportmapPins() { $this->components->task('pinning JS dependency (importmap)', function () { $this->callSilently('importmap:pin', [ - 'packages' => ['@hotwired/stimulus'], + 'packages' => collect($this->jsPackages()) + ->map(fn ($package, $version) => "{$package}@{$version}") + ->all(), ]); // Publishes the `@hotwired/stimulus-loading` package to public/ diff --git a/src/Commands/Concerns/InstallsForNode.php b/src/Commands/Concerns/InstallsForNode.php index 7989f4f..1088ac6 100644 --- a/src/Commands/Concerns/InstallsForNode.php +++ b/src/Commands/Concerns/InstallsForNode.php @@ -53,13 +53,12 @@ protected function updateNpmPackagesForNode() { $this->components->task('registering NPM dependency', function () { $this->updateNodePackages(function ($packages) { - return [ - '@hotwired/stimulus' => '^3.1.0', - ] + $packages; + return array_merge( + $packages, + $this->jsPackages(), + ); }); - $this->afterMessages[] = 'Run: `npm install && npm run dev`'; - return true; }); } diff --git a/src/Commands/InstallCommand.php b/src/Commands/InstallCommand.php index 2152d7b..f94c732 100644 --- a/src/Commands/InstallCommand.php +++ b/src/Commands/InstallCommand.php @@ -4,13 +4,15 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\File; +use RuntimeException; +use Symfony\Component\Process\Process; class InstallCommand extends Command { use Concerns\InstallsForImportmap; use Concerns\InstallsForNode; - public $signature = 'stimulus:install'; + public $signature = 'stimulus:install {--strada : Sets up Strada as well.}'; public $description = 'Installs the Stimulus Laravel package.'; @@ -24,21 +26,54 @@ public function handle(): int $this->installsForImportmaps(); } else { $this->installsForNode(); - } - if (! empty($this->afterMessages)) { - $this->newLine(); - $this->components->info('After Notes and Next Steps'); - $this->components->bulletList($this->afterMessages); - } else { - $this->components->info('Done'); + if (file_exists(base_path('pnpm-lock.yaml'))) { + $this->runCommands(['pnpm install', 'pnpm run build']); + } elseif (file_exists(base_path('yarn.lock'))) { + $this->runCommands(['yarn install', 'yarn run build']); + } else { + $this->runCommands(['npm install', 'npm run build']); + } } + $this->newLine(); + $this->components->info('Done'); $this->newLine(); return self::SUCCESS; } + protected function jsPackages(): array + { + return array_merge( + ['@hotwired/stimulus' => '^3.1.0'], + $this->hasOption('strada') ? ['@hotwired/strada' => '^1.0.0-beta1'] : [], + ); + } + + /** + * Run the given commands. + * + * @param array $commands + * @return void + */ + protected function runCommands($commands) + { + $process = Process::fromShellCommandline(implode(' && ', $commands), null, null, null, null); + + if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) { + try { + $process->setTty(true); + } catch (RuntimeException $e) { + $this->output->writeln(' WARN '.$e->getMessage().PHP_EOL); + } + } + + $process->run(function ($type, $line) { + $this->output->write(' '.$line); + }); + } + protected function usingImportmaps(): bool { return File::exists($this->importmapsFile()); diff --git a/src/Commands/MakeCommand.php b/src/Commands/MakeCommand.php index 96962c2..4fee4a6 100644 --- a/src/Commands/MakeCommand.php +++ b/src/Commands/MakeCommand.php @@ -5,6 +5,7 @@ use HotwiredLaravel\StimulusLaravel\StimulusGenerator; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; +use Illuminate\Support\Facades\Process; class MakeCommand extends Command { @@ -26,6 +27,14 @@ public function handle(StimulusGenerator $generator): int $this->components->task('regenerating manifest', function () { return $this->callSilently(ManifestCommand::class); }); + + if (file_exists(base_path('pnpm-lock.yaml'))) { + Process::forever()->path(base_path())->run(['pnpm', 'run', 'build']); + } elseif (file_exists(base_path('yarn.lock'))) { + Process::forever()->path(base_path())->run(['yarn', 'run', 'build']); + } else { + Process::forever()->path(base_path())->run(['npm', 'run', 'build']); + } } $this->newLine(); diff --git a/src/Commands/ManifestCommand.php b/src/Commands/ManifestCommand.php index ac6f881..3720a7f 100644 --- a/src/Commands/ManifestCommand.php +++ b/src/Commands/ManifestCommand.php @@ -31,7 +31,7 @@ public function handle(Manifest $generator) // Run that command whenever you add a new controller or create them with // `php artisan stimulus:make controllerName` - import { application } from '../libs/stimulus' + import { Stimulus } from '../libs/stimulus' {$manifest} JS); diff --git a/src/Commands/StradaMakeCommand.php b/src/Commands/StradaMakeCommand.php new file mode 100644 index 0000000..0baadb3 --- /dev/null +++ b/src/Commands/StradaMakeCommand.php @@ -0,0 +1,48 @@ +components->info('Making Strada Component'); + + $this->components->task('creating strada component', function () use ($generator) { + $generator->createStrada($this->option('prefix'), $this->argument('name'), $this->option('bridge-name')); + + return true; + }); + + if (! File::exists(base_path('routes/importmap.php'))) { + $this->components->task('regenerating manifest', function () { + return $this->callSilently(ManifestCommand::class); + }); + + if (file_exists(base_path('pnpm-lock.yaml'))) { + Process::forever()->path(base_path())->run(['pnpm', 'run', 'build']); + } elseif (file_exists(base_path('yarn.lock'))) { + Process::forever()->path(base_path())->run(['yarn', 'run', 'build']); + } else { + Process::forever()->path(base_path())->run(['npm', 'run', 'build']); + } + } + + $this->newLine(); + $this->components->info('Done'); + + return self::SUCCESS; + } +} diff --git a/src/Manifest.php b/src/Manifest.php index c78e325..376ccff 100644 --- a/src/Manifest.php +++ b/src/Manifest.php @@ -30,7 +30,7 @@ public function generateFrom(string $controllersPath): Collection return <<targetFolder ??= rtrim(resource_path('js/controllers'), '/'); } - public function create(string $name): array + public function create(string $name, string $stub = null, callable $replacementsCallback = null): array { + $replacementsCallback ??= fn ($replacements) => $replacements; $controllerName = $this->controllerName($name); $targetFile = $this->targetFolder.'/'.$controllerName.'_controller.js'; File::ensureDirectoryExists(dirname($targetFile)); + $replacements = $replacementsCallback([ + '[attribute]' => $attributeName = $this->attributeName($name), + ]); + File::put( $targetFile, - str_replace('[attribute]', $attributeName = $this->attributeName($name), File::get(__DIR__.'/../stubs/controller.stub')), + str_replace(array_keys($replacements), array_values($replacements), File::get($stub ?: __DIR__.'/../stubs/controller.stub')), ); return [ @@ -31,6 +36,16 @@ public function create(string $name): array ]; } + public function createStrada(string $prefix, string $name, string $bridgeName = null): array + { + return $this->create("$prefix/$name", stub: __DIR__.'/../stubs/strada.stub', replacementsCallback: function (array $replacements) use ($bridgeName) { + return array_merge( + $replacements, + ['[bridge-name]' => $bridgeName ?? (string) Str::of($replacements['[attribute]'])->afterLast('--')], + ); + }); + } + private function controllerName(string $name): string { return Str::of($name)->replace('_controller', '')->snake('_'); diff --git a/src/StimulusLaravelServiceProvider.php b/src/StimulusLaravelServiceProvider.php index cf23ac2..d35ab77 100644 --- a/src/StimulusLaravelServiceProvider.php +++ b/src/StimulusLaravelServiceProvider.php @@ -22,6 +22,7 @@ public function configurePackage(Package $package): void ->hasCommands([ Commands\InstallCommand::class, Commands\MakeCommand::class, + Commands\StradaMakeCommand::class, Commands\CoreMakeCommand::class, Commands\PublishCommand::class, Commands\ManifestCommand::class, diff --git a/stubs/resources/js/controllers/index-importmap.js b/stubs/resources/js/controllers/index-importmap.js index df1587e..9f9ee3b 100644 --- a/stubs/resources/js/controllers/index-importmap.js +++ b/stubs/resources/js/controllers/index-importmap.js @@ -1,5 +1,5 @@ -import { application } from 'libs/stimulus' +import { Stimulus } from 'libs/stimulus' // Eager load all controllers defined in the import map under controllers/**/*_controller import { eagerLoadControllersFrom } from '@hotwired/stimulus-loading' -eagerLoadControllersFrom('controllers', application) +eagerLoadControllersFrom('controllers', Stimulus) diff --git a/stubs/resources/js/controllers/index-node.js b/stubs/resources/js/controllers/index-node.js index 0a64188..105e4c6 100644 --- a/stubs/resources/js/controllers/index-node.js +++ b/stubs/resources/js/controllers/index-node.js @@ -2,7 +2,7 @@ // Run that command whenever you add a new controller or create them with // `php artisan stimulus:make controllerName` -import { application } from '../libs/stimulus' +import { Stimulus } from '../libs/stimulus' import HelloController from './hello_controller' -application.register('hello', HelloController) +Stimulus.register('hello', HelloController) diff --git a/stubs/resources/js/libs/stimulus.js b/stubs/resources/js/libs/stimulus.js index 28412f1..1ecdf34 100644 --- a/stubs/resources/js/libs/stimulus.js +++ b/stubs/resources/js/libs/stimulus.js @@ -1,9 +1,10 @@ import { Application } from '@hotwired/stimulus' -const application = Application.start() +const Stimulus = Application.start() // Configure Stimulus development experience -application.debug = false -window.Stimulus = application +Stimulus.debug = false -export { application } +window.Stimulus = Stimulus + +export { Stimulus } diff --git a/stubs/strada.stub b/stubs/strada.stub new file mode 100644 index 0000000..4253580 --- /dev/null +++ b/stubs/strada.stub @@ -0,0 +1,8 @@ +import { BridgeComponent, BridgeElement } from "@hotwired/strada" + +// Connects to data-controller="[attribute]" +export default class extends BridgeComponent { + static component = "[bridge-name]" + + // +} diff --git a/tests/ManifestTest.php b/tests/ManifestTest.php index 32c8b19..00f0540 100644 --- a/tests/ManifestTest.php +++ b/tests/ManifestTest.php @@ -19,7 +19,7 @@ public function generates_controllers_imports_given_a_path() <<<'JS' import HelloController from './hello_controller' - application.register('hello', HelloController) + Stimulus.register('hello', HelloController) JS, $manifest, ); @@ -28,7 +28,7 @@ public function generates_controllers_imports_given_a_path() <<<'JS' import Nested__DeepController from './nested/deep_controller' - application.register('nested--deep', Nested__DeepController) + Stimulus.register('nested--deep', Nested__DeepController) JS, $manifest, ); @@ -37,7 +37,7 @@ public function generates_controllers_imports_given_a_path() <<<'JS' import CoffeeController from './coffee_controller' - application.register('coffee', CoffeeController) + Stimulus.register('coffee', CoffeeController) JS, $manifest, ); @@ -46,7 +46,7 @@ public function generates_controllers_imports_given_a_path() <<<'JS' import TypeScriptController from './type_script_controller' - application.register('type-script', TypeScriptController) + Stimulus.register('type-script', TypeScriptController) JS, $manifest, ); @@ -55,7 +55,7 @@ public function generates_controllers_imports_given_a_path() <<<'JS' import Index from './index' - application.register('index', Index) + Stimulus.register('index', Index) JS, $manifest, );