Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Assetic Bundle Laravel Package

philetaylor/assetic-bundle

Integrates Assetic asset management into Laravel, letting you compile, combine, and filter CSS and JavaScript through configurable pipelines. Manage asset collections, apply filters, and serve optimized front-end assets from a familiar bundle-style setup.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a fit check. This is a community fork of the long-abandoned symfony/assetic-bundle, patched to keep running on Symfony 4. It has 0 stars and 0 dependents — you are the QA team. It is a compatibility shim for a legacy app that already has {% stylesheets %} / {% javascripts %} tags and Assetic filter config. If you are actually in a Laravel codebase, stop here: there is no Blade equivalent, no Laravel port, and no reason to bridge one — use Vite. If you are a Laravel developer inheriting a Symfony 4 app, this is the "make the old thing run" tool, and your job is to schedule its removal.

Install and pin.

composer require philetaylor/assetic-bundle

The fork is low-traffic and likely has no tag you should trust. Pin a commit SHA, then read the vendor source before wiring anything up:

  • vendor/philetaylor/assetic-bundle/composer.json — exact PHP / symfony/* / twig constraints.
  • vendor/philetaylor/assetic-bundle/AsseticBundle.php — confirm the namespace. Forks of this bundle usually keep Symfony\Bundle\AsseticBundle\AsseticBundle so it's a drop-in; verify, don't assume.
  • DependencyInjection/Configuration.php — the authoritative list of config keys for this version.

If symfony/assetic-bundle is still in composer.json, remove it first. Two packages claiming the same namespace is a class-collision bug, not a merge conflict Composer will save you from.

Register it manually. There is no Flex recipe, so nothing is auto-wired:

// config/bundles.php
return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
    // ...
    Symfony\Bundle\AsseticBundle\AsseticBundle::class => ['all' => true],
];

Write a minimal config. Symfony 4 defaults are wrong for you — Assetic assumes a web/ directory that Symfony 4 does not have:

# config/packages/assetic.yaml
assetic:
    debug: '%kernel.debug%'
    use_controller: false
    write_to: '%kernel.project_dir%/public'
    read_from: '%kernel.project_dir%/public'
    filters:
        cssrewrite: ~
        scssphp:
            apply_to: '\.scss$'

Verify the wiring before touching templates.

php bin/console list assetic                                    # dump, watch
php bin/console debug:container assetic --show-private          # which services actually exist
php bin/console debug:twig | grep -i assetic                    # is the Twig extension loaded?

First real use case. Keep it tiny: replace a hand-maintained stack of <link> tags with one block, dump, confirm the file lands in public/, then roll it out bundle by bundle.

{% stylesheets filter='cssrewrite' output='css/app.css'
    'bundles/app/css/base.css'
    'bundles/app/css/layout.css'
%}
    <link rel="stylesheet" href="{{ asset_url }}">
{% endstylesheets %}
php bin/console assetic:dump --env=prod --no-debug

Implementation Patterns

Prefer named assets in config over inline tag lists. Named assets are greppable, reusable, and testable; inline globs scattered across Twig are how "which file is this CSS coming from?" becomes unanswerable.

assetic:
    assets:
        app_css:
            inputs:
                - 'bundles/app/css/base.css'
                - 'bundles/app/css/layout.css'
            filters: ['cssrewrite', '?cssmin']
            output: 'css/app.css'
        app_js:
            inputs:
                - 'bundles/app/js/vendor/jquery.js'
                - 'bundles/app/js/app.js'
            output: 'js/app.js'
{% stylesheets '@app_css' %}<link rel="stylesheet" href="{{ asset_url }}">{% endstylesheets %}
{% javascripts '@app_js' %}<script src="{{ asset_url }}"></script>{% endjavascripts %}

Use the ? filter prefix deliberately. filters: ['?uglifyjs'] means "apply only when Assetic is not in debug" — i.e. minify in prod, readable output in dev. This is the single most useful convention in the bundle; without it, every dev rebuild pays the minifier cost and debugging becomes guesswork.

Let * handle naming, but pin it in config. output: 'css/*.css' derives the filename from the input set. Combined with named assets you get a stable, predictable public/css/app.css that nginx and your deploy checks can rely on. Don't rely on * for anything you reference by hand.

Deploy order matters. Assetic resolves Twig tags through the compiled template cache, so dump after warmup:

bin/console cache:clear  --env=prod --no-debug
bin/console cache:warmup --env=prod --no-debug
bin/console assetic:dump --env=prod --no-debug

Then verify, don't hope:

test -s public/css/app.css && test -s public/js/app.js || exit 1

Dev loop: assetic:watch. Rather than flipping use_controller on, run php bin/console assetic:watch in a spare terminal and keep use_controller: false everywhere. You get recompilation without a production-shaped footgun.

Custom filters are the supported extension point. Implement Assetic\Filter\FilterInterface, register as a service, tag it:

final class StripCommentsFilter implements \Assetic\Filter\FilterInterface
{
    public function filterLoad(\Assetic\Filter\FilterCollection $filters) {}
    public function filterDump(\Assetic\Asset\AssetInterface $asset): void { /* ... */ }
}
services:
    App\Assetic\StripCommentsFilter:
        tags:
            - { name: assetic.filter, alias: stripcomments }

Confirm the tag name with debug:container --tag=assetic.filter on your exact version — tag names drifted across the bundle's history.

Programmatic access from a console command. For custom build steps, resolve the factory/asset manager services out of the container. The IDs vary by fork version, so dump the container first rather than copying a Stack Overflow answer:

php bin/console debug:container assetic --show-private | grep -E 'factory|manager|filter'

Coexistence during migration. The pragmatic path off Assetic is to run it alongside Encore or AssetMapper, not instead of it: add the new toolchain, port one bundle's entrypoints, keep both writing into public/ under disjoint paths (public/build/ vs public/css/, public/js/), then delete Assetic config and tags in one reversible commit. Track burndown with:

grep -rn "{% \(stylesheets\|javascripts\|image\)" templates/ | wc -l

That number is your migration estimate, and it only goes down.

Gotchas and Tips

The web/ directory doesn't exist in Symfony 4. read_from and write_to still default to %kernel.root_dir%/../web. If you don't override them to %kernel.project_dir%/public, dumps fail or write to a phantom directory. This is the first thing to check when "it ran fine but nothing changed."

@AppBundle/Resources/public/... paths are usually dead. Symfony 4 moved assets out of bundle Resources/public/. Unless you deliberately preserved that layout, Assetic's bundle resolver can't find them. Either keep the directory, list the bundle under assetic.bundles, or — better — use explicit paths relative to read_from and stop depending on bundle magic.

cssrewrite silently misbehaves with @Bundle notation. The filter rewrites url() relative to the output location, and it needs to resolve the input path first. Feed it bundles/app/css/base.css (the public-relative form), not @AppBundle/Resources/public/css/base.css, or your images and fonts will 404 in prod while looking fine in dev.

use_controller: true in production is an outage waiting to happen. It compiles on request, meaning runtime filesystem writes into public/, permission errors under the web user, and latency spikes on cold cache. Keep it false. If you need the dev route, it comes from a routing loader:

# config/routes/dev/assetic.yaml
_assetic:
    resource: .
    type: assetic

Debug mode changes your output, not just your speed. With assetic.debug: '%kernel.debug%', filters are skipped by default in dev (unless prefixed with ? semantics inverted — that's what the prefix is for). The artifact you click through locally is not the artifact you deploy. Always smoke-test a dumped prod build before release.

Stale names live in the cache. Rename or restructure an asset and assetic:dump may still emit the old set. cache:clear first. If a template renders an empty block, suspect Twig cache, not your YAML.

Glob order is filesystem order. bundles/app/js/*.js produces a non-deterministic concatenation across machines, which is a genuinely nasty class of bug (jQuery loading after your plugin on CI but not on your laptop). Enumerate inputs explicitly for anything order-sensitive.

Two output names colliding is silent data loss. output: 'css/*.css' on two different input sets can produce the same file. Assetic won't warn; the last writer wins. Namespace outputs.

Filter binaries are an unmanaged toolchain. yui_* shells out to Java, compass/sass to Ruby, uglifyjs to Node. Each is a separate EOL'd dependency on the host and in CI. Pin them in your base image and pin their versions, or your CSS changes shape between environments with no diff to blame.

Error message decoder ring.

  • "There is no 'x' asset" — typo in @name, or the config file isn't loaded in that environment.
  • "Unable to find the asset ... in the ... bundle" — bundle missing from assetic.bundles, or the Resources/public path doesn't exist.
  • "Filter 'x' not found" — filter not declared under assetic.filters, or its binary isn't installed.

Source maps don't exist here. Minified Assetic output is anonymous. If your team debugs in the browser, that is itself an argument for the migration and should be in the business case.

apply_to and per-tag filters both exist, and they merge. A filter scoped via assetic.filters.scssphp.apply_to: '\.scss$' applies to every matching input; a filter="..." on the tag applies to that block. When a filter is running where you didn't expect, check both places.

Treat the dependency as owned code. Pin the commit, mirror the repo internally, put it in the risk register as unsupported third-party code, and name an owner. The adoption cost is small; the exit cost — rewriting Twig tags across every template — is not. The day you merge this, open the "de-Assetic" ticket with a date on it, or "it still works" becomes the reason the migration never happens.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings