简体   繁体   中英

remove console.log on assets precompile

During assets:precompile the javascript is minified, but console.logs are left in.

is there a way to remove all console.logs on precompile when the code is pushed to production?

As of Uglifier 2.4.0 the :compress option includes support for :drop_console which means you can easily remove all console.* functions using something like this in your config/environments/production.rb file:

# Compress JavaScripts
config.assets.compress = true
config.assets.js_compressor = Uglifier.new(
  # Remove all console.* functions
  :compress => { :drop_console => true }
) if defined? Uglifier

You could add this to application.js.erb . This solution would prevent any logging to console.log() in production environment, period. But it will still allow logging to console.error() .

<% if Rails.env.production? %>
  window.console = {};
  window.console.log = function(){};
<% else %>
  // the || in the code ensures IE compatability
  window.console = window.console || {};
  window.console.log = window.console.log || function(){};
<% end %>

To point you in the right direction, check out the Use as a code pre-processor section of UglifyJS .

I need to research more about how to pass a --define DEVMODE=false flag within the rake assets:precompile , but adjusting your code to wrap console.log in with the DEVMODE boolean as described in the link above should get you the result you're looking for.

Update:

In some file that will load during rake assets:precompile , add the following monkey patch.

class Uglifier
  private
    def mangle_options
      {
        "mangle" => @options[:mangle],
        "toplevel" => @options[:toplevel],
        "defines" => { DEVMODE: ["name", "null"] }, # This line sets DEVMODE
        "except" => @options[:except],
        "no_functions" => @options[:mangle] == :vars
      }
    end
end

As I mentioned in a comment below, Uglifier does not support passing a :defines mangle option . You could optionally change the marked line above to "defines" => @options[:defines] and update your config with this line

config.assets.js_compressor = Uglifier.new(defines: { DEVMODE: ["name", "null"] })

When running the rake task, DEVMODE will now be converted to null in your source. Now, given the following code in your Javascript source:

if (typeof DEVMODE === 'undefined') {
  DEVMODE = true;
}

if (DEVMODE) {
  console.log('some log message');
}

By default (in development mode) , DEVMODE will be set to true , causing the console.log() to execute. When rake assets:precompile is run, UglifyJS is going to set DEVMODE to null before compilation/compression begins. When walking over if (null) { it will see that the condition will never evaluate true , and will strip this dead code from the resulting source.

As long as you write your console.log() calls like above or shorthand as

DEVMODE && console.log('some log message');

the console.log() calls will be stripped from the production code. I can see other benefits to this too outside of stripping console.log() , allowing for other development-specific code to coexist with other Javascript in development mode and only development mode.

I'd like to mention the solution of bitcrowd . Their idea basically is:

  1. define a data attribute in your body tag that represents the state of your app (development/production/...) - eg <body data-env="<%= Rails.env %>">
  2. depending on this let console.log() print something out or do nothing at all - eg:

     if ($('body').data('env') == 'production' || typeof console == "undefined"){ var console = { log: function() {}, debug: function() {}, info: function() {} }; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM