locaine/lcn-include-assets-bundle
lcn-include-assets-bundle is a Symfony bundle for including CSS and JavaScript assets in templates, simplifying asset management and view rendering so you can organize frontend resources and inject them into your Symfony application with ease.
What it is. A Symfony 2 bundle that brings Symfony 1's use_javascript() / use_stylesheet() model to Twig: templates register asset paths as they render, and the layout dumps the accumulated list once. It is a compatibility shim, not an asset pipeline — it does not compile, minify, version, or combine files.
Install (legacy project only).
composer require locaine/lcn-include-assets-bundle
Then register it in app/AppKernel.php:
new Lcn\IncludeAssetsBundle\LcnIncludeAssetsBundle(),
Verify the exact bundle class/namespace against composer.json autoload rules and the README — at 1 star / 0 dependents, documentation drift is a real risk.
Where to look first.
README.md — the only reliable source of function names and config keys.Resources/config/services.xml (or .yml) — the service id, and crucially its scope (request vs container). This determines whether sub-requests see assets registered in them.use_javascript / use_stylesheet / include_javascripts / include_stylesheets, and whether the include helpers return markup or an array.composer.json — Symfony/Twig/PHP constraints. This is the gate: most installed projects will fail resolution here.First use case — per-partial scripts, rendered once by the layout:
{# AcmeBundle/Resources/views/Product/widget.html.twig #}
{{ use_javascript('bundles/acme/js/product-widget.js') }}
<div class="widget">...</div>
{# app/Resources/views/base.html.twig #}
<html>
<head>{{ include_stylesheets() }}</head>
<body>
{% block body %}{% endblock %}
{{ include_javascripts() }}
</body>
</html>
If the include helpers return arrays instead of markup, render them yourself so you keep control of asset() and tag attributes:
{% for file in include_javascripts() %}
<script src="{{ asset(file) }}"></script>
{% endfor %}
Declare at the point of use; render at the edge. The bundle's entire value is that the partial which needs a file declares it. Keep the declaration next to the markup it belongs to, and keep exactly one include call per layout. Scattering includes across multiple layouts defeats deduplication and makes ordering unpredictable.
Controller-side registration for conditional pages. Inject the bundle service (id from services.xml) where the business logic already knows the page needs an asset — a map, a chart, a WYSIWYG. This is cleaner than {% if %} blocks in templates:
public function showAction($id, IncludeAssets $assets)
{
$assets->addJavascript('bundles/acme/js/map.js');
// ...
}
Named groups, if available. If the package supports Symfony 1-style named slots/packages, use one group per layout region (head, body_end) rather than one global pile. Otherwise output order is whatever render order happened to be.
Make ordering explicit. Decide whether first-registered or last-registered wins and encode that intent: vendor libraries registered in the layout before {% block body %}, page-specific files in the partials. Never let the order of two partials on the same page determine load order.
Coexist with native Twig blocks during a migration. Keep {% block javascripts %} for layout-level files and use this bundle only for deep partials that native blocks genuinely cannot reach. That is the single capability Twig blocks lack, and the only real reason to install this package.
Play nicely with the existing pipeline. If the project uses Assetic, let the bundle emit paths and pass them through asset(); never let two pipelines own the same file. The long-term migration target is Webpack Encore (encore_entry_script_tags()) or AssetMapper (importmap()), which replace both this bundle and Assetic.
Sub-requests and embedded controllers. Always place include_javascripts() at the bottom of <body>, never in <head>. The content — including anything rendered via render(controller(...)) — must execute before the include call.
composer.json before anything else. If it pins symfony/symfony ~2.x, Twig 1.x, or PHP 5.x, it will not install on a supported Symfony without a fork. With 1 star and 0 dependents, assume nobody is maintaining compatibility.include_javascripts() sits in <head> and a body partial later registers a file, that file is registered after the list was already rendered — it vanishes with no error. Bottom of body, always.assets:install is still required. Files under Resources/public are not web-accessible until installed/symlinked. Register web-relative paths (bundles/acme/...), not bundle notation (@AcmeBundle/...), unless the extension explicitly resolves them.scope: request or prototype, it resets per sub-request and assets registered inside render() never reach the layout. Check services.xml; if request-scoped, register those assets in the parent action instead.js/a.js and /js/a.js will not match.defer/async. Generated tags are bare. If you need any of these you will write your own renderer anyway — use the array-returning form plus a native loop and you are done.cache:clear when touching config, and check whether the bundle memoizes across requests.{{ dump(include_javascripts()) }} under the debug bundle) or var_dump in the service getter. An empty list is almost always render order or service scope — not the use_* call.Configuration class, its extension key must appear in config.yml even when empty (lcn_include_assets: ~), otherwise the extension never loads and the Twig functions are undefined. "Unknown function" means the bundle isn't registered, not that the call is wrong.addJavascript. You keep the template-facing API and own the output markup. Overriding the bundle's Twig extension works too, but for a package this small, a small fork is usually cheaper than an override.Bottom line: reasonable only as a bridge for a Symfony 1 → Symfony 2 port, or for legacy partials that native Twig blocks cannot reach. For anything new, do not adopt it — Symfony's block model, Webpack Encore, or AssetMapper already covers this, is maintained, and is what the rest of the ecosystem assumes.
How can I help you explore Laravel packages today?