Should Rails uglifier uglify (mangle) function names? - ruby-on-rails

My .js files are compressed and variables mangled, but function names are not mangled (running latest Rails 3.2.8 and latest uglify 1.3.0 gem) on Heroku.
According to https://github.com/lautis/uglifier#usage the "mangle" option defaults to true. Below is my config.
From production.rb:
config.assets.compress = true
config.assets.js_compressor = :uglifier
I've also tried
config.assets.compress = true
config.assets.js_compressor = Uglifier.new(:mangle => true, :toplevel => true, :copyright => true)
but with no noticable difference.
As one commenter suggested, I did try changing contents of one my .js files, but didn't make a difference.
Example from output of the compressed precompiled .js file on Heroku:
show_slideout_notification=function(){jQuery(".slideout_notification").slideDown();var e=$(".slideout_notification .countdown
Seems that variable names are mangled, but function names are not.
Any ideas why function names are not mangled? Or is this not wanted behaviour as it would then be difficult to call the functions from my Rails/js code (i.e. javascript onclick events). Or would those onclick calls be renamed to the mangled name too if the function names were mangled?
Thanks :-)

Have you tried to modify the file? According to this the generation of asset files are based on file modification time. Maybe your settings not even being used.

Shouldn't it be like this?
config.assets.js_compressor = Uglifier.new(:mangle => { :toplevel => true }, :output => { :comments => :copyright })

Related

Rails webpacker.yml, extract_css option

According to rails/webpacker documentation, extract_css is default to true in production environment and false in development. From what I observed:
With extract_css true, webpacker will emit a css file from each stylesheet_pack_tag in application.html.erb.
And, with extract_css false, stylesheet_pack_tag return nil & stylesheet that gets imported in js files will get extracted and bundle into blobs and send to browser. Hence, link tags to blob url exist.
So, I assume that using extract_css true yield the same result as using inline styles in header since styles get downloaded to browser with the website document file. If what I understand is true then setting extract_css to true on production should be ok.
Is what I understand about extract_css option correct?
You mostly correct, you can read more about extract_css in css.md or v4-upgrade.md
With extract_css: true, webpacker will emit a single css <link rel="stylesheet"... from each stylesheet_pack_tag.
With extract_css: false, stylesheet_pack_tag return nil & stylesheet that gets imported in js files will get extracted and bundle into blobs and injected into as an inline .
In the end extract_css: false is the one that yields the same result as using inline styles.
I don't have anything to add other than "extract_css" in webpacker.yml has been a source of confusion for me as well. When it is "extract_css: false" in development and production, a stylesheet IS included in the document head (shouldn't this be "extract_css: true"?). And when I use "extract_css: true", styles are not included in the document.

rails app:update conflicts - cleanest way to select file content?

I'm trying to upgrade from Rails 5.0 to Rails 5.1.1.
Running rails app:update results in various conflicts where Rails 5.1.1 has a file with the same name as Rails 5.0, and I'm asked what I want to do about it.
The 'diff' for 'development.rb' look like this:
config.cache_store = :memory_store
config.public_file_server.headers = {
- 'Cache-Control' => 'public, max-age=172800'
+ 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
}
else
config.action_controller.perform_caching = false
## -30,8 +30,6 ##
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false
- host = 'localhost:3000' # Local server
- config.action_mailer.default_url_options = { host: host, protocol: 'http' }
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
So in this case, I'm happy for the 'Cache-Control' line to be changed, but want the other 2 lines ('host..', 'config...') left alone.
I know how to choose either the old file or the new file, but what do you do when you want parts of both? Do you just copy what you want to a separate file and paste in after the interactive process has finished, or is there a cleaner method?
As far as I can tell, the app:update process does not have an interactive way to edit. You just have to go back and edit it once the process is complete.
Looks like the easiest option for you in this case would be to choose your file in app:update and then copy the new cache control values in.

Rails: don't uglify HTML and CSS in test environment (using SLIM and Sass/Compass)?

I'm actively validating the HTML and CSS in request specs. Sadly, the error messages are very long because the HTML and CSS is uglified/compressed in test env.
I tried to remove the uglifier gem from the Gemfile, but this didn't work out. Do I miss some configuration option here? I can't find any for test.rb...
Update
I found that setting Slim::Engine.set_default_options pretty: true solved the problem for the HTML output.
The CSS is still compressed on one line though, I tried stuff like adding output_style = :nested to config/compass.css, setting Sass::Plugin.options[:style] = :expanded (raised an exception), add config.sass.output_style = :nested to test.rb, and setting # config.assets.css_compressor = nil also in test.rb. Didn't solve my problem.
Try setting this in test.rb:
config.assets.debug = true
In case you're using SLIM templating engine, set pretty: true:
Slim::Engine.set_default_options pretty: true
For more info see https://github.com/slim-template/slim#default-options.

Dynamic CSS using Sprockets

I'm working on a site builder in rails and I would like to render the sites css using Sprockets SCSS processors. Since the user can change colors and logos, I can't use Sprockets precompilation so I've started working on a Rails SCSS template handler to handle dynamic views.
The goal is to compile 'app/views/sites/show.css.scss' any time /sites/43543.css is requested. Here's what I have so far. You'll notice I first run the template through the ERB processor and then attempt to run it through Sprockets.
https://gist.github.com/3870095
Manuel Meurer came up with an alternative solution that writes the ERB output to a path and then triggers the Asset Pipeline to compile it. I was able to get his solution to work locally but it wont work on heroku because the asset path is not writable. Files can only be written to the tmp directory and those files are only guaranteed for a single request.
http://www.krautcomputing.com/blog/2012/03/27/how-to-compile-custom-sass-stylesheets-dynamically-during-runtime/
After a long day I was able to solve my problem thanks to John Feminella and his post on google. The challenging part for me was figuring out how to create a new Sprockets::Context. Luckily John's solution doesn't require a Context.
Updated gist here
Attempt #1
This code does not allow importing css files from the asset pipeline.
#import "foundation"; works because foundation is loaded as a compass module
#import "custom_css"; results in an error message saying the file could not be found
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
options = Compass.configuration.to_sass_engine_options.merge(
:syntax => :scss,
:custom => {:resolver => ::Sass::Rails::Resolver.new(CompassRails.context)},
)
Sass::Engine.new((begin;#{erb};end), options).render
}
end
Attempt #2
This code fails to embed base64 urls using asset-data-url
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
compiler = Compass::Compiler.new *Compass.configuration.to_compiler_arguments
options = compiler.options.merge({
:syntax => :scss,
:custom => {:resolver => ::Sass::Rails::Resolver.new(CompassRails.context)},
})
Sass::Engine.new((begin;#{erb};end), options).render
}
end
Attempt 3
Turns out you can use empty values while creating the context. Code below works in development but throws an error in production.
ActionView::Template::Error (can't modify immutable index)
It appears the error occurs in Sprockets::Index which is used instead of Sprockets::Environment in production. Switching to Sprockets::Environment doesn't solve the problem either.
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
context = CompassRails.context.new(::Rails.application.assets, '', Pathname.new(''))
resolver = ::Sass::Rails::Resolver.new(context)
compiler = Compass::Compiler.new *Compass.configuration.to_compiler_arguments
options = compiler.options.merge({
:syntax => :scss,
:custom => {:resolver => resolver}
})
Sass::Engine.new((begin;#{erb};end), options).render
}
end

Conditional javascript require in the asset pipeline

I'm struggling with the asset pipeline. I'm loading dojo from Google CDN putting this in my template:
= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/dojo/1.6.1/dojo/dojo.xd.js', :'data-dojo-config' => %Q(dojoBlankHtmlUrl:'/blank.html', baseUrl: 'assets/', modulePaths: {custom: 'javascripts/modules'})
I just want a fallback to a local version if running locally or if the CDN is down. I thought of doing this:
script typeof(dojo) === "undefined" && document.write(unescape('%3Cscript src="js/libs/dojo-1.6.1.min.js"%3E%3C/script%3E'));
But I don't like it as it works out of the asset pipeline. I want to keep dojo in vendors/assets/javascripts/dojo. How can I get the fallback to be served by the asset pipeline.
Is there a way do declare conditional require in the asset pipeline. What I want is to run some javascript tests, and depending on the result serve a file.
Thanks
I suggest you use yepnope, a lightweight library for loading libraries like this in parallel (for speed) and it gives you the option to run some other code to test if the library is loaded. For example:
yepnope([{
load: 'http://ajax.googleapis.com/ajax/libs/dojo/1.6.1/dojo/dojo.xd.js',
complete: function () {
if (!window.jQuery) {
yepnope('asset_path('you_local_copy_of_dojo') ');
}
}
}])
(Note: You will need erb tags around the asset_path helper)
The local dojo file would be in the assets/javascript folder, but not included in the application manifest. You need to add the dojo file to the precompile array:
config.assets.precompile += 'your_local_file.js'
And this will make it available to the asset_path helper.
Thanks Richard!
I don't want to have yepnope to load one library. It would be overkill imo. Here is the solution I came up with, based on your help (written in slim):
1/ In vendors/assets/javascripts/, I have my dojo.js.
2/ In config/application.rb:
# Precompile these assets files
config.assets.precompile += ['dojo.js']
3/ In the template:
= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/dojo/#{Settings.dojoVersion}/dojo/dojo.xd.js", :'data-dojo-config' => %Q(dojoBlankHtmlUrl:'/blank.html', baseUrl: 'assets/', modulePaths: {custom: 'javascripts/modules'})
script = "typeof(dojo) === \"undefined\" && document.write(unescape('%3Cscript src=\"#{asset_path('dojo')}\"%3E%3C/script%3E'));".html_safe
I also posted on the Rails Google Group to request the addition of two options to the javascript_include_tag, :test and :local that would take care of all the work. We'll see.

Resources