assetic
assetic copied to clipboard
way to combine files before applying filters
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.
+1
:+1:
:+1:
any traction on this at all?
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.
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.
This is an intriguing feature. I'm open to it, but don't see a huge demand for it.
I'm curious how other people handle this situation, or just that few people are doing something like this.
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.
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).
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.
@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.
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.
+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>
:+1:
+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.
:+1: @kriswallsmith I really need this for work, if you don't plan to implement it can you suggest a workaround? Thanks!
:+1:
:+1:
+1
@MatTheCat The snippet i've provided above does that. It's not ideal, but it works :)
I forgot to tell I'm using Twig tags, I don't know how I'm supposed to use your script :disappointed:
@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?
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
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.
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).
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.
+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!
:+1: Also, it seems like #605 is related to this?
+1 Is any workaround solution for this feature?