assetic icon indicating copy to clipboard operation
assetic copied to clipboard

way to combine files before applying filters

Open Zxurian opened this issue 11 years ago • 30 comments

so maybe I missed something, but is there a switch or method to combine the files of an asset collection before running them through the filters associated with the collection?

Ex:

        $AssetManager = new AssetManager();
        // Prepare the AssetManager with all core assets
        $AssetManager->set('coreCss', new AssetCollection(array(
            new FileAsset('module/Application/assets/css/sheet1.scss'),
            new FileAsset('module/Commerce/assets/css/sheet2.scss'),
        )));

        $FilterManager = new FilterManager();
        $FilterManager->set('scss', new ScssphpFilter());

        $factory = new AssetFactory('/');
        $factory->setAssetManager($AssetManager);
        $factory->setFilterManager($FilterManager);

        // Create the assets
        $coreCss = $factory->createAsset(array(
                '@coreCss',         
            ), array(
                'scss',
                '?cssmin',                  
            ), array('output' => 'assetic/core.css')
        );

if I have scss variables defined in sheet1, and referenced in sheet2.scss, the compiler fails when trying to compile sheet2.scss, as it's compiling the .scss files separately.

Zxurian avatar Jul 07 '13 04:07 Zxurian

+1

krmcbride avatar Jul 10 '13 17:07 krmcbride

:+1:

yguedidi avatar Jul 10 '13 18:07 yguedidi

:+1:

vkartaviy avatar Jul 14 '13 14:07 vkartaviy

any traction on this at all?

Zxurian avatar Aug 25 '13 17:08 Zxurian

If you need the variables in two independent SCSS files, import them in both. IMO this is a problem of your SCSS organization and not a missing feature in Assetic.

mpdude avatar Oct 13 '13 22:10 mpdude

if it was purely within scss, then sure, but when your using Assetic, then your paths are relative to your controllers, versus using imports, your paths are relative to the scss files.

it's not a problem of scss organization, it's a matter of using one method of organization vs another. If your using only scss, then great, use imports. If your using Assetic, then your organization should stay within that scope.

Zxurian avatar Oct 13 '13 22:10 Zxurian

This is an intriguing feature. I'm open to it, but don't see a huge demand for it.

kriswallsmith avatar Oct 25 '13 15:10 kriswallsmith

I'm curious how other people handle this situation, or just that few people are doing something like this.

Zxurian avatar Oct 28 '13 01:10 Zxurian

Any solution here? It's pretty bad if I have like 20 JS files and I want to use Packer filter, it results with one file with 20 eval() functions, instead of just 1 eval(). I really want to merge all files first and then apply filter once.

PawelAwmous avatar Nov 20 '13 12:11 PawelAwmous

We use Backbone and one view/model per file, so we have several hundred JS files. When we had Assetic configured to use yui our production builds ran about 12 minutes. By removing the compression responsibility from Assetic and firing up the JVM only once to compress the combined file later in the build process, our build time was cut by more than half.

From my perspective, I found it surprising and counterintuitive that filters were being applied before combining files. I had thought the ability to combine files and pipe the results into a filter was implied by the way the assets are configured.

I think there's many use cases, like those in the comments above, where some filters simply cannot realistically be applied to the individual files, and other use cases where filters must be applied to each file (cssrewrite), so having a way to flag one behavior or the other seems reasonable (or a must-have if I'm going to keep 100% of my asset pipeline in Assetic and out of my build scripts).

krmcbride avatar Nov 20 '13 16:11 krmcbride

I'm glad to see that more people are providing support to this. Hopefully it gains more traction, as @krmcbride said, it seems counterintuitive for it to filter before combining.

As a workaround, for those running apache, I'm using Google's mod_pagespeed, and have Assetic only running filters, since mod_pagespeed handles combination & minification.

It's a small workaround, since I still have to sometimes do multiple declarations in separate files depending on what filters are being used (scssphp for example), but hopefully this gets some more attention with the added interest and the feature is implemented.

Zxurian avatar Nov 20 '13 16:11 Zxurian

@kriswallsmith I'm pretty sure we will all see huge improvements on compiling performance, specially for .jar filters. I'm running closure compiler at least 20x faster by manually combining all files before running the filter. JS files may also be compressed even further if the compiler can combine strings and variables from multiple files.

Not only that, this combination allows LESS and SASS variables and mixins from separate files.

vfragosop avatar Mar 19 '14 00:03 vfragosop

For those interested, there's a small snippet for that:

$filesystem = new FilesystemCache('cache/assets');
$filter = new LessphpFilter();
$filter->setFormatter('compressed');

// NOTICE: collection has no filters
$files = new AssetCollection(array(
    new FileAsset('application/less/mixins.less'),
    new FileAsset('application/less/reset.less'),
    ...
));

// Caches the combination of files
$filesCache = new AssetCache($files, $filesystem);

// THIS IS THE JUICE!!!
// NOTICE: filters are passed to combined, instead
$combined = new StringAsset($filesCache->dump(), array($filter));
$combined->setLastModified($filesCache->getLastModified());

// Caches application of filters on the combined files
$combinedCache = new AssetCache($combined, $filesystem);
$combinedCache->setTargetPath('style.min.css');

$writer = new AssetWriter('public/css');
$writer->writeAsset($combinedCache);

You can use that with pretty much any filter.

vfragosop avatar Mar 19 '14 00:03 vfragosop

+1!

For me the use-case is to include assets for say bootstrap.less and my own less files so that I can override/inherit/use bootstrap's variables and macros.

Effectively allowing @import 'bootstrap.less' with assetic managing the path etc...etc...

</possibly bad explanation>

kmdm avatar May 07 '14 11:05 kmdm

:+1:

hectorj avatar May 10 '14 12:05 hectorj

+1 what kmdm said. would be great to merge bootstrap's variables with my customly defined ones before everything is compiled. otherwise I would have to import the vendor's scss. and importing is not cool as this increases rather intransparent dependencies beetween my files instead of managing all this centrally with assetic.

felixhayashi avatar Jul 02 '14 12:07 felixhayashi

:+1: @kriswallsmith I really need this for work, if you don't plan to implement it can you suggest a workaround? Thanks!

MatTheCat avatar Jul 11 '14 13:07 MatTheCat

:+1:

jipeprojects avatar Jul 11 '14 14:07 jipeprojects

:+1:

davidloubere avatar Jul 11 '14 14:07 davidloubere

+1

micari avatar Jul 11 '14 23:07 micari

@MatTheCat The snippet i've provided above does that. It's not ideal, but it works :)

vfragosop avatar Jul 14 '14 14:07 vfragosop

I forgot to tell I'm using Twig tags, I don't know how I'm supposed to use your script :disappointed:

MatTheCat avatar Jul 14 '14 14:07 MatTheCat

@vFragosop I've run into an issue where scss is using @import rules, but not combining them before applying the filter

        $filesystemCache = new FilesystemCache($this->cacheDir.'assets/');
        $assetWriter = new AssetWriter($this->cacheDir);

        $cssAssetCollection = new AssetCollection([
            new FileAsset('module/Application/assets/css/bootstrap-overrides.scss'),
            new FileAsset('vendor/bootstrap-sass-3.2.0/assets/stylesheets/bootstrap.scss'),
            //new FileAsset('vendor/awesome-bootstrap-checkbox.scss'),
        ], [new ScssphpFilter()]); //[new CssImportFilter(), new ScssphpFilter()]);

        echo $cssAssetCollection->dump();
        die();

if I run this as is, then it works. Assetic properly handles all of the @import commands within the initial bootstrap.scss file. However, if I uncomment the last FileAsset, which is a scss file that has a reference to mixins loaded by the previous bootstrap file, then ScssPhp fails with the exception

Undefined mixin transition: failed at `@include transition(border 0.15s ease-in-out, color 0.15s ease-in-out);
` line: 36

which shows that it's trying to apply the scssphp filter to awesome-bootstrap-checkbox.scss independently of bootstrap.scss

I tried combining the two before applying the Scssphp Filter using the following per your script

        $filesystemCache = new FilesystemCache($this->cacheDir.'assets/');
        $assetWriter = new AssetWriter($this->cacheDir);

        $bootstrapArray = [
            new FileAsset('module/Application/assets/css/bootstrap-overrides.scss'),
            new FileAsset('vendor/bootstrap-sass-3.2.0/assets/stylesheets/bootstrap.scss'),
            //new FileAsset('vendor/awesome-bootstrap-checkbox.scss'),
        ];
        $bootstrapCache = new AssetCache(new Assetcollection($bootstrapArray), $filesystemCache);
        $bootstrap = new StringAsset($bootstrapCache->dump());
        $bootstrap->setLastModified($bootstrapCache->getLastModified());

        $cssAssetCollection = new AssetCollection([
            $bootstrap,
        ], [new ScssphpFilter()]); //[new CssImportFilter(), new ScssphpFilter()]);

        echo $cssAssetCollection->dump();
        die();

however then it fails to include any of the @import directives at all, and the resulting dump still shows all of the @import directives in the original bootstrap.scss file. That to me means that the scssphp filter isn't actually following any of the import directives unless the assets themselves are FileAssets, and not StringAssets, which means I can't see a way of using your method while still using @imports.

Am I missing something?

Zxurian avatar Aug 13 '14 17:08 Zxurian

The issue is that your StringAsset does not have the paths defined in it, which means that the ScssphpFilter cannot resolve the imports. and the behavior of Sass for unresolvable imports is to keep them as client-side imports in the CSS files

stof avatar Aug 13 '14 21:08 stof

hm.. so this would be a key example for having Assetic combining files before applying filters, since it doesn't look like there's a way around this example of needing to use scssphpfilter @import directive and being able to reference mixins from non-imported files.

Zxurian avatar Aug 17 '14 17:08 Zxurian

I have one global less file and one more per view and all these use a variable definitions less file. As this issue isn't resolved I have to use @import in every file to reference any variable.

Now the problem is I must manage partners websites which are declinations of ours with some variables change and because of this issue I cannot use inheritance.

So basically I should recreate every less file for each partner in order to use its variables, and then override every {% stylesheets %} in every template, which is too much.

Apart from this edge-case it seems more logical to combine files before applying filters as some optimizations could result from combinations (like inlining i18n variables I guess).

MatTheCat avatar Sep 05 '14 14:09 MatTheCat

any traction on this one given' that we have a valid use-case? I'm about to go digging myself since it's hampering development, but wanted to see if anyone else had already investigated.

Zxurian avatar Oct 30 '14 15:10 Zxurian

+1!

I need to combine first and then apply less filtering on two bootstrap files:

  • variables.less // from AppBundle
  • bootstrap.less // from a vendor repo

Then i would create a named asset "bootstrap": assetic: assets: bootstrap: inputs: - '@AppBundle/Resources/public/less/variables.less' - '@VendorBundle/Resources/public/lib/bootstrap.less' filters: - lessphp

Thanks!

matteomoretti avatar Apr 28 '15 14:04 matteomoretti

:+1: Also, it seems like #605 is related to this?

daviddeutsch avatar May 20 '15 06:05 daviddeutsch

+1 Is any workaround solution for this feature?

popovserhii avatar Aug 07 '16 17:08 popovserhii