cartalyst/phpsass
Cartalyst PHPSass is a PHP implementation of the Sass CSS preprocessor, letting you compile SCSS and Sass stylesheets directly in PHP without Ruby. It supports variables, nesting, mixins, and inheritance for building maintainable stylesheets.
Architecture fit. cartalyst/phpsass occupies a narrow architectural niche: server-side SCSS compilation inside a PHP process, with no Node, Ruby, or Dart Sass in the deploy path. For a Laravel application already running the Cartalyst stack (Theme / Platform / Sentinel) whose theme layer assumes an in-PHP compiler, that is a coherent fit — the compiler sits alongside the code that consumes its output, and the deploy artifact is CSS. For everything else, it is the weaker answer to a question that should be framed as pipeline architecture, not package selection: the real choice is "does stylesheet compilation live inside the PHP application, or in a Vite / Laravel Mix / Dart Sass asset pipeline?" A maintained pure-PHP alternative (scssphp/scssphp) exists and should be the default comparison point. This package should never appear in an RFP or roadmap for greenfield work; it is a keep-the-lights-on input.
Integration feasibility. Technically straightforward, organizationally not. Composer installation works, the API is small (SassParser::parse_file() with an options array for style, load_paths, cache), and it can be driven from an Artisan command or a service provider within an hour. Two caveats dominate. First, the documentation and the code lineage disagree: the marketing copy describes a libsass wrapper (SassCompiler::compile()), while the richthegeek/phpsass lineage is a pure-PHP port of early Ruby Sass with a different API surface and a materially different performance and language-coverage profile. That contradiction is both a scoping risk and a documentation-integrity signal. Second, there is no published docs page and no package-discovery guarantee — the vendor directory is the documentation, and the first hour of work is reading it.
Technical risk. Ranked by severity:
@use, no @forward, no math.div, / still means division, and @each/@function coverage is partial. Modern-built stylesheets can compile cleanly with different semantics and emit subtly wrong CSS that passes every existing test.each() deprecations, dynamic-property warnings, implicit-nullable-parameter warnings, and possible fatals from removed functions. The composer.json php constraint may hard-block installation on 8.x — in which case you are already forking and owning the code.composer install --no-dev -o than in dev; the failure mode is a class-not-found at deploy time that never reproduces locally.set_error_handler to convert warnings into exceptions, which can collide with Laravel's handler under APP_DEBUG=true. Include-path resolution is also working-directory sensitive — php artisan, a queue worker, and PHPUnit resolve @import differently.memory_limit.Key questions.
scssphp/scssphp or a Node pipeline? If the latter, the decision needs justification.@use, @forward, @function, @each, or math.div? A single grep quantifies the migration cost.php constraint, and does it install on every version in our CI matrix?Stack fit. Adopt only behind a contract the application owns. This is the cheapest risk control available and it is non-negotiable for an unmaintained parser: it converts an irreversible vendor choice into a one-line container binding.
interface StylesheetCompiler { public function compile(string $source, array $options = []): string; }
A PhpSassCompiler implementation wraps SassParser; AppServiceProvider::register() binds the interface as a singleton. No Blade template, controller, or model calls the parser directly. When the swap to scssphp/scssphp happens, only that one class changes — commands, tests, and helpers stay put.
Migration path. Start with a parity spike, not an integration. Compile the full production stylesheet set with this package and with Dart Sass, then diff:
npx sass resources/scss/app.scss /tmp/dart.css --style=compressed
php spike.php > /tmp/phpsass.css
diff -u /tmp/dart.css /tmp/phpsass.css | head -100
Cosmetic, explainable diffs → a contained legacy dependency. Structural diffs — missing rules, wrong values, dropped media queries — → stop and go straight to scssphp/scssphp. Everything downstream depends on this one result.
Compatibility. Pin an exact version (composer require cartalyst/phpsass:1.0.4), never a floating constraint on an unmaintained package. Put include paths, output style, and entrypoint lists in config/styles.php and resolve them absolute via resource_path() / base_path() — relative paths fail differently across artisan, queue workers, and tests. Disable the parser's internal disk cache ('cache' => false) and do hash-based caching yourself, keyed explicitly on source content; the parser's own mtime cache writes to temp directories that misbehave on read-only or containerized filesystems. Verify composer install --no-dev -o in a clean container before relying on autoload behavior.
Sequencing.
php constraint, autoload strategy, whether a Laravel provider block exists, and the actual entry class and methods. Correct the "libsass wrapper" claim in any internal deck before it reaches an estimate.StylesheetCompiler contract and the wrapper implementation. No application code touches the parser.php artisan styles:compile with a --force flag, md5-based staleness check, and per-entrypoint output. Call it from the deploy hook after composer install, before route:cache.--update-snapshots path so a compiler swap or PHP upgrade produces a loud, reviewable diff instead of a silent one. Add a test that compiles from a different working directory.scssphp/scssphp, similar shape), the interface, and the validation steps (parity diff plus golden-file suite).Dynamic theming. Do not compile at request time. Compile design tokens to CSS custom properties at build time and emit per-tenant values from the database:
<style>:root { --brand-primary: {{ $tenant->brand_primary }}; }</style>
Same white-label capability, faster, safer, and it removes the compiler from the request cycle entirely — which is the stronger product decision regardless of which compiler is underneath.
Maintenance. Self-owned from the moment it is installed. Zero stars, zero dependents, no upstream maintainer, no security process. Budget ongoing effort for: patching PHP 8.x deprecations and fatals, keeping the pinned version consistent across environments, regenerating golden fixtures on intentional stylesheet changes, and periodically re-running the parity diff. The realistic ceiling is a small, static, legacy stylesheet set — not a growing design system.
Support. There is no external support channel. Documentation is the vendor directory. Institutional knowledge must be written down in the same week as adoption: the runbook, the replacement note, and the named owner. The person who can swap this out in an afternoon is the person who wrote that note; if that person leaves without it, the cost of replacement rises sharply.
Scaling. Poorly. Compilation is CPU-bound and single-threaded per entrypoint; pure-PHP parsing of large stylesheet sets is orders of magnitude slower than libsass or Dart Sass and can push a 200ms build past 10 seconds. Mitigations: keep compilation strictly in the build/deploy path, parallelize per entrypoint when there are many, watch memory_limit (large ASTs), and cache aggressively on source hash. Under no circumstances should it run in the request cycle — that path does not scale at all and turns a build-time cost into user-facing latency.
Failure modes. The dangerous ones are quiet:
--no-dev -o. Caught only by a clean-container composer install verification.set_error_handler interfering with Laravel's exception pipeline under APP_DEBUG=true. Bounded by running compilation in a separate process (Artisan command or CI step), which is the right architecture anyway.'cache' => false.Ramp-up. Low technical ramp-up, moderate organizational ramp-up. A competent Laravel developer can wrap SassParser and wire an Artisan command in under a day; the API is small and the concept familiar. The real ramp-up cost is elsewhere: reading the vendor directory to establish what was actually installed (the libsass-versus-pure-PHP contradiction must be resolved from source, not from the description), building the parity-spike habit, and internalizing that the Sass dialect is early Ruby Sass — that / is division, that @use and @forward do not exist, and that a "clean compile" is not evidence of correctness. Budget the first hour for reading the vendor tree, the first day for the parity spike, and one engineer-week for the wrapper, command, config, golden-file suite, and the two runbook artifacts — and treat that estimate as contingent on the parity spike passing.
How can I help you explore Laravel packages today?