Удаляем вызовы firebug'овской консоли перед выкладкой на produciton

    Предисловие

    В последнее время на хабре стало как-то мало постов, относящихся к веб-разработке. Надеюсь, мой пост будет смотреться выигрышней за счет контраста :)

    Сама статья:


    На днях надо было сходить показать представителю заказчика, как пользоваться одной свежевстроенной в проект фичей.

    За полчаса до выхода подготовил новый билд, протестировал.

    По приезду оказалось, что у заказчика фича не работает. Неприятно получилось, в общем.

    Оказалось, что я забыл удалить в функции-обработчике события вызов firebug'овской консоли (console.log… и т.п.) Со мной вообще часто бывает такое, что я то какой-то символ, случайно ткнув на клавиатуру, допишу, то, наоборот, удалю — короче, использование редакторов без подсветки синтакса и (желательно) анализа структуры кода мне противопоказаны.

    Так как я использую apache ant для развертывания приложения на боевой сервер, я дописал маленький скриптик, который уберет все вызовы console.log(/* something */) или console.dir(/* something */) из вашего кода.

    Собственно, вот он:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project name="deploy" default="stripFirebugConsoleCalls" basedir=".">
    3.     <!-- место, где сложены наши еще не сжатые и не слитые в один файл -->
    4.     <property name="js" value="js/"/>
    5.  
    6.     <!-- регулярка для отлова нездоровых элементов (беззастенчиво утянута с yui builder'a, и слегка доведена напильником)
    7.         github.com/yui/builder/blob/master/componentbuild/shared/properties.xml 79-я строка -->
    8.     <property name="firebug.console.regex" value="^.*?(?:console.log|console.dir).*?(?:;|\).*;|(?:\r?\n.*?)*?\).*;).*;?.*?\r?\n" />
    9.     <property name="firebug.console.regex.flags" value="mg" />
    10.     <property name="firebug.console.regex.byline" value="false" />
    11.     <property name="firebug.console.regex.replace" value="" />
    12.     
    13.     <!-- Сам таргет тоже без затей "вдохновен" YUI Builder'ом, оригинал тут:
    14.         github.com/yui/builder/blob/master/componentbuild/3.x/module.xml 19-я строка -->
    15.     <target name="stripFirebugConsoleCalls" description="Replace firebug console calls">
    16.         <replaceregexp byline="${firebug.console.regex.byline}"
    17.                       match="${firebug.console.regex}"
    18.                       replace="${firebug.console.regex.replace}"
    19.                       flags="${firebug.console.regex.flags}">
    20.             <fileset dir="${js}" includes="*.js" />
    21.         </replaceregexp>
    22.     </target>
    23. </project>
    * This source code was highlighted with Source Code Highlighter.

    Использовать так: создать xml-файл с удобным вам именем (например, boom.xml) и скопипастить в него этот код. Разумеется, стоит поправить значение переменной js, которая указывает на папку с еще не сжатыми js-скриптами. После этого запускаем адскую машину такой командой (для bash):

    ant stripFirebugConsoleCalls -buildfile /path/to/boom.xml

    Вот и все. Засим я откланиваюсь до следующего ЧП или конца проекта.
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 79
    • +2
      Ничего мудрёного, но как всегда познавательно. Спасибо!
    • +2
      а чем плохо console.log = console.dir = function(){};?
      • +3
        Вы что?! Это же 356 байт! (если скрипт в кодировке UTF-8) :)

        Вообще — ничем не плохо. Раньше я вообще такую штуку «на все случаи жизни» использовал:

        if (! ("console" in window) || !("firebug" in console)) {
          var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group"
                 , "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
          window.console = {};
          for (var i = 0; i <names.length; ++i) { window.console[names[i]] = function() {} };
        }

        * This source code was highlighted with Source Code Highlighter.


        Но потом отказался. Вызовы mock-объекта — ненужное замедление, да и api firebug'овской консоли очень уж удобно для использования напрямую.
        Так что я предпочитаю убирать всю отладочную информацию из продакшена.
        • +14
          Вы что?! Это же 356 байт! (если скрипт в кодировке UTF-8) :)
          Это 41 байт, хоть в UTF-8, хоть в KOI-8R, хоть в Windows CP1251
          • +2
            Опс, точно. Спасибо за исправление, плюсик вам. Все, спать, спать.
            • 0
              а если UTF-16?
              • 0
                К чему вопрос?
      • +4
        Оставлять отладочную информацию в коде — не самое правильное решение. Даже в dev версии.

        Я бы на вашем месте создал бы mock объект console с нужными методами, а после доводки кода до рабочего состояния, убрал бы все вызовы console.
        Этим вы также убережетесь от случайных совпадений регулярного выражения не там где надо.
        • +1
          Это типа такого?

          Не, спасибо, но лучше я положусь на регулярку.
          • +2
            Вообще, совет, конечно здравый — спасибо — я с вызовами консоли никогда не коммичусь. Но в этот раз выкладка на сервер была произведена в такой спешке и на таких нервах, что удивительно, как я только такую маленькую ошибку допустил, а не угробил, скажем, файловую систему или еще чего учудил.
            • +1
              Создание mock объекта 100% убережет вас от подобной ошибки в будущем.

              А вот ошибки, которые могут вылезти из-за парсинга исходников по регулярному выражению, будут очень трудно уловимыми (несмотря на очень низкую вероятность появления).

              Лично я бы никогда не стал бы парсить исходники регулярками. Только если больше вообще вариантов нет.
              • +2
                Согласен, согласен по всем пунктам. Ваш вариант куда лучше для проекта, чем мой.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              Ну это как-то излишне сурово, на мой вкус.

              Понятное дело, deflate все прекрасно скопом пожмет и на итоговом размере это не скажется, но чисто с точки зрения эстетики и красоты кода, и с точки зрения облегчения безопасности (типа для наилучшей понятности код должен быть максимально сокращен не в ущерб читаемости) это лишнее.

              Ну и вообще, лишняя проверка при каждом вызове логгинга, ни к чему.

              Все вышенаписанное — полное имхо, конечно.
              • 0
                вообще-то удобно сделать что-то вроде

                var dbg = true;
                function Log(str) {
                if (dbg) console.log(str);
                }

                function Dump(obj) {
                if (dbg) console.dir(obj);
                }

                ну и немножко их развить (ООП).
                у нас раньше так было (приведён упрощённый вариант).
                в принципе удобно.
                и перед выкладкой можно даже скриптом распарсить — просто заменить одну строку и всё.
                а можно и руками поменять параметр, а не вычищать весь код от вызовов. но это можно забыть сделать)
            • +2
              Вот до чего доводит пренебрежение подсветкой синтаксиса, как вы сами правильно заметили :)
              Сам, кстати, могу час дебажыть код, пока не увижу тупую опечятку в числе где-нибудь :(
              • +1
                Ага.
                До смешного доходит — печатаешь себе, никого не трогаешь. Кто-нибудь отвлечет, надо отойти. Возвращаешься, смотришь — вроде все ок. Компилируется прекрасно, и запускается, только как-то очень затейливо глючит. И потом полчаса ищешь ошибку.
              • 0
                Кстати, вы не знаете каких-нибудь статистических анализаторов для JS? Проверкe наличия такого кода неплохо было бы вынести туда. Просто я очень серьезно думаю о написании проекта на JS (компилятор rhino) и там это неплохо помогло бы.
                • +1
                  Нет, к сожалению, не сталкивался. Но был бы рад, если бы вы черкнули пару строк или написали статью если найдете таковой — вдруг пригодится :)
                  • –1
                    в Factor'е есть готовый парсер, разбирающий программу на Javascript в AST, из которого можно сделать все, что душе угодно. Минус один: придется подучить Forth и Factor ;-)
                  • +2
                    Если 'статистических' == 'статических', то стоит посмотреть на www.javascriptlint.com/
                    • 0
                      А ничего новее с большим кол-во проверок нет?
                      • 0
                        Искал замену несколько месяцев назад, но ничего подходящего не нашел.
                        • 0
                          А почему замену? По-моему, очень достойная тулза. Прикрутил ее к geany — одно нажатие, синтаксис проверен, ошибки в консоли, клик по ошибке переносит к ее локации. При желании, можно настроить Option Explicit.
                          • 0
                            Во FreeBSD из портов оно не компиляется на amd64 архитектуре. Сначала искал альтернативу, потом уже пришлось самому запатчить.
                          • 0
                            Я тут нашел http://www.jslint.com/. Название похожее, но, вроде, другое. Ничего не скажите?
                            • 0
                              Оно писано на J(ava)script, вроде бы:
                              JSLint is also available in a WSH Command Line version. JSLint is also available in a Rhino Command Line version.

                              Неохота ставить Rhino, чтобы потестить. Через WSH — вариант, но меня вполне устраивает pipe-oriented jsl.
                              А для онлайн проверки — хорошо, конечно, да толку мне с нее?
                              • 0
                                См. Acknowledgements на странице www.javascriptlint.com/download.htm
                                Цитирую:

                                I would like to especially acknowledge Douglas Crockford's work on JSLint. This lint is itself written in Javascript and is an interesting and rather sophisticated script. Crockford's ideas about good coding practices served as a springboard for many of these lint rules.

                                • 0
                                  Спасибо, не заметил ранее :) Но тем не менее, проверять синтаксис JS тулзой на JS из IDE — чересчур много нужно сделать лишних телодвижений, имхо.
                      • +1
                        А если отладочные вызовы заранее сделать отключаемыми по значению переменной, значение которой хранится в конфиг-файле, который разный для продакшена и девелоперской копии? Там же (у меня) настройки базы данных, включение-выключение счётчиков и т. п.
                        • +1
                          Так и у меня сделано.
                          Только вот в обычной ситуации я вообще не парился по поводу этих вызовов консоли — потому что они не попадали не то, что на продакшен, но даже в основную ветку проекта в репозитории.
                          А тут вот случился форс мажор, все дела.

                          В общем, поставлю это дело на учет, да.
                        • +2
                          Какая-то стремная регулярка. Что будет с комментариями или строкой?
                          Имхо не стоит делать такие вещи на серьезной операции.

                          Обычно на деплой вешаются проверки, но автозамена — путь к долго исследуемым багам в окружении :) В крайнем случае комментируйте команды, что бы видно было что натворил скрипт.
                          • 0
                            Пример строки, на которой регулярка сломается, будет?
                            • +2
                              Мммм… Аля Perl boolVar || console.log(...) пойдет? Не факт что корректно с точки зрения синтаксиса, но…
                              • 0
                                Уели, есть такая строка :)

                                И синтаксически верная, хотя я и не могу представить себе, для чего может понадобится так странно что-то в лог писать :)

                                Ну и кстати сказать, по поводу того, что использование регулярки в данном случае путь к труднообнаруживаемым багам — согласен.
                                • 0
                                  Выводить в лог только если переменная true. Возможно, не самое лучше решение и не сразу приходит в голову, но тем не менее короткое (в одну строчку) и, как вы сами заметили, корректное.
                                  • 0
                                    Ошибся. Если переменная false.
                              • +2
                                Вы всегда отвечаете вопросом на вопрос? :)

                                например так сожрет всю строку
                                any_code(); console.log(); more_code();
                                и так тоже
                                any_code(); // console.log();

                                если честно вот этот кусок — это просто шедевр
                                .*;?.*?\r?
                                • –1
                                  Нет, не всегда :)

                                  Вообще, я на то и рассчитывал — чтобы грохалась вся строка, содержащая console.log / console.dir.
                                  По code conventions, принятым в нашей компании, нельзя написать вызов двух функций в одной строке.
                                  То есть, такого встретиться в коде в принципе не может:
                                  var someObject = {
                                      someAction : function (parameter) {
                                           doSomething(); console.log();
                                      }
                                  }


                                  * This source code was highlighted with Source Code Highlighter.


                                  И комментарии, представляющие собой закомментированный код, тоже нельзя оставлять при коммите — код, который был до того, как вы написали свой, всегда можно получить назад через систему контроля версий, а остальной код, полученный в процессе написания, в принципе никому не нужен.

                                  Понятное дело, это я просто брюзжу, и на самом деле правы вы — регулярку надо доработать, а то может в результате получиться веселое приключение в стиле «сидели всю ночь перед выкладкой проекта, искали баг в js».
                            • +1
                              У меня другое решение:

                              Master.log = function(var){
                                  if (console && console.log) {
                                      console.log(var)
                                  }
                              }
                              
                              • 0
                                К этому решению каждый, кто хоть пять минут думал над проблемой, приходил. Вот мое.

                                Мне кажется не совсем верным оставлять на продакшене любой код, который делает что-то, не относящееся напрямую к функционалу.

                                И, таким образом, вызовы вида Master.log('message') опять же придется как-то чистить.

                                Все вышенаписанное, конечно, имхо.
                                • 0
                                  По-моему, это самое гибкое и корректное ООП решение. Но вообще, это такая мелочь, что тут и обсуждать нечего.

                                  П.С. Кто повнимательнее, мог заметить, что Хабр тоже выводят инфу в консоль.
                                  • 0
                                    Ну хабр иногда так глючит — например, подгрузка новых комментариев и прокрутка до следующего не прочитанного, что я бы не стал ставить его как пример «того, как надо».
                                    А при чем тут ООП в вашем решении — извините, не совсем понимаю.
                                    • 0
                                      ООП: один класс реализует интерфейс другого класса.
                                  • 0
                                    использую «глобальный» флаг вкл/выкл логирование и функцию для вывода
                                    var showLog = true;
                                    function d(smth){
                                    if(!showLog)
                                    return;
                                    try{
                                    /* If Mozilla + FireBug Productions */
                                    console.debug(smth);
                                    }catch(e){
                                    /*Nothing to do */
                                    }
                                    }

                                    Master.log — очень длинное название метода
                                    • 0
                                      Не согласен.

                                      Для алгоритма Хаффмана, который используется в gzip и deflate, нет совершенно никакой разницы, насколько длинное название метода, он все равно заменит его на один символ+смещение.

                                      Так что на размере итогового файла название метода не скажется, а вот эти вот имена переменных вроде d('message') скорее мешают разработке, чем помагают.
                                • +1
                                  вот к чему приводит отсутствие вменяемых отладчиков…
                                  • 0
                                    У вас есть на примете такой?
                                    Я бы не отказался от такого :)
                                    • 0
                                      Отладчик Rhino совсем плох?
                                      • 0
                                        Я не пробовал rhino применять ни для чего серьезного, только пару раз поигрался и все.
                                        Надо будет попробовать.
                                  • 0
                                    такое ощущение, что вы тестируете только в одном браузере
                                    то, что это не internet explorer, всё равно не делает вам чести
                                    • –1
                                      Гм. Я даже в прострацию какую-то впал, когда увидел ваш комментарий.
                                      Зачем мне честь от того, что я проверяю код во всех браузерах? И что это за честь такая странная? :)

                                      И почему вы решили, что в данном конкретном случае не идет речь о том, что все веб-приложение пишется ровно под один браузер — ff 3.1+ и что это прямо так и прописано в ТЗ, прямо самим заказчиком?

                                      • +1
                                        чёрт, кажется, я перенёсся на десять лет назад в альтернативное прошлое, где вместо ie ff…
                                        • 0
                                          В этот раз мы пишем корпоративное приложение, которое будет работать только в интранете одной компании, где везде установлен ff в качестве основного браузера.
                                          Это программа — веб-морда CMS.
                                          Есть еще сам публичный сайт, и он работает кроссбраузерно, но он давно написан и сдан, сейчас вот добиваем последние задачи перед сдачей CMS.

                                          Прочитал и сам офигел — действительно, для корпоративных нужд используется не ie, а ff ;)
                                          • –1
                                            такое ощущение, что вы совсем не понимаете, что таким подходом компания гонит себя в тот же тупик, в котором в нашей реальности находятся тысячи других компаний, ориентировавшихся на единственный браузер
                                            • 0
                                              Меня не оставляет ощущение, что вы считаете себя исключительно умным человеком, который изволит объяснять что-то несмышленышу.

                                              Конечно, эта манера увеличивает доверие к вашим словам. В разы.

                                              Лично я вижу другую тенденцию. Тенденцию писать не под браузеры, а под стандарты. Мы писали все под ff 3.1+, но все работает и под ie8, safari4, chrome3, только в опере глюки иногда вылазят.

                                              А тенденция следовать стандартам, на мой взгляд, только набирает силу, и, таким образом, наше приложение и через сравнительно длительное время будет живее всех живых.
                                              • 0
                                                скажите пожалуйста, в каких браузерах вы тестировали сайт перед показом заказчику, что не обнаружили этих проблем с console?
                                                • 0
                                                  FF и webkit night build.
                                                  Но вообще работало бы во всех перечисленных браузерах — в каждом из них есть объект console.

                                                  Единственный браузер, в котором могли возникнуть проблемы — ff без установленного файрбага, и именно он и стоял у заказчика.
                                                  • 0
                                                    смотрите, почему я считаю, что вы ведёте разработку под один браузер, а не под единый стандарт:

                                                    1) вы используете не входящую в стандарт функцию console.dir
                                                    2) вы тестируете приложение только в одном популярном браузере (ночнушки к популярным относить нельзя), хотя известно, что браузеры могут ошибаться в интерпретации стандартов

                                                    посмотрите сами со стороны на свои действия. Вы серьёзно продолжаете считать, что они выглядят, как разработка по стандартам?
                                                    • 0
                                                      1) Это не так, и, более того, это никак не следует из моих слов. Я писал, что нашелся неучтенный вызов console.log. Так что остальные браузеры бы спокойно под них работали. Вот регулярка, которую я написал, удалит также и вызов console.dir, но это скорее перестраховка, чем необходимость.

                                                      2) Список фич, отличающих webkit night build от safari 4.0 настолько мал, и мы настолько далеко от него разрабатываем, что можно с полной уверенностью утверждать, что все, работающее в webkit, работает и в safari.
                                                      Привычка тестировать все в webkit, а не в сафари у меня осталась с тех времен, когда в webkit'е были нормальные инструменты разработчика, а в safari — нет.

                                                      • 0
                                                        а) в посте написано «console.log… и т.п.», в коде написано «console.log|console.dir» — это те самые слова, из которых логично следует вывод, что вы использовали console.dir. Да, вы подобрали неудачные слова для поста, из-за чего возникло непонимание.
                                                        б) вы этот код написали, закоммитили и отрелизили — вы его используете.
                                                        в) «остальные браузеры бы спокойно под них работали» — неверно, опера бы не работала, а доля оперы больше доли ff3, таким образом, ваш код не работает в самом популярном клиенте из целевых. Даже не ночной сафари далеко в хвосте списка.

                                                        в общем, из изначального поста и первых комментариев про разработку только под ff вполне однозначно *следует*, что вы ведёте разработку только под один браузер. Неудивительно, что я так отреагировал. Да, дальше вы проясняете свои цели и мотивы лучше, однако вам можно дать ещё несколько хороших советов о том, как идти к целям верным путём. Например, в комментариях уже предлагали использовать кроссбраузерные обёртки над дебажными функциями. Я могу добавить к этому тестирование в *популярных* браузерах, придерживающихся стандартов, и отказ от такого чрезвычайно грубого исправления кода инструментами, ничего не знающими о синтаксисе.
                                                        • 0
                                                          В посте написано — «оказалось, что в функции-обработчике события оказался вызов console.log». Точка. Именно вот это и было.

                                                          А то, что написано в коде — это я, обжегшись на молоке, решил дуть и на воду и добавил еще и удаление console.dir — ну, чисто на всякий случай — мало ли, кто-то еще погорит. То, что вы поняли это вот так, как вы поняли — это, простите, ваше личное дело. Написано было другое.

                                                          Не было ни коммита, ни релиза. Был форс мажор в разгаре разработки. Я думаю, об этом можно догадаться, прочитав, что билд был выкачен за полчаса до встречи — такого после сдачи проекта не бывает.

                                                          Вот как оно есть.

                                                          Из этого не следует ни а), ни б), ни в).

                                                          Что касается оперы — во-первых, популярность этого браузера не идет ни в какое сравнение с популярностью ff3 ни в целом по миру, ни по данным статистики сайта клиента. Кроме того, добавлю вот что — поддержка оперы стандартов долгое время оставляла желать лучшего, и даже сейчас им до вебкита далеко. Это я к тому, если вдруг кто не понял, что я отказываю опере как в определении «популярный браузер», так и в определении «браузер, поддерживающий стандарты». Такой вот я нелюбитель оперы, да.

                                                          Что касается того, что вы написали после этих ваших пунктов — начали вы с того, что обвинили меня в разработке под один браузер. Прочитайте еще раз ваше первый комментарий в этом треде.

                                                          Это не я подобрал неудачные слова, а вы неудачно их поняли. А после того, как неудачно их поняли, считаете нужным оставить за собой последнее слово, для чего ищете любые способы придраться к моим словам и выставить себя правым. Именно вот так я понимаю ситуацию.
                                                          • 0
                                                            Оказалось, что я забыл удалить в функции-обработчике события вызов firebug'овской консоли (console.log… и т.п.)
                                                            а) в посте написано «console.log… и т.п.»
                                                            В посте написано — «оказалось, что в функции-обработчике события оказался вызов console.log». Точка. Именно вот это и было.
                                                            ладно, дальше бесполезно обсуждать
                                                            • 0
                                                              Конечно, бесполезно.
                                                              Уже давно идет не обсуждение, а черте-что.
                                                    • 0
                                                      console.dir, кстати, не работал бы в IE8
                                                      • 0
                                                        А его в коде и не было. Так что претензия не по адресу.
                                                        • 0
                                                          чуть выше в пункте «а» я написал, почему по адресу: )
                                                • +1
                                                  Точно так же гонят себя в тупик компании, которые разрабатывают свой внутренний софт только под одну ОС.
                                                  Или использующие только одну CRM.
                                                  • 0
                                                    согласен: сейчас что-то не видать разработчиков софта под beos или os/2

                                                    а хорошие веб-приложения как раз растут благодаря независимости от ОС и браузеров
                                                    • 0
                                                      Чёрт. Это был сарказм.

                                                      Плюсы разработки корпоративного софта как раз в том и заключаются, что разработчик знает и даже может диктовать, на какой платформе будет работать его приложение — а это экономия времени и денег на разработку и поддержку.

                                                      Бизнес, если он вменяемый, ориентируется в первую очередь именно на стоимость, а не на поддержку чьих-то идеалов :)
                                                      • –1
                                                        я подозревал сарказм, но решил думать о вас хорошо. Теперь придётся исправлять своё отношение

                                                        сэкономьте в 1970, купив программу на фортране, и сорок лет подряд каждый год удваивайте сумму на её поддержку

                                                        опыт западных неудачников вас ничему не учит
                                                        • 0
                                                          А что нужно было покупать в 1970-м? Программы на Си?
                                                          У нас примерно с того времени до сих пор работают программы на Коболе, Дельте и Natural :)

                                        • 0
                                          Еще можно использовать bb-код: полужирный, курсив, перечеркнуто дебаггер, тогда в console.log писать ничего не надо.
                                          • +1
                                            мне кажется простейший способ избавиться от консоли — по окончанию проверить все в опере, у нее нет консоли и будут ошибки (ие 8 понимает консоль=))…

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.