mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-28 03:44:19 +08:00
Preserve schema files when renderer overwrite is declined
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -24,6 +24,8 @@ Then customize the generated view, following [custom component classes](#custom-
|
||||
|
||||
### Generating a JavaScript component
|
||||
|
||||
Install your application's existing JavaScript dependencies, including Vite, before running the generator, for example with `npm install`. The command reads the installed Vite version to select compatible compiler plugins, including when you use `--skip-install`.
|
||||
|
||||
Add one renderer flag to generate a component using React, Vue, Svelte, or framework-free JavaScript:
|
||||
|
||||
```bash
|
||||
@@ -33,7 +35,7 @@ php artisan make:filament-schema-component Chart --svelte
|
||||
php artisan make:filament-schema-component Chart --js
|
||||
```
|
||||
|
||||
The command creates a PHP component class and a renderer in `resources/js/filament/schemas/components/`, without a Blade view. It installs any required development dependencies, updates recognizable Vite configurations, and offers to compile your assets. Use the generated class in your schema as shown above, then replace the starter paragraph with your own UI.
|
||||
The command creates a PHP component class and a renderer in `resources/js/filament/schemas/components/`, without a Blade view. It installs missing development dependencies, updates recognizable Vite configurations, and offers to compile your assets. Existing compatible dependency declarations keep their version constraints and their `package.json` sections. Incompatible dependencies require a manual upgrade instead of being replaced automatically. Use the generated class in your schema as shown above, then replace the starter paragraph with your own UI.
|
||||
|
||||
For TypeScript, add `--typescript` or its alias `--ts`:
|
||||
|
||||
@@ -745,7 +747,7 @@ For methods on the owning Livewire component rather than the schema component, u
|
||||
|
||||
### Typing renderers
|
||||
|
||||
Use `--typescript` or `--ts` to generate typed starters. The generator installs TypeScript 6 because Vue and Svelte tooling still requires its JavaScript compiler API, which TypeScript 7 does not provide. If you use `--skip-install`, install `typescript@^6.0` yourself.
|
||||
Use `--typescript` or `--ts` to generate typed starters. When TypeScript is not already declared, the generator installs `typescript@^6.0` because Vue and Svelte tooling still requires its JavaScript compiler API, which TypeScript 7 does not provide. Existing compatible TypeScript 5 or 6 installations are preserved. If you use `--skip-install`, follow the printed installation command for missing dependencies.
|
||||
|
||||
New TypeScript configurations use `"jsx": "react-jsx"` so Vite compiles React renderers. Existing configurations are preserved. If your configuration uses `"jsx": "preserve"`, switch it to `"react-jsx"` or configure a React JSX transform in Vite; Vite 8 otherwise leaves JSX uncompiled and the production build fails.
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ class MakeComponentCommand extends Command
|
||||
|
||||
protected function createComponent(): void
|
||||
{
|
||||
if (! $this->option('force') && $this->checkForCollision($this->path)) {
|
||||
if (! $this->option('force') && $this->checkForCollision([$this->path, ...array_keys($this->rendererFiles)])) {
|
||||
throw new FailureCommandOutput;
|
||||
}
|
||||
|
||||
@@ -296,10 +296,6 @@ class MakeComponentCommand extends Command
|
||||
|
||||
protected function createRenderer(): void
|
||||
{
|
||||
if (! $this->option('force') && $this->checkForCollision(array_keys($this->rendererFiles))) {
|
||||
throw new FailureCommandOutput;
|
||||
}
|
||||
|
||||
foreach ($this->rendererFiles as $path => $stub) {
|
||||
$this->copyStubToApp($stub, $path, [
|
||||
'componentName' => class_basename($this->fqn),
|
||||
|
||||
@@ -12,9 +12,13 @@ beforeEach(function (): void {
|
||||
Process::preventStrayProcesses();
|
||||
$this->originalSetupFiles = [];
|
||||
|
||||
foreach (['vite.config.js', 'tsconfig.json'] as $path) {
|
||||
foreach (['vite.config.js', 'tsconfig.json', 'package.json', 'node_modules/vite/package.json'] as $path) {
|
||||
$this->originalSetupFiles[$path] = File::exists(base_path($path)) ? File::get(base_path($path)) : null;
|
||||
}
|
||||
|
||||
File::put(base_path('package.json'), '{}');
|
||||
File::ensureDirectoryExists(base_path('node_modules/vite'));
|
||||
File::put(base_path('node_modules/vite/package.json'), '{"version":"8.0.0"}');
|
||||
});
|
||||
|
||||
afterEach(function (): void {
|
||||
@@ -69,7 +73,7 @@ it('installs dependencies and configures Vite for a typed React component', func
|
||||
->expectsConfirmation('Would you like to compile the component now?', 'yes')
|
||||
->assertSuccessful();
|
||||
|
||||
Process::assertRan(static fn (PendingProcess $process): bool => $process->command === ['yarn', 'add', 'react', 'react-dom', 'typescript@^6.0', '@types/react', '@types/react-dom', '--dev']);
|
||||
Process::assertRan(static fn (PendingProcess $process): bool => $process->command === ['yarn', 'add', 'react@^19.0', 'react-dom@^19.0', 'typescript@^6.0', '@types/react@^19.0', '@types/react-dom@^19.0', '--dev']);
|
||||
expect(File::get(base_path('vite.config.js')))->toContain('preserveEntrySignatures', 'resources/js/filament/schemas/components/sales-chart.tsx');
|
||||
});
|
||||
|
||||
@@ -113,6 +117,64 @@ it('overwrites existing renderers with `--force`', function (): void {
|
||||
expect(File::get($path))->toContain('export default function mountExistingChart');
|
||||
});
|
||||
|
||||
it('preserves every component file when a renderer overwrite is declined', function (): void {
|
||||
$paths = [
|
||||
app_path('Filament/Schemas/Components/CancelledChart.php'),
|
||||
resource_path('js/filament/schemas/components/cancelled-chart.js'),
|
||||
resource_path('js/filament/schemas/components/CancelledChart.vue'),
|
||||
];
|
||||
|
||||
foreach ($paths as $path) {
|
||||
File::ensureDirectoryExists(dirname($path));
|
||||
File::put($path, 'Original ' . basename($path));
|
||||
}
|
||||
|
||||
$environment = app()['env'];
|
||||
|
||||
try {
|
||||
app()['env'] = 'local';
|
||||
|
||||
$this->artisan('make:filament-schema-component', [
|
||||
'name' => 'CancelledChart',
|
||||
'--vue' => true,
|
||||
'--skip-install' => true,
|
||||
'--skip-build' => true,
|
||||
])
|
||||
->expectsConfirmation('CancelledChart.php already exists, do you want to overwrite it?', 'yes')
|
||||
->expectsConfirmation('cancelled-chart.js already exists, do you want to overwrite it?', 'yes')
|
||||
->expectsConfirmation('CancelledChart.vue already exists, do you want to overwrite it?', 'no')
|
||||
->assertFailed();
|
||||
|
||||
foreach ($paths as $path) {
|
||||
expect(File::get($path))->toBe('Original ' . basename($path));
|
||||
}
|
||||
} finally {
|
||||
app()['env'] = $environment;
|
||||
File::delete($paths);
|
||||
}
|
||||
});
|
||||
|
||||
it('requires installed Vite before selecting renderer dependencies', function (bool $skipInstall): void {
|
||||
File::delete(base_path('node_modules/vite/package.json'));
|
||||
$componentPath = app_path('Filament/Schemas/Components/UninstalledViteChart.php');
|
||||
$rendererPath = resource_path('js/filament/schemas/components/uninstalled-vite-chart.svelte.js');
|
||||
File::delete([$componentPath, $rendererPath]);
|
||||
|
||||
$this->artisan('make:filament-schema-component', [
|
||||
'name' => 'UninstalledViteChart',
|
||||
'--svelte' => true,
|
||||
'--skip-install' => $skipInstall,
|
||||
'--skip-build' => true,
|
||||
'--no-interaction' => true,
|
||||
])
|
||||
->expectsOutputToContain('Install your application\'s existing JavaScript dependencies, including Vite, before generating a JavaScript renderer.')
|
||||
->assertFailed();
|
||||
|
||||
expect(File::exists($componentPath))->toBeFalse();
|
||||
expect(File::exists($rendererPath))->toBeFalse();
|
||||
Process::assertNotRan(static fn (PendingProcess $process): bool => in_array('install', $process->command));
|
||||
})->with([false, true]);
|
||||
|
||||
it('returns failure when compiling the generated component fails', function (): void {
|
||||
File::put(base_path('vite.config.js'), file_get_contents(__DIR__ . '/../../Panels/Commands/Fixture/MakeThemeCommandTest/vite-config/standard.js'));
|
||||
Process::fake(static fn (PendingProcess $process) => Process::result(exitCode: ($process->command === ['npm', 'run', 'build']) ? 1 : 0));
|
||||
|
||||
Reference in New Issue
Block a user