@tacman1123/twig-browser
v0.4.14
Published
Browser-only Twig subset renderer for Symfony + Stimulus
Maintainers
Readme
@tacman1123/twig-browser
Browser-only Twig subset engine for modern ESM + importmap deployments.
No /dist. No CommonJS. No Node runtime path.
Features
- Source-first ESM package (
type: module), shipped fromsrc/. - Importmap-friendly — works with Symfony AssetMapper out of the box.
- Built-in
stimulus_controller,stimulus_target,stimulus_actionfunctions. - Built-in
path,ux_icon,renderfunction stubs — throw clear errors until adapters wire them up. - Symfony adapter for FOS JS Routing and UX Icons.
- Auto-detection of FOS routing via
autoInstallFosRouting(). - Template loading from URL via
loadTemplateFromUrl().
Supported Twig subset
- Output:
{{ expr }} - Control flow:
{% if %},{% elseif %},{% else %},{% endif %} - Loops:
{% for item in list %},{% for key, value in map %},{% endfor %} - Assignment:
{% set x = expr %}, multi-assignment,{% set x %}...{% endset %} - Expressions:
and,or,not, Elvis?:,is [not] <test>
Filters: length, default, merge, raw, e/escape, upper, lower, capitalize, title, trim, striptags, nl2br, join, keys, first, last, reverse, sort, slice, split, abs, round, number_format, replace, format, url_encode, json_encode, date
is tests: defined, null/none, empty, odd, even, iterable, divisibleby, sameas
Functions: path, ux_icon, stimulus_controller, stimulus_target, stimulus_action, render, range, min, max, cycle, dump
Unsupported tags fail fast with clear diagnostics.
Installation (Symfony AssetMapper)
php bin/console importmap:require @tacman1123/twig-browser
php bin/console importmap:require "@tacman1123/twig-browser/adapters/symfony"Basic usage
import { createEngine, compileTwigBlocks, twigRender } from '@tacman1123/twig-browser';
import { installSymfonyTwigAPI } from '@tacman1123/twig-browser/adapters/symfony';
const engine = createEngine();
installSymfonyTwigAPI(engine, {
Routing, // FOS Routing instance
uxIconResolver: (name) => `<svg>…</svg>` // UX Icons resolver
});
// Compile blocks from a <script id="my-blocks"> tag containing JSON
compileTwigBlocks(engine, null, 'my-blocks');
const html = twigRender(engine, null, 'blockName', { item });
document.querySelector('#target').innerHTML = html;Symfony adapter
installSymfonyTwigAPI(engine, options)
Wires path() and ux_icon() into the engine synchronously.
import { installSymfonyTwigAPI } from '@tacman1123/twig-browser/adapters/symfony';
installSymfonyTwigAPI(engine, {
Routing, // FOS Routing object with .generate()
// or:
pathGenerator: (route, params) => myRouter.generate(route, params),
uxIconResolver: (name, attrs) => iconMap[name] ?? '',
// or alias:
iconResolver: (name, attrs) => iconMap[name] ?? '',
});If path() or ux_icon() are called in a template before being configured, they throw a clear error at render time.
autoInstallFosRouting(engine)
Async helper that auto-detects FOS JS Routing and wires path() — no config needed.
import { autoInstallFosRouting } from '@tacman1123/twig-browser/adapters/symfony';
const engine = createEngine();
autoInstallFosRouting(engine); // fire-and-forget; no-op if fos-routing not installedDynamically imports fos-routing and /js/fos_js_routes.js. If both succeed, calls Routing.setData() and registers path(). Silently skips on any import failure.
Loading templates from a URL
import { loadTemplateFromUrl } from '@tacman1123/twig-browser';
const blockName = await loadTemplateFromUrl(engine, '/templates/hit.html.twig');
const html = engine.renderBlock(blockName, { hit });Fetches the URL, auto-detects whether it contains <twig:block name="…"> wrappers or is a plain template, compiles it, and returns the primary block name.
File layout
.
├── package.json
├── src/
│ ├── index.js # exports: createEngine, compileTwigBlocks, twigRender, loadTemplateFromUrl
│ ├── engine/
│ │ ├── createEngine.js
│ │ └── compile.js
│ ├── compat/
│ │ ├── compileTwigBlocks.js # compile <twig:block> tags from DOM or string
│ │ ├── twigRender.js # render with registry guard
│ │ └── loadTemplateFromUrl.js # fetch URL → compile → return block name
│ ├── extensions/
│ │ ├── filters.js # all core filters
│ │ ├── tests.js # is defined/null/empty/odd/even/iterable/…
│ │ ├── functions.js # range, min, max, cycle, dump
│ │ └── stimulus.js # stimulus_controller / _target / _action
│ └── testing/
│ └── detailContextHeader.cases.js
└── adapters/
└── symfony/
└── installSymfonyTwigAPI.js # installSymfonyTwigAPI + autoInstallFosRoutingTesting
npm testTable-driven fixture tests using Vitest and parse5 HTML normalization.
License
BSD-2-Clause. See THIRD_PARTY_NOTICES.md for upstream Twig.js attribution.
