【问题标题】:How to minify JS in PHP easily...Or something else如何轻松地在 PHP 中缩小 JS ......或其他
【发布时间】:2012-06-15 13:08:59
【问题描述】:

我已经环顾四周了,但我还是有点困惑。

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

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

之所以会这样,是因为: 我有 2 个文件(例如)正在处理:scripts.js 和 scripts_template.js

scripts_template 是我写出的普通代码——然后我必须将其缩小并将缩小后的脚本粘贴到 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 类...有没有猴子可以理解的东西,也许是正则表达式?

我们如何让这更简单?

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

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

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

【问题讨论】:

标签: php javascript minify


【解决方案1】:

JavaScriptPacker 从 2008 年开始工作,非常简单

【讨论】:

    【解决方案2】:

    使用“PHPWee”:https://github.com/searchturbine/phpwee-php-minifier (也使用JSmin),我将@Robert K 解决方案推得更远一点。

    此解决方案允许缩小 CSS 和 JS 文件。如果找不到非缩小文件,它将返回一个空字符串。如果缩小文件比非缩小文件旧,它将尝试创建它。如果压缩文件不存在,它将为压缩文件创建一个子文件夹。如果该方法可以成功地缩小文件,它会在 &lt;script&gt; (javascript) 或 &lt;link&gt; (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)$@',
                $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>'
        );
    }
    

    在 (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
            )
        );
    }
    

    补充说明

    1. phpwee.php 中,我必须将&lt;? 替换为&lt;?php
    2. 我的命名空间有问题(函数class_exists() 无法找到这些类,即使它们在同一个文件中)。我通过删除每个文件中的命名空间解决了这个问题。

    【讨论】:

      【解决方案3】:

      我已经使用Douglas CrockfordPHP implementation 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;
      }
      

      【讨论】:

      • 我尝试使用它,但它并没有缩小整个代码。事实上,它在脚本中途削减了代码,所以我正处于 for() 循环的中间,这无论如何都会导致脚本损坏。
      • @RickyAYoder 是否有任何通知或错误输出?这可能是您的 Javascript 中的语法错误。
      • 不。当我运行手工制作且未缩小的脚本时,不会报告任何错误。
      • 另外请注意,除非他们这样说,否则这些包通常不支持 getter/setter。如果你的环境中确实有 Node.js,我建议改用 UglifyJS
      • 我对我的一个源文件进行了测试。 jsmin:(46,385 => 26,031 字节)。 JShrink:(463,85->26,027 字节)。非常相似的表现。但是,javascript-minifier.com 将其缩小到 19,526 字节,因为它用较短的版本替换了长变量名。
      【解决方案4】:

      根据您的服务器的限制(例如,不在safe mode 中运行),也许您还可以在PHP 之外寻找一个缩小器并使用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”文件夹中。像魅力一样工作。

      【讨论】:

      • 为一个小型实用程序启动一个 JAVA 应用程序对我来说似乎是一个巨大的膨胀。不可能按照 OP 的要求将此解决方案放入请求-响应流中。
      • 您所说的并不完全适用于 Java 应用程序。对于任何实用程序,重新缩小每个请求都是不必要的费用。注意Robert-K's earlier advice 缓存结果或我的“其他建议”,将其移动到自动构建步骤中。现在,三年后,无论如何,有比 YUI 更好的缩小选择。
      【解决方案5】:

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

      https://github.com/kriswallsmith/assetic

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-27
        • 1970-01-01
        相关资源
        最近更新 更多