承接 bennypowers/backlit 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

bennypowers/backlit

Composer 安装命令:

composer require bennypowers/backlit

包简介

Server-render Lit web components from Drupal. No Node.js. No containers. Just vibes and NUL bytes.

README 文档

README

Backlit

Server-render Lit web components from Drupal. No Node.js. No containers. No HTTP sidecar. Just a single binary that speaks NUL bytes.

Backlit hooks into Drupal's response pipeline and renders every Lit web component with Declarative Shadow DOM. Users see styled, laid-out content on first paint -- before any JavaScript loads. Disable JS entirely and the components still render. That is the way of the Lit.

Quick start

composer require bennypowers/backlit
drush en backlit

That's it. Composer downloads the right binary for your platform. Drush enables the module. Every page response now gets its web components server-rendered.

If the binary download didn't run automatically:

cd web/modules/contrib/backlit
./scripts/download-binary.sh

How it works

Backlit ships a pre-compiled Go binary that embeds a WASM module. Inside that WASM module: QuickJS running @lit-labs/ssr. On startup, the binary bundles your component source files (JS or TS) with esbuild, evaluates the bundle inside QuickJS, and registers your custom elements.

When Drupal finishes rendering a page, Backlit's SsrResponseSubscriber intercepts the response, pipes the HTML through the binary's stdin, and reads Declarative Shadow DOM enhanced HTML from stdout. The binary uses a NUL-delimited read-loop protocol, so the WASM instance and your component definitions stay warm across renders.

First render:  ~350ms  (WASM cold start -- paid once per PHP-FPM worker)
Every render after:  ~0.32ms  (just pipe I/O)

The binary auto-detects your platform. Supported: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64, win32-arm64. Yes, we support Windows. No, we haven't tested it. Godspeed.

Adding your components

Drop JS or TS source files into one of these locations. Backlit aggregates component files from all of them:

  1. $settings['backlit']['components_dir'] in settings.php
  2. Your active theme's components/ directory -- e.g., themes/custom/my_theme/components/
  3. Any custom module's js/ directory -- e.g., modules/custom/my_components/js/

The binary bundles your source files with esbuild at startup, resolving imports from node_modules. Declaration files (.d.ts) and test files (.test.ts, .test.js) are excluded automatically.

What the source looks like

Standard LitElement with standard imports:

import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('my-card')
class MyCard extends LitElement {
  @property() heading = '';

  static styles = css`
    :host { display: block; border: 1px solid #ccc; border-radius: 8px; }
    #header { padding: 16px; font-weight: 600; }
    #body { padding: 16px; }
  `;

  render() {
    return html`
      <div id="header">${this.heading}</div>
      <div id="body"><slot></slot></div>
    `;
  }
}

Then use it in any Drupal content (Full HTML format):

<my-card heading="Dashboard">
  <p>All systems operational.</p>
</my-card>

Components stay registered across renders -- the binary bundles and evaluates your source once, then keeps the definitions warm.

Pre-bundled mode (advanced)

If you prefer to bundle components yourself, you can pass a pre-built JS bundle via $settings['backlit']['bundle'] in settings.php. The binary will skip esbuild and evaluate the bundle directly.

Performance

Metric Value
Cold start ~350ms (once per PHP-FPM worker)
Warm render ~0.32ms
Binary size ~9 MB (statically linked, no dependencies)
Memory ~20 MB per WASM instance
Dependencies Zero. The binary is the dependency.

For comparison, the previous approach required a Node.js container, HTTP round-trips, and ~50ms per render. The drop has moved.

Requirements

  • Drupal 10 or 11
  • PHP 8.1+
  • A server that can run a binary (so, any server)
  • node_modules with lit installed (esbuild resolves imports at startup)
  • No PHP extensions, no PECL, no FFI, no containers

Graceful degradation

If the binary isn't available or fails to start, Backlit returns the original HTML unchanged. Your components will still work client-side once their JavaScript loads -- they just won't have the instant first paint from DSD. This means you can develop locally without the binary and deploy with it.

Architecture

Browser request
       |
   Drupal renders page (Twig, etc.)
       |
   KernelEvents::RESPONSE
       |
   SsrResponseSubscriber
       |
   LitSsrRenderer::render()
       |
   proc_open() -> lit-ssr binary (Go + wazero + QuickJS + @lit-labs/ssr)
       |
   stdin: HTML\0  ->  stdout: HTML-with-DSD\0
       |
   Response sent to browser with Declarative Shadow DOM
       |
   User sees styled content immediately
   (JavaScript loads later, hydrates if needed)

FAQ

Does this work with any web component framework? Only Lit. The SSR engine is @lit-labs/ssr, which understands Lit's template system. Vanilla custom elements or other frameworks would need their own SSR implementation.

What about caching? Backlit operates on every response. If you have Drupal's page cache enabled, the rendered HTML (with DSD) gets cached, so subsequent requests skip the binary entirely. This is the recommended setup.

What about BigPipe? Backlit runs in a KernelEvents::RESPONSE subscriber, which processes the initial HTML response before it is sent to the browser. BigPipe replaces placeholder markup with real content after that initial response, streaming replacement <script> tags that swap in the final HTML on the client. Web components inside BigPipe-delivered placeholders will not be server-rendered by Backlit, since those fragments arrive after the response subscriber has already run. Components will still render client-side once their JavaScript loads, but they will not benefit from Declarative Shadow DOM on first paint. If your site relies heavily on BigPipe for lazy block rendering and those blocks contain web components, be aware of this limitation.

Can I use this in production? The binary is statically linked with no runtime dependencies. The protocol is simple (NUL-delimited pipes). The failure mode is graceful (returns original HTML). So... probably? But this is still early days. File issues, send PRs, report back.

Why "Backlit"? Because your Lit components are lit from behind -- server-rendered before the browser even sees them. Also because naming things is hard and this one was available.

Links

License

MIT

bennypowers/backlit 适用场景与选型建议

bennypowers/backlit 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5 次下载、GitHub Stars 达 8, 最近一次更新时间为 2026 年 03 月 19 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 bennypowers/backlit 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 bennypowers/backlit 我们能提供哪些服务?
定制开发 / 二次开发

基于 bennypowers/backlit 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 5
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 8
  • 点击次数: 36
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 8
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-19