I was working on a project and concluded that working with components in Laravel is working okay, but switching between a lot of files became cumbersome. So, I decided to create Laravel Single File Components. The code is not yet ready for release, if any, but I would like to get some feedback/input from you, such as:
- What do you think of the setup?
- Would you use it, if it would get released?
- What features should not be skipped before a potential release (if there is enough demand for this package)?
- Any other feedback/input.
In short, when a SFC is saved, automatically reload the page, break down the SFC in its parts, if needed it gets changed and then copied to the correct file/path. When this is done output the modified html and resources.
Currently Supported:
Component Parts
-
Template: Includes support for frontend frameworks like Alpine. The template tag is rendered to a dedicated Blade file in the components directory.
-
Style: Supports Tailwind, and the style is written in SCSS format. You can make use of the
@apply directive. All the CSS is rendered to a components.scss file.
-
JavaScript: Renders all component JavaScript to a file, deduplicates, and sorts import statements. If you use Vite, you can import other code. In a later stage, I plan to add TypeScript support. The JavaScript tag gets rendered to a
components.js file.
-
PHP: You can create a Component class. This part is rendered to a component class in the
app/ directory.
Features
- Full-page reload on component save (Template, Style, JavaScript, and PHP are taken into account during the reload).
- In PhpStorm, you get autocompletion for all 4 parts in the same file. Visual Studio Code is not yet tested.
- Support for namespaces.
- There is an install command that helps you set up the package.
- There is a
make:sfcomponent command to create a Single File Component (SFC).
- A lot can be tweaked via a config file.
Todo
- Removing files for a removed SFC.
- More configuration options for the developer per part.
An example of how a single file component looks like:
<template>
<div class="x-app" x-data="app('{{ $name }}')">
<div x-show="open" x-text="componentName">{{ $name }}</div>
<div @click="toggle">Toggle</div>
</div>
</template>
<script lang="js">
import Alpine from 'alpinejs';
Alpine.data('app', (componentName) => ({
open: true,
componentName,
toggle() {
this.open = !this.open
this.componentName += '1';
},
}))
</script>
<style>
.x-app {
@apply p-4 m-4 font-bold bg-amber-100
}
</style>
<?php
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Application;
use Illuminate\View\Component;
class App extends Component
{
public function __construct(protected string $name)
{
}
/**
* @inheritdoc
*/
public function render(): Factory|View|Application
{
return view('components.app', ['name' => $this->name]);
}
}