Как легко минимизировать JS в PHP... Или что-то еще

Я немного поглядел, но я все еще немного смущен.

Я попробовал Crockford JSMin, но Win XP не может распаковать исполняемый файл по какой-то причине.

Я действительно хочу, но это простой и простой в использовании JS minifier, который использует PHP для минимизации кода JS и возвращает результат.

Причина в том, что: У меня есть 2 файла (например), с которыми я работаю: scripts.js и scripts_template.js

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

Я хочу искоренить среднего человека, просто сделав что-то вроде этого на моей странице:

<script type="text/javascript" src="scripts.php"></script>

И затем для содержимого scripts.php:

<?php include("include.inc"); header("Content-type:text/javascript"); echo(minify_js(file_get_contents("scripts_template.js")));

Таким образом, всякий раз, когда я обновляю свой JS, мне не нужно постоянно переходить на сайт, чтобы его минимизировать и повторно вставить в scripts.js - все автоматически обновляется.

Да, я также попробовал Crockford PHP minifier, и я взглянул на PHP Speedy, но пока не понял PHP-классы... Есть ли что-нибудь, что обезьяна могла бы понять, может быть, что-то с RegExp?

Как насчет того, чтобы сделать это еще проще?

Я просто хочу удалить области вкладок - я все еще хочу, чтобы мой код был доступен для чтения.

Это не похоже на то, что script заставляет мой сайт отставать эпично, это просто ничего лучше, чем ничего.

Удаление табуляции, кто-нибудь? И если это возможно, как насчет удаления полностью BLANK строк?

Ответ 1

Я использовал реализацию PHP JSMin Дуглас Крокфорд в течение некоторого времени. При конкатенации файлов может быть немного рискованно, так как в конце закрытия может отсутствовать точка с запятой.

Было бы разумной идеей кэшировать миниатюрный вывод и эхо кэшировать до тех пор, пока он будет более новым, чем исходный файл.

require 'jsmin.php';

if(filemtime('scripts_template.js') < filemtime('scripts_template.min.js')) {
  read_file('scripts_template.min.js');
} else {
  $output = JSMin::minify(file_get_contents('scripts_template.js'));
  file_put_contents('scripts_template.min.js', $output);
  echo $output;
}

Вы также можете попробовать JShrink. Я никогда не использовал его раньше, так как раньше у меня не было проблем с JSMin, но этот код ниже должен делать трюк. Я этого не осознал, но JShrink требует PHP 5.3 и пространства имен.

require 'JShrink/Minifier.php';

if(filemtime('scripts_template.js') < filemtime('scripts_template.min.js')) {
  read_file('scripts_template.min.js');
} else {
  $output = \JShrink\Minifier::minify(file_get_contents('scripts_template.js'));
  file_put_contents('scripts_template.min.js', $output);
  echo $output;
}

Ответ 2

Взгляните на Assetic, отличную библиотеку управления активами в PHP. Он хорошо интегрирован с Symfony2 и широко используется.

https://github.com/kriswallsmith/assetic

Ответ 3

В зависимости от ограничений вашего сервера (например, не работает в безопасном режиме), возможно, вы также можете смотреть за пределы PHP для minifier и запустите его, используя shell_exec(). Например, если вы можете запускать Java на своем сервере, поместите копию YUI Compressor на сервер и используйте его напрямую.

Тогда scripts.php будет выглядеть примерно так:

<?php 

  $cmd = "java -cp [path-to-yui-dir] -jar [path-to-yuicompressor.jar] [path-to-scripts_template.js]";

  echo(shell_exec($cmd));

?>

Другое предложение: постройте шаг минимизации в рабочий процесс разработки, прежде чем развертывать его на сервере. Например, я настроил свои проекты Eclipse PHP для сжатия JS и CSS файлов в папку "build". Работает как шарм.

Ответ 4

Использование "PHPWee": https://github.com/searchturbine/phpwee-php-minifier (который также использует JSmin), я немного продвинул решение @Robert K.

Это решение позволяет минимизировать файлы CSS и JS. Если не-минированный файл не может быть найден, он вернет пустую строку. Если миниатюрный файл старше, чем неминифицированный, он попытается его создать. Он создаст подпапку для мини файла, если он не существует. Если метод может успешно минимизировать файл, он возвращает его либо в теге <script> (javascript), либо в теге <link> (CSS). В противном случае метод вернет неминифицированную версию в соответствующий тег.

Примечание: проверено с помощью PHP 7.0.13

/**
* Try to minify the JS/CSS file. If we are not able to minify,
*   returns the path of the full file (if it exists).
*
* @param $matches Array
*   0 = Full partial path
*   1 = Path without the file
*   2 = File name and extension
*
* @param $fileType Boolean
*   FALSE: css file.
*   TRUE: js file
*
* @return String
*/
private static function createMinifiedFile(array $matches, bool $fileType)
{
    if (strpos($matches[1], 'shared_code') !== false) {

        $path = realpath(dirname(__FILE__)) . str_replace(
            'shared_code',
            '..',
            $matches[1]
        );

    } else {

        $path = realpath(dirname(__FILE__)) .
            "/../../" . $matches[1];
    }

    if (is_file($path . $matches[2])) {

        $filePath = $link = $matches[0];

        $min = 'min/' . str_replace(
            '.',
            '.min.',
            $matches[2]
        );

        if (!is_file($path . $min) or 
            filemtime($path . $matches[2]) > 
            filemtime($path . $min)
        ) {

            if (!is_dir($path . 'min')) {

                mkdir($path . 'min');   
            }

            if ($fileType) { // JS

                $minified = preg_replace(
                        array(
                            '/(\))\R({)/',
                            '/(})\R/'
                        ),
                        array(
                            '$1$2',
                            '$1'
                        ),
                        Minify::js(
                        (string) file_get_contents(
                            $path . $matches[2]
                        )
                    )
                );

            } else { // CSS

                $minified = preg_replace(
                    '@/\*(?:[\r\s\S](?!\*/))+\R?\*/@', //deal with multiline comments
                    '',
                    Minify::css(
                        (string) file_get_contents(
                            $path . $matches[2]
                        )
                    )
                );
            }

            if (!empty($minified) and file_put_contents(
                    $path . $min, 
                    $minified 
                )
            ) {

                $filePath = $matches[1] . $min;
            }

        } else { // up-to-date

            $filePath = $matches[1] . $min;
        }

    } else { // full file doesn't exists

        $filePath = "";
    }

    return $filePath;
}

/**
* Return the minified version of a CSS file (must end with the .css extension).
*   If the minified version of the file is older than the full CSS file,
*   the CSS file will be shrunk.
*
*   Note: An empty string will be return if the CSS file doesn't exist.
*
*   Note 2: If the file exists, but the minified file cannot be created, 
*       we will return the path of the full file.
*
* @link https://github.com/searchturbine/phpwee-php-minifier Source
*
* @param $path String name or full path to reach the CSS file.
*   If only the file name is specified, we assume that you refer to the shared path.
*
* @return String
*/
public static function getCSSMin(String $path)
{
    $link = "";
    $matches = array();

    if (preg_match(
            '@^(/[\w-]+/view/css/)?([\w-]+\.css)[email protected]',
            $path,
            $matches
        )
    ) {

        if (empty($matches[1])) { // use the default path

            $matches[1] = self::getCssPath();

            $matches[0] = $matches[1] . $matches[2];
        }

        $link = self::createMinifiedFile($matches, false);

    } else {

        $link = "";
    }

    return (empty($link) ?
        '' :
        '<link rel="stylesheet" href="' . $link . '">'
    );
}

/**
* Return the path to fetch CSS sheets.
* 
* @return String
*/
public static function getCssPath()
{
    return '/shared_code/css/' . self::getCurrentCSS() . "/";
}

/**
* Return the minified version of a JS file (must end with the .css extension).
*   If the minified version of the file is older than the full JS file,
*   the JS file will be shrunk.
*
*   Note: An empty string will be return if the JS file doesn't exist.
*
*   Note 2: If the file exists, but the minified file cannot be created, 
*       we will return the path of the full file.
*
* @link https://github.com/searchturbine/phpwee-php-minifier Source
*
* @param $path String name or full path to reach the js file.
*
* @return String
*/
public static function getJSMin(String $path)
{
    $matches = array();

    if (preg_match(
            '@^(/[\w-]+(?:/view)?/js/)([\w-]+\.js)[email protected]',
            $path,
            $matches
        )
    ) {
        $script = self::createMinifiedFile($matches, true);

    } else {

        $script = "";
    }

    return (empty($script) ? 
        '' :
        '<script src="' . $script . '"></script>'
    );
}

В шаблоне (Smarty) вы можете использовать следующие методы:

{$PageController->getCSSMin("main_frame.css")}
//Output: <link rel="stylesheet" href="/shared_code/css/default/min/main_frame.min.css">

{$PageController->getCSSMin("/gem-mechanic/view/css/gem_mechanic.css")}
//Output: <link rel="stylesheet" href="/gem-mechanic/view/css/min/gem_mechanic.min.css">

{$PageController->getJSMin("/shared_code/js/control_utilities.js")}
//Output: <script src="/shared_code/js/min/control_utilities.min.js"></script>

{$PageController->getJSMin("/PC_administration_interface/view/js/error_log.js")}
//Output: <script src="/PC_administration_interface/view/js/min/error_log.min.js"></script>

Единичные тесты:

/**
* Test that we can minify CSS files successfully.
*/
public function testGetCSSMin()
{
    //invalid style
    $this->assertEmpty(
        PageController::getCSSMin('doh!!!')
    );


    //shared style
    $path = realpath(dirname(__FILE__)) . '/../css/default/min/main_frame.min.css';

    if (is_file($path)) {

        unlink ($path);
    }

    $link = PageController::getCSSMin("main_frame.css");

    $this->assertNotEmpty($link);

    $this->assertEquals(
        '<link rel="stylesheet" href="/shared_code/css/default/min/main_frame.min.css">',
        $link
    );

    $this->validateMinifiedFile($path);


    //project style
    $path = realpath(dirname(__FILE__)) . '/../../gem-mechanic/view/css/min/gem_mechanic.min.css';

    if (is_file($path)) {

        unlink ($path);
    }

    $link = PageController::getCSSMin("/gem-mechanic/view/css/gem_mechanic.css");

    $this->assertNotEmpty($link);

    $this->assertEquals(
        '<link rel="stylesheet" href="/gem-mechanic/view/css/min/gem_mechanic.min.css">',
        $link
    );

    $this->validateMinifiedFile($path);
}

/**
* Test that we can minify JS files successfully.
*/
public function testGetJSMin()
{
    //invalid script
    $this->assertEmpty(
        PageController::getJSMin('doh!!!')
    );


    //shared script
    $path = realpath(dirname(__FILE__)) . '/../js/min/control_utilities.min.js';

    if (is_file($path)) {

        unlink ($path);
    }

    $script = PageController::getJSMin("/shared_code/js/control_utilities.js");

    $this->assertNotEmpty($script);

    $this->assertEquals(
        '<script src="/shared_code/js/min/control_utilities.min.js"></script>',
        $script
    );

    $this->validateMinifiedFile($path);


    //project script
    $path = realpath(dirname(__FILE__)) . '/../../PC_administration_interface/view/js/min/error_log.min.js';

    if (is_file($path)) {

        unlink ($path);
    }

    $script = PageController::getJSMin("/PC_administration_interface/view/js/error_log.js");

    $this->assertNotEmpty($script);

    $this->assertEquals(
        '<script src="/PC_administration_interface/view/js/min/error_log.min.js"></script>',
        $script
    );

    $this->validateMinifiedFile($path);
}

/**
* Make sure that the minified file exists and that its content is valid.
*
* @param $path String the path to reach the file
*/
private function validateMinifiedFile(string $path)
{
    $this->assertFileExists($path);

    $content = (string) file_get_contents($path);

    $this->assertNotEmpty($content);

    $this->assertNotContains('/*', $content);

    $this->assertEquals(
        0,
        preg_match(
            '/\R/',
            $content
        )
    );
}

Дополнительные примечания:

  • В phpwee.php мне пришлось заменить <? на <?php.
  • У меня были проблемы с пространством имен (функция class_exists() не могла найти классы, даже если они были в одном файле). Я решил эту проблему, удалив пространство имен в каждом файле.