Javascript 如何轻松地在 PHP 中缩小 JS ......或其他东西

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11000261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:57:22  来源:igfitidea点击:

How to minify JS in PHP easily...Or something else

phpjavascriptminify

提问by RickyAYoder

I've done some looking around, but I'm still confused a bit.

我环顾四周,但我仍然有点困惑。

I tried Crockford's JSMin, but Win XP can't unzip the executable file for some reason.

我尝试了 Crockford 的 JSMin,但由于某些原因,Win XP 无法解压缩可执行文件。

What I really want though is a simple and easy-to-use JS minifier that uses PHP to minify JS code--and return the result.

不过,我真正想要的是一个简单易用的 JS 缩小器,它使用 PHP 来缩小 JS 代码——并返回结果。

The reason why is because: I have 2 files (for example) that I'm working between: scripts.js and scripts_template.js

原因是因为:我有 2 个文件(例如)在我之间工作:scripts.js 和 scripts_template.js

scripts_template is normal code that I write out--then I have to minify it and paste the minified script into scripts.js--the one that I actually USE on my website.

scripts_template 是我写出的普通代码——然后我必须缩小它并将缩小后的脚本粘贴到scripts.js——我在我的网站上实际使用的那个。

I want to eradicate the middle man by simply doing something like this on my page:

我想通过在我的页面上简单地做这样的事情来根除中间人:

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

And then for the contents of scripts.php:

然后是scripts.php的内容:

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

This way, whenever I update my JS, I don't have to constantly go to a website to minify it and re-paste it into scripts.js--everything is automatically updated.

这样,每当我更新我的 JS 时,我就不必经常去网站缩小它并将其重新粘贴到 scripts.js 中——一切都会自动更新。

Yes, I have also tried Crockford's PHP Minifier and I've taken a look at PHP Speedy, but I don't understand PHP classes just yet...Is there anything out there that a monkey could understand, maybe something with RegExp?

是的,我也尝试过 Crockford 的 PHP Minifier 并且我看过 PHP Speedy,但我还不了解 PHP 类......有没有猴子可以理解的东西,也许是 RegExp 的东西?

How about we make this even simpler?

我们让这更简单如何?

I just want to remove tab spaces--I still want my code to be readable.

我只想删除制表符空间——我仍然希望我的代码可读。

It's not like the script makes my site lag epically, it's just anything is better than nothing.

这并不是说脚本让我的网站严重滞后,只是有总比没有好。

Tab removal, anyone? And if possible, how about removing completely BLANK lines?

标签删除,有人吗?如果可能,如何完全删除空白行?

回答by Robert K

I have used a PHP implementationof JSMin by Douglas Crockfordfor quite some time. It can be a little risky when concatenating files, as there may be a missing semicolon on the end of a closure.

我使用Douglas Crockford的 JSMin的PHP 实现已经有一段时间了。连接文件时可能有点冒险,因为闭包末尾可能缺少分号。

It'd be a wise idea to cache the minified output and echo what is cached so long as it's newer than the source file.

缓存缩小的输出并回显缓存的内容是一个明智的想法,只要它比源文件更新。

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;
}

You could also try JShrink. I haven't ever used it before, since I haven't had difficulty with JSMin before, but this code below should do the trick. I hadn't realized this, but JShrink requires PHP 5.3 and namespaces.

你也可以试试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;
}

回答by Louis-Philippe Huberdeau

Take a look at Assetic, a great asset management library in PHP. It is well integrated with Symfony2 and widely used.

看看 Assetic,一个很棒的 PHP 资产管理库。它与Symfony2很好地集成并被广泛使用。

https://github.com/kriswallsmith/assetic

https://github.com/kriswallsmith/assetic

回答by Kevin Bray

Depending on the restrictions of your server (eg, not running in safe mode), perhaps you can also look beyond PHP for a minifier and run it using shell_exec(). For instance, if you can run Java on your server, put a copy of YUI Compressoron the server and use it directly.

根据您的服务器的限制(例如,不在安全模式下运行),也许您还可以在 PHP 之外寻找一个缩小器并使用shell_exec(). 例如,如果您可以在您的服务器上运行 Java,则将YUI Compressor的副本放在服务器上并直接使用它。

Then scripts.php would be something like:

然后scripts.php将是这样的:

<?php 

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

  echo(shell_exec($cmd));

?>

Other suggestion: build the minification step into your development workflow, before you deploy to the server. For example I set up my Eclipse PHP projects to compress JS and CSS files into a "build" folder. Works like a charm.

其他建议:在部署到服务器之前,将缩小步骤构建到您的开发工作流程中。例如,我将 Eclipse PHP 项目设置为将 JS 和 CSS 文件压缩到“build”文件夹中。奇迹般有效。

回答by Jonathan Parent Lévesque

Using "PHPWee": https://github.com/searchturbine/phpwee-php-minifier(which also uses JSmin), I pushed @Robert K solution a little bit further.

使用“ PHPWee”:https: //github.com/searchturbine/phpwee-php-minifier(也使用JSmin),我进一步推动了@Robert K 解决方案。

This solution allows minifying both CSS and JS files. If the non-minified file cannot be found, it will return an empty string. If the minified file is older than the non-minified, it will try to create it. It will create a sub-folder for the minified file if it doesn't exist. If the method can minify the file successfully, it returns it either in a <script>(javascript) or a <link>(CSS) tag. Otherwise, the method will return the non-minified version in the proper tag.

此解决方案允许缩小 CSS 和 JS 文件。如果找不到非缩小文件,它将返回一个空字符串。如果缩小的文件比未缩小的文件旧,它将尝试创建它。如果它不存在,它将为缩小的文件创建一个子文件夹。如果该方法可以成功缩小文件,它会在<script>(javascript) 或<link>(CSS) 标记中返回它。否则,该方法将在适当的标签中返回非缩小版本。

Note: tested with PHP 7.0.13

注意:使用 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(
                            '',
                            ''
                        ),
                        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)$@',
            $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)$@',
            $path,
            $matches
        )
    ) {
        $script = self::createMinifiedFile($matches, true);

    } else {

        $script = "";
    }

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

In a (Smarty) template, you might use those methods like this:

在 (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>

Unit tests:

单元测试:

/**
* 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
        )
    );
}

Additional notes:

附加说明

  1. In phpwee.phpI had to replace <?by <?php.
  2. I had problems with the namespace (the function class_exists()was not able to find the classes even though they were in the same file). I solved this problem by removing the namespace in every file.
  1. phpwee.php我不得不替换<?<?php.
  2. 我遇到了命名空间问题(class_exists()即使它们在同一个文件中,该函数也无法找到这些类)。我通过删除每个文件中的命名空间解决了这个问题。

回答by Michal - wereda-net

JavaScriptPackerworks since 2008, and is quite simple

JavaScriptPacker自 2008 年开始工作,并且非常简单