Минимизация и обфускация Javascript

Главные вкладки

Аватар пользователя VladSavitsky VladSavitsky 6 сентября 2008 в 5:25

Задача

Некоторые Javascript-файлы имеют излишне большой размер. Они содержат много комментариев и других символов, которые совсем не нужны для правильной работы скрипта. Нужно удалить все лишнее из js-файлов.

Решение

Минимизация и обфускация JavascriptМинимизация скрипта — это удаление из кода всех несущественных символов с целью уменьшения объема файла скрипта и ускорения его загрузки. В минимизированном коде удаляются все комментарии и незначащие пробелы, переносы строк, символы табуляции. В случае с Javascript, это уменьшает время загрузки страницы, т.к. размер файла уменьшается. Две самых популярных утилиты для минимизации javascript — JSMin и YUI Compressor.

Обфускация является альтернативным способом сокращения исходного кода. Также, как минимизация, она удаляет пробельные символы и вырезает комментарии, но в дополнение она измененяет сам код. К примеру, во время обфускации имена функций и переменных заменяются на более короткие, что делает код более компактным, но менее читабельным. Обычно этот прием используется для усложнения реверс-инжиниринга программы. Но обфускация помогает также уменьшить код настолько, насколько это не получится сделать одной минимизацией. С выбором средства для обфускации javascript не все так ясно, но я думаю, что самая распространенная утилита для этого — Dojo Compressor (ShrinkSafe).

Минимизация javascript — безопасный и довольно простой процесс. С другой стороны, обфускация из-за своей сложности может вносить в код баги. Обфускация также требует правки вашего кода для выделения в нем API-функций и других элементов. которые не должны быть изменены. Это также делает более сложной отладку в продакшне. Я никогда не видел, чтобы минимизация кода создавала в нем баги, но вот при обфускации такое случалось. Среди первой десятки американский сайтов при минимизации в среднем достигалось 21% сжатие, тогда как при обфускации — 25%. И хотя обфускация позволяет добиться большего сжатия, я все же рекомендую применять минимизацию кода, так как она не добавит в ваш код ошибок и полученный скрипт проще будет отлаживать.

Варианты решений

JSMin

JSMin - это маленькая консольная утилита (33 Кб), которая получает на вход код JavaScript, а на выходе выдаёт код JavaScript с удаленными комментариями и переносами строк.
Код остаётся работоспособен и не принимает вид одной строки - я так думаю, потому, что в JavaScript концом оператора может считаться как точка с запятой, так и конец строки, а в последнем случае слепить две строки означает нарушить работоспособность программы.

В среднем файл сжимается на 40-50%.
Доступные кодировки: ASCII и UTF-8.

Использование JSMin

Внимательный читатель, думаю, заметил, что “получает на вход код JavaScript” - сие означает, что надо передать параметром не имя файла, а его текст.

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

jsmin.exe < in.js > out.js

Можно “жать” все файлы с Си-подобным синтаксисом: не только JavaScript и Си, но и РНР, и даже CSS.

Dojo ShrinkSafe

К сожалению, подавляющее большинство этих скриптов либо не слишком эффективны, либо в определенных случаях разрушают код (а иногда - и то и другое вместе). Без подробного грамматического разбора упаковщику трудно отличить комментарий от похожей конструкции, размещенной в закавыченной строке. Кроме того, с помощью регулярных выражений не так-то просто оценить, какая из переменных имеет ограниченный контекст, так что некоторые техники сокращения имен переменных могут разрушить сам код.

Этих проблем можно избежать, сжимая код с помощью Dojo Compressor (alex.dojotoolkit.org/shrinksafe), использующий Rhino (мозилловский JavaScript-движок, написанный на Java) для построения дерева, которое оптимизируется перед работой с файлами. С работой Dojo Compressor справляется неплохо, ресурсов отнимает немного. Расширив наш процесс сборки билда с помощью этого инструмента, мы можем забыть об экономии, писать пространные комментарии, вставлять сколько угодно пробелов и т. д. На рабочем коде это нисколько не отразится.

Пример сжатия

Исходный код:

function MyClass(){
    this.foo = function(argument1, argument2){
        var addedArgs = parseInt(argument1)+parseInt(argument2);
        return addedArgs;
    }
    var anonymousInnerFunction = function(){
        // do stuff here!
    }
}
function MyFunc(){
    // this is a top-level function
}
// we've got multiple lines of whitespace here

Команда сжатия:

java -jar custom_rhino.jar -c infile.js > outfile.js 2>&1

Минимизированная версия кода:

function MyClass(){
this.foo=function(_1,_2){
var _3=parseInt(_1)+parseInt(_2);
return _3;
};
var _4=function(){
};
}
function MyFunc(){
}

Исходный код занимал 321 байт, а минимизированный - 140 байт. Уменьшение - 56%.

Online ShrinkSafe

Онлайн обфускация: http://shrinksafe.dojotoolkit.org/
Отличие от Online Packer в том, что JS-файл загружается на сервер, а не вставляется в форму и обрабатывается средствами JavaScript.

Про YUI Compressor, Packer и Online Packer можно узнать в полной версии статьи Минимизация и обфускация Javascript.

Вывод

Быстрое решение
Если вам нужно сжать 1-2 файла, то самым быстрым и простым вариантом будет использовать онлайн-утилиты. Лучшая из которых - Online ShrinkSafe.

Использование Java и командной строки
2 скрипта написаны на Java: YUI Compressor и Dojo ShrinkSafe. Оба решения являются достойными. Dojo ShrinkSafe выделяет то, что используется Rhino (мозилловский JavaScript-движок, написанный на Java) для построения дерева, которое оптимизируется перед работой с файлами.

Использование с собственном скрипте
Если нужно использовать упаковку с своем коде, то можно использовать JSMin и Packer, которые реализованы на нескольких языках программирования.

Реализации JSMin:

  • скопилированный MS-DOS.exe файл
  • исходный код на C (можете сами компилировать)
  • исходный код на C#
  • исходный код на Java
  • исходный код на JavaScript
  • исходный код на Perl
  • исходный код на PHP
  • исходный код на Python
  • исходный код на OCAML
  • исходный код на Ruby

Продолжение статьи Минимизация и обфускация Javascript на Drupal CookBook.ru

Комментарии

Аватар пользователя beerman beerman 6 сентября 2008 в 12:49

спасибо за статью.

одно важное замечание: когда указываете названия проектов или утилит, давайте ссылку на оригинал (хомяк) этого проекта/утилиты.

Аватар пользователя VladSavitsky VladSavitsky 6 сентября 2008 в 13:41

beerman, спасибо за замечание. Я как-то даже не подумал, что это может сбивать с толку...
Я так понял, что речь идёт о ссылка в разделе "Варианты". Правильно?
Идея была в том, чтобы сделать оглавление разделов статьи (как, например, в Википедии), чтобы улучшить навигацию. Когда статья маленькая, что это не имеет значения, а для большой это уже необходимость.
Википедия автоматом создает оглавление, если больше чем 3 раздела есть в статье...

Ок. Ладно. Как можно это исправить/улучшить/изменить?
В разделе "Варианты" я в скобках буду давать URL проекта, чтобы можно было сразу перейти туда. Да. Это хорошая мысль.
Спасибо.

PS
Может быть модуль стоит написать для автоматических оглавлений?!...

Аватар пользователя shamaner shamaner 7 сентября 2008 в 3:57

чутка неверно, обфускация придумана не для уменьшения кода а для кодирования

http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%84%D1%83%D1%81%D0%BA%D0%B0%...

если надо сжать js
Сжать можно до такой степени, что прочитать очень сложно.
Самый простенький пример html компрессор. маленькая утилитка. 56% это мало.

Аватар пользователя VladSavitsky VladSavitsky 8 сентября 2008 в 12:34

Цитата из той же Википедии:

Цели обфускации

  1. Защита программ от декомпиляции и незаконного использования, нарушения авторских прав программистов.
  2. Оптимизация программы с целью уменьшения размера работающего кода и (если используется некомпилируемый язык) ускорения работы.
  3. Скрытие спама. Спамовое сообщение может содержать код на JavaScript, выводящий рекламу; обфускация кода может помочь сообщению обойти фильтры.

Обратите внимание на п.2!

Аватар пользователя VladSavitsky VladSavitsky 9 сентября 2008 в 18:52

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

Ок. По GPL нужно оставить информацию об авторе - значит нужно так и сделать, а номера версий и прочие комментарии можно вычистить.

Аватар пользователя shamaner shamaner 14 сентября 2008 в 7:01

Уважаемый Влад, не путайте яйца с яйчницой. обфускация в первую очередь это кодирование, а уменьшение кода может являться побочным эффектом, и то не всегда. Обфускация была придумана для увеличения хоть какой то стойкости прикладных (написанных не скриптовым языком) программ от взлома деассемблерами.Первый вроде память не изменяет-где была применена этакая функция это asp. Посмотрите как это работает. А вот zend guard - разрабатывался для php как акселератор, преобразующий скрипт в псевдо байт код-заявленное зендом ускорение примерно 20%, реально меньше. Побочный эффект-уменьшение размера файла и кодирование. Но так как кодирование побочный эффект- то взлом достаточно простой.

Добавлю простой пример обфускации--

$var=$abcdf + $bcdr; --исходник

$var=$ab_f +$bc_r --итог

Аватар пользователя laxa laxa 9 октября 2008 в 12:45

Здравствуйте. Сначала кратко: вот ссылка где можно взять стабильный компрессор:
http://www.russkiy-rim.ru/public/soft/jscompressor.html

Теперь подробнее: Нужно было сжать один .js файл. Стал я пользоваться всеми этими онлайн-компрессорами, котоых так много в сети. Нашел даже один платный!! И во всех них нашел какие-то баги. Вот пример кода, который сжимается неправильно простым компрессором

if(boolean)var varname=smth
else if (boolean) ..

Короче не понравилось мне это и я написал свой собственный компрессор. В нем удалось избежать многих проблем. Единственное, прога будет портить код при регулярных выражениях вида /a = b/g (ну без кавычек). Но все же более стабильная чем большинство онлайн-компрессоров. Не удивляйтесь - сайт, на котором лежит дистрибутив посвящен наружной рекламе

Аватар пользователя laxa laxa 10 октября 2008 в 23:53

Друзья, смею обрадовать вас. Теперь по той же ссылке доступна новая версия - которая ко всему прочему сжимает локальные переменные и не портит регулярные выражения, записанные без кавычек.
Я тестировал программу на довольно больших кусках кода. Но вот маленький примерчик, с которым она легко справляется:
function test() {
var varOut/*a*/ = "opa";
function testIn(param) {
var str = varOut+"2, param: "+param;
return str.replace(/ p/i, '');
}
alert(testIn("!"));
}
Если кто-то пришлет мне код, на котором моя программа спотыкается - буду очень благодарен.