I've recently been using Compass with Sass to do some CSS spriting, as it's extremely useful.
However, the filename is always appended with a random string. E.g. icons-s5eb424578c.png. And I don't want this random string to be appended, because it means I'm required to upload both the new CSS file & the new sprite image every time there's a change.
So, does anyone know which Ruby or other config file within the Compass gem directory, that is appending this random string? Then I can just comment the code out for that bit. Unless I'm missing an official variable I can set within Compass to tell it I don't want this string appended?
Thanks in advance for any help on this.
Try to add these lines into your config.rb:
module Compass::SassExtensions::Functions::Sprites
def sprite_url(map)
verify_map(map, "sprite-url")
map.generate
generated_image_url(Sass::Script::String.new(map.name_and_hash))
end
end
module Compass::SassExtensions::Sprites::SpriteMethods
def name_and_hash
"sprite-#{path}.png"
end
def cleanup_old_sprites
Dir[File.join(::Compass.configuration.generated_images_path, "sprite-#{path}.png")].each do |file|
log :remove, file
FileUtils.rm file
::Compass.configuration.run_sprite_removed(file)
end
end
end
module Compass
class << SpriteImporter
def find_all_sprite_map_files(path)
glob = "sprite-*{#{self::VALID_EXTENSIONS.join(",")}}"
Dir.glob(File.join(path, "**", glob))
end
end
end
Works for me with Compass 0.12.2 (Alnilam)
in your project config file enter something like this
asset_cache_buster :none
# Make a copy of sprites with a name that has no uniqueness of the hash.
on_sprite_saved do |filename|
if File.exists?(filename)
FileUtils.mv filename, filename.gsub(%r{-s[a-z0-9]{10}\.png$}, '.png')
end
end
# Replace in stylesheets generated references to sprites
# by their counterparts without the hash uniqueness.
on_stylesheet_saved do |filename|
if File.exists?(filename)
css = File.read filename
File.open(filename, 'w+') do |f|
f << css.gsub(%r{-s([a-z0-9]{10})\.png}, '.png?v\1')
end
end
end
credits goes here How to remove the hash from Compass's generated sprite image filenames?
Related
I tried PGP encrypting a file in ChoPGP library. At the end of the process it shows embedded file name along with the whole original file name path.
But I thought it will show only the filename without the whole path. Which I intend to work on and figure out a way to do so?
Doing the following:
using (ChoPGPEncryptDecrypt pgp = new ChoPGPEncryptDecrypt())
{
pgp.EncryptFile(#"\\appdevtest\c$\appstest\Transporter\test\Test.txt",
#"\\appdevtest\c$\appstest\Transporter\test\OSCTestFile_ChoPGP.gpg",
#"\\appdevtest\c$\appstest\Transporter\pgpKey\PublicKey\atorres\atorres_publicKey.asc",
true,
true);
}
which will result in:
But I would like to only extract the Test.txt in the end something
like this:
Looking at this line from the ChoPGP sources: https://github.com/Cinchoo/ChoPGP/blob/7152c7385022823013324408e84cb7e25d33c3e7/ChoPGP/ChoPGPEncryptDecrypt.cs#L221
You may find out that it uses internal function GetFileName, which ends up with this for the FileStream: return ((FileStream)stream).Name;.
And this one, according to documentation, Gets the absolute path of the file opened in the FileStream..
So you should either make fork of ChoPGP and modify this line to extract just filename, or submit a pull request to the ChoPGP. Btw, it's just a wrapper around the BouncyCastle so you may use that instead.
So I have a file not found problem.
I have an engine that works in development mode in the engines test/dummy app, the engine allows the editing of sass variables and stores them in a theme table, the variables are used by a sass partial such as _banner.scss containing variables used in the main stylesheet such as $banner_color which is then imported into the main stylesheet which in turn is precompiled using an initializer in the engine.rb file and inclusion in the app/config/engine_name_manifest.js.
The files are all available in development with the local dummy app but not in the eventual host app due to the assets being compiled.
I have a rake task that takes the data, updates the relevant partial e.g. _banner.scss with the data from the theme table but of course the partials are not not available in a host app as the engine has already compiled them.
I'm looking for a solution that will allow me to edit the raw, uncompiled stylesheets then recompile them. Obviously my Capistrano deploy script will need to reapply the stylesheet changes every deployment but that is just a rake task call.
What approach should I take? Should I find a way to copy the css files to the host app in an engine initializer? Should I use a different approach entirely, I have started looking at propshaft but that is a massive step to replace sass rails and I'm not sure how that would help
The engine
require "deface"
require 'ccs_cms_admin_dashboard'
require 'ccs_cms_custom_page'
require 'ccs_cms_core'
require 'css_menu'
#require 'tinymce-rails'
require 'delayed_job_active_record'
require 'daemons'
require 'sprockets/railtie'
require 'sassc-rails'
module CcsCms
module PublicTheme
class Engine < ::Rails::Engine
isolate_namespace CcsCms::PublicTheme
paths["app/views"] << "app/views/ccs_cms/public_theme"
initializer "ccs_cms.assets.precompile" do |app|
app.config.assets.precompile += %w( public_theme_manifest.js )
end
initializer :append_migrations do |app|
unless app.root.to_s.match?(root.to_s)
config.paths['db/migrate'].expanded.each do |p|
app.config.paths['db/migrate'] << p
end
end
end
initializer :active_job_setup do |app|
app.config.active_job.queue_adapter = :delayed_job
end
config.to_prepare do
Dir.glob(Engine.root.join("app", "decorators", "**", "*_decorator*.rb")) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
end
config.generators do |g|
g.test_framework :rspec,
fixtures: false,
request: false,
view_specs: false,
helper_specs: false,
controller_specs: false,
routing_specs: false
g.fixture_replacement :factory_bot
g.factory_bot dir: 'spec/factories'
end
end
end
end
The Css class that writes the css
class Css
def get_stylesheet_path
Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
def write_css(theme)
update_css_files_for(theme.banner, '_public_banner.scss', BANNER_ARRAY, BANNER_FIELD_MAP)
update_css_files_for(theme.banner.font, '_public_banner_font.scss', BANNER_FONT_ARRAY, BANNER_FONT_FIELD_MAP)
end
private
def update_css_files_for(model_record_to_use, css_file, array_to_use, field_map)
amended_css = amend_css_for(model_record_to_use, css_file, array_to_use, field_map)
create_css_files_for(css_file, amended_css)
end
def amend_css_for(model_record_to_use, file_name, array_to_use, field_map)
original_css_array = IO.readlines("#{get_stylesheet_path}/#{file_name}")
new_array = []
original_css_array.each do |line|
new_line = line
array_to_use.each do |ma|
if line.start_with?(ma)
field_name = field_map[ma.to_sym]
new_line = ma + ": #{model_record_to_use[field_name.to_sym]};"
#puts("#### original line: #{line}, ma: #{ma}, Field name: #{field_name}, value: #{theme[field_name]}")
break
end
end
new_array << new_line
end
new_array
end
# ---- File and I/O Handling ---- #
def create_css_files_for(file_name, css_array)
File.open("#{get_stylesheet_path}/#{file_name}", "w") do |file|
file.puts css_array
end
end
end
Thanks for clarifying. If I understood correctly here my take on it.
partials are not not available in a host app as the engine has already compiled them
Partials are still there, precompilation just outputs *.{css/js} files into public/assets/ that are declared in app/assets/config/manifest.js.
To get to engines files, instead of Rails.root use:
CcsCms::PublicTheme::Engine.root
In Css class, for example:
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
To support changing theme engines. Theme root can be set in an engine initializer to something like Rails.configuration.theme_root and used in the main app.
Because your theme is also configurable, I think it's better to read theme's original sass files but not modify them, copy them into a tmp folder and update with values from theme table, then output a theme.css in the main app with sass.
https://sass-lang.com/documentation/cli/dart-sass
# Compiles all Sass
$ sass tmp/theme/application.scss:app/stylesheets/theme.css
Then let Rails take over the precompilation process.
Another option is to have one sass configuration file and only update this file. That way there is no dependency on the file structure of any particular theme.
import 'configuration' // sass variables with values from theme table
import 'banner' // uses sass variables only
...
Also just use css variables, if that's an option, and avoid all of the above complexity; no precompilation, no redeploys when theme table changes.
Update for css variables.
Just so we're on the same page. I meant these css variables:
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties. If Internet Explorer is not a priority for you, this is the best solution.
The setup is something like this:
<!-- app/views/layouts/application.erb -->
<!-- NOTE: with turbo this loads only once; full page refresh is needed when #theme changes -->
<head>
<style>
:root { --text-color: <%= #theme.text_color %>; }
</style>
<%= stylesheet_link_tag 'application' %>
</head>
/* app/assets/stylesheets/application.css */
p { color: var(--text-color); }
Possible fix to avoid amending css files. Use erb interpolation inside the sass files. No need to amend every time a theme configuration is changed. In development compiles on the fly. In production it has to be precompiled again when theme configuration is changed; no amending.
// _banner.scss.erb
p { color: <%= Theme.text_color %>; }
You could even use amend_css_for function to insert literal erb code and save some time. For example
new_line = ma + ": <%= Theme.#{model_name}.#{field_name} %>;"
Finally, if you don't want to touch engine files and because these files are not part of the main/host app (as in literally two separate folders in the filesystem). You have to make a copy when amending; read from CcsCms::PublicTheme::Engine.root write to Rails.root.
def get_stylesheet_path
CcsCms::PublicTheme::Engine.root.join("app/assets/stylesheets/ccs_cms/public_theme")
end
# but save to main app
def create_css_files_for(file_name, css_array)
File.open("#{Rails.root.join("app/assets/stylesheets/ccs_cms/public_theme")}/#{file_name}", "w") do |file|
file.puts css_array
end
end
I'm using Google Closure Compiler to minify my JS scripts: https://developers.google.com/closure/compiler/docs/gettingstarted_app?hl=en
The command I'm using is:
java -jar /home/user/compiler/compiler.jar --js $File::Find::name --create_source_map $File::Find::name.map --source_map_format=V3 --compilation_level=WHITESPACE_ONLY --js_output_file $minified --charset=Windows-1251 --output_wrapper '%output%\n//# sourceMappingURL=output.js.map'
Thats fine, apart from one thing - the .js.map file has the FULL path for the file, not the relative one:
"version":3,
"file":"/home/user/public_html/new_design/common37.min.js",
"lineCount":375,
....
I assume I can change this in the invocation of the compiler.jar script? Otherwise, I guess I will have to add some more code into my script (not something I want to do, if its possible "out of the box")
EDIT: I've done a little bit of a dirty hack in my Perl script:
# now open the map file one, and edit it to remove the full path.. needs to be relative
my $contents = File::Slurp::read_file("/home/user/public_html/$tmp.map");
$contents =~ s|/home/user/public_html||g;
File::Slurp::write_file("/home/user/public_html/$tmp.map",$contents);
That gets rid of the path info correctly. I've prefer if there were an option to use relative urls in the .map file (compared to the full path it currently puts in)
Thanks!
Specify sourcemap location transformations by using the --source_map_location_mapping flag. The flag expects a value formatted as:
--source_map_location_mapping=/filesystem/src/root|relative/source/root
I am working on a Compass project and my final css output is huge so it needs to be be blessed .
I am using Codekit to compile my SCSS files, and it has the bless option for the less and sass files but unluckly this option seems to be not available for the compass projects (BTW there is no workaround to fix the problem https://github.com/bdkjones/CodeKit/issues/163)
Is there an alternative way to do that automatically after the compiling process? Is it possible to watch the css file with nodejs and then bless it?
====================================================
UPDATE
I am not using Codekit anymore I use Grunt to build the project assets and it works like a charm.
Well, it seems that using this reference you can simply do something like:
on_stylesheet_saved do |filename|
system('blessc ' + File.basename(filename))
end
after you have installed Bless.
What it does is simply attaching that event after you compile your Compass file :) Enjoy
This works for the regular compile command, but it doesn't work when you watch it. After Bless is completed the watch process ends.
I found that blessc just wouldn't execute, I'd get one of these two errors:
config.rb: No such file or directory - blessc (whatever filename)
or
env: node: No such file or directory
It turns out this is because blessc/node.js are installed in /usr/local/bin, and that is not in the PATH variable for ruby exec (/usr/bin:/bin:/usr/sbin:/sbin). The following code worked:
on_stylesheet_saved do |filename|
exec('PATH=$PATH:/usr/local/bin; blessc ' + filename + ' -f')
end
Edited to add: If after this you get errors saying that the files aren't css from bless, check if your absolute path to the file contains white space. You can escape the white space by doing the following:
on_stylesheet_saved do |filename|
exec('PATH=$PATH:/usr/local/bin; blessc ' + (filename.gsub! ' ', '\ ') + ' -f')
end
You can try the following code block, I've made couple of changes of Julian Xhokaxhiu answer:
on_stylesheet_saved do |filename|
begin
puts "Counting number of selector in :: " + filename
result = system('blessc',filename,'-f')
if not result
Kernel.exit(false)
else
puts "Blessed the file to support Older version of IE."
end
rescue Exception => e
puts "Please install bless.\nsudo npm install -g bless."
Kernel.exit(false)
end
end
Is there a way to do file rev cache busting in SASS? It appears to be possible using compass per this answer here:
SASS Image CSS Cache Busting (via Compass)
but I haven't found any way to do this just using SASS. Is there any way to have SASS get file modification info from the filesystem, and append to an image path?
And I'd prefer to not append query strings- rather, I think this is a better methodology.
Thanks Dawn for chiming in after all this time! I've since figured this out, but forgot I posted here about it.
I have a custom rb file that I reference when I run sass via the command line - like so:
sass --update sass:css -r file_mod.rb
in file_mod.rb, I have the following ruby function which does the trick:
require 'sass'
module GETMODINT
def file_url(staticFilePath,staticHost,filePath)
assert_type filePath, :String
filePath = filePath.value #get string value of literal
staticFilePath = staticFilePath.value
staticHost = staticHost.value
modtime = File.mtime(filePath).to_i
#Sass::Script::Number.new(modtime)
fileBaseName = File.basename filePath, '.*'
fileDir = File.dirname(filePath).sub(staticFilePath,'')
fileExt = File.extname(filePath)
path = "url('#{staticHost}#{fileDir}/#{fileBaseName}.#{modtime}#{fileExt}')"
return Sass::Script::String.new(path)
end
Sass::Script::Functions.declare :modInt, [:filePath]
end
module Sass::Script::Functions
include GETMODINT
end
Then, in a sass mixin, I simply reference the file_url function, passing it the parameters it needs to build the result:
#mixin backgroundImage($path, $position:0 0, $repeat:no-repeat) {
background: {
image:file_url($staticFilePath,$staticHost,$path);
position:$position;
repeat:$repeat;
}
}
In my case, I'm using it to construct a css background image path. Should be easily modified to suit other purposes.