打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
对css,js压缩之combo以及七牛cdn的思考

    之前发布的一个JFinal的css,js压缩的Combo Handler:http://www.dreamlu.net/blog/17

    该Handler可按照指定规则压缩并合并js和css,比较常见!淘宝,窝窝团都是采用的类似的方式!之前我也是参看窝窝团研发副总裁的博客才写了这样一个插件

    在强大的BAE2.0的cdn下,不得不承认该Handler还是有一定的效果!在迁移到3.0时,想使用七牛的镜像来做cdn!由于七牛云镜像不支持URL参数,发现之前的Combo Handler完全失效了!被迫开启了2.0的cnd依然使用2.0的来实现加速!

    昨天在github查看express-coffee源码的时候发现了connect-assets插件,这是一个实现类似rails中的asset框架!connect-assets中的源码采用coffee编写,这个我再喜欢不过了!大致的看了下,他是使用的一个模版标签去生成css,js的链接的,我恍然大悟!

    于是,我也采用类似的方法,写了个combo的Jade的模版标签!

    由于我的博分得有前台和后台不能像那些rails一样将所有的js,css压成一个(感觉这样比较浪费),于是多加了一个参数‘assets-web.jcss’,它用来记录这需要合并的js或者css,我对其分别以jcss和jjs的后缀区分!

    用@标记需要合并压缩的css或者js,加一个版本信息是为了更改之后方便重新生成合并压缩后的文件(没有采用对整个需要合并压缩的文件哈希的方式,看官可自行完善)!


    上面是ruby-china的js链接!

    下面是本博Jade模版的标签生成的css链接!这样做的最大好处就是节省请求时间,在第一次请求发现木有此css时则自动根绝规则文件去生成这个css,如果存在,则直接返回路径!如果规则文件被修改该文件的hex值发生改变,也同样会去生成新的css文件!

    最核心的代码:AssetsKit.java (有问题可以骚扰我,欢迎点击osc地址留言!)

    private static final Logger log = Logger.getLogger(AssetsKit.class);\r\n    public static final String CHARSET = "UTF-8";\r\n    public static final String JS_EXT = ".js", CSS_EXT = ".css";\r\n\r\n    /**\r\n     * 压缩css,js\r\n     * @param queryString\r\n     * @param isCss\r\n     * @param out\r\n     * @return\r\n     */\r\n    public static boolean compressorHelper(List fileList, boolean isCss, Writer out) {\r\n        Reader in = null;\r\n        try {\r\n            if (isCss) {\r\n                for (String path : fileList) {\r\n                    in = new InputStreamReader(new FileInputStream(path), CHARSET);\r\n                    if(path.indexOf(".min.") > 0){// 对.min.css的css放弃压缩\r\n                        out.append(IOKit.readerToString(in));\r\n                    }else{\r\n                        CssCompressor css = new CssCompressor(in);\r\n                        in.close(); in = null;\r\n                        css.compress(out, -1);\r\n                    }\r\n                }\r\n            }else{\r\n                // nomunge: 混淆,verbose:显示信息消息和警告,preserveAllSemiColons:保留所有的分号 ,disableOptimizations 禁止优化\r\n                boolean munge = true, verbose = false, preserveAllSemiColons = false, disableOptimizations = false;\r\n                for (String path : fileList) {\r\n                    in = new InputStreamReader(new FileInputStream(path), CHARSET);\r\n                    if(path.indexOf(".min.") > 0){ // 对.min.js的js放弃压缩\r\n                        out.append(IOKit.readerToString(in));\r\n                    }else{\r\n                        JavaScriptCompressor compressor = new JavaScriptCompressor(in, new ErrorReporter() {\r\n                            public void warning(String message, String sourceName,\r\n                                  int line, String lineSource, int lineOffset) {\r\n                                if (line < 0) {\r\n                                    log.error("\\n[WARNING] " + message);\r\n                                } else {\r\n                                    log.error("\\n[WARNING] " + line + ':' + lineOffset + ':' + message);\r\n                                }\r\n                            }\r\n                            public void error(String message, String sourceName,\r\n                                  int line, String lineSource, int lineOffset) {\r\n                                if (line < 0) {\r\n                                    log.error("\\n[ERROR] " + message);\r\n                                } else {\r\n                                    log.error("\\n[ERROR] " + line + ':' + lineOffset + ':' + message);\r\n                                }\r\n                            }\r\n                            public EvaluatorException runtimeError(String message, String sourceName,\r\n                                  int line, String lineSource, int lineOffset) {\r\n                                error(message, sourceName, line, lineSource, lineOffset);\r\n                                return new EvaluatorException(message);\r\n                            }\r\n                        });\r\n                        in.close(); in = null;\r\n                        compressor.compress(out, -1, munge, verbose, preserveAllSemiColons, disableOptimizations);\r\n                    }\r\n                }\r\n            }\r\n            out.flush();\r\n            return true;\r\n        }catch(IOException e){\r\n            e.printStackTrace();\r\n            log.error(e);\r\n            return false;\r\n        }finally{\r\n            IOUtils.closeQuietly(in);\r\n            IOUtils.closeQuietly(out);\r\n        }\r\n    }\r\n    \r\n    @SuppressWarnings("unchecked")\r\n    public static String combo(String fileName) {\r\n//         String fileName = "/assets/assets-web.jcss";\r\n//         String fileName = "/assets/assets-web.jjs";\r\n        String rootPath = PathKit.getWebRootPath();\r\n        String comboName = fileName.substring(0, fileName.indexOf(".")); // /assets/assets-web\r\n        \r\n        Writer out = null;\r\n        try {\r\n             // 读取文件中的js或者css路径\r\n             List list = FileUtils.readLines(new File(rootPath + fileName), CHARSET);\r\n             List comboList = Lists.newArrayList(); // 文件路基\r\n             StringBuilder sb = new StringBuilder(); // 文件内容\r\n             for (String string : list) {\r\n                 if (string.startsWith("@")) {\r\n                     comboList.add(PathKit.getWebRootPath() + string.substring(1, string.length()));\r\n                 }\r\n                 sb.append(string);\r\n             }\r\n            // 文件内容hex\r\n             String hex = DigestUtils.md5Hex(sb.toString()); // 为了方便没有md5整个文件集\r\n             \r\n             boolean isCss = true;\r\n             if (fileName.endsWith(".jjs")) {\r\n                 isCss = false;\r\n             }\r\n             \r\n             String newFileName = comboName + "-"  + hex + (isCss ? CSS_EXT : JS_EXT);\r\n             \r\n             String newPath = rootPath + newFileName;\r\n             File file = new File(newPath);\r\n             \r\n             boolean temp = file.exists();\r\n             if (temp) {\r\n                 return newFileName;\r\n             }\r\n         \r\n            out  = new OutputStreamWriter(new FileOutputStream(newPath), CHARSET);\r\n            compressorHelper(comboList, isCss, out);\r\n            \r\n            return newFileName;\r\n        } catch (UnsupportedEncodingException e) {\r\n            e.printStackTrace();\r\n        } catch (FileNotFoundException e) {\r\n            e.printStackTrace();\r\n        } catch (IOException e) {\r\n            e.printStackTrace();\r\n        }finally{\r\n            IOUtils.closeQuietly(out);\r\n        }\r\n        return null;\r\n    }

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
前端优化:淘宝的Combo Handler和新浪微博的link标签includes属性
在服务端合并和压缩JavaScript和CSS文件 @ 随网之舞
python测试开发django-113.使用Bootstrap框架
webpack打包首页如何优化及路由懒加载?本文详解
Flask-加载静态文件
前端工程与性能优化(下):静态资源管理与模板框架
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服