Strange Issue When Minifying CSS via django-pipeline - django

I'm using django-pipeline to minify my CSS. Everything minifies correctly until I use PipelineCachedStorage so I can get the versioned, cache-busting filenames. I get the following error:
ValueError: The file 'img/glyphicons-halflings.png' could not be found with <pipeline.storage.PipelineCachedStorage object at 0x19069d0>
I've grepped all the files in my project and have found that this PNG is in bootstrap.css, but I am not including that file to be minified. Here's my django-pipeline specific settings:
PIPELINE_CSS = {
'ab': {
'source_filenames': (
'main.css',
'segment-animation.css',
),
'output_filename' : 'ab.css',
}
}
PIPELINE_YUGLIFY_BINARY = '/home/redacted/ts/redacted/node_modules/yuglify/bin/yuglify'
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
Thanks in advance!
EDIT:
new settings for pipeline:
PIPELINE_COMPILERS = (
'pipeline.compilers.less.LessCompiler',
)
PIPELINE_CSS = {
'ab': {
'source_filenames': (
'bootstrap-less/bootstrap.less',
'main.css',
'segment-animation.css',
),
'output_filename' : 'ab.css',
}
}
PIPELINE_YUGLIFY_BINARY = '/home/redacted/ts/redacted/node_modules/yuglify/bin/yuglify'
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'

The error isn't entirely related to Pipeline but rather what Django's CachedStaticFilesStorage that PipelineCachedStorage extends. The cached storage will look for file references in your css files and replace url('asset-link') and #import 'resource-link' with the appropriate link to the version with the md5 hash appended to it.
This will turn url('img/glyphicons-halflings.png') into url('img/glyphicons-halflings.<hash>.png'). So if you have asset references in your css files but don't have the underlying assets, the post_process() of CachedStaticFilesStorage is going to throw that error.
You can read more here. I'd recommend to compile the less version of bootstrap with django pipeline and remove the less components that you don't need, such as the icons if you don't want to include the bootstrap icons. Or you can include the appropriate assets.

I've found the django-pipeline-forgiving package resolves this issue with the stock Django CachedStaticFilesStorage / PipelineCachedStorage very nicely

Related

Django Bootstrap 4 unable to use scss

I'm trying to set a 4-column card view with this: Card Columns
Here is a successful online example: DEMO
I followed this tutorial to setup Django compressor.
I have following code in main.scss file:
#import 'bootstrap';
.card-columns {
#include media-breakpoint-only(lg) {
column-count: 4;
}
#include media-breakpoint-only(xl) {
column-count: 5;
}
}
And I can't import Bootstrap. I tried to put the bootstrap.css in the same folder but the system pops the error says:
Error: no mixin named media-breakpoint-only
I'm kind of new to this. How do I fix it? Thanks.
I believe you should put this into your settings.py file:
COMPRESS_PRECOMPILERS = (
('text/x-sass', 'sass main.scss output_file.css')
)
in order for the compressor to "precompile" your .scss file.

Is there a way to prevent django-pipeline from creating new jsx files every time it compiles react.js code?

I currently have the PyReact JSX compiler installed using django-pipeline.
Whenever I run collectstatic on my files, rather than overwriting a prior version of my react .jsx and compiled .js files, it creates a new version in the same folder. Is there a way to stop this and have the program simply overwrite the prior version? Or, is the best practice for using django-pipeline to use it only once?
My settings.py:
PIPELINE_COMPILERS = (
'react.utils.pipeline.JSXCompiler',
'pipeline.compilers.less.LessCompiler',
)
PIPELINE_JS = {
'bootstrap': {
'source_filenames': (
'twitter_bootstrap/js/transition.js',
'twitter_bootstrap/js/modal.js',
'twitter_bootstrap/js/dropdown.js',
'twitter_bootstrap/js/scrollspy.js',
'twitter_bootstrap/js/tab.js',
'twitter_bootstrap/js/tooltip.js',
'twitter_bootstrap/js/popover.js',
'twitter_bootstrap/js/alert.js',
'twitter_bootstrap/js/button.js',
'twitter_bootstrap/js/collapse.js',
'twitter_bootstrap/js/carousel.js',
'twitter_bootstrap/js/affix.js',
),
'output_filename': 'js/b.js',
},
'clubs': {
'source_filenames': (
'js/clubs.jsx',
),
'output_filename': 'js/clubs.js',
},
'react': {
'source_filenames': (
'react/js/react.min.js',),
'output_filename': 'js/r.js',
},
'jquery': {
'source_filenames': (
'js/jquery.js',
),
'output_filename': 'js/jq.js',
},
}
STATIC_ROOT = BASE_DIR + '/static/'
STATIC_URL = '/static/'
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
If I understand your question correctly, your concern is that after running collectstatic, you have files like foo.2d32ed.js, foo.4bhf45.js, foo.09d9fg.js in your STATIC_ROOT directory.
If so, then this isn't an issue with PyReact or even with django-pipeline; this is occurring because you're using a cached storage backend (i.e. your STATICFILES_STORAGE setting). The string appended to your filename is a hash of the file's contents, which effectively acts like versioning of your static files.
The reason for this is cache-busting on browsers. With filenames as functions of the file's contents, a browser can cache the file forever, which will speed up page load times for your users on subsequent visits.
If you want to disable this behavior, you can use a non-caching storage backend like PipelineStorage instead.
Here's some documentation that may help:
https://django-pipeline.readthedocs.org/en/latest/storages.html
https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#storages

CSS files not compiled into app.css as expected in Ember CLI?

Ember CLI docs says about /app/styles folder following:
Contains your stylesheets, whether SASS, LESS, Stylus, Compass, or plain CSS (though only one type is allowed, see Asset Compilation). These are all compiled into app.css.
I have the following files in /app/styles: app.css, one.css, two.css.
I would expect when starting server that in folder /dist/assets there will be file called appName.css and the content would be concatenation of all three files. Instead there is only content of app.css file. So I resolved this with #import in app.css:
#import url("one.css");
#import url("two.css");
That worked with 0.0.46, although not optimal because of more request were made to server. Now I updated to 0.1.1 and files one.css and two.css are no longer copied to /dist/assets folder.
But main question is: How can I achieve the concatenation of all css files in /app/styles folder? Am I missing something basic or are there some commands needed to be included into Brocfile.js?
Updated
Here is the snippet of Brocfile.js showing how we concatenate our CSS files:
var concat = require('broccoli-concat');
var cleanCSS = require('broccoli-clean-css');
var concatenatedCss = concat('app/styles', {
inputFiles: [
'reset.css',
'common.css',
'layout.css',
...
],
outputFile: '/assets/appName.css',
wrapInFunction: false
});
if (app.env === 'production') {
concatenatedCss = cleanCSS(concatenatedCss, {restructuring: false});
}
module.exports = app.toTree([concatenatedCss]);
We manually add files to inputFiles array.
It's known issue with 0.1.1 version: Static css compiler broken (0.1.x regression)
You probably should wait for update.
As for main question, try broccoli-concat.
Now there is this ember-cli-concat add-on available: https://github.com/sir-dunxalot/ember-cli-concat.
Looks super easy to use: https://github.com/sir-dunxalot/ember-cli-concat/wiki/Installation

Font asset without digest in Ruby on Rails 4

I've got a problem with my font assets being served without digest in production.
As soon as I do rake assets:precompile I get:
5futurebit-webfont-c133dbefd9e1ca208741ed53c7396062.eot
I was trying to link it with font-face in scss with asset-url, asset-path, font-url and font-path but all of them end up outputting path:
/assets/5futurebit-webfont.eot
For now I'm copying assets from /app/assets/fonts straight to /public/assets/ but it doesn't feel like that's the way to do it.
I've been looking at a similar issue and am currently using the non-stupid-digest-assets gem: https://github.com/alexspeller/non-stupid-digest-assets
For more info on how you can use it, see here.
Correct use of non-stupid-digest-assets gem
Now that being said, the link provided by Chris (specifically, https://stackoverflow.com/a/17367264/291640) seems like it may accomplish the same as the gem without the gem itself. I know I need to look into it further.
Make sure you have the exact filename WITH extention name of the font in your font-url declaration like:
Correct:
#font-face{
font-family: 'Sawasdee';
src: font-url('Sawasdee.ttf') format('truetype');
}
Wrong:
#font-face{
font-family: 'Sewasdee';
src: font-url('Sewasdee') format('truetype');
}
My font folder:
fonts
|_ Sewasdee.ttf
|_ Otherfont.ttf
Here is our solution, that is based partially on what Sprocets does. It is working with Rails4. It automatically generates a nondigest version for all assets, that were listed in config.assets.precompile, after precompilation was done.
# lib/tasks/assets_nondigest.rake
require 'fileutils'
namespace "assets:precompile" do
desc "Create nondigest versions of defined assets"
task :nondigest => :environment do
sprocket_task = Sprockets::Rails::Task.new ::Rails.application
assets = ::Rails.application.config.assets.precompile
paths = sprocket_task.index.each_logical_path(assets).to_a +
assets.select { |asset| Pathname.new(asset).absolute? if asset.is_a?(String)}
paths.each do |path|
if asset = sprocket_task.index.find_asset(path)
copy_target = File.join(sprocket_task.output, asset.digest_path)
target = File.join(sprocket_task.output, asset.logical_path)
sprocket_task.logger.info "Writing #{target}"
asset.write_to target
asset.write_to "#{target}.gz" if asset.is_a?(Sprockets::BundledAsset)
end
end
end
end
Rake::Task['assets:precompile'].enhance do
Rake::Task['assets:precompile:nondigest'].invoke
end

How can I control infile and outfile passed to compiler when specifying files to compile with django-pipeline?

I've written a rudimentary requirejs compiler for Django-Pipeline and I'm trying to polish it up but I'm stuck with a certain problem. I've noticed the same "problem" with the SASS compiler so I wonder if this is a setting I'm missing or something.
PIPELINE_CSS = {
'main': {
'source_filenames': (
'sass/main.scss',
),
'output_filename': 'css/crushcode.css',
'extra_context': {
'media': 'screen,projection',
}
}
}
PIPELINE_JS = {
'requirejs': {
'source_filenames': (
'js/lib/requirejs-2.0.4.js',
),
'output_filename': 'js/require.js',
'extra_context': {
'data': '/static/js/bootstrap'
}
}
}
Both of these create an output file in the source directory of the same name as the input file, with the extension changed to output_extension of the respective compiler class. For SASS, this is ok as the extension is .css so you end up with main.css next to your main.scss, but with my requirejs plugin the first time I ran it, because the extensions are the same, I actually overwrote my original file (Nothing lost of course, thankyou version control).
I noticed that infile and outfile were both pointing to:
APP_ROOT/static/js/lib/require-2.0.4.js
when I would have thought outfile should point to output_filename in the settings.
The easy fix was to change the output_extension of my custom compiler class to be 'optimized.js', but at this point I'm adding a .gitignore for every compiled file, and not to mention collectstatic then brings everything across, and also creates the desired output_filename file in the target directory.
What I was hoping for was that collectstatic would simply create the js/require.js file in my STATIC_ROOT directory.
It feels like I'm doing something wrong here, any tips? Is this expected behaviour? If so, what's the best should I go about changing it?