全模式下的后台编译less


前言-吐槽

之前的一篇blog ([less前台调试环境的选择]({{ page_url 2012-05-07-less前台调试环境的选择.md }}))中提到了之前使用的在前端编译less,在不同的浏览器的执行效率有很大的不同

除了页面的css加载慢而影响调试者的心情之外还会导致$(windows).load的触发时间大幅的波动…..

在调试代码的时候发现很多时候,基于加载完图片的重排页面的js代码不起作用;或者变成了很奇怪的触发时间….

怀疑到了less的实时编译上来了…..

查询测试确实是不同浏览器编译时间不同导致的问题,直接加载css的话就不会出现这些问题

最后不得已只能另寻方法,好在已经有了一个神器:lessphp (官网) (直接下载)

有了这个之后我们就可以简单的在后台编译好less->;css,再把css流返回给浏览器了~

简单的使用看看document(英文)就好了..虽然很长

使用后台编译的优点:

  1. 规避浏览器兼容问题
  2. 可以缓存数据,避免每次都编译
  3. 根据文件最后修改时间重新编译
  4. 后端隐藏,实际环境无法分辨是原生css还是less
  5. 开发与正式环境统一

缺点:

  1. 无法直观的调试less代码

说明

下面重点讲讲我在项目上的具体应用吧.

lessphp提供了一个很好的函数: cachedCompile,这个函数接收一编译后数组,并判断包含的文件是否有更新,然后返回直接/重新编译的数组

基本上这个函数做了我们想做的全部事情,检查less文件是否有更新,有更新则重新编译,并且定义了一个保存和检查less文件的数组结构体

我们要做的就是对这个函数进行外部的封装,将这个php的数组放在cache文件中,然后压缩什么的也一并支持上.

具体的功能都写在注释里面了:

<?php
//引入编译文件 就这一个
require "lessc.inc.php";
//配置缓存文件名,默认保存当前目录
$cacheFile = "main.cache";
//获取传来的要编译less文件路径,给个默认值啥的
$inputFile = isset($_GET['path']) ? $_GET['path'] : "main.less";
//检查缓存文件
if (file_exists($cacheFile)) {
     $cache = json_decode(file_get_contents($cacheFile), true);
} else {
     $cache = $inputFile;
}
$less = new lessc;
//这里默认压缩css(去掉注释啥的)
$less ->; setFormatter("compressed");
//最核心(唯一的)关键函数调用
$newCache = $less ->; cachedCompile($cache);
//检查获取情况
if (!is_array($cache) || $newCache["updated"] >; $cache["updated"]) {
    $newCache['compiled'] = $newCache['compiled'];
    //有更新的话写回到缓存文件
    file_put_contents($cacheFile, json_encode($newCache));
}
$output =$newCache['compiled'];
//向前台输出,设置header为css
header('Content-type: text/css');
echo $output;
//保证退出执行
exit ;
?>

编译之后的css文件已经可以应用到实际部署环境了.

更新

上面的代码已经不错了,不过我们希望能再有点功能

下面代码增加了输出是谁在编译这段less和启用gzip压缩回传数据的功能

大部分代码都是相同的:(只注释了关键的修改部分)

<?php
require "lessc.inc.php";
$cacheFile = "main.cache";
$inputFile = isset($_GET['path']) ? $_GET['path'] : "main.less";
if (file_exists($cacheFile)) {
     $cache = json_decode(file_get_contents($cacheFile), true);
} else {
     $cache = $inputFile;
}
$less = new lessc;
$less ->; setFormatter("compressed");
$newCache = $less ->; cachedCompile($cache);
if (!is_array($cache) || $newCache["updated"] >; $cache["updated"]) {
    //增加版权啊时间啊等信息
    $newCache['compiled'] = "/* Less Server OF ZZJIN's Powered By lessPHP */" . $newCache['compiled'];
    //增加gz方法 json_encode之前base64一下才能写入 (::)
    $newCache['compiled'] = base64_encode(gzencode($newCache['compiled']));
    file_put_contents($cacheFile, json_encode($newCache));
}
//导出的时候decode一下
$output = base64_decode($newCache['compiled']);
header('Content-type: text/css');
//写入header,通知浏览器是gzip之后的数据
header('Content-Encoding: gzip');
echo $output;
exit ;
?>

细心的人可能会注意到我在新的gz之后的代码做了一层bas64编解码,原因在于gzencode之后的代码是二进制的,不被json_encode支持,需要转换成别的字符结构的代码才能正确的写入文件缓存中

到此,整个(编译/缓存/重编译)的流程和逻辑都完整了

最后给出一个最小限度修改已有代码结构的使用方法:

  • 把这段代码保存为buildCss.php,再和官网下载的lessc.inc.php一起放在现有结构的less文件夹处
  • 然后修改前端的所有的less地址到buildCss.php?path=less/name .比如,修改之前less加载位置为:"/Public/Less/main.less",修改后为:"/Public/Less/buildCss.php?path=main.less"

当然,也可以通过各个web服务器的rewrite方式把所有的less重定向到php所在位置

进一步的改进:

  1. 支持编译多个less文件到一个css(易实现)
  2. 支持编译错误的返回提示(较难直观在页面表现)

如果有更好的想法~非常欢迎留言交流~

文章原创 链接地址:[原文地址]({{ page.url }})

comments powered by Disqus