evheniy/jquery-bundle
Symfony2 bundle that provides jQuery from Google CDN or a local path, with configurable version, CDN domain, HTML5/legacy script tags, and async loading. Install via Composer and register JqueryBundle in AppKernel.
This bundle does one thing: it renders a <script> tag pointing at jQuery on ajax.googleapis.com, with the version under your control. Treat it as a config-driven version pin, not a JavaScript toolchain.
Install (Symfony 2.x only):
composer require evheniy/jquery-bundle
Register it in app/AppKernel.php:
$bundles = array(
// ...
new Evheniy\JqueryBundle\JqueryBundle(),
);
Set the version in app/config/config.yml:
jquery:
version: 1.12.4
Where to look first. The bundle is tiny — read these in order:
DependencyInjection/Configuration.php — the only real options (version).DependencyInjection/*Extension.php — confirms whether the version lands in a container parameter or a Twig global.Resources/views/ — the template that actually emits the script tag.Twig/ directory — the extension or function name you call from your layout.First use case. Replace the hand-written CDN tag in your base layout:
{# app/Resources/views/base.html.twig #}
<head>
{{ jquery() }} {# confirm the exact function name in Twig/ #}
{% javascripts '@YourBundle/Resources/public/js/app.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
</head>
Then verify by inspecting the rendered HTML — you should see https://ajax.googleapis.com/ajax/libs/jquery/<version>/jquery.min.js. If the tag is missing or the version is wrong, the problem is config or bundle registration, not the template.
Environment-specific versioning. Keep the version in config.yml but override per environment so you can smoke-test an upgrade without touching production:
# app/config/config_dev.yml
jquery:
version: 3.7.1
Because this is a single scalar parameter, this is low-risk and easy to roll back.
Centralizing the tag behind a Twig macro. Even with the bundle installed, wrap the call once so you can swap implementations later:
{# app/Resources/views/_jquery.html.twig #}
{% macro script() %}{{ jquery() }}{% endmacro %}
Every layout includes that macro instead of calling the bundle directly. When you eventually move to Encore/AssetMapper, you edit one file.
Ordering with Assetic / script concatenation. jQuery must be emitted before any plugin bundle (Bootstrap, select2, your app.js). Since the bundle prints a standalone <script src> rather than participating in an Assetic javascripts block, keep it outside the block and above it. If a plugin throws $ is not defined, the ordering is almost always the cause.
Version pinning as a supply-chain control. The URL has no hash/SRI, so the version string is your only integrity lever. Pin an exact patch (3.7.1, not 3 or latest) and record it in your deployment notes. ajax.googleapis.com is the same host Google's own CDN docs use; if your org blocks Google domains, you need the local-asset pattern below.
Local-asset fallback. For intranets, offline dev, or CSP that disallows third-party script hosts, bypass the bundle and serve jQuery from your own bundle:
<script src="{{ asset('bundles/app/vendor/jquery-3.7.1.min.js') }}"></script>
Install the file with composer require components/jquery and copy it into Resources/public/vendor/. This is the recommended escape hatch — you keep the same variable names elsewhere in the app.
Test coverage hook. The bundle ships Travis/Coveralls configs, meaning the maintainers test the DI + Twig layers, not the browser. Mirror that: assert in a functional test that the response HTML contains the expected CDN URL and version for each environment.
It is Symfony2-era and effectively unmaintained (last release June 2016). Expect AppKernel-style registration, no Flex recipe, no composer.json constraints for Symfony 4+. On Symfony 4+ the autoloading, Kernel, and DI conventions diverge — installing it usually produces container/class-not-found errors rather than a clean "incompatible" message. Do not attempt to modernize it; copy the 20 lines of logic into your app instead.
No SRI, no crossorigin, no CSP nonce. If you enforce script-src with nonces or hashes, the emitted tag will be blocked. Either add ajax.googleapis.com to script-src or host jQuery locally so you can attach the nonce yourself.
version is not validated against real jQuery releases. A typo like 1.12 or 3.7.11 renders happily and 404s in the browser. Symptom: Uncaught ReferenceError: $ is not defined with a green Symfony page. Confirm the exact filename exists at https://ajax.googleapis.com/ajax/libs/jquery/<version>/jquery.min.js before deploying.
The min vs non-min variant is not configurable in the README. In dev you may want the readable build; check the bundle's template — if the filename is hardcoded, you must override the template (Symfony's standard app/Resources/<Bundle>/views/... override path) rather than rely on config.
Cache-busting is outside the bundle's control. The URL is stable per version, which is good for caching but means a bad deploy of a same-version local override can serve stale JS. Bump the version or add your own query string in a custom macro.
Debugging checklist, in order: (1) is the bundle in AppKernel? (2) php app/console config:dump-reference jquery to see the real config tree — the README only shows one key. (3) php app/console debug:twig (or twig:debug) to find the actual function/global name. (4) Clear the cache — DI parameter changes are not hot-reloaded. (5) Grep the rendered HTML for googleapis to confirm it is this bundle and not a leftover manual tag.
Extension point is only the template. There is no event, no service decoration worth doing. Any real customization (SRI hash, defer/async, local hosting, multi-version) means overriding the bundle's view template or abandoning the bundle. The latter is almost always the better day-to-day choice for anything beyond a demo.
Migration note. For any project still on this, the day-one move is: replace the Twig call with a macro that emits the tag yourself, delete the dependency, and add a browser test asserting the URL. That removes an unmaintained, zero-dependent package from your lockfile with roughly ten minutes of work.
How can I help you explore Laravel packages today?