Search by

dmvdigital / phpsfc

demve

PHP Single File Components: CSS, JS, and HTML sections in one PHP file, Vue-SFC style.

Package info

github.com/dmvdigital/phpsfc

pkg:composer/dmvdigital/phpsfc

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.1.1 2026-09-28 03:56 UTC

This package is auto-updated.

Last update: 2026-10-15 20:12:23 UTC


README

tests Packagist Version License

PHP Single File Components: CSS, JS, and HTML sections in one .php file, Vue-SFC style, no build step.

<!--section::style-->
<style>.__self { padding: 1rem; }</style>

<!--section::output-->
<div class="__self">Hello, <?= htmlspecialchars($name) ?></div>
$engine = new Phpsfc\Engine($componentsDir, $cacheDir);
echo $engine->render('widgets/hello', ['name' => 'World']);

Install

composer require dmvdigital/phpsfc

Requires PHP 8.1+.

For the full method reference, file-format grammar, caching internals, and security model, see DOCUMENTATION.md. Using an AI coding agent to write components? Point it at AGENTS.md first.

Quickstart

A component is referenced by its path, extension omitted, no separately invented name:

$engine->render('sections/hero-animated', ['title' => 'Hello']);
$engine->component('widgets/card')->set('title', 'Getting Started');

A page needs a layout's shell but also needs to hand its own sections into that shell, that's what extends/load and slot()/block()/files() are for:

<!--extends::layout-->
<!--section::content-->
<div class="__self">page body</div>
<!--section::output-->
<head><?= $this->block('style') ?></head>
<body><?= $this->slot('content') ?></body>

The setup section declares props once, and that single declaration drives both the runtime default and Editor Mode's control panel, no separate schema to keep in sync:

<!--section::setup-->
<?php
$setup->metadata('Hero Section')
    ->variable('title', ['default' => 'Welcome', 'control' => 'text']);

Then open a standalone visual viewer (with a Monaco source editor a click away) for every component:

$engine->editor(); // dispatches based on $_GET

CLI

bin/phpsfc wraps cacheBuild()/cacheDelete()/listComponents()/scaffolding for deploy scripts, given a bootstrap file that returns a configured Engine:

vendor/bin/phpsfc --bootstrap=bootstrap.php cache:build
vendor/bin/phpsfc --bootstrap=bootstrap.php make widgets/hero

bootstrap.php (or phpsfc.php/.phpsfc-cli.php in the current directory, picked up automatically without --bootstrap):

<?php
require __DIR__ . '/vendor/autoload.php';
return new Phpsfc\Engine(__DIR__ . '/components', __DIR__ . '/cache');

Examples

Runnable, in examples/. Clone the repo, then:

php -S localhost:8000 -t examples/01-basic

...and open http://localhost:8000. Same pattern for any other example directory.

  • 01-basic, render/load/extends, a setup schema, and a non-strict missing-component error.
  • 02-layout, a page extending a layout and loading a widget component.
  • 03-modifier, a custom modifier (CSS minification) and a custom OutputStrategy, both registered under a key.
  • 04-vue-sfc, Vue x-template mode: two views compiled to <script> templates, swapped by a hash router.
  • 05-php-logic, loops, conditionals, other plain PHP running inside sections, and __DIR__ reaching a sibling data file.
  • 06-css-file-cache, a modifier that writes bundled CSS to a file instead of inlining it.
  • 07-auto-load, components discovered by being rendered from inside another component's output, not declared upfront.
  • 08-content-blocks, CMS-style blocks in random order per request, with per-block styles injected into <head> regardless of load order.
  • 09-file-modifiers, bundling both CSS and JS out to public files.
  • 10-editor, Editor Mode's standalone visual viewer and Monaco source editor.
  • 11-clear-cache, cacheBuild()/cacheDelete() and their opt-in GET-triggered variants.
  • 12-conditional-slot, hasSlot() picking a sidebar layout depending on what the page defines.
  • 13-autoload, explicit <!--load::--> markers for shared components.
  • 14-component-and-assets, the component()->set() OOP wrapper and asset()'s copy-if-stale + cache-busted URL.
  • 15-strict-props, strict mode (the default) throwing MissingPropException/ComponentNotFoundException instead of soft-erroring.
  • 16-slot-content, passing pre-rendered markup into a component as a prop, ob_start()/ob_get_clean() capturing a nested render() call.
  • 17-hooks, lifecycle hooks: onError()/onErrorsFinal(), render.before/render.after.
  • 18-modifier-chaining, minify() chaining after a custom modifier instead of replacing it.
  • 19-scoped-sections, ConfigKey::ScopedSections narrowing slot()/block() to the current render tree.
  • 20-multi-root, multi-root componentsDir, an app-local root shadowing a shared one.

License

MIT